зеркало из https://github.com/mozilla/gecko-dev.git
Merge with m-c fd478c02c29c
This commit is contained in:
Коммит
56609ba3d8
|
@ -13,11 +13,11 @@ ID
|
|||
.*.sw[a-z]
|
||||
|
||||
# User files that may appear at the root
|
||||
.mozconfig
|
||||
mozconfig
|
||||
configure
|
||||
config.cache
|
||||
config.log
|
||||
/.mozconfig*
|
||||
/mozconfig
|
||||
/configure
|
||||
/config.cache
|
||||
/config.log
|
||||
|
||||
# Empty marker file that's generated when we check out NSS
|
||||
security/manager/.nss.checkout
|
||||
|
|
|
@ -52,7 +52,6 @@ import sys
|
|||
import threading
|
||||
import tempfile
|
||||
import sqlite3
|
||||
import zipfile
|
||||
|
||||
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
|
@ -98,69 +97,6 @@ _log.setLevel(logging.INFO)
|
|||
_log.addHandler(handler)
|
||||
|
||||
|
||||
class ZipFileReader(object):
|
||||
"""
|
||||
Class to read zip files in Python 2.5 and later. Limited to only what we
|
||||
actually use.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
self._zipfile = zipfile.ZipFile(filename, "r")
|
||||
|
||||
def __del__(self):
|
||||
self._zipfile.close()
|
||||
|
||||
def _getnormalizedpath(self, path):
|
||||
"""
|
||||
Gets a normalized path from 'path' (or the current working directory if
|
||||
'path' is None). Also asserts that the path exists.
|
||||
"""
|
||||
if path is None:
|
||||
path = os.curdir
|
||||
path = os.path.normpath(os.path.expanduser(path))
|
||||
assert os.path.isdir(path)
|
||||
return path
|
||||
|
||||
def _extractname(self, name, path):
|
||||
"""
|
||||
Extracts a file with the given name from the zip file to the given path.
|
||||
Also creates any directories needed along the way.
|
||||
"""
|
||||
filename = os.path.normpath(os.path.join(path, name))
|
||||
if name.endswith("/"):
|
||||
os.makedirs(filename)
|
||||
else:
|
||||
path = os.path.split(filename)[0]
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
with open(filename, "wb") as dest:
|
||||
dest.write(self._zipfile.read(name))
|
||||
|
||||
def namelist(self):
|
||||
return self._zipfile.namelist()
|
||||
|
||||
def read(self, name):
|
||||
return self._zipfile.read(name)
|
||||
|
||||
def extract(self, name, path = None):
|
||||
if hasattr(self._zipfile, "extract"):
|
||||
return self._zipfile.extract(name, path)
|
||||
|
||||
# This will throw if name is not part of the zip file.
|
||||
self._zipfile.getinfo(name)
|
||||
|
||||
self._extractname(name, self._getnormalizedpath(path))
|
||||
|
||||
def extractall(self, path = None):
|
||||
if hasattr(self._zipfile, "extractall"):
|
||||
return self._zipfile.extractall(path)
|
||||
|
||||
path = self._getnormalizedpath(path)
|
||||
|
||||
for name in self._zipfile.namelist():
|
||||
self._extractname(name, path)
|
||||
|
||||
|
||||
#################
|
||||
# PROFILE SETUP #
|
||||
#################
|
||||
|
@ -1053,7 +989,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
|||
os.makedirs(extensionsRootDir)
|
||||
|
||||
if os.path.isfile(extensionSource):
|
||||
reader = ZipFileReader(extensionSource)
|
||||
reader = automationutils.ZipFileReader(extensionSource)
|
||||
|
||||
for filename in reader.namelist():
|
||||
# Sanity check the zip file.
|
||||
|
|
|
@ -36,11 +36,13 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
import glob, logging, os, platform, shutil, subprocess, sys
|
||||
from __future__ import with_statement
|
||||
import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile
|
||||
import re
|
||||
from urlparse import urlparse
|
||||
|
||||
__all__ = [
|
||||
"ZipFileReader",
|
||||
"addCommonOptions",
|
||||
"checkForCrashes",
|
||||
"dumpLeakLog",
|
||||
|
@ -70,6 +72,68 @@ DEBUGGER_INFO = {
|
|||
}
|
||||
}
|
||||
|
||||
class ZipFileReader(object):
|
||||
"""
|
||||
Class to read zip files in Python 2.5 and later. Limited to only what we
|
||||
actually use.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
self._zipfile = zipfile.ZipFile(filename, "r")
|
||||
|
||||
def __del__(self):
|
||||
self._zipfile.close()
|
||||
|
||||
def _getnormalizedpath(self, path):
|
||||
"""
|
||||
Gets a normalized path from 'path' (or the current working directory if
|
||||
'path' is None). Also asserts that the path exists.
|
||||
"""
|
||||
if path is None:
|
||||
path = os.curdir
|
||||
path = os.path.normpath(os.path.expanduser(path))
|
||||
assert os.path.isdir(path)
|
||||
return path
|
||||
|
||||
def _extractname(self, name, path):
|
||||
"""
|
||||
Extracts a file with the given name from the zip file to the given path.
|
||||
Also creates any directories needed along the way.
|
||||
"""
|
||||
filename = os.path.normpath(os.path.join(path, name))
|
||||
if name.endswith("/"):
|
||||
os.makedirs(filename)
|
||||
else:
|
||||
path = os.path.split(filename)[0]
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
with open(filename, "wb") as dest:
|
||||
dest.write(self._zipfile.read(name))
|
||||
|
||||
def namelist(self):
|
||||
return self._zipfile.namelist()
|
||||
|
||||
def read(self, name):
|
||||
return self._zipfile.read(name)
|
||||
|
||||
def extract(self, name, path = None):
|
||||
if hasattr(self._zipfile, "extract"):
|
||||
return self._zipfile.extract(name, path)
|
||||
|
||||
# This will throw if name is not part of the zip file.
|
||||
self._zipfile.getinfo(name)
|
||||
|
||||
self._extractname(name, self._getnormalizedpath(path))
|
||||
|
||||
def extractall(self, path = None):
|
||||
if hasattr(self._zipfile, "extractall"):
|
||||
return self._zipfile.extractall(path)
|
||||
|
||||
path = self._getnormalizedpath(path)
|
||||
|
||||
for name in self._zipfile.namelist():
|
||||
self._extractname(name, path)
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
def isURL(thing):
|
||||
|
@ -102,7 +166,6 @@ def addCommonOptions(parser, defaults={}):
|
|||
|
||||
def checkForCrashes(dumpDir, symbolsPath, testName=None):
|
||||
stackwalkPath = os.environ.get('MINIDUMP_STACKWALK', None)
|
||||
stackwalkCGI = os.environ.get('MINIDUMP_STACKWALK_CGI', None)
|
||||
# try to get the caller's filename if no test name is given
|
||||
if testName is None:
|
||||
try:
|
||||
|
@ -110,70 +173,70 @@ def checkForCrashes(dumpDir, symbolsPath, testName=None):
|
|||
except:
|
||||
testName = "unknown"
|
||||
|
||||
foundCrash = False
|
||||
# Check preconditions
|
||||
dumps = glob.glob(os.path.join(dumpDir, '*.dmp'))
|
||||
for d in dumps:
|
||||
log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
|
||||
print "Crash dump filename: " + d
|
||||
if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
|
||||
p = subprocess.Popen([stackwalkPath, d, symbolsPath],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(out, err) = p.communicate()
|
||||
if len(out) > 3:
|
||||
# minidump_stackwalk is chatty, so ignore stderr when it succeeds.
|
||||
print out
|
||||
else:
|
||||
print "stderr from minidump_stackwalk:"
|
||||
print err
|
||||
if p.returncode != 0:
|
||||
print "minidump_stackwalk exited with return code %d" % p.returncode
|
||||
elif stackwalkCGI and symbolsPath and isURL(symbolsPath):
|
||||
f = None
|
||||
try:
|
||||
f = open(d, "rb")
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "poster.zip"))
|
||||
from poster.encode import multipart_encode
|
||||
from poster.streaminghttp import register_openers
|
||||
import urllib2
|
||||
register_openers()
|
||||
datagen, headers = multipart_encode({"minidump": f,
|
||||
"symbols": symbolsPath})
|
||||
request = urllib2.Request(stackwalkCGI, datagen, headers)
|
||||
result = urllib2.urlopen(request).read()
|
||||
if len(result) > 3:
|
||||
print result
|
||||
if len(dumps) == 0:
|
||||
return False
|
||||
|
||||
foundCrash = False
|
||||
removeSymbolsPath = False
|
||||
|
||||
# If our symbols are at a remote URL, download them now
|
||||
if isURL(symbolsPath):
|
||||
print "Downloading symbols from: " + symbolsPath
|
||||
removeSymbolsPath = True
|
||||
# Get the symbols and write them to a temporary zipfile
|
||||
data = urllib2.urlopen(symbolsPath)
|
||||
symbolsFile = tempfile.TemporaryFile()
|
||||
symbolsFile.write(data.read())
|
||||
# extract symbols to a temporary directory (which we'll delete after
|
||||
# processing all crashes)
|
||||
symbolsPath = tempfile.mkdtemp()
|
||||
zfile = ZipFileReader(symbolsFile)
|
||||
zfile.extractall(symbolsPath)
|
||||
|
||||
try:
|
||||
for d in dumps:
|
||||
log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
|
||||
print "Crash dump filename: " + d
|
||||
if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
|
||||
# run minidump stackwalk
|
||||
p = subprocess.Popen([stackwalkPath, d, symbolsPath],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(out, err) = p.communicate()
|
||||
if len(out) > 3:
|
||||
# minidump_stackwalk is chatty, so ignore stderr when it succeeds.
|
||||
print out
|
||||
else:
|
||||
print "stackwalkCGI returned nothing."
|
||||
finally:
|
||||
if f:
|
||||
f.close()
|
||||
else:
|
||||
if not symbolsPath:
|
||||
print "No symbols path given, can't process dump."
|
||||
if not stackwalkPath and not stackwalkCGI:
|
||||
print "Neither MINIDUMP_STACKWALK nor MINIDUMP_STACKWALK_CGI is set, can't process dump."
|
||||
print "stderr from minidump_stackwalk:"
|
||||
print err
|
||||
if p.returncode != 0:
|
||||
print "minidump_stackwalk exited with return code %d" % p.returncode
|
||||
else:
|
||||
if stackwalkPath and not os.path.exists(stackwalkPath):
|
||||
if not symbolsPath:
|
||||
print "No symbols path given, can't process dump."
|
||||
if not stackwalkPath:
|
||||
print "MINIDUMP_STACKWALK not set, can't process dump."
|
||||
elif stackwalkPath and not os.path.exists(stackwalkPath):
|
||||
print "MINIDUMP_STACKWALK binary not found: %s" % stackwalkPath
|
||||
elif stackwalkCGI and not isURL(stackwalkCGI):
|
||||
print "MINIDUMP_STACKWALK_CGI is not a URL: %s" % stackwalkCGI
|
||||
elif symbolsPath and not isURL(symbolsPath):
|
||||
print "symbolsPath is not a URL: %s" % symbolsPath
|
||||
dumpSavePath = os.environ.get('MINIDUMP_SAVE_PATH', None)
|
||||
if dumpSavePath:
|
||||
shutil.move(d, dumpSavePath)
|
||||
print "Saved dump as %s" % os.path.join(dumpSavePath,
|
||||
os.path.basename(d))
|
||||
else:
|
||||
os.remove(d)
|
||||
extra = os.path.splitext(d)[0] + ".extra"
|
||||
if os.path.exists(extra):
|
||||
os.remove(extra)
|
||||
foundCrash = True
|
||||
dumpSavePath = os.environ.get('MINIDUMP_SAVE_PATH', None)
|
||||
if dumpSavePath:
|
||||
shutil.move(d, dumpSavePath)
|
||||
print "Saved dump as %s" % os.path.join(dumpSavePath,
|
||||
os.path.basename(d))
|
||||
else:
|
||||
os.remove(d)
|
||||
extra = os.path.splitext(d)[0] + ".extra"
|
||||
if os.path.exists(extra):
|
||||
os.remove(extra)
|
||||
foundCrash = True
|
||||
finally:
|
||||
if removeSymbolsPath:
|
||||
shutil.rmtree(symbolsPath)
|
||||
|
||||
return foundCrash
|
||||
|
||||
|
||||
def getFullPath(directory, path):
|
||||
"Get an absolute path relative to 'directory'."
|
||||
return os.path.normpath(os.path.join(directory, os.path.expanduser(path)))
|
||||
|
|
Двоичные данные
build/poster.zip
Двоичные данные
build/poster.zip
Двоичный файл не отображается.
|
@ -1954,6 +1954,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
if (tmp->mAnimationController) {
|
||||
tmp->mAnimationController->Unlink();
|
||||
}
|
||||
|
||||
tmp->mPendingTitleChangeEvent.Revoke();
|
||||
|
||||
tmp->mInUnlinkOrDeletion = false;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
|
|
@ -427,7 +427,7 @@ nsSVGPathElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
gfxFloat
|
||||
nsSVGPathElement::GetScale()
|
||||
nsSVGPathElement::GetPathLengthScale()
|
||||
{
|
||||
if (mPathLength.IsExplicitlySet()) {
|
||||
|
||||
|
|
|
@ -98,7 +98,12 @@ public:
|
|||
return nsGkAtoms::d;
|
||||
}
|
||||
|
||||
gfxFloat GetScale();
|
||||
/**
|
||||
* Gets the ratio of the actual path length to the content author's estimated
|
||||
* length (as provided by the <path> element's 'pathLength' attribute). This
|
||||
* is used to scale stroke dashing, and to scale offsets along a textPath.
|
||||
*/
|
||||
gfxFloat GetPathLengthScale();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -287,16 +287,27 @@ nsDOMStorageManager::Initialize()
|
|||
if (!os)
|
||||
return NS_OK;
|
||||
|
||||
os->AddObserver(gStorageManager, "cookie-changed", false);
|
||||
os->AddObserver(gStorageManager, "offline-app-removed", false);
|
||||
os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
|
||||
os->AddObserver(gStorageManager, "profile-after-change", false);
|
||||
os->AddObserver(gStorageManager, "perm-changed", false);
|
||||
os->AddObserver(gStorageManager, "browser:purge-domain-data", false);
|
||||
nsresult rv;
|
||||
rv = os->AddObserver(gStorageManager, "cookie-changed", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, "offline-app-removed", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC,
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, "profile-after-change", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, "perm-changed", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, "browser:purge-domain-data", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Used for temporary table flushing
|
||||
os->AddObserver(gStorageManager, "profile-before-change", false);
|
||||
os->AddObserver(gStorageManager, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
os->AddObserver(gStorageManager, NS_DOMSTORAGE_FLUSH_TIMER_TOPIC, false);
|
||||
rv = os->AddObserver(gStorageManager, "profile-before-change", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = os->AddObserver(gStorageManager, NS_DOMSTORAGE_FLUSH_TIMER_TOPIC, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1095,7 +1095,9 @@ abstract public class GeckoApp
|
|||
} catch (Exception e) {
|
||||
Log.e(LOG_NAME, "top level exception", e);
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.flush();
|
||||
GeckoAppShell.reportJavaCrash(sw.toString());
|
||||
}
|
||||
// resetting this is kinda pointless, but oh well
|
||||
|
|
|
@ -346,7 +346,7 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
|
|||
|
||||
// If animation mode is "loop once", it's time to stop animating
|
||||
if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) {
|
||||
mAnimationFinished = PR_TRUE;
|
||||
mAnimationFinished = true;
|
||||
EvaluateAnimation();
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
|
|||
}
|
||||
|
||||
if (!(timeout > 0)) {
|
||||
mAnimationFinished = PR_TRUE;
|
||||
mAnimationFinished = true;
|
||||
EvaluateAnimation();
|
||||
}
|
||||
|
||||
|
@ -404,13 +404,13 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
|
|||
nextFrame, nextFrameIndex))) {
|
||||
// something went wrong, move on to next
|
||||
NS_WARNING("RasterImage::AdvanceFrame(): Compositing of frame failed");
|
||||
nextFrame->SetCompositingFailed(PR_TRUE);
|
||||
nextFrame->SetCompositingFailed(true);
|
||||
mAnim->currentAnimationFrameIndex = nextFrameIndex;
|
||||
mAnim->currentAnimationFrameTime = aTime;
|
||||
return false;
|
||||
}
|
||||
|
||||
nextFrame->SetCompositingFailed(PR_FALSE);
|
||||
nextFrame->SetCompositingFailed(false);
|
||||
}
|
||||
|
||||
// Set currentAnimationFrameIndex at the last possible moment
|
||||
|
|
|
@ -124,10 +124,10 @@ jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
void* hookData;
|
||||
|
||||
if( ! jsdc || ! jsdc->inited )
|
||||
return JSD_HOOK_RETURN_CONTINUE_THROW;
|
||||
return JSTRAP_CONTINUE;
|
||||
|
||||
if( JSD_IS_DANGEROUS_THREAD(jsdc) )
|
||||
return JSD_HOOK_RETURN_CONTINUE_THROW;
|
||||
return JSTRAP_CONTINUE;
|
||||
|
||||
/* local in case jsdc->throwHook gets cleared on another thread */
|
||||
JSD_LOCK();
|
||||
|
@ -135,13 +135,13 @@ jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
hookData = jsdc->throwHookData;
|
||||
JSD_UNLOCK();
|
||||
if (!hook)
|
||||
return JSD_HOOK_RETURN_CONTINUE_THROW;
|
||||
return JSTRAP_CONTINUE;
|
||||
|
||||
JSD_LOCK_SCRIPTS(jsdc);
|
||||
jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, NULL);
|
||||
JSD_UNLOCK_SCRIPTS(jsdc);
|
||||
if( ! jsdscript )
|
||||
return JSD_HOOK_RETURN_CONTINUE_THROW;
|
||||
return JSTRAP_CONTINUE;
|
||||
|
||||
JS_GetPendingException(cx, rval);
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
#include "nsImageFrame.h"
|
||||
#include "nsRenderingContext.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -470,6 +472,27 @@ FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer()
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
FrameLayerBuilder::FlashPaint(gfxContext *aContext)
|
||||
{
|
||||
static bool sPaintFlashingEnabled;
|
||||
static bool sPaintFlashingPrefCached = false;
|
||||
|
||||
if (!sPaintFlashingPrefCached) {
|
||||
sPaintFlashingPrefCached = true;
|
||||
mozilla::Preferences::AddBoolVarCache(&sPaintFlashingEnabled,
|
||||
"nglayout.debug.paint_flashing");
|
||||
}
|
||||
|
||||
if (sPaintFlashingEnabled) {
|
||||
float r = float(rand()) / RAND_MAX;
|
||||
float g = float(rand()) / RAND_MAX;
|
||||
float b = float(rand()) / RAND_MAX;
|
||||
aContext->SetColor(gfxRGBA(r, g, b, 0.2));
|
||||
aContext->Paint();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ nsTArray<FrameLayerBuilder::DisplayItemData>*
|
||||
FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -2127,6 +2150,8 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
|||
if (setClipRect) {
|
||||
aContext->Restore();
|
||||
}
|
||||
|
||||
FlashPaint(aContext);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -441,6 +441,9 @@ protected:
|
|||
// LayerManagerData needs to see DisplayItemDataEntry.
|
||||
friend class LayerManagerData;
|
||||
|
||||
// Flash the area within the context clip if paint flashing is enabled.
|
||||
static void FlashPaint(gfxContext *aContext);
|
||||
|
||||
/*
|
||||
* Get the DisplayItemData array associated with this frame, or null if one
|
||||
* doesn't exist.
|
||||
|
|
|
@ -120,7 +120,8 @@ nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat **aDashes, PRUint32 *aCount)
|
|||
gfxFloat pathScale = 1.0;
|
||||
|
||||
if (mContent->Tag() == nsGkAtoms::path) {
|
||||
pathScale = static_cast<nsSVGPathElement*>(mContent)->GetScale();
|
||||
pathScale =
|
||||
static_cast<nsSVGPathElement*>(mContent)->GetPathLengthScale();
|
||||
if (pathScale <= 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -751,7 +751,7 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
|
|||
if (!aCharacterPositions->SetLength(strLength))
|
||||
return false;
|
||||
|
||||
gfxFloat pathScale = textPath->GetPathScale();
|
||||
gfxFloat pathScale = textPath->GetOffsetScale();
|
||||
|
||||
CharacterPosition *cp = aCharacterPositions->Elements();
|
||||
|
||||
|
@ -877,7 +877,7 @@ nsSVGGlyphFrame::GetSubStringAdvance(PRUint32 aCharnum,
|
|||
gfxFloat pathScale = 1.0;
|
||||
nsSVGTextPathFrame *textPath = FindTextPathParent();
|
||||
if (textPath)
|
||||
pathScale = textPath->GetPathScale();
|
||||
pathScale = textPath->GetOffsetScale();
|
||||
if (dxcount > aFragmentChars)
|
||||
dxcount = aFragmentChars;
|
||||
for (PRUint32 i = aCharnum; i < dxcount; i++) {
|
||||
|
@ -1101,7 +1101,7 @@ nsSVGGlyphFrame::SetGlyphPosition(gfxPoint *aPosition, bool aForceGlobalTransfor
|
|||
|
||||
gfxFloat pathScale = 1.0;
|
||||
if (textPath)
|
||||
pathScale = textPath->GetPathScale();
|
||||
pathScale = textPath->GetOffsetScale();
|
||||
|
||||
nsTArray<float> dxList, dyList;
|
||||
GetEffectiveDxDy(strLength, dxList, dyList);
|
||||
|
|
|
@ -166,17 +166,18 @@ nsSVGTextPathFrame::GetStartOffset()
|
|||
nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath();
|
||||
return data ? (val * data->GetLength() / 100.0) : 0.0;
|
||||
}
|
||||
return val * GetPathScale();
|
||||
return val * GetOffsetScale();
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
nsSVGTextPathFrame::GetPathScale()
|
||||
nsSVGTextPathFrame::GetOffsetScale()
|
||||
{
|
||||
nsIFrame *pathFrame = GetPathFrame();
|
||||
if (!pathFrame)
|
||||
return 1.0;
|
||||
|
||||
return static_cast<nsSVGPathElement*>(pathFrame->GetContent())->GetScale();
|
||||
return static_cast<nsSVGPathElement*>(pathFrame->GetContent())->
|
||||
GetPathLengthScale();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -84,8 +84,20 @@ public:
|
|||
already_AddRefed<gfxFlattenedPath> GetFlattenedPath();
|
||||
nsIFrame *GetPathFrame();
|
||||
|
||||
/**
|
||||
* Gets the scale by which offsets along this textPath must be scaled. This
|
||||
* scaling is due to the user provided 'pathLength' attribute on the <path>
|
||||
* element, which is a user provided estimate of the path length.
|
||||
*/
|
||||
gfxFloat GetOffsetScale();
|
||||
|
||||
/**
|
||||
* Gets the offset from the start of the path at which the first character
|
||||
* should be positioned. The value returned already takes GetOffsetScale
|
||||
* into account.
|
||||
*/
|
||||
gfxFloat GetStartOffset();
|
||||
gfxFloat GetPathScale();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY);
|
||||
|
|
|
@ -84,7 +84,6 @@ _HARNESS_FILES = \
|
|||
$(topsrcdir)/build/mobile/devicemanagerADB.py \
|
||||
$(topsrcdir)/build/mobile/devicemanagerSUT.py \
|
||||
$(topsrcdir)/build/automationutils.py \
|
||||
$(topsrcdir)/build/poster.zip \
|
||||
$(topsrcdir)/build/mobile/remoteautomation.py \
|
||||
$(topsrcdir)/testing/mochitest/server.js \
|
||||
$(topsrcdir)/build/pgo/server-locations.txt \
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Hyatt <hyatt@mozilla.org> (Original Author)
|
||||
* Jan Varga <varga@ku.sk>
|
||||
* Scott Johnson <sjohnson@mozilla.com>, Mozilla Corporation
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsITreeImageListener_h__
|
||||
#define nsITreeImageListener_h__
|
||||
|
||||
// The interface for our image listener.
|
||||
// {90586540-2D50-403e-8DCE-981CAA778444}
|
||||
#define NS_ITREEIMAGELISTENER_IID \
|
||||
{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } }
|
||||
|
||||
class nsITreeImageListener : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITREEIMAGELISTENER_IID)
|
||||
|
||||
NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol) = 0;
|
||||
|
||||
/**
|
||||
* Clear the internal frame pointer to prevent dereferencing an object
|
||||
* that no longer exists.
|
||||
*/
|
||||
NS_IMETHOD ClearFrame() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsITreeImageListener, NS_ITREEIMAGELISTENER_IID)
|
||||
|
||||
#endif
|
|
@ -2157,9 +2157,11 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, bool aUseContex
|
|||
// We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
|
||||
nsCOMPtr<imgIDecoderObserver> obs;
|
||||
imgReq->GetDecoderObserver(getter_AddRefs(obs));
|
||||
nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
|
||||
if (listener)
|
||||
listener->AddCell(aRowIndex, aCol);
|
||||
|
||||
if (obs) {
|
||||
static_cast<nsTreeImageListener*> (obs.get())->AddCell(aRowIndex, aCol);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
#include "nsScrollbarFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "nsITreeImageListener.h"
|
||||
|
||||
class nsOverflowChecker;
|
||||
class nsTreeImageListener;
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "imgIRequest.h"
|
||||
#include "imgIContainer.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver, nsITreeImageListener)
|
||||
NS_IMPL_ISUPPORTS2(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver)
|
||||
|
||||
nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame)
|
||||
: mTreeFrame(aTreeFrame),
|
||||
|
@ -92,7 +92,7 @@ NS_IMETHODIMP nsTreeImageListener::FrameChanged(imgIContainer *aContainer,
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
void
|
||||
nsTreeImageListener::AddCell(PRInt32 aIndex, nsITreeColumn* aCol)
|
||||
{
|
||||
if (!mInvalidationArea) {
|
||||
|
@ -114,8 +114,6 @@ nsTreeImageListener::AddCell(PRInt32 aIndex, nsITreeColumn* aCol)
|
|||
mInvalidationArea->AddRow(aIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,10 +45,9 @@
|
|||
#include "nsITreeColumns.h"
|
||||
#include "nsStubImageDecoderObserver.h"
|
||||
#include "nsTreeBodyFrame.h"
|
||||
#include "nsITreeImageListener.h"
|
||||
|
||||
// This class handles image load observation.
|
||||
class nsTreeImageListener : public nsStubImageDecoderObserver, public nsITreeImageListener
|
||||
class nsTreeImageListener : public nsStubImageDecoderObserver
|
||||
{
|
||||
public:
|
||||
nsTreeImageListener(nsTreeBodyFrame *aTreeFrame);
|
||||
|
@ -64,7 +63,6 @@ public:
|
|||
NS_IMETHOD FrameChanged(imgIContainer *aContainer,
|
||||
const nsIntRect *aDirtyRect);
|
||||
|
||||
NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol);
|
||||
NS_IMETHOD ClearFrame();
|
||||
|
||||
friend class nsTreeBodyFrame;
|
||||
|
@ -72,6 +70,7 @@ public:
|
|||
protected:
|
||||
void UnsuppressInvalidation() { mInvalidationSuppressed = false; }
|
||||
void Invalidate();
|
||||
void AddCell(PRInt32 aIndex, nsITreeColumn* aCol);
|
||||
|
||||
private:
|
||||
nsTreeBodyFrame* mTreeFrame;
|
||||
|
|
|
@ -166,7 +166,8 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
nsresult
|
||||
nsHttpPipeline::ResumeSend()
|
||||
{
|
||||
NS_NOTREACHED("nsHttpPipeline::ResumeSend");
|
||||
if (mConnection)
|
||||
return mConnection->ResumeSend();
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -411,7 +412,17 @@ nsHttpPipeline::OnTransportStatus(nsITransport* transport,
|
|||
bool
|
||||
nsHttpPipeline::IsDone()
|
||||
{
|
||||
return (mRequestQ.Length() == 0) && (mResponseQ.Length() == 0);
|
||||
bool done = true;
|
||||
|
||||
PRUint32 i, count = mRequestQ.Length();
|
||||
for (i = 0; done && (i < count); i++)
|
||||
done = Request(i)->IsDone();
|
||||
|
||||
count = mResponseQ.Length();
|
||||
for (i = 0; done && (i < count); i++)
|
||||
done = Response(i)->IsDone();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
"test_privbrw_tabs.js",
|
||||
"test_bookmarks_in_same_named_folder.js",
|
||||
"test_client_wipe.js",
|
||||
"test_special_tabs.js",
|
||||
"test_mozmill_sanity.js"
|
||||
"test_special_tabs.js"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* The list of phases mapped to their corresponding profiles. The object
|
||||
* here must be in strict JSON format, as it will get parsed by the Python
|
||||
* testrunner (no single quotes, extra comma's, etc).
|
||||
*/
|
||||
|
||||
var phases = { "phase1": "profile1",
|
||||
"phase2": "profile1",
|
||||
"phase3": "profile1",
|
||||
"phase4": "profile1",
|
||||
"phase5": "profile1" };
|
||||
|
||||
/*
|
||||
* Test phases
|
||||
*/
|
||||
|
||||
Phase('phase1', [
|
||||
[Addons.install, ['unsigned-1.0.xml']],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Sync, SYNC_WIPE_SERVER],
|
||||
]);
|
||||
|
||||
Phase('phase2', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase3', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED],
|
||||
[Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase4', [
|
||||
[Sync],
|
||||
[Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED],
|
||||
[Addons.uninstall, ['unsigned-xpi@tests.mozilla.org']],
|
||||
[Sync],
|
||||
]);
|
||||
|
||||
Phase('phase5', [
|
||||
[Sync],
|
||||
[Addons.verifyNot, ['unsigned-xpi@tests.mozilla.org']],
|
||||
]);
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<searchresults total_results="1">
|
||||
<addon id="5612">
|
||||
<name>Unsigned Test XPI</name>
|
||||
<type id="1">Extension</type>
|
||||
<guid>unsigned-xpi@tests.mozilla.org</guid>
|
||||
<slug>unsigned-xpi</slug>
|
||||
<version>1.0</version>
|
||||
|
||||
<compatible_applications><application>
|
||||
<name>Firefox</name>
|
||||
<application_id>1</application_id>
|
||||
<min_version>3.6</min_version>
|
||||
<max_version>*</max_version>
|
||||
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
|
||||
</application></compatible_applications>
|
||||
<all_compatible_os><os>ALL</os></all_compatible_os>
|
||||
|
||||
<install os="ALL" size="452">http://127.0.0.1:4567/unsigned-1.0.xpi</install>
|
||||
<created epoch="1252903662">
|
||||
2009-09-14T04:47:42Z
|
||||
</created>
|
||||
<last_updated epoch="1315255329">
|
||||
2011-09-05T20:42:09Z
|
||||
</last_updated>
|
||||
</addon>
|
||||
</searchresults>
|
Двоичный файл не отображается.
|
@ -30,9 +30,8 @@ tail =
|
|||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = os == "android"
|
||||
[test_errorhandler_sync_checkServerError.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_forms_store.js]
|
||||
[test_forms_tracker.js]
|
||||
[test_history_engine.js]
|
||||
|
@ -80,13 +79,11 @@ skip-if = os == "win" || os == "android"
|
|||
[test_service_sync_401.js]
|
||||
[test_service_sync_locked.js]
|
||||
[test_service_sync_remoteSetup.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_service_sync_updateEnabledEngines.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_service_verifyLogin.js]
|
||||
[test_service_wipeClient.js]
|
||||
[test_service_wipeServer.js]
|
||||
|
@ -94,9 +91,8 @@ skip-if = (os == "mac" && debug) || os == "android"
|
|||
[test_status_checkSetup.js]
|
||||
[test_syncengine.js]
|
||||
[test_syncengine_sync.js]
|
||||
# Bug 604565: this test intermittently hangs on OS X debug builds.
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
skip-if = (os == "mac" && debug) || os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_syncscheduler.js]
|
||||
[test_syncstoragerequest.js]
|
||||
[test_tab_engine.js]
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Crossweave.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Griffin <jgriffin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Addon", "STATE_ENABLED", "STATE_DISABLED"];
|
||||
|
||||
const CC = Components.classes;
|
||||
const CI = Components.interfaces;
|
||||
const CU = Components.utils;
|
||||
|
||||
CU.import("resource://gre/modules/AddonManager.jsm");
|
||||
CU.import("resource://gre/modules/AddonRepository.jsm");
|
||||
CU.import("resource://gre/modules/Services.jsm");
|
||||
CU.import("resource://services-sync/async.js");
|
||||
CU.import("resource://services-sync/util.js");
|
||||
CU.import("resource://tps/logger.jsm");
|
||||
var XPIProvider = CU.import("resource://gre/modules/XPIProvider.jsm")
|
||||
.XPIProvider;
|
||||
|
||||
const ADDONSGETURL = 'http://127.0.0.1:4567/';
|
||||
const STATE_ENABLED = 1;
|
||||
const STATE_DISABLED = 2;
|
||||
|
||||
function GetFileAsText(file)
|
||||
{
|
||||
let channel = Services.io.newChannel(file, null, null);
|
||||
let inputStream = channel.open();
|
||||
if (channel instanceof CI.nsIHttpChannel &&
|
||||
channel.responseStatus != 200) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let streamBuf = "";
|
||||
let sis = CC["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(CI.nsIScriptableInputStream);
|
||||
sis.init(inputStream);
|
||||
|
||||
let available;
|
||||
while ((available = sis.available()) != 0) {
|
||||
streamBuf += sis.read(available);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
return streamBuf;
|
||||
}
|
||||
|
||||
function Addon(TPS, id) {
|
||||
this.TPS = TPS;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Addon.prototype = {
|
||||
_addons_requiring_restart: [],
|
||||
_addons_pending_install: [],
|
||||
|
||||
Delete: function() {
|
||||
// find our addon locally
|
||||
let cb = Async.makeSyncCallback();
|
||||
XPIProvider.getAddonsByTypes(null, cb);
|
||||
let results = Async.waitForSyncCallback(cb);
|
||||
var addon;
|
||||
var id = this.id;
|
||||
results.forEach(function(result) {
|
||||
if (result.id == id) {
|
||||
addon = result;
|
||||
}
|
||||
});
|
||||
Logger.AssertTrue(!!addon, 'could not find addon ' + this.id + ' to uninstall');
|
||||
addon.uninstall();
|
||||
},
|
||||
|
||||
Find: function(state) {
|
||||
let cb = Async.makeSyncCallback();
|
||||
let addon_found = false;
|
||||
var that = this;
|
||||
|
||||
var log_addon = function(addon) {
|
||||
that.addon = addon;
|
||||
Logger.logInfo('addon ' + addon.id + ' found, isActive: ' + addon.isActive);
|
||||
if (state == STATE_ENABLED || state == STATE_DISABLED) {
|
||||
Logger.AssertEqual(addon.isActive,
|
||||
state == STATE_ENABLED ? true : false,
|
||||
"addon " + that.id + " has an incorrect enabled state");
|
||||
}
|
||||
};
|
||||
|
||||
// first look in the list of all addons
|
||||
XPIProvider.getAddonsByTypes(null, cb);
|
||||
let addonlist = Async.waitForSyncCallback(cb);
|
||||
addonlist.forEach(function(addon) {
|
||||
if (addon.id == that.id) {
|
||||
addon_found = true;
|
||||
log_addon.call(that, addon);
|
||||
}
|
||||
});
|
||||
|
||||
if (!addon_found) {
|
||||
// then look in the list of recent installs
|
||||
cb = Async.makeSyncCallback();
|
||||
XPIProvider.getInstallsByTypes(null, cb);
|
||||
addonlist = Async.waitForSyncCallback(cb);
|
||||
for (var i in addonlist) {
|
||||
if (addonlist[i].addon && addonlist[i].addon.id == that.id &&
|
||||
addonlist[i].state == AddonManager.STATE_INSTALLED) {
|
||||
addon_found = true;
|
||||
log_addon.call(that, addonlist[i].addon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addon_found;
|
||||
},
|
||||
|
||||
Install: function() {
|
||||
// For Install, the id parameter initially passed is really the filename
|
||||
// for the addon's install .xml; we'll read the actual id from the .xml.
|
||||
let url = this.id;
|
||||
|
||||
// set the url used by getAddonsByIDs
|
||||
var prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
prefs.setCharPref('extensions.getAddons.get.url', ADDONSGETURL + url);
|
||||
|
||||
// read the XML and find the addon id
|
||||
xml = GetFileAsText(ADDONSGETURL + url);
|
||||
Logger.AssertTrue(xml.indexOf("<guid>") > -1, 'guid not found in ' + url);
|
||||
this.id = xml.substring(xml.indexOf("<guid>") + 6, xml.indexOf("</guid"));
|
||||
Logger.logInfo('addon XML = ' + this.id);
|
||||
|
||||
// find our addon on 'AMO'
|
||||
let cb = Async.makeSyncCallback();
|
||||
AddonRepository.getAddonsByIDs([this.id], {
|
||||
searchSucceeded: cb,
|
||||
searchFailed: cb
|
||||
}, false);
|
||||
|
||||
// Result will be array of addons on searchSucceeded or undefined on
|
||||
// searchFailed.
|
||||
let install_addons = Async.waitForSyncCallback(cb);
|
||||
|
||||
Logger.AssertTrue(install_addons,
|
||||
"no addons found for id " + this.id);
|
||||
Logger.AssertEqual(install_addons.length,
|
||||
1,
|
||||
"multiple addons found for id " + this.id);
|
||||
|
||||
let addon = install_addons[0];
|
||||
Logger.logInfo(JSON.stringify(addon), null, ' ');
|
||||
if (XPIProvider.installRequiresRestart(addon)) {
|
||||
this._addons_requiring_restart.push(addon.id);
|
||||
}
|
||||
|
||||
// Start installing the addon asynchronously; finish up in
|
||||
// onInstallEnded(), onInstallFailed(), or onDownloadFailed().
|
||||
this._addons_pending_install.push(addon.id);
|
||||
this.TPS.StartAsyncOperation();
|
||||
|
||||
Utils.nextTick(function() {
|
||||
let callback = function(aInstall) {
|
||||
addon.install = aInstall;
|
||||
Logger.logInfo("addon install: " + addon.install);
|
||||
Logger.AssertTrue(addon.install,
|
||||
"could not get install object for id " + this.id);
|
||||
addon.install.addListener(this);
|
||||
addon.install.install();
|
||||
};
|
||||
|
||||
AddonManager.getInstallForURL(addon.sourceURI.spec,
|
||||
callback.bind(this),
|
||||
"application/x-xpinstall");
|
||||
}, this);
|
||||
},
|
||||
|
||||
SetState: function(state) {
|
||||
if (!this.Find())
|
||||
return false;
|
||||
this.addon.userDisabled = state == STATE_ENABLED ? false : true;
|
||||
return true;
|
||||
},
|
||||
|
||||
// addon installation callbacks
|
||||
onInstallEnded: function(addon) {
|
||||
try {
|
||||
Logger.logInfo('--------- event observed: addon onInstallEnded');
|
||||
Logger.AssertTrue(addon.addon,
|
||||
"No addon object in addon instance passed to onInstallEnded");
|
||||
Logger.AssertTrue(this._addons_pending_install.indexOf(addon.addon.id) > -1,
|
||||
"onInstallEnded received for unexpected addon " + addon.addon.id);
|
||||
this._addons_pending_install.splice(
|
||||
this._addons_pending_install.indexOf(addon.addon.id),
|
||||
1);
|
||||
}
|
||||
catch(e) {
|
||||
// We can't throw during a callback, as it will just get eaten by
|
||||
// the callback's caller.
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError(e);
|
||||
}, this);
|
||||
return;
|
||||
}
|
||||
this.TPS.FinishAsyncOperation();
|
||||
},
|
||||
|
||||
onInstallFailed: function(addon) {
|
||||
Logger.logInfo('--------- event observed: addon onInstallFailed');
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError('Installation failed for addon ' +
|
||||
(addon.addon && addon.addon.id ? addon.addon.id : 'unknown'));
|
||||
}, this);
|
||||
},
|
||||
|
||||
onDownloadFailed: function(addon) {
|
||||
Logger.logInfo('--------- event observed: addon onDownloadFailed');
|
||||
Utils.nextTick(function() {
|
||||
this.DumpError('Download failed for addon ' +
|
||||
(addon.addon && addon.addon.id ? addon.addon.id : 'unknown'));
|
||||
}, this);
|
||||
},
|
||||
|
||||
};
|
|
@ -48,9 +48,11 @@ const CU = Components.utils;
|
|||
|
||||
CU.import("resource://services-sync/service.js");
|
||||
CU.import("resource://services-sync/constants.js");
|
||||
CU.import("resource://services-sync/async.js");
|
||||
CU.import("resource://services-sync/util.js");
|
||||
CU.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
CU.import("resource://gre/modules/Services.jsm");
|
||||
CU.import("resource://tps/addons.jsm");
|
||||
CU.import("resource://tps/bookmarks.jsm");
|
||||
CU.import("resource://tps/logger.jsm");
|
||||
CU.import("resource://tps/passwords.jsm");
|
||||
|
@ -61,6 +63,8 @@ CU.import("resource://tps/tabs.jsm");
|
|||
|
||||
var hh = CC["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(CI.nsIHttpProtocolHandler);
|
||||
var prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
|
||||
var mozmillInit = {};
|
||||
CU.import('resource://mozmill/modules/init.js', mozmillInit);
|
||||
|
@ -73,37 +77,16 @@ const ACTION_SYNC = "sync";
|
|||
const ACTION_DELETE = "delete";
|
||||
const ACTION_PRIVATE_BROWSING = "private-browsing";
|
||||
const ACTION_WIPE_SERVER = "wipe-server";
|
||||
const ACTION_SETSTATE = "set-state";
|
||||
const ACTIONS = [ACTION_ADD, ACTION_VERIFY, ACTION_VERIFY_NOT,
|
||||
ACTION_MODIFY, ACTION_SYNC, ACTION_DELETE,
|
||||
ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER];
|
||||
ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER,
|
||||
ACTION_SETSTATE];
|
||||
|
||||
const SYNC_WIPE_SERVER = "wipe-server";
|
||||
const SYNC_RESET_CLIENT = "reset-client";
|
||||
const SYNC_WIPE_CLIENT = "wipe-client";
|
||||
|
||||
function GetFileAsText(file)
|
||||
{
|
||||
let channel = Services.io.newChannel(file, null, null);
|
||||
let inputStream = channel.open();
|
||||
if (channel instanceof CI.nsIHttpChannel &&
|
||||
channel.responseStatus != 200) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let streamBuf = "";
|
||||
let sis = CC["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(CI.nsIScriptableInputStream);
|
||||
sis.init(inputStream);
|
||||
|
||||
let available;
|
||||
while ((available = sis.available()) != 0) {
|
||||
streamBuf += sis.read(available);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
return streamBuf;
|
||||
}
|
||||
|
||||
var TPS =
|
||||
{
|
||||
_waitingForSync: false,
|
||||
|
@ -351,6 +334,33 @@ var TPS =
|
|||
}
|
||||
},
|
||||
|
||||
HandleAddons: function (addons, action, state) {
|
||||
for (var i in addons) {
|
||||
Logger.logInfo("executing action " + action.toUpperCase() +
|
||||
" on addon " + JSON.stringify(addons[i]));
|
||||
var addon = new Addon(this, addons[i]);
|
||||
switch(action) {
|
||||
case ACTION_ADD:
|
||||
addon.Install();
|
||||
break;
|
||||
case ACTION_DELETE:
|
||||
addon.Delete();
|
||||
break;
|
||||
case ACTION_VERIFY:
|
||||
Logger.AssertTrue(addon.Find(state), 'addon ' + addon.id + ' not found');
|
||||
break;
|
||||
case ACTION_VERIFY_NOT:
|
||||
Logger.AssertTrue(!addon.Find(state), 'addon ' + addon.id + " is present, but it shouldn't be");
|
||||
break;
|
||||
case ACTION_SETSTATE:
|
||||
Logger.AssertTrue(addon.SetState(state), 'addon ' + addon.id + ' not found');
|
||||
break;
|
||||
}
|
||||
}
|
||||
Logger.logPass("executing action " + action.toUpperCase() +
|
||||
" on addons");
|
||||
},
|
||||
|
||||
HandleBookmarks: function (bookmarks, action) {
|
||||
try {
|
||||
let items = [];
|
||||
|
@ -460,7 +470,7 @@ var TPS =
|
|||
let phase = this._phaselist["phase" + this._currentPhase];
|
||||
let action = phase[this._currentAction];
|
||||
Logger.logInfo("starting action: " + JSON.stringify(action));
|
||||
action[0].call(this, action[1]);
|
||||
action[0].apply(this, action.slice(1));
|
||||
|
||||
// if we're in an async operation, don't continue on to the next action
|
||||
if (this._operations_pending)
|
||||
|
@ -517,8 +527,6 @@ var TPS =
|
|||
|
||||
// Store account details as prefs so they're accessible to the mozmill
|
||||
// framework.
|
||||
let prefs = CC["@mozilla.org/preferences-service;1"]
|
||||
.getService(CI.nsIPrefBranch);
|
||||
prefs.setCharPref('tps.account.username', this.config.account.username);
|
||||
prefs.setCharPref('tps.account.password', this.config.account.password);
|
||||
prefs.setCharPref('tps.account.passphrase', this.config.account.passphrase);
|
||||
|
@ -634,6 +642,24 @@ var TPS =
|
|||
},
|
||||
};
|
||||
|
||||
var Addons = {
|
||||
install: function Addons__install(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_ADD);
|
||||
},
|
||||
setState: function Addons__setState(addons, state) {
|
||||
TPS.HandleAddons(addons, ACTION_SETSTATE, state);
|
||||
},
|
||||
uninstall: function Addons__uninstall(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_DELETE);
|
||||
},
|
||||
verify: function Addons__verify(addons, state) {
|
||||
TPS.HandleAddons(addons, ACTION_VERIFY, state);
|
||||
},
|
||||
verifyNot: function Addons__verifyNot(addons) {
|
||||
TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
|
||||
},
|
||||
};
|
||||
|
||||
var Bookmarks = {
|
||||
add: function Bookmarks__add(bookmarks) {
|
||||
TPS.HandleBookmarks(bookmarks, ACTION_ADD);
|
||||
|
|
|
@ -82,7 +82,6 @@ _SERV_FILES = \
|
|||
$(topsrcdir)/build/mobile/devicemanagerADB.py \
|
||||
$(topsrcdir)/build/mobile/devicemanagerSUT.py \
|
||||
$(topsrcdir)/build/automationutils.py \
|
||||
$(topsrcdir)/build/poster.zip \
|
||||
$(topsrcdir)/build/mobile/remoteautomation.py \
|
||||
gen_template.pl \
|
||||
server.js \
|
||||
|
|
|
@ -38,4 +38,5 @@
|
|||
from firefoxrunner import TPSFirefoxRunner
|
||||
from pulse import TPSPulseMonitor
|
||||
from testrunner import TPSTestRunner
|
||||
from mozhttpd import MozHttpd
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# the Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Joel Maher <joel.maher@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import BaseHTTPServer
|
||||
import SimpleHTTPServer
|
||||
import threading
|
||||
import sys
|
||||
import os
|
||||
import urllib
|
||||
import re
|
||||
from urlparse import urlparse
|
||||
from SocketServer import ThreadingMixIn
|
||||
|
||||
DOCROOT = '.'
|
||||
|
||||
class EasyServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
class MozRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def translate_path(self, path):
|
||||
# It appears that the default path is '/' and os.path.join makes the '/'
|
||||
o = urlparse(path)
|
||||
return "%s%s" % ('' if sys.platform == 'win32' else '/', '/'.join([i.strip('/') for i in (DOCROOT, o.path)]))
|
||||
|
||||
# I found on my local network that calls to this were timing out
|
||||
# I believe all of these calls are from log_message
|
||||
def address_string(self):
|
||||
return "a.b.c.d"
|
||||
|
||||
# This produces a LOT of noise
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
class MozHttpd(object):
|
||||
def __init__(self, host="127.0.0.1", port=8888, docroot='.'):
|
||||
global DOCROOT
|
||||
self.host = host
|
||||
self.port = int(port)
|
||||
DOCROOT = docroot
|
||||
|
||||
def start(self):
|
||||
self.httpd = EasyServer((self.host, self.port), MozRequestHandler)
|
||||
self.server = threading.Thread(target=self.httpd.serve_forever)
|
||||
self.server.setDaemon(True) # don't hang on exit
|
||||
self.server.start()
|
||||
#self.testServer()
|
||||
|
||||
#TODO: figure this out
|
||||
def testServer(self):
|
||||
fileList = os.listdir(DOCROOT)
|
||||
filehandle = urllib.urlopen('http://%s:%s' % (self.host, self.port))
|
||||
data = filehandle.readlines();
|
||||
filehandle.close()
|
||||
|
||||
for line in data:
|
||||
found = False
|
||||
# '@' denotes a symlink and we need to ignore it.
|
||||
webline = re.sub('\<[a-zA-Z0-9\-\_\.\=\"\'\/\\\%\!\@\#\$\^\&\*\(\) ]*\>', '', line.strip('\n')).strip('/').strip().strip('@')
|
||||
if webline != "":
|
||||
if webline == "Directory listing for":
|
||||
found = True
|
||||
else:
|
||||
for fileName in fileList:
|
||||
if fileName == webline:
|
||||
found = True
|
||||
|
||||
if (found == False):
|
||||
print "NOT FOUND: " + webline.strip()
|
||||
|
||||
def stop(self):
|
||||
if self.httpd:
|
||||
self.httpd.shutdown()
|
||||
|
||||
__del__ = stop
|
||||
|
|
@ -53,7 +53,7 @@ from mozprofile import Profile
|
|||
|
||||
from tps.firefoxrunner import TPSFirefoxRunner
|
||||
from tps.phase import TPSTestPhase
|
||||
|
||||
from tps.mozhttpd import MozHttpd
|
||||
|
||||
class TempFile(object):
|
||||
"""Class for temporary files that delete themselves when garbage-collected.
|
||||
|
@ -397,6 +397,9 @@ class TPSTestRunner(object):
|
|||
testlist = [os.path.basename(self.testfile)]
|
||||
testdir = os.path.dirname(self.testfile)
|
||||
|
||||
self.mozhttpd = MozHttpd(port=4567, docroot=testdir)
|
||||
self.mozhttpd.start()
|
||||
|
||||
# run each test, and save the results
|
||||
for test in testlist:
|
||||
result = self.run_single_test(testdir, test)
|
||||
|
@ -415,6 +418,8 @@ class TPSTestRunner(object):
|
|||
else:
|
||||
self.numfailed += 1
|
||||
|
||||
self.mozhttpd.stop()
|
||||
|
||||
# generate the postdata we'll use to post the results to the db
|
||||
self.postdata = { 'tests': self.results,
|
||||
'os':os_string,
|
||||
|
@ -440,7 +445,7 @@ class TPSTestRunner(object):
|
|||
self.numpassed,
|
||||
self.numfailed,
|
||||
self.config['account']['serverURL'],
|
||||
self.buildUrl)
|
||||
buildUrl)
|
||||
|
||||
subj = "TPS Report: "
|
||||
if self.numfailed == 0 and self.numpassed > 0:
|
||||
|
|
|
@ -65,7 +65,6 @@ EXTRA_BUILD_FILES := \
|
|||
automationutils.py \
|
||||
manifestparser.py \
|
||||
mozinfo.py \
|
||||
poster.zip \
|
||||
$(NULL)
|
||||
|
||||
# And files for running xpcshell remotely from $(topsrcdir)/build/mobile
|
||||
|
|
Загрузка…
Ссылка в новой задаче