merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-10-01 14:51:20 +02:00
Родитель a521762182 784c2ac8ee
Коммит bcd85e4b9f
115 изменённых файлов: 1525 добавлений и 482 удалений

Просмотреть файл

@ -196,7 +196,7 @@ def dumpLeakLog(leakLogFile, filter = False):
# Simply copy the log. # Simply copy the log.
log.info(leakReport.rstrip("\n")) log.info(leakReport.rstrip("\n"))
def processSingleLeakFile(leakLogFileName, processType, leakThreshold): def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMissingLeaks):
"""Process a single leak log. """Process a single leak log.
""" """
@ -273,11 +273,14 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
if crashedOnPurpose: if crashedOnPurpose:
log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log" log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log"
% processString) % processString)
else: elif ignoreMissingLeaks:
# TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
# due to too many intermittent failures (see bug 831223).
log.info("WARNING | leakcheck | %s missing output line for total leaks!"
% processString) % processString)
else:
log.info("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!"
% processString)
log.info("TEST-INFO | leakcheck | missing output line from log file %s"
% leakLogFileName)
return return
if totalBytesLeaked == 0: if totalBytesLeaked == 0:
@ -306,7 +309,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
log.info("%s | leakcheck | %s %d bytes leaked (%s)" log.info("%s | leakcheck | %s %d bytes leaked (%s)"
% (prefix, processString, totalBytesLeaked, leakedObjectSummary)) % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
def processLeakLog(leakLogFile, leakThresholds): def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
"""Process the leak log, including separate leak logs created """Process the leak log, including separate leak logs created
by child processes. by child processes.
@ -363,7 +366,8 @@ def processLeakLog(leakLogFile, leakThresholds):
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s" log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
% processType) % processType)
leakThreshold = leakThresholds.get(processType, 0) leakThreshold = leakThresholds.get(processType, 0)
processSingleLeakFile(thisFile, processType, leakThreshold) processSingleLeakFile(thisFile, processType, leakThreshold,
processType in ignoreMissingLeaks)
def replaceBackSlashes(input): def replaceBackSlashes(input):
return input.replace('\\', '/') return input.replace('\\', '/')

Просмотреть файл

@ -31,7 +31,7 @@ gyp_vars = {
'use_openssl': 0, 'use_openssl': 0,
# saves 4MB when webrtc_trace is off # saves 4MB when webrtc_trace is off
'enable_lazy_trace_alloc': 0, 'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0,
'use_x11': 1 if CONFIG['MOZ_X11'] else 0, 'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0, 'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,

Просмотреть файл

@ -9178,14 +9178,6 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
nsresult rv = clone->Init(); nsresult rv = clone->Init();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Set URI/principal
clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
// Must set the principal first, since SetBaseURI checks it.
clone->SetPrincipal(NodePrincipal());
clone->mDocumentBaseURI = mDocumentBaseURI;
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
if (mCreatingStaticClone) { if (mCreatingStaticClone) {
nsCOMPtr<nsILoadGroup> loadGroup; nsCOMPtr<nsILoadGroup> loadGroup;
@ -9210,6 +9202,18 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
clone->SetContainer(mDocumentContainer); clone->SetContainer(mDocumentContainer);
} }
// Now ensure that our clone has the same URI, base URI, and principal as us.
// We do this after the mCreatingStaticClone block above, because that block
// can set the base URI to an incorrect value in cases when base URI
// information came from the channel. So we override explicitly, and do it
// for all these properties, in case ResetToURI messes with any of the rest of
// them.
clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
clone->SetPrincipal(NodePrincipal());
clone->mDocumentBaseURI = mDocumentBaseURI;
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
// Set scripting object // Set scripting object
bool hasHadScriptObject = true; bool hasHadScriptObject = true;
nsIScriptGlobalObject* scriptObject = nsIScriptGlobalObject* scriptObject =

Просмотреть файл

@ -1090,7 +1090,7 @@ nsXMLHttpRequest::GetResponseURL(nsAString& aUrl)
} }
nsAutoCString temp; nsAutoCString temp;
responseUrl->GetSpec(temp); responseUrl->GetSpecIgnoringRef(temp);
CopyUTF8toUTF16(temp, aUrl); CopyUTF8toUTF16(temp, aUrl);
} }

Просмотреть файл

@ -189,6 +189,11 @@ function testSuccessResponse() {
skip: isInWorker(), skip: isInWorker(),
reason: "cross-origin redirect request not works on Workers, see bug 882458" reason: "cross-origin redirect request not works on Workers, see bug 882458"
}, },
{
message: "request URL has fragment",
requestURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text#fragment",
responseURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text"
},
// tests for non-http(s) URL // tests for non-http(s) URL
{ {

Просмотреть файл

@ -63,7 +63,7 @@ PRLogModuleInfo* gMediaStreamGraphLog;
/** /**
* The singleton graph instance. * The singleton graph instance.
*/ */
static MediaStreamGraphImpl* gGraph; static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
MediaStreamGraphImpl::~MediaStreamGraphImpl() MediaStreamGraphImpl::~MediaStreamGraphImpl()
{ {
@ -1633,9 +1633,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
NS_DispatchToMainThread(event); NS_DispatchToMainThread(event);
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
if (this == gGraph) { MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
// null out gGraph if that's the graph being shut down // null out gGraph if that's the graph being shut down
gGraph = nullptr; gGraphs.Remove(mAudioChannel);
} }
} }
} else { } else {
@ -1786,9 +1787,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
delete aMessage; delete aMessage;
if (IsEmpty() && if (IsEmpty() &&
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) { mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
if (gGraph == this) {
gGraph = nullptr; MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
gGraphs.Remove(mAudioChannel);
} }
Destroy(); Destroy();
} }
return; return;
@ -2736,6 +2740,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
#ifdef DEBUG #ifdef DEBUG
, mCanRunMessagesSynchronously(false) , mCanRunMessagesSynchronously(false)
#endif #endif
, mAudioChannel(static_cast<uint32_t>(aChannel))
{ {
#ifdef PR_LOGGING #ifdef PR_LOGGING
if (!gMediaStreamGraphLog) { if (!gMediaStreamGraphLog) {
@ -2774,15 +2779,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
static bool gShutdownObserverRegistered = false; static bool gShutdownObserverRegistered = false;
namespace {
PLDHashOperator
ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
MediaStreamGraphImpl* aGraph,
void* /* aUnused */)
{
aGraph->ForceShutDown();
return PL_DHASH_NEXT;
}
} // anonymous namespace
NS_IMETHODIMP NS_IMETHODIMP
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject, MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic, const char *aTopic,
const char16_t *aData) const char16_t *aData)
{ {
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
if (gGraph) { gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
gGraph->ForceShutDown();
}
nsContentUtils::UnregisterShutdownObserver(this); nsContentUtils::UnregisterShutdownObserver(this);
gShutdownObserverRegistered = false; gShutdownObserverRegistered = false;
} }
@ -2794,7 +2810,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
{ {
NS_ASSERTION(NS_IsMainThread(), "Main thread only"); NS_ASSERTION(NS_IsMainThread(), "Main thread only");
if (!gGraph) { uint32_t channel = static_cast<uint32_t>(aChannel);
MediaStreamGraphImpl* graph = nullptr;
if (!gGraphs.Get(channel, &graph)) {
if (!gShutdownObserverRegistered) { if (!gShutdownObserverRegistered) {
gShutdownObserverRegistered = true; gShutdownObserverRegistered = true;
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver()); nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
@ -2802,12 +2821,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
CubebUtils::InitPreferredSampleRate(); CubebUtils::InitPreferredSampleRate();
gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel); graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
gGraphs.Put(channel, graph);
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph)); STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
} }
return gGraph; return graph;
} }
MediaStreamGraph* MediaStreamGraph*
@ -2978,7 +2998,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
bool bool
MediaStreamGraph::IsNonRealtime() const MediaStreamGraph::IsNonRealtime() const
{ {
return this != gGraph; const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
MediaStreamGraphImpl* graph;
return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
} }
void void

Просмотреть файл

@ -654,6 +654,8 @@ public:
nsRefPtr<AudioOutputObserver> mFarendObserverRef; nsRefPtr<AudioOutputObserver> mFarendObserverRef;
#endif #endif
uint32_t AudioChannel() const { return mAudioChannel; }
private: private:
virtual ~MediaStreamGraphImpl(); virtual ~MediaStreamGraphImpl();
@ -687,6 +689,9 @@ private:
bool mCanRunMessagesSynchronously; bool mCanRunMessagesSynchronously;
#endif #endif
// We use uint32_t instead AudioChannel because this is just used as key for
// the hashtable gGraphs.
uint32_t mAudioChannel;
}; };
} }

Просмотреть файл

@ -168,9 +168,11 @@ static const int32_t MAX_VIDEO_HEIGHT = 3000;
void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio); void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
// The amount of virtual memory reserved for thread stacks. // The amount of virtual memory reserved for thread stacks.
#if (defined(XP_WIN) || defined(LINUX)) && !defined(MOZ_ASAN) #if defined(MOZ_ASAN)
#define MEDIA_THREAD_STACK_SIZE (128 * 1024) // Use the system default in ASAN builds, because the default is assumed to be
#elif defined(XP_MACOSX) && !defined(MOZ_ASAN) // larger than the size we want to use and is hopefully sufficient for ASAN.
#define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
#elif defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
#define MEDIA_THREAD_STACK_SIZE (256 * 1024) #define MEDIA_THREAD_STACK_SIZE (256 * 1024)
#else #else
// All other platforms use their system defaults. // All other platforms use their system defaults.

Просмотреть файл

@ -263,8 +263,12 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
// Enable sandboxing here -- we know the plugin file's path, but // Enable sandboxing here -- we know the plugin file's path, but
// this process's execution hasn't been affected by its content yet. // this process's execution hasn't been affected by its content yet.
MOZ_ASSERT(mozilla::CanSandboxMediaPlugin()); if (mozilla::CanSandboxMediaPlugin()) {
mozilla::SetMediaPluginSandbox(nativePath.get()); mozilla::SetMediaPluginSandbox(nativePath.get());
} else {
printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
nativePath.get());
}
#endif // XP_LINUX && MOZ_GMP_SANDBOX #endif // XP_LINUX && MOZ_GMP_SANDBOX
libFile->Load(&mLib); libFile->Load(&mLib);

Просмотреть файл

@ -18,6 +18,9 @@
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "GMPTimerParent.h" #include "GMPTimerParent.h"
#include "runnable_utils.h" #include "runnable_utils.h"
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
#include "mozilla/Sandbox.h"
#endif
#include "mozilla/dom/CrashReporterParent.h" #include "mozilla/dom/CrashReporterParent.h"
using mozilla::dom::CrashReporterParent; using mozilla::dom::CrashReporterParent;
@ -852,6 +855,17 @@ GMPParent::ReadGMPMetaData()
} }
} }
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (cap->mAPIName.EqualsLiteral("eme-decrypt") &&
!mozilla::CanSandboxMediaPlugin()) {
printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
" but this system can't sandbox it; not loading.\n",
mDisplayName.get());
delete cap;
return NS_ERROR_FAILURE;
}
#endif
mCapabilities.AppendElement(cap); mCapabilities.AppendElement(cap);
} }

Просмотреть файл

@ -435,6 +435,14 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
const nsAString& aOrigin, const nsAString& aOrigin,
GMPDecryptorProxy** aDecryptor) GMPDecryptorProxy** aDecryptor)
{ {
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::CanSandboxMediaPlugin()) {
NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
"EME decryption not available without sandboxing support.");
return NS_ERROR_NOT_AVAILABLE;
}
#endif
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0); NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aDecryptor); NS_ENSURE_ARG(aDecryptor);
@ -625,11 +633,6 @@ NS_IMETHODIMP
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory) GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::CanSandboxMediaPlugin()) {
return NS_ERROR_NOT_AVAILABLE;
}
#endif
nsCOMPtr<nsIThread> thread; nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread)); nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {

Просмотреть файл

@ -240,8 +240,7 @@ static int webm_read(void* aBuffer, size_t aLength, void* aUserData)
// Check the read length. // Check the read length.
if (aLength > ioData->data.Length()) { if (aLength > ioData->data.Length()) {
NS_ERROR("Invalid read length"); return 0;
return -1;
} }
// Check eos. // Check eos.
@ -292,7 +291,7 @@ static int webm_seek(int64_t aOffset, int aWhence, void* aUserData)
return -1; return -1;
} }
return 1; return 0;
} }
static int64_t webm_tell(void* aUserData) static int64_t webm_tell(void* aUserData)

Просмотреть файл

@ -289,7 +289,15 @@ void
SourceBuffer::StopUpdating() SourceBuffer::StopUpdating()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mUpdating); if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
//
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
// the first StopUpdating() runnable runs, then a second StopUpdating()
// runnable will be scheduled, but still only one (the first) will queue
// events.
return;
}
mUpdating = false; mUpdating = false;
QueueAsyncSimpleEvent("update"); QueueAsyncSimpleEvent("update");
QueueAsyncSimpleEvent("updateend"); QueueAsyncSimpleEvent("updateend");

Просмотреть файл

@ -648,12 +648,6 @@ AudioContext::MozAudioChannelType() const
return mDestination->MozAudioChannelType(); return mDestination->MozAudioChannelType();
} }
void
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
{
mDestination->SetMozAudioChannelType(aValue, aRv);
}
AudioChannel AudioChannel
AudioContext::TestAudioChannelInAudioNodeStream() AudioContext::TestAudioChannelInAudioNodeStream()
{ {

Просмотреть файл

@ -222,7 +222,6 @@ public:
JSObject* GetGlobalJSObject() const; JSObject* GetGlobalJSObject() const;
AudioChannel MozAudioChannelType() const; AudioChannel MozAudioChannelType() const;
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
AudioChannel TestAudioChannelInAudioNodeStream(); AudioChannel TestAudioChannelInAudioNodeStream();

Просмотреть файл

@ -376,16 +376,17 @@ public:
float* higherWaveData = nullptr; float* higherWaveData = nullptr;
float* lowerWaveData = nullptr; float* lowerWaveData = nullptr;
float tableInterpolationFactor; float tableInterpolationFactor;
float rate = 1.0 / mSource->SampleRate(); // Phase increment at frequency of 1 Hz.
// mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
float basePhaseIncrement =
static_cast<float>(periodicWaveSize) / mSource->SampleRate();
for (uint32_t i = aStart; i < aEnd; ++i) { for (uint32_t i = aStart; i < aEnd; ++i) {
UpdateParametersIfNeeded(ticks, i); UpdateParametersIfNeeded(ticks, i);
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency, mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
lowerWaveData, lowerWaveData,
higherWaveData, higherWaveData,
tableInterpolationFactor); tableInterpolationFactor);
// mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
mPhase += periodicWaveSize * mFinalFrequency * rate;
mPhase = fmod(mPhase, periodicWaveSize); mPhase = fmod(mPhase, periodicWaveSize);
// Bilinear interpolation between adjacent samples in each table. // Bilinear interpolation between adjacent samples in each table.
uint32_t j1 = floor(mPhase); uint32_t j1 = floor(mPhase);
@ -394,12 +395,14 @@ public:
j2 -= periodicWaveSize; j2 -= periodicWaveSize;
} }
float sampleInterpolationFactor = mPhase - j1; float sampleInterpolationFactor = mPhase - j1;
float lower = sampleInterpolationFactor * lowerWaveData[j1] + float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
(1 - sampleInterpolationFactor) * lowerWaveData[j2]; sampleInterpolationFactor * lowerWaveData[j2];
float higher = sampleInterpolationFactor * higherWaveData[j1] + float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
(1 - sampleInterpolationFactor) * higherWaveData[j2]; sampleInterpolationFactor * higherWaveData[j2];
aOutput[i] = tableInterpolationFactor * lower + aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
(1 - tableInterpolationFactor) * higher; tableInterpolationFactor * higher;
mPhase += basePhaseIncrement * mFinalFrequency;
} }
} }

Просмотреть файл

@ -18,27 +18,23 @@ function test_basic() {
// Default // Default
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// random wrong channel
ac.mozAudioChannelType = "foo";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// Unpermitted channels // Unpermitted channels
ac.mozAudioChannelType = "content"; ac = new AudioContext("content");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "notification"; ac = new AudioContext("notification");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "alarm"; ac = new AudioContext("alarm");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "telephony"; ac = new AudioContext("telephony");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "ringer"; ac = new AudioContext("ringer");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac.mozAudioChannelType = "publicnotification"; ac = new AudioContext("publicnotification");
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'"); is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
runTest(); runTest();
@ -56,7 +52,7 @@ function test_permission(aChannel) {
SpecialPowers.pushPermissions( SpecialPowers.pushPermissions(
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }], [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
function() { function() {
ac.mozAudioChannelType = aChannel; var ac = new AudioContext(aChannel);
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'"); is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream(); var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();

Просмотреть файл

@ -11,11 +11,26 @@
<script class="testbody" type="text/javascript"> <script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
// real and imag are used in separate PeriodicWaves to make their peak values
// easy to determine.
const realMax = 99;
var real = new Float32Array(realMax + 1);
real[1] = 2.0; // fundamental
real[realMax] = 3.0;
const realPeak = real[1] + real[realMax];
const realFundamental = 19.0;
var imag = new Float32Array(4);
imag[0] = 6.0; // should be ignored.
imag[3] = 0.5;
const imagPeak = imag[3];
const imagFundamental = 551.0;
const testLength = 4096;
addLoadEvent(function() { addLoadEvent(function() {
var ac = new AudioContext(); var ac = new AudioContext();
var real = new Float32Array(4096); ac.createPeriodicWave(new Float32Array(4096), new Float32Array(4096));
var imag = new Float32Array(4096);
var table = ac.createPeriodicWave(real, imag);
expectException(function() { expectException(function() {
ac.createPeriodicWave(new Float32Array(512), imag); ac.createPeriodicWave(new Float32Array(512), imag);
}, DOMException.NOT_SUPPORTED_ERR); }, DOMException.NOT_SUPPORTED_ERR);
@ -25,9 +40,54 @@ addLoadEvent(function() {
expectException(function() { expectException(function() {
ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097)); ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097));
}, DOMException.NOT_SUPPORTED_ERR); }, DOMException.NOT_SUPPORTED_ERR);
SimpleTest.finish();
runTest();
}); });
var gTest = {
createGraph: function(context) {
var merger = context.createChannelMerger();
var osc0 = context.createOscillator();
var osc1 = context.createOscillator();
osc0.setPeriodicWave(context.
createPeriodicWave(real,
new Float32Array(real.length)));
osc1.setPeriodicWave(context.
createPeriodicWave(new Float32Array(imag.length),
imag));
osc0.frequency.value = realFundamental;
osc1.frequency.value = imagFundamental;
osc0.start();
osc1.start();
osc0.connect(merger, 0, 0);
osc1.connect(merger, 0, 1);
return merger;
},
createExpectedBuffers: function(context) {
var buffer = context.createBuffer(2, testLength, context.sampleRate);
for (var i = 0; i < buffer.length; ++i) {
buffer.getChannelData(0)[i] = 1.0 / realPeak *
(real[1] * Math.cos(2 * Math.PI * realFundamental * i /
context.sampleRate) +
real[realMax] * Math.cos(2 * Math.PI * realMax * realFundamental * i /
context.sampleRate));
buffer.getChannelData(1)[i] = 1.0 / imagPeak *
imag[3] * Math.sin(2 * Math.PI * 3 * imagFundamental * i /
context.sampleRate);
}
return buffer;
},
};
</script> </script>
</pre> </pre>
</body> </body>

Просмотреть файл

@ -56,6 +56,9 @@ TestInterfaceJS.prototype = {
get cachedAttr() { return this._cachedAttr; }, get cachedAttr() { return this._cachedAttr; },
setCachedAttr: function(n) { this._cachedAttr = n; }, setCachedAttr: function(n) { this._cachedAttr = n; },
clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); }, clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
testSequenceOverload: function(arg) {},
testSequenceUnion: function(arg) {},
}; };
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS]) this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])

Просмотреть файл

@ -50,3 +50,5 @@ skip-if = debug == false
[test_throwing_method_noDCE.html] [test_throwing_method_noDCE.html]
[test_treat_non_object_as_null.html] [test_treat_non_object_as_null.html]
[test_traceProtos.html] [test_traceProtos.html]
[test_sequence_detection.html]
skip-if = debug == false

Просмотреть файл

@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1066432
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1066432</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1066432 **/
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
var testInterfaceJS = new TestInterfaceJS();
ok(testInterfaceJS, "got a TestInterfaceJS object");
try {
testInterfaceJS.testSequenceOverload(
{ "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
ok(false, "Should have thrown in the overload case");
} catch (e) {
ise(e.name, "TypeError", "Should get a TypeError for the overload case");
ok(e.message.contains("not iterable"),
"Should have a message about being non-iterable in the overload case");
}
try {
testInterfaceJS.testSequenceUnion(
{ "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
ok(false, "Should have thrown in the union case");
} catch (e) {
ise(e.name, "TypeError", "Should get a TypeError for the union case");
ok(e.message.contains("not iterable"),
"Should have a message about being non-iterable in the union case");
}
SimpleTest.finish();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1066432">Mozilla Bug 1066432</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -824,7 +824,7 @@ private:
param.data = (unsigned char*) &oaepParams; param.data = (unsigned char*) &oaepParams;
param.len = sizeof(oaepParams); param.len = sizeof(oaepParams);
uint32_t outLen; uint32_t outLen = 0;
if (mEncrypt) { if (mEncrypt) {
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k' // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
@ -841,9 +841,9 @@ private:
mResult.Elements(), &outLen, mResult.Length(), mResult.Elements(), &outLen, mResult.Length(),
mData.Elements(), mData.Length())); mData.Elements(), mData.Length()));
} }
mResult.SetLength(outLen);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
mResult.SetLength(outLen);
return NS_OK; return NS_OK;
} }
}; };

Просмотреть файл

@ -342,6 +342,7 @@ namespace mozilla {
namespace dom { namespace dom {
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
int32_t ContentParent::sNuwaPid = 0;
bool ContentParent::sNuwaReady = false; bool ContentParent::sNuwaReady = false;
#endif #endif
@ -587,6 +588,7 @@ ContentParent::RunNuwaProcess()
/* aIsNuwaProcess = */ true); /* aIsNuwaProcess = */ true);
nuwaProcess->Init(); nuwaProcess->Init();
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
sNuwaPid = nuwaProcess->Pid();
sNuwaReady = false; sNuwaReady = false;
#endif #endif
return nuwaProcess.forget(); return nuwaProcess.forget();
@ -1990,6 +1992,7 @@ ContentParent::~ContentParent()
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) { if (IsNuwaProcess()) {
sNuwaReady = false; sNuwaReady = false;
sNuwaPid = 0;
} }
#endif #endif
} }
@ -3699,6 +3702,12 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false; return false;
} }
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess() && IsNuwaReady()) {
// Nuwa won't receive frame messages after it is frozen.
return true;
}
#endif
return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal)); return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
} }

Просмотреть файл

@ -79,6 +79,10 @@ class ContentParent MOZ_FINAL : public PContentParent
public: public:
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
static int32_t NuwaPid() {
return sNuwaPid;
}
static bool IsNuwaReady() { static bool IsNuwaReady() {
return sNuwaReady; return sNuwaReady;
} }
@ -725,6 +729,7 @@ private:
#endif #endif
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
static int32_t sNuwaPid;
static bool sNuwaReady; static bool sNuwaReady;
#endif #endif
}; };

Просмотреть файл

@ -301,7 +301,6 @@ function RTCPeerConnection() {
this._localType = null; this._localType = null;
this._remoteType = null; this._remoteType = null;
this._trickleIce = false;
this._peerIdentity = null; this._peerIdentity = null;
/** /**
@ -326,7 +325,6 @@ RTCPeerConnection.prototype = {
init: function(win) { this._win = win; }, init: function(win) { this._win = win; },
__init: function(rtcConfig) { __init: function(rtcConfig) {
this._trickleIce = Services.prefs.getBoolPref("media.peerconnection.trickle_ice");
if (!rtcConfig.iceServers || if (!rtcConfig.iceServers ||
!Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) { !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
rtcConfig.iceServers = rtcConfig.iceServers =
@ -365,8 +363,7 @@ RTCPeerConnection.prototype = {
this._queueOrRun({ this._queueOrRun({
func: this._initialize, func: this._initialize,
args: [rtcConfig], args: [rtcConfig],
// If not trickling, suppress start. wait: false
wait: !this._trickleIce
}); });
}, },
@ -500,7 +497,11 @@ RTCPeerConnection.prototype = {
}, },
dispatchEvent: function(event) { dispatchEvent: function(event) {
this.__DOM_IMPL__.dispatchEvent(event); // PC can close while events are firing if there is an async dispatch
// in c++ land
if (!this._closed) {
this.__DOM_IMPL__.dispatchEvent(event);
}
}, },
// Log error message to web console and window.onerror, if present. // Log error message to web console and window.onerror, if present.

Просмотреть файл

@ -1937,6 +1937,10 @@ PeerConnectionWrapper.prototype = {
var self = this; var self = this;
self._remote_ice_candidates.push(candidate); self._remote_ice_candidates.push(candidate);
if (self.signalingstate === 'closed') {
info("Received ICE candidate for closed PeerConnection - discarding");
return;
}
if (self.remoteDescriptionSet) { if (self.remoteDescriptionSet) {
self.addIceCandidate(candidate); self.addIceCandidate(candidate);
} else { } else {
@ -2566,15 +2570,9 @@ PeerConnectionWrapper.prototype = {
* Closes the connection * Closes the connection
*/ */
close : function PCW_close() { close : function PCW_close() {
// It might be that a test has already closed the pc. In those cases this._ice_candidates_to_add = [];
// we should not fail. this._pc.close();
try { info(this + ": Closed connection.");
this._pc.close();
info(this + ": Closed connection.");
}
catch (e) {
info(this + ": Failure in closing connection - " + e.message);
}
}, },
/** /**

Просмотреть файл

@ -589,8 +589,15 @@ DOMStorageDBParent::Observe(const char* aTopic,
const nsACString& aScopePrefix) const nsACString& aScopePrefix)
{ {
if (mIPCOpen) { if (mIPCOpen) {
mozilla::unused << SendObserve(nsDependentCString(aTopic), #ifdef MOZ_NUWA_PROCESS
nsCString(aScopePrefix)); if (!(static_cast<ContentParent*>(Manager())->IsNuwaProcess() &&
ContentParent::IsNuwaReady())) {
#endif
mozilla::unused << SendObserve(nsDependentCString(aTopic),
nsCString(aScopePrefix));
#ifdef MOZ_NUWA_PROCESS
}
#endif
} }
return NS_OK; return NS_OK;

Просмотреть файл

@ -78,8 +78,8 @@ interface AudioContext : EventTarget {
// Mozilla extensions // Mozilla extensions
partial interface AudioContext { partial interface AudioContext {
// Read AudioChannel.webidl for more information about this attribute. // Read AudioChannel.webidl for more information about this attribute.
[Pref="media.useAudioChannelService", SetterThrows] [Pref="media.useAudioChannelService"]
attribute AudioChannel mozAudioChannelType; readonly attribute AudioChannel mozAudioChannelType;
// These 2 events are dispatched when the AudioContext object is muted by // These 2 events are dispatched when the AudioContext object is muted by
// the AudioChannelService. It's call 'interrupt' because when this event is // the AudioChannelService. It's call 'interrupt' because when this event is

Просмотреть файл

@ -42,4 +42,10 @@ interface TestInterfaceJS {
readonly attribute short cachedAttr; readonly attribute short cachedAttr;
void setCachedAttr(short n); void setCachedAttr(short n);
void clearCachedAttrCache(); void clearCachedAttrCache();
// Test for sequence overloading and union behavior
void testSequenceOverload(sequence<DOMString> arg);
void testSequenceOverload(DOMString arg);
void testSequenceUnion((sequence<DOMString> or DOMString) arg);
}; };

Просмотреть файл

@ -2205,7 +2205,7 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow)
for (uint32_t index = 0; index < workers.Length(); index++) { for (uint32_t index = 0; index < workers.Length(); index++) {
WorkerPrivate*& worker = workers[index]; WorkerPrivate*& worker = workers[index];
if (worker->IsSharedWorker()) { if (worker->IsSharedWorker() || worker->IsServiceWorker()) {
worker->CloseSharedWorkersForWindow(aWindow); worker->CloseSharedWorkersForWindow(aWindow);
} else if (!worker->Cancel(cx)) { } else if (!worker->Cancel(cx)) {
JS_ReportPendingException(cx); JS_ReportPendingException(cx);

Просмотреть файл

@ -128,7 +128,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
endFrame = aImportedBy->mFirstNotImported; endFrame = aImportedBy->mFirstNotImported;
} }
#ifdef PR_LOGGING #if defined(PR_LOGGING) && defined(TX_TO_STRING)
txPattern* match = 0; txPattern* match = 0;
#endif #endif
@ -149,7 +149,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
if (templ.mMatch->matches(aNode, aContext)) { if (templ.mMatch->matches(aNode, aContext)) {
matchTemplate = templ.mFirstInstruction; matchTemplate = templ.mFirstInstruction;
*aImportFrame = frame; *aImportFrame = frame;
#ifdef PR_LOGGING #if defined(PR_LOGGING) && defined(TX_TO_STRING)
match = templ.mMatch; match = templ.mMatch;
#endif #endif
} }

Просмотреть файл

@ -64,8 +64,7 @@ MOZ_END_ENUM_CLASS(BufferMode)
MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t) MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t)
DRAW, DRAW,
DRAW_SNAPPED, NONE
CLIP_NONE
MOZ_END_ENUM_CLASS(DrawRegionClip) MOZ_END_ENUM_CLASS(DrawRegionClip)
MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t) MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t)

Просмотреть файл

@ -695,7 +695,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
nsIntRegion invalidate; nsIntRegion invalidate;
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect); invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
result.mClip = DrawRegionClip::DRAW_SNAPPED; result.mClip = DrawRegionClip::DRAW;
result.mMode = mode; result.mMode = mode;
return result; return result;

Просмотреть файл

@ -229,7 +229,7 @@ public:
: mRegionToDraw() : mRegionToDraw()
, mRegionToInvalidate() , mRegionToInvalidate()
, mMode(SurfaceMode::SURFACE_NONE) , mMode(SurfaceMode::SURFACE_NONE)
, mClip(DrawRegionClip::CLIP_NONE) , mClip(DrawRegionClip::NONE)
, mContentType(gfxContentType::SENTINEL) , mContentType(gfxContentType::SENTINEL)
, mDidSelfCopy(false) , mDidSelfCopy(false)
{} {}

Просмотреть файл

@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext,
groupContext = aContext; groupContext = aContext;
} }
SetAntialiasingFlags(this, groupContext->GetDrawTarget()); SetAntialiasingFlags(this, groupContext->GetDrawTarget());
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData); aCallback(this, groupContext, toDraw, DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
if (needsGroup) { if (needsGroup) {
aContext->PopGroupToSource(); aContext->PopGroupToSource();
if (needsClipToVisibleRegion) { if (needsClipToVisibleRegion) {

Просмотреть файл

@ -443,7 +443,17 @@ ClientLayerManager::MakeSnapshotIfRequired()
} }
if (mWidget) { if (mWidget) {
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) { if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
// The compositor doesn't draw to a different sized surface
// when there's a rotation. Instead we rotate the result
// when drawing into dt
nsIntRect outerBounds;
mWidget->GetBounds(outerBounds);
nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
if (mTargetRotation) {
bounds = RotateRect(bounds, outerBounds, mTargetRotation);
}
SurfaceDescriptor inSnapshot; SurfaceDescriptor inSnapshot;
if (!bounds.IsEmpty() && if (!bounds.IsEmpty() &&
mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(), mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
@ -452,11 +462,18 @@ ClientLayerManager::MakeSnapshotIfRequired()
remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot); RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
DrawTarget* dt = mShadowTarget->GetDrawTarget(); DrawTarget* dt = mShadowTarget->GetDrawTarget();
Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height); Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
Rect srcRect(0, 0, bounds.width, bounds.height); Rect srcRect(0, 0, bounds.width, bounds.height);
gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);
gfx::Matrix oldMatrix = dt->GetTransform();
dt->SetTransform(oldMatrix * rotate);
dt->DrawSurface(surf, dstRect, srcRect, dt->DrawSurface(surf, dstRect, srcRect,
DrawSurfaceOptions(), DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER)); DrawOptions(1.0f, CompositionOp::OP_OVER));
dt->SetTransform(oldMatrix);
} }
mForwarder->DestroySharedSurface(&inSnapshot); mForwarder->DestroySharedSurface(&inSnapshot);
} }

Просмотреть файл

@ -934,7 +934,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw", PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
js::ProfileEntry::Category::GRAPHICS); js::ProfileEntry::Category::GRAPHICS);
mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData); mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
} }
#ifdef GFX_TILEDLAYER_PREF_WARNINGS #ifdef GFX_TILEDLAYER_PREF_WARNINGS
@ -1304,7 +1304,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
Scale(mResolution, mResolution)); Scale(mResolution, mResolution));
mCallback(mPaintedLayer, ctxt, mCallback(mPaintedLayer, ctxt,
tileRegion.GetBounds(), tileRegion.GetBounds(),
DrawRegionClip::CLIP_NONE, DrawRegionClip::NONE,
nsIntRegion(), mCallbackData); nsIntRegion(), mCallbackData);
} }

Просмотреть файл

@ -537,7 +537,7 @@ PaintedLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y)); context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y));
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); cbInfo.Callback(this, context, aRegion, DrawRegionClip::NONE, nsIntRegion(), cbInfo.CallbackData);
for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,

Просмотреть файл

@ -13,6 +13,7 @@
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h" #include "ipc/Nuwa.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/dom/ContentParent.h"
#endif #endif
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
@ -70,6 +71,9 @@ ProcessLink::ProcessLink(MessageChannel *aChan)
, mTransport(nullptr) , mTransport(nullptr)
, mIOLoop(nullptr) , mIOLoop(nullptr)
, mExistingListener(nullptr) , mExistingListener(nullptr)
#ifdef MOZ_NUWA_PROCESS
, mIsToNuwaProcess(false)
#endif
{ {
} }
@ -168,6 +172,26 @@ ProcessLink::SendMessage(Message *msg)
mChan->AssertWorkerThread(); mChan->AssertWorkerThread();
mChan->mMonitor->AssertCurrentThreadOwns(); mChan->mMonitor->AssertCurrentThreadOwns();
#ifdef MOZ_NUWA_PROCESS
if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
switch (msg->type()) {
case mozilla::dom::PContent::Msg_NuwaFork__ID:
case mozilla::dom::PContent::Reply_AddNewProcess__ID:
case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
case GOODBYE_MESSAGE_TYPE:
break;
default:
#ifdef DEBUG
MOZ_CRASH();
#else
// In optimized build, message will be dropped.
printf_stderr("Sending message to frozen Nuwa");
return;
#endif
}
}
#endif
mIOLoop->PostTask( mIOLoop->PostTask(
FROM_HERE, FROM_HERE,
NewRunnableMethod(mTransport, &Transport::Send, msg)); NewRunnableMethod(mTransport, &Transport::Send, msg));
@ -360,6 +384,10 @@ ProcessLink::OnChannelConnected(int32_t peer_pid)
if (mExistingListener) if (mExistingListener)
mExistingListener->OnChannelConnected(peer_pid); mExistingListener->OnChannelConnected(peer_pid);
#ifdef MOZ_NUWA_PROCESS
mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid());
#endif
if (notifyChannel) { if (notifyChannel) {
mChan->OnChannelConnected(peer_pid); mChan->OnChannelConnected(peer_pid);
} }

Просмотреть файл

@ -170,6 +170,9 @@ class ProcessLink
Transport* mTransport; Transport* mTransport;
MessageLoop* mIOLoop; // thread where IO happens MessageLoop* mIOLoop; // thread where IO happens
Transport::Listener* mExistingListener; // channel's previous listener Transport::Listener* mExistingListener; // channel's previous listener
#ifdef MOZ_NUWA_PROCESS
bool mIsToNuwaProcess;
#endif
}; };
class ThreadLink : public MessageLink class ThreadLink : public MessageLink

Просмотреть файл

@ -2016,6 +2016,12 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
*answer = true; *answer = true;
} }
} }
if (pn->isHoistedLetUse()) {
// Hoisted uses of lexical bindings throw on access.
*answer = true;
}
if (pn->isKind(PNK_DOT)) { if (pn->isKind(PNK_DOT)) {
/* Dotted property references in general can call getters. */ /* Dotted property references in general can call getters. */
*answer = true; *answer = true;

Просмотреть файл

@ -0,0 +1,23 @@
function assertThrowsReferenceError(f) {
var e = null;
try {
f();
} catch (ex) {
e = ex;
}
assertEq(e instanceof ReferenceError, true);
}
assertThrowsReferenceError(function () { delete x; let x; });
// FIXME do this unconditionally once bug 611388 lands.
function constIsLexical() {
try {
(function () { z++; const z; })();
return false;
} catch (e) {
return true;
}
}
if (constIsLexical())
assertThrowsReferenceError(function () { delete x; const x; });

Просмотреть файл

@ -0,0 +1,24 @@
function assertThrowsReferenceError(f) {
var e = null;
try {
f();
} catch (ex) {
e = ex;
}
assertEq(e instanceof ReferenceError, true);
}
// TDZ is effectful, don't optimize out x.
assertThrowsReferenceError(function () { x; let x; });
// FIXME do this unconditionally once bug 611388 lands.
function constIsLexical() {
try {
(function () { z++; const z; })();
return false;
} catch (e) {
return true;
}
}
if (constIsLexical())
assertThrowsReferenceError(function () { x; const x; });

Просмотреть файл

@ -0,0 +1,5 @@
// |jit-test| error: ReferenceError
{
while (x && 0) {}
let x
}

Просмотреть файл

@ -0,0 +1,10 @@
try {
let x = ((function f(y) {
if (y > 0) {
f(-1)
}
x
})(1))
} catch (e) {
assertEq(e instanceof ReferenceError, true);
}

Просмотреть файл

@ -7911,13 +7911,28 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch); masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
masm.storePtr(scratch, shapeAddr); masm.storePtr(scratch, shapeAddr);
// Change the object's type if required. // Try to change the object's type.
Label noTypeChange; Label noTypeChange;
// Check if the cache has a new type to change to.
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch); masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange); masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange);
// Check if the old type still has a newScript.
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch);
masm.branchPtr(Assembler::Equal,
Address(scratch, types::TypeObject::offsetOfNewScript()),
ImmWord(0),
&noTypeChange);
// Reload the new type from the cache.
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
// Change the object's type.
Address typeAddr(objReg, JSObject::offsetOfType()); Address typeAddr(objReg, JSObject::offsetOfType());
EmitPreBarrier(masm, typeAddr, MIRType_TypeObject); EmitPreBarrier(masm, typeAddr, MIRType_TypeObject);
masm.storePtr(scratch, typeAddr); masm.storePtr(scratch, typeAddr);
masm.bind(&noTypeChange); masm.bind(&noTypeChange);
Register holderReg; Register holderReg;

Просмотреть файл

@ -2583,11 +2583,27 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
if (oldType != obj->type()) { if (oldType != obj->type()) {
// Changing object's type from a partially to fully initialized type, // Changing object's type from a partially to fully initialized type,
// per the acquired properties analysis. // per the acquired properties analysis. Only change the type if the
// old type still has a newScript.
Label noTypeChange, skipPop;
masm.push(object);
masm.loadPtr(Address(object, JSObject::offsetOfType()), object);
masm.branchPtr(Assembler::Equal,
Address(object, types::TypeObject::offsetOfNewScript()),
ImmWord(0),
&noTypeChange);
masm.pop(object);
Address typeAddr(object, JSObject::offsetOfType()); Address typeAddr(object, JSObject::offsetOfType());
if (cx->zone()->needsIncrementalBarrier()) if (cx->zone()->needsIncrementalBarrier())
masm.callPreBarrier(typeAddr, MIRType_TypeObject); masm.callPreBarrier(typeAddr, MIRType_TypeObject);
masm.storePtr(ImmGCPtr(obj->type()), typeAddr); masm.storePtr(ImmGCPtr(obj->type()), typeAddr);
masm.jump(&skipPop);
masm.bind(&noTypeChange);
masm.pop(object);
masm.bind(&skipPop);
} }
// Set the value on the object. Since this is an add, obj->lastProperty() // Set the value on the object. Since this is an add, obj->lastProperty()

Просмотреть файл

@ -573,6 +573,13 @@ jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *
return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::ObjectType(obj)); return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::ObjectType(obj));
} }
static types::TemporaryTypeSet *
MakeUnknownTypeSet()
{
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::UnknownType());
}
MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints) MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
: value_(vp) : value_(vp)
{ {
@ -582,6 +589,16 @@ MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constra
// other types as the result type encodes all needed information. // other types as the result type encodes all needed information.
setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject())); setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
} }
if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
// JS_UNINITIALIZED_LEXICAL does not escape to script and is not
// observed in type sets. However, it may flow around freely during
// Ion compilation. Give it an unknown typeset to poison any type sets
// it merges with.
//
// TODO We could track uninitialized lexicals more precisely by tracking
// them in type sets.
setResultTypeSet(MakeUnknownTypeSet());
}
setMovable(); setMovable();
} }

Просмотреть файл

@ -7,17 +7,19 @@ The tests in this directory exercise the JSAPI.
If you built JS, you already built the tests. If you built JS, you already built the tests.
If you did `make check` in your JS objdir, you already ran them.
The tests are built by default when you build JS. All the tests are compiled The tests are built by default when you build JS. All the tests are compiled
into a single binary named jsapi-tests. They all run in a single process. into a single binary named jsapi-tests. They all run in a single process.
To run the tests:
cd $OBJDIR/dist/bin
./jsapi-tests
To run the tests in a debugger: To run the tests in a debugger:
cd $OBJDIR/jsapi-tests cd $OBJDIR/dist/bin
gdb ./jsapi-tests gdb ./jsapi-tests
--- Creating new tests --- Creating new tests
1. You can either add to an existing test*.cpp file or make a new one. 1. You can either add to an existing test*.cpp file or make a new one.

Просмотреть файл

@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
'testException.cpp', 'testException.cpp',
'testExternalStrings.cpp', 'testExternalStrings.cpp',
'testFindSCCs.cpp', 'testFindSCCs.cpp',
'testForOfIterator.cpp',
'testFreshGlobalEvalRedefinition.cpp', 'testFreshGlobalEvalRedefinition.cpp',
'testFuncCallback.cpp', 'testFuncCallback.cpp',
'testFunctionProperties.cpp', 'testFunctionProperties.cpp',

Просмотреть файл

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi-tests/tests.h"
BEGIN_TEST(testForOfIterator_basicNonIterable)
{
JS::RootedValue v(cx);
// Hack to make it simple to produce an object that has a property
// named Symbol.iterator.
EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
JS::ForOfIterator iter(cx);
bool ok = iter.init(v);
CHECK(!ok);
JS_ClearPendingException(cx);
return true;
}
END_TEST(testForOfIterator_basicNonIterable)
BEGIN_TEST(testForOfIterator_bug515273_part1)
{
JS::RootedValue v(cx);
// Hack to make it simple to produce an object that has a property
// named Symbol.iterator.
EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
JS::ForOfIterator iter(cx);
bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
CHECK(!ok);
JS_ClearPendingException(cx);
return true;
}
END_TEST(testForOfIterator_bug515273_part1)
BEGIN_TEST(testForOfIterator_bug515273_part2)
{
JS::RootedObject obj(cx,
JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
CHECK(obj);
JS::RootedValue v(cx, JS::ObjectValue(*obj));
JS::ForOfIterator iter(cx);
bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
CHECK(ok);
CHECK(!iter.valueIsIterable());
return true;
}
END_TEST(testForOfIterator_bug515273_part2)

Просмотреть файл

@ -5191,10 +5191,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) {
}; };
/* /*
* Initialize the iterator. If AllowNonIterable is passed then if iterable * Initialize the iterator. If AllowNonIterable is passed then if getting
* does not have a callable @@iterator init() will just return true instead * the @@iterator property from iterable returns undefined init() will just
* of throwing. Callers should then check valueIsIterable() before * return true instead of throwing. Callers must then check
* continuing with the iteration. * valueIsIterable() before continuing with the iteration.
*/ */
bool init(JS::HandleValue iterable, bool init(JS::HandleValue iterable,
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);

Просмотреть файл

@ -1236,6 +1236,10 @@ struct TypeObject : public gc::TenuredCell
return offsetof(TypeObject, proto_); return offsetof(TypeObject, proto_);
} }
static inline uint32_t offsetOfNewScript() {
return offsetof(TypeObject, newScript_);
}
private: private:
inline uint32_t basePropertyCount() const; inline uint32_t basePropertyCount() const;
inline void setBasePropertyCount(uint32_t count); inline void setBasePropertyCount(uint32_t count);

Просмотреть файл

@ -1366,13 +1366,17 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee)) if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
return false; return false;
// Throw if obj[@@iterator] isn't callable if we were asked to do so. // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
// bail out now without setting iterator. This will make valueIsIterable(),
// which our caller should check, return false.
if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
return true;
// Throw if obj[@@iterator] isn't callable.
// js::Invoke is about to check for this kind of error anyway, but it would // js::Invoke is about to check for this kind of error anyway, but it would
// throw an inscrutable error message about |method| rather than this nice // throw an inscrutable error message about |method| rather than this nice
// one about |obj|. // one about |obj|.
if (!callee.isObject() || !callee.toObject().isCallable()) { if (!callee.isObject() || !callee.toObject().isCallable()) {
if (nonIterableBehavior == AllowNonIterable)
return true;
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr()); char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
if (!bytes) if (!bytes)
return false; return false;

Просмотреть файл

@ -254,7 +254,10 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
return false; return false;
} }
} }
return true;
// NAME operations are the slow paths already, so unconditionally check
// for uninitialized lets.
return CheckUninitializedLexical(cx, name, vp);
} }
inline bool inline bool
@ -264,7 +267,7 @@ FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp)
return false; return false;
vp.set(pobj->nativeGetSlot(shape->slot())); vp.set(pobj->nativeGetSlot(shape->slot()));
return true; return !IsUninitializedLexical(vp);
} }
inline bool inline bool

Просмотреть файл

@ -298,17 +298,9 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle
/* Kludge to allow (typeof foo == "undefined") tests. */ /* Kludge to allow (typeof foo == "undefined") tests. */
JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]); JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
if (op2 == JSOP_TYPEOF) { if (op2 == JSOP_TYPEOF)
if (!FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp)) return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
return false; return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
} else {
if (!FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
return false;
}
// NAME operations are the slow paths already, so unconditionally check
// for uninitialized lets.
return CheckUninitializedLexical(cx, nameRoot, vp);
} }
static inline bool static inline bool
@ -3564,7 +3556,7 @@ js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name
if (!JSObject::getProperty(cx, obj, obj, name, vp)) if (!JSObject::getProperty(cx, obj, obj, name, vp))
return false; return false;
// See note in NameOperation. // See note in FetchName.
return CheckUninitializedLexical(cx, name, vp); return CheckUninitializedLexical(cx, name, vp);
} }
@ -3589,7 +3581,7 @@ js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandleProperty
if (!JSObject::getProperty(cx, obj, obj, name, vp)) if (!JSObject::getProperty(cx, obj, obj, name, vp))
return false; return false;
// See note in NameOperation. // See note in FetchName.
return CheckUninitializedLexical(cx, name, vp); return CheckUninitializedLexical(cx, name, vp);
} }
@ -3874,6 +3866,13 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco
return true; return true;
} }
// NAME operations are the slow paths already, so unconditionally check
// for uninitialized lets.
if (pobj == scope && IsUninitializedLexicalSlot(scope, shape)) {
ReportUninitializedLexical(cx, name);
return false;
}
bool succeeded; bool succeeded;
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
if (!JSObject::deleteGeneric(cx, scope, id, &succeeded)) if (!JSObject::deleteGeneric(cx, scope, id, &succeeded))

Просмотреть файл

@ -4371,7 +4371,7 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip) static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
{ {
if (!gfxPrefs::LayoutPaintRectsSeparately() || if (!gfxPrefs::LayoutPaintRectsSeparately() ||
aClip == DrawRegionClip::CLIP_NONE) { aClip == DrawRegionClip::NONE) {
return false; return false;
} }
@ -4453,9 +4453,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip); bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
if (!shouldDrawRectsSeparately) { if (!shouldDrawRectsSeparately) {
if (aClip == DrawRegionClip::DRAW_SNAPPED) { if (aClip == DrawRegionClip::DRAW) {
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
} else if (aClip == DrawRegionClip::DRAW) {
gfxUtils::ClipToRegion(aContext, aRegionToDraw); gfxUtils::ClipToRegion(aContext, aRegionToDraw);
} }
@ -4486,7 +4484,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
while (const nsIntRect* iterRect = it.Next()) { while (const nsIntRect* iterRect = it.Next()) {
gfxContextAutoSaveRestore save(aContext); gfxContextAutoSaveRestore save(aContext);
aContext->NewPath(); aContext->NewPath();
aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED); aContext->Rectangle(*iterRect);
aContext->Clip(); aContext->Clip();
DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
@ -4522,9 +4520,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
if (presContext->GetPaintFlashing() && isActiveLayerManager) { if (presContext->GetPaintFlashing() && isActiveLayerManager) {
gfxContextAutoSaveRestore save(aContext); gfxContextAutoSaveRestore save(aContext);
if (shouldDrawRectsSeparately) { if (shouldDrawRectsSeparately) {
if (aClip == DrawRegionClip::DRAW_SNAPPED) { if (aClip == DrawRegionClip::DRAW) {
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
} else if (aClip == DrawRegionClip::DRAW) {
gfxUtils::ClipToRegion(aContext, aRegionToDraw); gfxUtils::ClipToRegion(aContext, aRegionToDraw);
} }
} }

Просмотреть файл

@ -3069,6 +3069,16 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
oldContext.get(), newContext.get()); oldContext.get(), newContext.get());
oldContext->SwapStyleData(newContext, equalStructs); oldContext->SwapStyleData(newContext, equalStructs);
*aSwappedStructs |= equalStructs; *aSwappedStructs |= equalStructs;
#ifdef RESTYLE_LOGGING
uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
if (structs) {
LOG_RESTYLE_INDENT();
LOG_RESTYLE("old style context now has: %s",
oldContext->GetCachedStyleDataAsString(structs).get());
LOG_RESTYLE("new style context now has: %s",
newContext->GetCachedStyleDataAsString(structs).get());
}
#endif
} }
LOG_RESTYLE("setting new style context"); LOG_RESTYLE("setting new style context");
aSelf->SetStyleContext(newContext); aSelf->SetStyleContext(newContext);
@ -3636,6 +3646,39 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame,
} }
} }
#ifdef RESTYLE_LOGGING
uint32_t
RestyleManager::StructsToLog()
{
static bool initialized = false;
static uint32_t structs;
if (!initialized) {
structs = 0;
const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
if (value) {
nsCString s(value);
while (!s.IsEmpty()) {
int32_t index = s.FindChar(',');
nsStyleStructID sid;
bool found;
if (index == -1) {
found = nsStyleContext::LookupStruct(s, sid);
s.Truncate();
} else {
found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
s = Substring(s, index + 1);
}
if (found) {
structs |= nsCachedStyleData::GetBitForSID(sid);
}
}
}
initialized = true;
}
return structs;
}
#endif
#ifdef DEBUG #ifdef DEBUG
/* static */ nsCString /* static */ nsCString
RestyleManager::RestyleHintToString(nsRestyleHint aHint) RestyleManager::RestyleHintToString(nsRestyleHint aHint)

Просмотреть файл

@ -386,6 +386,13 @@ public:
return animations; return animations;
} }
// Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
// style struct names -- such as "Font,SVGReset" -- to log the style context
// tree and those cached struct pointers before each restyle. This
// function returns a bitfield of the structs named in the
// environment variable.
static uint32_t StructsToLog();
static nsCString StructNamesToString(uint32_t aSIDs); static nsCString StructNamesToString(uint32_t aSIDs);
int32_t& LoggingDepth() { return mLoggingDepth; } int32_t& LoggingDepth() { return mLoggingDepth; }
#endif #endif

Просмотреть файл

@ -162,7 +162,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
RestyleManager::ChangeHintToString(aChangeHint).get()); RestyleManager::ChangeHintToString(aChangeHint).get());
nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (aRestyleHint & ~eRestyle_LaterSiblings) { if (aRestyleHint & ~eRestyle_LaterSiblings) {
#ifdef RESTYLE_LOGGING
if (ShouldLogRestyle() && primaryFrame &&
RestyleManager::StructsToLog() != 0) {
LOG_RESTYLE("style context tree before restyle:");
LOG_RESTYLE_INDENT();
primaryFrame->StyleContext()->LogStyleContextTree(
LoggingDepth(), RestyleManager::StructsToLog());
}
#endif
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint, mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
*this, aRestyleHint); *this, aRestyleHint);
} else if (aChangeHint && } else if (aChangeHint &&

Просмотреть файл

@ -1224,7 +1224,8 @@ void
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine, nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
int32_t aNumFramesOnLine, int32_t aNumFramesOnLine,
WritingMode aLineWM, WritingMode aLineWM,
nscoord& aLineWidth) nscoord& aLineWidth,
nscoord aStart)
{ {
// If this line consists of a line frame, reorder the line frame's children. // If this line consists of a line frame, reorder the line frame's children.
if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) { if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
@ -1237,7 +1238,7 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
} }
BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine); BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth); RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
} }
nsIFrame* nsIFrame*
@ -1279,6 +1280,7 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame)
void void
nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame, nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
nsContinuationStates* aContinuationStates, nsContinuationStates* aContinuationStates,
bool aSpanDirMatchesLineDir,
bool& aIsFirst /* out */, bool& aIsFirst /* out */,
bool& aIsLast /* out */) bool& aIsLast /* out */)
{ {
@ -1293,6 +1295,7 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
* chain on this line. * chain on this line.
*/ */
bool firstInLineOrder, lastInLineOrder;
nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame); nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
nsFrameContinuationState* firstFrameState; nsFrameContinuationState* firstFrameState;
@ -1327,16 +1330,30 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
} }
frameState->mHasContOnNextLines = (frame != nullptr); frameState->mHasContOnNextLines = (frame != nullptr);
aIsFirst = !frameState->mHasContOnPrevLines; firstInLineOrder = true;
firstFrameState = frameState; firstFrameState = frameState;
} else { } else {
// aFrame is not the first visual frame of its continuation chain // aFrame is not the first visual frame of its continuation chain
aIsFirst = false; firstInLineOrder = false;
firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame); firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
} }
aIsLast = (firstFrameState->mFrameCount == 1 && lastInLineOrder = (firstFrameState->mFrameCount == 1);
!firstFrameState->mHasContOnNextLines);
if (aSpanDirMatchesLineDir) {
aIsFirst = firstInLineOrder;
aIsLast = lastInLineOrder;
} else {
aIsFirst = lastInLineOrder;
aIsLast = firstInLineOrder;
}
if (frameState->mHasContOnPrevLines) {
aIsFirst = false;
}
if (firstFrameState->mHasContOnNextLines) {
aIsLast = false;
}
if ((aIsFirst || aIsLast) && if ((aIsFirst || aIsLast) &&
(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
@ -1356,6 +1373,24 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
// Reduce number of remaining frames of the continuation chain on the line. // Reduce number of remaining frames of the continuation chain on the line.
firstFrameState->mFrameCount--; firstFrameState->mFrameCount--;
nsInlineFrame* testFrame = do_QueryFrame(aFrame);
if (testFrame) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
if (aIsFirst) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
} else {
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
}
if (aIsLast) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
} else {
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
}
}
} }
void void
@ -1363,55 +1398,46 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
bool aIsEvenLevel, bool aIsEvenLevel,
nscoord& aStart, nscoord& aStart,
nsContinuationStates* aContinuationStates, nsContinuationStates* aContinuationStates,
WritingMode aLineWM, WritingMode aContainerWM,
nscoord& aLineWidth) nscoord& aContainerWidth)
{ {
if (!aFrame) if (!aFrame)
return; return;
bool isFirst, isLast; bool isFirst, isLast;
WritingMode frameWM = aFrame->GetWritingMode();
IsFirstOrLast(aFrame, IsFirstOrLast(aFrame,
aContinuationStates, aContinuationStates,
aContainerWM.IsBidiLTR() == frameWM.IsBidiLTR(),
isFirst /* out */, isFirst /* out */,
isLast /* out */); isLast /* out */);
WritingMode frameWM = aFrame->GetWritingMode(); // We only need the margin if the frame is first or last in its own
nsInlineFrame* testFrame = do_QueryFrame(aFrame); // writing mode, but we're traversing the frames in the order of the
// container's writing mode. To get the right values, we set start and
// end margins on a logical margin in the frame's writing mode, and
// then convert the margin to the container's writing mode to set the
// coordinates.
if (testFrame) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
if (isFirst) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
} else {
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
}
if (isLast) {
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
} else {
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
}
}
// This method is called from nsBlockFrame::PlaceLine via the call to // This method is called from nsBlockFrame::PlaceLine via the call to
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
// have been reflowed, which is required for GetUsedMargin/Border/Padding // have been reflowed, which is required for GetUsedMargin/Border/Padding
LogicalMargin margin(aLineWM, aFrame->GetUsedMargin()); LogicalMargin frameMargin = aFrame->GetLogicalUsedMargin(frameWM);
if (isFirst) { LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(frameWM);
aStart += margin.IStart(aLineWM); if (!isFirst) {
frameMargin.IStart(frameWM) = 0;
borderPadding.IStart(frameWM) = 0;
} }
if (!isLast) {
frameMargin.IEnd(frameWM) = 0;
borderPadding.IEnd(frameWM) = 0;
}
LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM);
aStart += margin.IStart(aContainerWM);
nscoord start = aStart; nscoord start = aStart;
nscoord frameISize = aFrame->ISize(aLineWM);
if (!IsBidiLeaf(aFrame))
{
nscoord iCoord = 0;
LogicalMargin borderPadding(frameWM, aFrame->GetUsedBorderAndPadding());
if (isFirst) {
iCoord += borderPadding.IStart(frameWM);
}
if (!IsBidiLeaf(aFrame)) {
// If the resolved direction of the container is different from the // If the resolved direction of the container is different from the
// direction of the frame, we need to traverse the child list in reverse // direction of the frame, we need to traverse the child list in reverse
// order, to make it O(n) we store the list locally and iterate the list // order, to make it O(n) we store the list locally and iterate the list
@ -1430,35 +1456,33 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
// Reposition the child frames // Reposition the child frames
int32_t index = 0; int32_t index = 0;
nscoord iCoord = borderPadding.IStart(frameWM);
while (frame) { while (frame) {
RepositionFrame(frame, RepositionFrame(frame,
aIsEvenLevel, aIsEvenLevel,
iCoord, iCoord,
aContinuationStates, aContinuationStates,
frameWM, frameWM,
frameISize); aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
index++; index++;
frame = reverseOrder ? frame = reverseOrder ?
childList[childList.Length() - index - 1] : childList[childList.Length() - index - 1] :
frame->GetNextSibling(); frame->GetNextSibling();
} }
if (isLast) { aStart += iCoord + borderPadding.IEnd(frameWM);
iCoord += borderPadding.IEnd(frameWM);
}
aStart += iCoord;
} else { } else {
aStart += frameISize; aStart += aFrame->ISize(aContainerWM);
} }
LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth); LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
logicalRect.IStart(aLineWM) = start; aContainerWidth);
logicalRect.ISize(aLineWM) = aStart - start; logicalRect.IStart(aContainerWM) = start;
aFrame->SetRect(aLineWM, logicalRect, aLineWidth); logicalRect.ISize(aContainerWM) = aStart - start;
aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
if (isLast) { aStart += margin.IEnd(aContainerWM);
aStart += margin.IEnd(aLineWM);
}
} }
void void
@ -1485,20 +1509,10 @@ void
nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld, nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
nsIFrame* aFirstChild, nsIFrame* aFirstChild,
WritingMode aLineWM, WritingMode aLineWM,
nscoord& aLineWidth) nscoord& aLineWidth,
nscoord& aStart)
{ {
nscoord startSpace = 0; nscoord start = aStart;
// This method is called from nsBlockFrame::PlaceLine via the call to
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
// have been reflowed, which is required for GetUsedMargin/Border/Padding
LogicalMargin margin(aLineWM, aFirstChild->GetUsedMargin());
if (!aFirstChild->GetPrevContinuation() &&
!aFirstChild->FrameIsNonFirstInIBSplit())
startSpace = margin.IStart(aLineWM);
nscoord start = LogicalRect(aLineWM, aFirstChild->GetRect(),
aLineWidth).IStart(aLineWM) - startSpace;
nsIFrame* frame; nsIFrame* frame;
int32_t count = aBld->mVisualFrames.Length(); int32_t count = aBld->mVisualFrames.Length();
int32_t index; int32_t index;

Просмотреть файл

@ -160,7 +160,8 @@ public:
static void ReorderFrames(nsIFrame* aFirstFrameOnLine, static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
int32_t aNumFramesOnLine, int32_t aNumFramesOnLine,
mozilla::WritingMode aLineWM, mozilla::WritingMode aLineWM,
nscoord& aLineWidth); nscoord& aLineWidth,
nscoord aStart);
/** /**
* Format Unicode text, taking into account bidi capabilities * Format Unicode text, taking into account bidi capabilities
@ -397,8 +398,8 @@ private:
bool aIsEvenLevel, bool aIsEvenLevel,
nscoord& aStart, nscoord& aStart,
nsContinuationStates* aContinuationStates, nsContinuationStates* aContinuationStates,
mozilla::WritingMode aLineWM, mozilla::WritingMode aContainerWM,
nscoord& aLineWidth); nscoord& aContainerWidth);
/* /*
* Initialize the continuation state(nsFrameContinuationState) to * Initialize the continuation state(nsFrameContinuationState) to
@ -412,22 +413,32 @@ private:
nsContinuationStates* aContinuationStates); nsContinuationStates* aContinuationStates);
/* /*
* Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and * Determine if aFrame is first or last, and set aIsFirst and
* aIsRightMost values. Also set continuation states of aContinuationStates. * aIsLast values. Also set continuation states of
* aContinuationStates.
* *
* A frame is leftmost if it's the first appearance of its continuation chain * A frame is first if it's the first appearance of its continuation
* on the line and the chain is on its first line if it's LTR or the chain is * chain on the line and the chain is on its first line.
* on its last line if it's RTL. * A frame is last if it's the last appearance of its continuation
* A frame is rightmost if it's the last appearance of its continuation chain * chain on the line and the chain is on its last line.
* on the line and the chain is on its first line if it's RTL or the chain is
* on its last line if it's LTR.
* *
* @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState * N.B: "First appearance" and "Last appearance" in the previous
* @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation * paragraph refer to the frame's inline direction, not necessarily
* @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation * the line's.
*
* @param aContinuationStates A map from nsIFrame* to
* nsFrameContinuationState
* @param[in] aSpanDirMatchesLineDir TRUE means that the inline
* direction of aFrame is the same
* as its container
* @param[out] aIsFirst TRUE means aFrame is first frame
* or continuation
* @param[out] aIsLast TRUE means aFrame is last frame
* or continuation
*/ */
static void IsFirstOrLast(nsIFrame* aFrame, static void IsFirstOrLast(nsIFrame* aFrame,
nsContinuationStates* aContinuationStates, nsContinuationStates* aContinuationStates,
bool aSpanInLineOrder /* in */,
bool& aIsFirst /* out */, bool& aIsFirst /* out */,
bool& aIsLast /* out */); bool& aIsLast /* out */);
@ -441,7 +452,8 @@ private:
static void RepositionInlineFrames(BidiLineData* aBld, static void RepositionInlineFrames(BidiLineData* aBld,
nsIFrame* aFirstChild, nsIFrame* aFirstChild,
mozilla::WritingMode aLineWM, mozilla::WritingMode aLineWM,
nscoord& aLineWidth); nscoord& aLineWidth,
nscoord& aStart);
/** /**
* Helper method for Resolve() * Helper method for Resolve()

Просмотреть файл

@ -2598,20 +2598,22 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
} }
} }
if (dx) { if (mPresContext->BidiEnabled() &&
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
aLine->GetChildCount(),
lineWM, mContainerWidth,
psd->mIStart + mTextIndent + dx);
if (dx) {
aLine->IndentBy(dx, mContainerWidth);
}
} else if (dx) {
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
pfd->mBounds.IStart(lineWM) += dx; pfd->mBounds.IStart(lineWM) += dx;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth); pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
} }
aLine->IndentBy(dx, mContainerWidth); aLine->IndentBy(dx, mContainerWidth);
} }
if (mPresContext->BidiEnabled() &&
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
aLine->GetChildCount(),
lineWM, mContainerWidth);
}
} }
void void

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for bug 1069941 -- borders</title>
</head>
<body>
<div dir="ltr">
<span dir="ltr" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
</div>
<div dir="ltr">
<span dir="ltr" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for bug 1069941 -- borders</title>
</head>
<body>
<div dir="ltr">
<span dir="rtl" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
</div>
<div dir="ltr">
<span dir="rtl" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for bug 1069941 -- margins</title>
<style type="text/css">
.outer {
display: inline-block;
border: 1px solid lime;
}
.inner {
color:transparent;
margin-left: 50px;
border: 2px solid teal;
}
</style>
</head>
<body>
<span class="outer"><span class="inner">(12]</span></span>
</body>
</html>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for bug 1069941 -- margins</title>
<style type="text/css">
.outer {
display: inline-block;
border: 1px solid lime;
}
.inner {
color:transparent;
margin-left: 50px;
border: 2px solid teal;
}
</style>
</head>
<body>
<span class="outer"><span class="inner" dir="rtl">[12)</span></span>
</body>
</html>

Просмотреть файл

@ -142,3 +142,6 @@ skip-if(B2G) == 726420-1.html 726420-1-ref.html
skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul
== 922530-1.html 922530-1-ref.html == 922530-1.html 922530-1-ref.html
== 922550-1.html 922550-1-ref.html == 922550-1.html 922550-1-ref.html
== 1069941-inline-bidi-border-1.html 1069941-inline-bidi-border-1-ref.html
== 1069941-inline-bidi-margin-1.html 1069941-inline-bidi-margin-1-ref.html

Просмотреть файл

@ -1048,6 +1048,21 @@ nsStyleContext::StructName(nsStyleStructID aSID)
return "Unknown"; return "Unknown";
} }
} }
/* static */ bool
nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
{
if (false)
;
#define STYLE_STRUCT(name_, checkdata_cb_) \
else if (aName.EqualsLiteral(#name_)) \
aResult = eStyleStruct_##name_;
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
else
return false;
return true;
}
#endif #endif
bool bool
@ -1162,3 +1177,96 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
ClearCachedInheritedStyleDataOnDescendants(aStructs); ClearCachedInheritedStyleDataOnDescendants(aStructs);
} }
#ifdef RESTYLE_LOGGING
nsCString
nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
{
nsCString structs;
for (nsStyleStructID i = nsStyleStructID(0);
i < nsStyleStructID_Length;
i = nsStyleStructID(i + 1)) {
if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
const void* data = GetCachedStyleData(i);
if (!structs.IsEmpty()) {
structs.Append(' ');
}
structs.AppendPrintf("%s=%p", StructName(i), data);
if (HasCachedInheritedStyleData(i)) {
structs.AppendLiteral("(dependent)");
} else {
structs.AppendLiteral("(owned)");
}
}
}
return structs;
}
int32_t&
nsStyleContext::LoggingDepth()
{
static int32_t depth = 0;
return depth;
}
void
nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
{
LoggingDepth() = aLoggingDepth;
LogStyleContextTree(true, aStructs);
}
void
nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
{
nsCString structs = GetCachedStyleDataAsString(aStructs);
if (!structs.IsEmpty()) {
structs.Append(' ');
}
nsCString pseudo;
if (mPseudoTag) {
nsAutoString pseudoTag;
mPseudoTag->ToString(pseudoTag);
AppendUTF16toUTF8(pseudoTag, pseudo);
pseudo.Append(' ');
}
nsCString flags;
if (IsStyleIfVisited()) {
flags.AppendLiteral("IS_STYLE_IF_VISITED ");
}
if (UsesGrandancestorStyle()) {
flags.AppendLiteral("USES_GRANDANCESTOR_STYLE ");
}
if (IsShared()) {
flags.AppendLiteral("IS_SHARED ");
}
nsCString parent;
if (aFirst) {
parent.AppendPrintf("parent=%p ", mParent);
}
LOG_RESTYLE("%p(%d) %s%s%s%s",
this, mRefCnt,
structs.get(), pseudo.get(), flags.get(), parent.get());
LOG_RESTYLE_INDENT();
if (nullptr != mChild) {
nsStyleContext* child = mChild;
do {
child->LogStyleContextTree(false, aStructs);
child = child->mNextSibling;
} while (mChild != child);
}
if (nullptr != mEmptyChild) {
nsStyleContext* child = mEmptyChild;
do {
child->LogStyleContextTree(false, aStructs);
child = child->mNextSibling;
} while (mEmptyChild != child);
}
}
#endif

Просмотреть файл

@ -8,6 +8,7 @@
#ifndef _nsStyleContext_h_ #ifndef _nsStyleContext_h_
#define _nsStyleContext_h_ #define _nsStyleContext_h_
#include "mozilla/RestyleLogging.h"
#include "nsRuleNode.h" #include "nsRuleNode.h"
#include "nsCSSPseudoElements.h" #include "nsCSSPseudoElements.h"
@ -397,6 +398,13 @@ public:
void List(FILE* out, int32_t aIndent); void List(FILE* out, int32_t aIndent);
static void AssertStyleStructMaxDifferenceValid(); static void AssertStyleStructMaxDifferenceValid();
static const char* StructName(nsStyleStructID aSID); static const char* StructName(nsStyleStructID aSID);
static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
#endif
#ifdef RESTYLE_LOGGING
nsCString GetCachedStyleDataAsString(uint32_t aStructs);
void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
int32_t& LoggingDepth();
#endif #endif
private: private:
@ -450,6 +458,15 @@ private:
int32_t aLevels) const; int32_t aLevels) const;
#endif #endif
#ifdef RESTYLE_LOGGING
void LogStyleContextTree(bool aFirst, uint32_t aStructs);
// This only gets called under call trees where we've already checked
// that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
// It exists here just to satisfy LOG_RESTYLE's expectations.
bool ShouldLogRestyle() { return true; }
#endif
nsStyleContext* mParent; // STRONG nsStyleContext* mParent; // STRONG
// Children are kept in two circularly-linked lists. The list anchor // Children are kept in two circularly-linked lists. The list anchor

Просмотреть файл

@ -164,6 +164,7 @@ class RemoteOptions(ReftestOptions):
# Android does not run leak tests, but set some reasonable defaults to avoid errors. # Android does not run leak tests, but set some reasonable defaults to avoid errors.
options.leakThresholds = {} options.leakThresholds = {}
options.ignoreMissingLeaks = []
# TODO: Copied from main, but I think these are no longer used in a post xulrunner world # TODO: Copied from main, but I think these are no longer used in a post xulrunner world
#options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner' #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'

Просмотреть файл

@ -344,7 +344,7 @@ class RefTest(object):
# give the JS harness 30 seconds to deal # give the JS harness 30 seconds to deal
# with its own timeouts # with its own timeouts
timeout=options.timeout + 30.0) timeout=options.timeout + 30.0)
processLeakLog(self.leakLogFile, options.leakThresholds) processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks)
self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.") self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
finally: finally:
self.cleanup(profileDir) self.cleanup(profileDir)
@ -513,6 +513,8 @@ class ReftestOptions(OptionParser):
options.leakThresholds = {"default": options.defaultLeakThreshold} options.leakThresholds = {"default": options.defaultLeakThreshold}
options.ignoreMissingLeaks = []
return options return options
def main(): def main():

0
media/libcubeb/update.sh Normal file → Executable file
Просмотреть файл

Просмотреть файл

@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/kinetiknz/nestegg.svg?branch=master)](https://travis-ci.org/kinetiknz/nestegg)
See INSTALL for build instructions. See INSTALL for build instructions.
Licensed under an ISC-style license. See LICENSE for details. Licensed under an ISC-style license. See LICENSE for details.

Просмотреть файл

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The nestegg git repository is: git://github.com/kinetiknz/nestegg.git The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284. The git commit ID used was 59220ae3e801cbad0f8160129c4df315469af671.

Просмотреть файл

@ -381,8 +381,11 @@ int nestegg_sniff(unsigned char const * buffer, size_t length);
* Set the underlying allocation function for library allocations. * Set the underlying allocation function for library allocations.
* *
* @param realloc_func The desired function. * @param realloc_func The desired function.
* @retval 0 realloc_func(p, 0) does not act as free()
* @retval 1 realloc_func(p, 0) acts as free()
* @retval -1 malloc failed during realloc_func test
*/ */
void nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t)); int nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
#if defined(__cplusplus) #if defined(__cplusplus)
} }

Просмотреть файл

@ -46,7 +46,7 @@ realloc_t halloc_allocator = NULL;
/* /*
* static methods * static methods
*/ */
static void _set_allocator(void); int halloc_set_allocator(realloc_t realloc_func);
static void * _realloc(void * ptr, size_t n); static void * _realloc(void * ptr, size_t n);
static int _relate(hblock_t * b, hblock_t * p); static int _relate(hblock_t * b, hblock_t * p);
@ -62,7 +62,10 @@ void * halloc(void * ptr, size_t len)
/* set up default allocator */ /* set up default allocator */
if (! allocator) if (! allocator)
{ {
_set_allocator(); if (halloc_set_allocator(realloc) == 0)
{
halloc_set_allocator(_realloc);
}
assert(allocator); assert(allocator);
} }
@ -172,7 +175,7 @@ char * h_strdup(const char * str)
/* /*
* static stuff * static stuff
*/ */
static void _set_allocator(void) int halloc_set_allocator(realloc_t realloc_func)
{ {
void * p; void * p;
assert(! allocator); assert(! allocator);
@ -187,17 +190,17 @@ static void _set_allocator(void)
* *
* Thanks to Stan Tobias for pointing this tricky part out. * Thanks to Stan Tobias for pointing this tricky part out.
*/ */
allocator = realloc; if (! (p = realloc_func(NULL, 1)))
if (! (p = malloc(1)))
/* hmm */ /* hmm */
return; return -1;
if ((p = realloc(p, 0))) if ((p = realloc_func(p, 0)))
{ {
/* realloc cannot be used as free() */ /* realloc_func cannot be used as free() */
allocator = _realloc; return 0;
free(p);
} }
allocator = realloc_func;
return 1;
} }
static void * _realloc(void * ptr, size_t n) static void * _realloc(void * ptr, size_t n)

Просмотреть файл

@ -321,9 +321,18 @@ struct block_additional {
struct block_additional * next; struct block_additional * next;
}; };
#define NE_IO_BUFSZ 16384
struct nestegg_io_buf {
nestegg_io io;
unsigned char buffer[NE_IO_BUFSZ];
size_t bufsz;
int offset;
};
/* Public (opaque) Structures */ /* Public (opaque) Structures */
struct nestegg { struct nestegg {
nestegg_io * io; struct nestegg_io_buf * io;
nestegg_log log; nestegg_log log;
struct pool_ctx * alloc_pool; struct pool_ctx * alloc_pool;
uint64_t last_id; uint64_t last_id;
@ -546,19 +555,99 @@ ne_alloc(size_t size)
} }
static int static int
ne_io_read(nestegg_io * io, void * buffer, size_t length) ne_io_read(struct nestegg_io_buf * io, void * buffer, size_t length)
{ {
return io->read(buffer, length, io->userdata); int64_t off;
int r;
size_t avail;
assert(io->offset == -1 || (io->offset >= 0 && (unsigned int) io->offset < io->bufsz));
/* Too big to buffer, invalidate buffer and read through */
if (length > io->bufsz) {
if (io->offset != -1) {
r = io->io.seek(-(io->bufsz - io->offset), NESTEGG_SEEK_CUR, io->io.userdata);
if (r != 0) {
return -1;
}
}
io->offset = -1;
return io->io.read(buffer, length, io->io.userdata);
}
/* Buffer invalid */
if (io->offset == -1) {
off = io->io.tell(io->io.userdata);
if (off == -1) {
return -1;
}
/* Refill buffer */
r = io->io.read(io->buffer, io->bufsz, io->io.userdata);
if (r != 1) {
/* Read truncated due to being within io->bufsz of EOS, reset read
position and switch to read through mode */
io->offset = -1;
io->bufsz = 0;
if (r == 0) {
r = io->io.seek(off, NESTEGG_SEEK_SET, io->io.userdata);
}
if (r == 0) {
return io->io.read(buffer, length, io->io.userdata);
}
return -1;
}
if (r == 1) {
io->offset = 0;
}
}
/* Service request with what we have */
avail = length;
if (io->bufsz - io->offset < length) {
avail = io->bufsz - io->offset;
}
memcpy(buffer, io->buffer + io->offset, avail);
io->offset += avail;
if ((unsigned int) io->offset == io->bufsz) {
io->offset = -1;
}
/* Still more to read, invalidate buffer and read more */
if (length - avail > 0) {
return ne_io_read(io, (char *) buffer + avail, length - avail);
}
return 1;
} }
static int static int
ne_io_seek(nestegg_io * io, int64_t offset, int whence) ne_io_seek(struct nestegg_io_buf * io, int64_t offset, int whence)
{ {
return io->seek(offset, whence, io->userdata); /* Invalidate buffer */
io->offset = -1;
return io->io.seek(offset, whence, io->io.userdata);
}
static int64_t
ne_io_tell(struct nestegg_io_buf * io)
{
int64_t off;
off = io->io.tell(io->io.userdata);
if (off == -1) {
return -1;
}
if (io->offset == -1) {
return off;
}
assert(off >= (int64_t) io->bufsz - io->offset);
return off - io->bufsz + (unsigned int) io->offset;
} }
static int static int
ne_io_read_skip(nestegg_io * io, size_t length) ne_io_read_skip(struct nestegg_io_buf * io, size_t length)
{ {
size_t get; size_t get;
unsigned char buf[8192]; unsigned char buf[8192];
@ -575,14 +664,8 @@ ne_io_read_skip(nestegg_io * io, size_t length)
return r; return r;
} }
static int64_t
ne_io_tell(nestegg_io * io)
{
return io->tell(io->userdata);
}
static int static int
ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) ne_bare_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag)
{ {
int r; int r;
unsigned char b; unsigned char b;
@ -619,19 +702,19 @@ ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vin
} }
static int static int
ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length) ne_read_id(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
{ {
return ne_bare_read_vint(io, value, length, MASK_NONE); return ne_bare_read_vint(io, value, length, MASK_NONE);
} }
static int static int
ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length) ne_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
{ {
return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT); return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
} }
static int static int
ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length) ne_read_svint(struct nestegg_io_buf * io, int64_t * value, uint64_t * length)
{ {
int r; int r;
uint64_t uvalue; uint64_t uvalue;
@ -653,7 +736,7 @@ ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
} }
static int static int
ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length) ne_read_uint(struct nestegg_io_buf * io, uint64_t * val, uint64_t length)
{ {
unsigned char b; unsigned char b;
int r; int r;
@ -675,7 +758,7 @@ ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
} }
static int static int
ne_read_int(nestegg_io * io, int64_t * val, uint64_t length) ne_read_int(struct nestegg_io_buf * io, int64_t * val, uint64_t length)
{ {
int r; int r;
uint64_t uval, base; uint64_t uval, base;
@ -688,8 +771,8 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
base = 1; base = 1;
base <<= length * 8 - 1; base <<= length * 8 - 1;
if (uval >= base) { if (uval >= base) {
base = 1; base = 1;
base <<= length * 8; base <<= length * 8;
} else { } else {
base = 0; base = 0;
} }
@ -702,7 +785,7 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
} }
static int static int
ne_read_float(nestegg_io * io, double * val, uint64_t length) ne_read_float(struct nestegg_io_buf * io, double * val, uint64_t length)
{ {
union { union {
uint64_t u; uint64_t u;
@ -736,9 +819,9 @@ ne_read_string(nestegg * ctx, char ** val, uint64_t length)
if (!str) if (!str)
return -1; return -1;
if (length) { if (length) {
r = ne_io_read(ctx->io, (unsigned char *) str, length); r = ne_io_read(ctx->io, (unsigned char *) str, length);
if (r != 1) if (r != 1)
return r; return r;
} }
str[length] = '\0'; str[length] = '\0';
*val = str; *val = str;
@ -1018,8 +1101,9 @@ ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
break; break;
case TYPE_MASTER: case TYPE_MASTER:
case TYPE_UNKNOWN: case TYPE_UNKNOWN:
assert(0); default:
r = 0; r = 0;
assert(0);
break; break;
} }
@ -1136,7 +1220,7 @@ ne_xiph_lace_value(unsigned char ** np)
} }
static int static int
ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) ne_read_xiph_lace_value(struct nestegg_io_buf * io, uint64_t * value, size_t * consumed)
{ {
int r; int r;
uint64_t lace; uint64_t lace;
@ -1159,7 +1243,7 @@ ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
} }
static int static int
ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) ne_read_xiph_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
{ {
int r; int r;
size_t i = 0; size_t i = 0;
@ -1182,7 +1266,7 @@ ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, ui
} }
static int static int
ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) ne_read_ebml_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
{ {
int r; int r;
uint64_t lace, sum, length; uint64_t lace, sum, length;
@ -1792,9 +1876,9 @@ struct sniff_buffer {
}; };
static int static int
ne_buffer_read(void * buffer, size_t length, void * user_data) ne_buffer_read(void * buffer, size_t length, void * userdata)
{ {
struct sniff_buffer * sb = user_data; struct sniff_buffer * sb = userdata;
int rv = 1; int rv = 1;
size_t available = sb->length - sb->offset; size_t available = sb->length - sb->offset;
@ -1809,21 +1893,21 @@ ne_buffer_read(void * buffer, size_t length, void * user_data)
} }
static int static int
ne_buffer_seek(int64_t offset, int whence, void * user_data) ne_buffer_seek(int64_t offset, int whence, void * userdata)
{ {
struct sniff_buffer * sb = user_data; struct sniff_buffer * sb = userdata;
int64_t o = sb->offset; int64_t o = sb->offset;
switch(whence) { switch(whence) {
case NESTEGG_SEEK_SET: case NESTEGG_SEEK_SET:
o = offset; o = offset;
break; break;
case NESTEGG_SEEK_CUR: case NESTEGG_SEEK_CUR:
o += offset; o += offset;
break; break;
case NESTEGG_SEEK_END: case NESTEGG_SEEK_END:
o = sb->length + offset; o = sb->length + offset;
break; break;
} }
if (o < 0 || o > (int64_t) sb->length) if (o < 0 || o > (int64_t) sb->length)
@ -1834,9 +1918,9 @@ ne_buffer_seek(int64_t offset, int whence, void * user_data)
} }
static int64_t static int64_t
ne_buffer_tell(void * user_data) ne_buffer_tell(void * userdata)
{ {
struct sniff_buffer * sb = user_data; struct sniff_buffer * sb = userdata;
return sb->offset; return sb->offset;
} }
@ -1860,7 +1944,9 @@ ne_match_webm(nestegg_io io, int64_t max_offset)
nestegg_destroy(ctx); nestegg_destroy(ctx);
return -1; return -1;
} }
*ctx->io = io; ctx->io->io = io;
ctx->io->bufsz = NE_IO_BUFSZ;
ctx->io->offset = -1;
ctx->alloc_pool = ne_pool_init(); ctx->alloc_pool = ne_pool_init();
if (!ctx->alloc_pool) { if (!ctx->alloc_pool) {
nestegg_destroy(ctx); nestegg_destroy(ctx);
@ -1918,7 +2004,9 @@ nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t ma
nestegg_destroy(ctx); nestegg_destroy(ctx);
return -1; return -1;
} }
*ctx->io = io; ctx->io->io = io;
ctx->io->bufsz = NE_IO_BUFSZ;
ctx->io->offset = -1;
ctx->log = callback; ctx->log = callback;
ctx->alloc_pool = ne_pool_init(); ctx->alloc_pool = ne_pool_init();
if (!ctx->alloc_pool) { if (!ctx->alloc_pool) {
@ -2264,35 +2352,35 @@ nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item,
return -1; return -1;
if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
&& nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS) && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
return -1; return -1;
if (ne_get_binary(entry->codec_private, &codec_private) != 0) if (ne_get_binary(entry->codec_private, &codec_private) != 0)
return -1; return -1;
if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) { if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
p = codec_private.data; p = codec_private.data;
count = *p++ + 1; count = *p++ + 1;
if (count > 3) if (count > 3)
return -1;
i = 0;
total = 0;
while (--count) {
sizes[i] = ne_xiph_lace_value(&p);
total += sizes[i];
i += 1;
}
sizes[i] = codec_private.length - total - (p - codec_private.data);
for (i = 0; i < item; ++i) {
if (sizes[i] > LIMIT_FRAME)
return -1; return -1;
p += sizes[i];
i = 0; }
total = 0; *data = p;
while (--count) { *length = sizes[item];
sizes[i] = ne_xiph_lace_value(&p);
total += sizes[i];
i += 1;
}
sizes[i] = codec_private.length - total - (p - codec_private.data);
for (i = 0; i < item; ++i) {
if (sizes[i] > LIMIT_FRAME)
return -1;
p += sizes[i];
}
*data = p;
*length = sizes[item];
} else { } else {
*data = codec_private.data; *data = codec_private.data;
*length = codec_private.length; *length = codec_private.length;
@ -2494,7 +2582,7 @@ nestegg_free_packet(nestegg_packet * pkt)
free(block_additional); free(block_additional);
} }
free(pkt); free(pkt);
} }
int int
@ -2588,28 +2676,31 @@ int
nestegg_has_cues(nestegg * ctx) nestegg_has_cues(nestegg * ctx)
{ {
return ctx->segment.cues.cue_point.head || return ctx->segment.cues.cue_point.head ||
ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
} }
int int
nestegg_sniff(unsigned char const * buffer, size_t length) nestegg_sniff(unsigned char const * buffer, size_t length)
{ {
nestegg_io io; nestegg_io io;
struct sniff_buffer user_data; struct sniff_buffer userdata;
user_data.buffer = buffer; userdata.buffer = buffer;
user_data.length = length; userdata.length = length;
user_data.offset = 0; userdata.offset = 0;
io.read = ne_buffer_read; io.read = ne_buffer_read;
io.seek = ne_buffer_seek; io.seek = ne_buffer_seek;
io.tell = ne_buffer_tell; io.tell = ne_buffer_tell;
io.userdata = &user_data; io.userdata = &userdata;
return ne_match_webm(io, length); return ne_match_webm(io, length);
} }
void /* From halloc.c */
int halloc_set_allocator(realloc_t realloc_func);
int
nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t)) nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t))
{ {
halloc_allocator = realloc_func; return halloc_set_allocator(realloc_func);
} }

Просмотреть файл

@ -7,7 +7,7 @@ cp $1/halloc/src/halloc.c src
cp $1/halloc/src/hlist.h src cp $1/halloc/src/hlist.h src
cp $1/halloc/src/macros.h src cp $1/halloc/src/macros.h src
cp $1/LICENSE . cp $1/LICENSE .
cp $1/README . cp $1/README.md .
cp $1/AUTHORS . cp $1/AUTHORS .
if [ -d $1/.git ]; then if [ -d $1/.git ]; then
rev=$(cd $1 && git rev-parse --verify HEAD) rev=$(cd $1 && git rev-parse --verify HEAD)

Просмотреть файл

@ -2549,12 +2549,12 @@ cc_boolean vcmCheckAttribs(cc_uint32_t media_type, void *sdp_p, int level,
rcap->max_cpb = t_uint; rcap->max_cpb = t_uint;
} }
if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) if ( ccsdpAttrGetFmtpMaxDpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
{ {
rcap->max_dpb = t_uint; rcap->max_dpb = t_uint;
} }
if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS ) if ( ccsdpAttrGetFmtpMaxBr(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
{ {
rcap->max_br = t_uint; rcap->max_br = t_uint;
} }

Просмотреть файл

@ -1124,6 +1124,7 @@ public abstract class GeckoApp
mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY"); mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
final Intent intent = getIntent(); final Intent intent = getIntent();
final String action = intent.getAction();
final String args = intent.getStringExtra("args"); final String args = intent.getStringExtra("args");
earlyStartJavaSampler(intent); earlyStartJavaSampler(intent);
@ -1163,7 +1164,13 @@ public abstract class GeckoApp
} }
} }
BrowserDB.initialize(getProfile().getName()); // Speculatively pre-fetch the profile in the background.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
getProfile();
}
});
// Workaround for <http://code.google.com/p/android/issues/detail?id=20915>. // Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
try { try {
@ -1205,6 +1212,30 @@ public abstract class GeckoApp
// without killing the entire application (see Bug 769269). // without killing the entire application (see Bug 769269).
mIsRestoringActivity = true; mIsRestoringActivity = true;
Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1); Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1);
} else {
final String uri = getURIFromIntent(intent);
GeckoThread.setArgs(args);
GeckoThread.setAction(action);
GeckoThread.setUri(TextUtils.isEmpty(uri) ? null : uri);
}
if (!ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching,
GeckoThread.LaunchState.Launched)) {
GeckoThread.createAndStart();
} else if (ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching,
GeckoThread.LaunchState.WaitForDebugger)) {
ThreadUtils.getUiHandler().postDelayed(new Runnable() {
@Override
public void run() {
GeckoThread.setLaunchState(GeckoThread.LaunchState.Launched);
GeckoThread.createAndStart();
}
}, 1000 * 5 /* 5 seconds */);
} }
Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE); Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
@ -1368,6 +1399,9 @@ public abstract class GeckoApp
layerView.initializeView(EventDispatcher.getInstance()); layerView.initializeView(EventDispatcher.getInstance());
mLayerView = layerView; mLayerView = layerView;
GeckoAppShell.setLayerView(layerView); GeckoAppShell.setLayerView(layerView);
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, layerView.getLayerClientObject()));
// bind the GeckoEditable instance to the new LayerView // bind the GeckoEditable instance to the new LayerView
GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", ""); GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", "");
} }
@ -1425,6 +1459,8 @@ public abstract class GeckoApp
initializeChrome(); initializeChrome();
BrowserDB.initialize(getProfile().getName());
// If we are doing a restore, read the session data and send it to Gecko // If we are doing a restore, read the session data and send it to Gecko
if (!mIsRestoringActivity) { if (!mIsRestoringActivity) {
String restoreMessage = null; String restoreMessage = null;
@ -1467,25 +1503,6 @@ public abstract class GeckoApp
Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal()); Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal());
if (!mIsRestoringActivity) {
GeckoThread.setArgs(intent.getStringExtra("args"));
GeckoThread.setAction(intent.getAction());
GeckoThread.setUri(passedUri);
}
if (!ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
GeckoThread.createAndStart();
} else if (ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) {
ThreadUtils.getUiHandler().postDelayed(new Runnable() {
@Override
public void run() {
GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching);
GeckoThread.createAndStart();
}
}, 1000 * 5 /* 5 seconds */);
}
// Check if launched from data reporting notification. // Check if launched from data reporting notification.
if (ACTION_LAUNCH_SETTINGS.equals(action)) { if (ACTION_LAUNCH_SETTINGS.equals(action)) {
Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class); Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
@ -1580,7 +1597,6 @@ public abstract class GeckoApp
if (selectedTab != null) if (selectedTab != null)
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
geckoConnected(); geckoConnected();
GeckoAppShell.setLayerClient(mLayerView.getLayerClientObject());
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
} }
@ -1647,7 +1663,7 @@ public abstract class GeckoApp
} }
} }
public GeckoProfile getProfile() { public synchronized GeckoProfile getProfile() {
// fall back to default profile if we didn't load a specific one // fall back to default profile if we didn't load a specific one
if (mProfile == null) { if (mProfile == null) {
mProfile = GeckoProfile.get(this); mProfile = GeckoProfile.get(this);

Просмотреть файл

@ -205,8 +205,6 @@ public class GeckoAppShell
public static native void nativeInit(); public static native void nativeInit();
// helper methods // helper methods
// public static native void setSurfaceView(GeckoSurfaceView sv);
public static native void setLayerClient(Object client);
public static native void onResume(); public static native void onResume();
public static void callObserver(String observerKey, String topic, String data) { public static void callObserver(String observerKey, String topic, String data) {
sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data)); sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
@ -342,9 +340,6 @@ public class GeckoAppShell
// run gecko -- it will spawn its own thread // run gecko -- it will spawn its own thread
GeckoAppShell.nativeInit(); GeckoAppShell.nativeInit();
if (sLayerView != null)
GeckoAppShell.setLayerClient(sLayerView.getLayerClientObject());
// First argument is the .apk path // First argument is the .apk path
String combinedArgs = apkPath + " -greomni " + apkPath; String combinedArgs = apkPath + " -greomni " + apkPath;
if (args != null) if (args != null)

Просмотреть файл

@ -76,6 +76,7 @@ public class GeckoEvent {
KEY_EVENT(1), KEY_EVENT(1),
MOTION_EVENT(2), MOTION_EVENT(2),
SENSOR_EVENT(3), SENSOR_EVENT(3),
PROCESS_OBJECT(4),
LOCATION_EVENT(5), LOCATION_EVENT(5),
IME_EVENT(6), IME_EVENT(6),
SIZE_CHANGED(8), SIZE_CHANGED(8),
@ -183,6 +184,8 @@ public class GeckoEvent {
public static final int ACTION_GAMEPAD_BUTTON = 1; public static final int ACTION_GAMEPAD_BUTTON = 1;
public static final int ACTION_GAMEPAD_AXES = 2; public static final int ACTION_GAMEPAD_AXES = 2;
public static final int ACTION_OBJECT_LAYER_CLIENT = 1;
private final int mType; private final int mType;
private int mAction; private int mAction;
private boolean mAckNeeded; private boolean mAckNeeded;
@ -245,6 +248,8 @@ public class GeckoEvent {
private String[] mPrefNames; private String[] mPrefNames;
private Object mObject;
private GeckoEvent(NativeGeckoEvent event) { private GeckoEvent(NativeGeckoEvent event) {
mType = event.value; mType = event.value;
} }
@ -597,6 +602,13 @@ public class GeckoEvent {
return event; return event;
} }
public static GeckoEvent createObjectEvent(final int action, final Object object) {
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PROCESS_OBJECT);
event.mAction = action;
event.mObject = object;
return event;
}
public static GeckoEvent createLocationEvent(Location l) { public static GeckoEvent createLocationEvent(Location l) {
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT); GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT);
event.mLocation = l; event.mLocation = l;

Просмотреть файл

@ -17,7 +17,7 @@ import java.util.Hashtable;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException; import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException; import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.LocalBrowserDB;
import org.mozilla.gecko.distribution.Distribution; import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.mozglue.RobocopTarget; import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.INIParser; import org.mozilla.gecko.util.INIParser;
@ -209,7 +209,7 @@ public final class GeckoProfile {
* Now do the things that createProfileDirectory normally does -- * Now do the things that createProfileDirectory normally does --
* right now that's kicking off DB init. * right now that's kicking off DB init.
*/ */
profile.enqueueInitialization(); profile.enqueueInitialization(profile.getDir());
return profile; return profile;
} catch (Exception ex) { } catch (Exception ex) {
@ -650,7 +650,7 @@ public final class GeckoProfile {
// Trigger init for non-webapp profiles. // Trigger init for non-webapp profiles.
if (!mIsWebAppProfile) { if (!mIsWebAppProfile) {
enqueueInitialization(); enqueueInitialization(profileDir);
} }
// Write out profile creation time, mirroring the logic in nsToolkitProfileService. // Write out profile creation time, mirroring the logic in nsToolkitProfileService.
@ -684,7 +684,7 @@ public final class GeckoProfile {
* This is public for use *from tests only*! * This is public for use *from tests only*!
*/ */
@RobocopTarget @RobocopTarget
public void enqueueInitialization() { public void enqueueInitialization(final File profileDir) {
Log.i(LOGTAG, "Enqueuing profile init."); Log.i(LOGTAG, "Enqueuing profile init.");
final Context context = mApplicationContext; final Context context = mApplicationContext;
@ -697,13 +697,24 @@ public final class GeckoProfile {
final ContentResolver cr = context.getContentResolver(); final ContentResolver cr = context.getContentResolver();
// We pass the number of added bookmarks to ensure that the // Because we are running in the background, we want to synchronize on the
// indices of the distribution and default bookmarks are // GeckoProfile instance so that we don't race with main thread operations
// contiguous. Because there are always at least as many // such as locking/unlocking/removing the profile.
// bookmarks as there are favicons, we can also guarantee that synchronized (GeckoProfile.this) {
// the favicon IDs won't overlap. // Skip initialization if the profile directory has been removed.
final int offset = BrowserDB.addDistributionBookmarks(cr, distribution, 0); if (!profileDir.exists()) {
BrowserDB.addDefaultBookmarks(context, cr, offset); return;
}
// We pass the number of added bookmarks to ensure that the
// indices of the distribution and default bookmarks are
// contiguous. Because there are always at least as many
// bookmarks as there are favicons, we can also guarantee that
// the favicon IDs won't overlap.
final LocalBrowserDB db = new LocalBrowserDB(getName());
final int offset = db.addDistributionBookmarks(cr, distribution, 0);
db.addDefaultBookmarks(context, cr, offset);
}
} }
}); });
} }

Просмотреть файл

@ -136,25 +136,29 @@ public class GeckoThread extends Thread implements GeckoEventListener {
} }
private String addCustomProfileArg(String args) { private String addCustomProfileArg(String args) {
String profile = ""; String profileArg = "";
String guest = ""; String guestArg = "";
if (GeckoAppShell.getGeckoInterface() != null) { if (GeckoAppShell.getGeckoInterface() != null) {
if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) { final GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile();
if (profile.inGuestMode()) {
try { try {
profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath(); profileArg = " -profile " + profile.getDir().getCanonicalPath();
} catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); } } catch (final IOException ioe) {
Log.e(LOGTAG, "error getting guest profile path", ioe);
}
if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) { if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) {
guest = " " + BrowserApp.GUEST_BROWSING_ARG; guestArg = " " + BrowserApp.GUEST_BROWSING_ARG;
} }
} else if (!GeckoProfile.sIsUsingCustomProfile) { } else if (!GeckoProfile.sIsUsingCustomProfile) {
// If nothing was passed in in the intent, force Gecko to use the default profile for // If nothing was passed in the intent, make sure the default profile exists and
// for this activity // force Gecko to use the default profile for this activity
profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName(); profileArg = " -P " + profile.forceCreate().getName();
} }
} }
return (args != null ? args : "") + profile + guest; return (args != null ? args : "") + profileArg + guestArg;
} }
@Override @Override

Просмотреть файл

@ -174,6 +174,8 @@ public class GeckoView extends LayerView
BrowserDB.initialize(profile.getName()); BrowserDB.initialize(profile.getName());
GeckoAppShell.setLayerView(this); GeckoAppShell.setLayerView(this);
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject()));
GeckoThread.createAndStart(); GeckoThread.createAndStart();
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { } else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
// If Gecko is already running, that means the Activity was // If Gecko is already running, that means the Activity was
@ -247,7 +249,6 @@ public class GeckoView extends LayerView
if (selectedTab != null) if (selectedTab != null)
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
geckoConnected(); geckoConnected();
GeckoAppShell.setLayerClient(getLayerClientObject());
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
} }

Просмотреть файл

@ -157,7 +157,7 @@ public class SuggestedSites {
final Context context; final Context context;
final Distribution distribution; final Distribution distribution;
final File file; private File cachedFile;
private Map<String, Site> cachedSites; private Map<String, Site> cachedSites;
private Set<String> cachedBlacklist; private Set<String> cachedBlacklist;
@ -166,14 +166,20 @@ public class SuggestedSites {
} }
public SuggestedSites(Context appContext, Distribution distribution) { public SuggestedSites(Context appContext, Distribution distribution) {
this(appContext, distribution, this(appContext, distribution, null);
GeckoProfile.get(appContext).getFile(FILENAME));
} }
public SuggestedSites(Context appContext, Distribution distribution, File file) { public SuggestedSites(Context appContext, Distribution distribution, File file) {
this.context = appContext; this.context = appContext;
this.distribution = distribution; this.distribution = distribution;
this.file = file; this.cachedFile = file;
}
synchronized File getFile() {
if (cachedFile == null) {
cachedFile = GeckoProfile.get(context).getFile(FILENAME);
}
return cachedFile;
} }
private static boolean isNewLocale(Context context, Locale requestedLocale) { private static boolean isNewLocale(Context context, Locale requestedLocale) {
@ -306,6 +312,7 @@ public class SuggestedSites {
setCachedSites(sites); setCachedSites(sites);
// Save the result to disk. // Save the result to disk.
final File file = getFile();
synchronized (file) { synchronized (file) {
saveSites(file, sites); saveSites(file, sites);
} }
@ -349,6 +356,7 @@ public class SuggestedSites {
private Map<String, Site> loadFromProfile() { private Map<String, Site> loadFromProfile() {
try { try {
final File file = getFile();
synchronized (file) { synchronized (file) {
return loadSites(file); return loadSites(file);
} }
@ -462,7 +470,7 @@ public class SuggestedSites {
// Force the suggested sites file in profile dir to be re-generated // Force the suggested sites file in profile dir to be re-generated
// if the locale has changed. // if the locale has changed.
if (isNewLocale) { if (isNewLocale) {
file.delete(); getFile().delete();
} }
if (cachedSites == null || isNewLocale) { if (cachedSites == null || isNewLocale) {

Просмотреть файл

@ -133,7 +133,7 @@ abstract class BaseTest extends BaseRobocopTest {
// In Robocop tests, we typically don't get initialized correctly, because // In Robocop tests, we typically don't get initialized correctly, because
// GeckoProfile doesn't create the profile directory. // GeckoProfile doesn't create the profile directory.
profile.enqueueInitialization(); profile.enqueueInitialization(profile.getDir());
} }
@Override @Override

Просмотреть файл

@ -12,44 +12,65 @@ import java.util.concurrent.SynchronousQueue;
final class GeckoBackgroundThread extends Thread { final class GeckoBackgroundThread extends Thread {
private static final String LOOPER_NAME = "GeckoBackgroundThread"; private static final String LOOPER_NAME = "GeckoBackgroundThread";
// Guarded by 'this'. // Guarded by 'GeckoBackgroundThread.class'.
private static Handler sHandler; private static Handler handler;
private SynchronousQueue<Handler> mHandlerQueue = new SynchronousQueue<Handler>(); private static Thread thread;
// The initial Runnable to run on the new thread. Its purpose
// is to avoid us having to wait for the new thread to start.
private Runnable initialRunnable;
// Singleton, so private constructor. // Singleton, so private constructor.
private GeckoBackgroundThread() { private GeckoBackgroundThread(final Runnable initialRunnable) {
super(); this.initialRunnable = initialRunnable;
} }
@Override @Override
public void run() { public void run() {
setName(LOOPER_NAME); setName(LOOPER_NAME);
Looper.prepare(); Looper.prepare();
try {
mHandlerQueue.put(new Handler()); synchronized (GeckoBackgroundThread.class) {
} catch (InterruptedException ie) {} handler = new Handler();
GeckoBackgroundThread.class.notify();
}
if (initialRunnable != null) {
initialRunnable.run();
initialRunnable = null;
}
Looper.loop(); Looper.loop();
} }
// Get a Handler for a looper thread, or create one if it doesn't yet exist. private static void startThread(final Runnable initialRunnable) {
/*package*/ static synchronized Handler getHandler() { thread = new GeckoBackgroundThread(initialRunnable);
if (sHandler == null) { ThreadUtils.setBackgroundThread(thread);
GeckoBackgroundThread lt = new GeckoBackgroundThread();
ThreadUtils.setBackgroundThread(lt); thread.setDaemon(true);
lt.start(); thread.start();
try {
sHandler = lt.mHandlerQueue.take();
} catch (InterruptedException ie) {}
}
return sHandler;
} }
/*package*/ static void post(Runnable runnable) { // Get a Handler for a looper thread, or create one if it doesn't yet exist.
Handler handler = getHandler(); /*package*/ static synchronized Handler getHandler() {
if (handler == null) { if (thread == null) {
throw new IllegalStateException("No handler! Must have been interrupted. Not posting."); startThread(null);
} }
handler.post(runnable);
while (handler == null) {
try {
GeckoBackgroundThread.class.wait();
} catch (final InterruptedException e) {
}
}
return handler;
}
/*package*/ static synchronized void post(final Runnable runnable) {
if (thread == null) {
startThread(runnable);
return;
}
getHandler().post(runnable);
} }
} }

Просмотреть файл

@ -189,6 +189,7 @@ public final class ThreadUtils {
return isOnThread(getUiThread()); return isOnThread(getUiThread());
} }
@RobocopTarget
public static boolean isOnBackgroundThread() { public static boolean isOnBackgroundThread() {
if (sBackgroundThread == null) { if (sBackgroundThread == null) {
return false; return false;
@ -197,6 +198,7 @@ public final class ThreadUtils {
return isOnThread(sBackgroundThread); return isOnThread(sBackgroundThread);
} }
@RobocopTarget
public static boolean isOnThread(Thread thread) { public static boolean isOnThread(Thread thread) {
return (Thread.currentThread().getId() == thread.getId()); return (Thread.currentThread().getId() == thread.getId());
} }

Просмотреть файл

@ -9,7 +9,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
if (!PrivateBrowsingUtils.isWindowPrivate(window)) { if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
document.body.setAttribute("class", "normal"); document.body.setAttribute("class", "normal");
}, false); }, false);

Просмотреть файл

@ -98,6 +98,8 @@ if test ! "$RELEASE_BUILD"; then
MOZ_ANDROID_DOWNLOADS_INTEGRATION=1 MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
fi fi
# Enable generational GC on mobile. # Enable generational GC on mobile.
JSGC_GENERATIONAL=1 JSGC_GENERATIONAL=1
# Use the low-memory GC tuning.
JS_GC_SMALL_CHUNK_SIZE=1

Просмотреть файл

@ -12,6 +12,9 @@ jar.sources += [
'src/harness/BrowserInstrumentationTestRunner.java', 'src/harness/BrowserInstrumentationTestRunner.java',
'src/harness/BrowserTestListener.java', 'src/harness/BrowserTestListener.java',
'src/TestDistribution.java', 'src/TestDistribution.java',
'src/TestGeckoBackgroundThread.java',
'src/TestGeckoMenu.java',
'src/TestGeckoProfilesProvider.java',
'src/TestGeckoSharedPrefs.java', 'src/TestGeckoSharedPrefs.java',
'src/TestImageDownloader.java', 'src/TestImageDownloader.java',
'src/TestJarReader.java', 'src/TestJarReader.java',

Просмотреть файл

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import org.mozilla.gecko.util.ThreadUtils;
public class TestGeckoBackgroundThread extends BrowserTestCase {
private boolean finishedTest;
private boolean ranFirstRunnable;
public void testGeckoBackgroundThread() throws InterruptedException {
final Thread testThread = Thread.currentThread();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// Must *not* be on thread that posted the Runnable.
assertFalse(ThreadUtils.isOnThread(testThread));
// Must be on background thread.
assertTrue(ThreadUtils.isOnBackgroundThread());
ranFirstRunnable = true;
}
});
// Post a second Runnable to make sure it still runs on the background thread,
// and it only runs after the first Runnable has run.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
// Must still be on background thread.
assertTrue(ThreadUtils.isOnBackgroundThread());
// This Runnable must be run after the first Runnable had finished.
assertTrue(ranFirstRunnable);
synchronized (TestGeckoBackgroundThread.this) {
finishedTest = true;
TestGeckoBackgroundThread.this.notify();
}
}
});
synchronized (this) {
while (!finishedTest) {
wait();
}
}
}
}

Просмотреть файл

@ -135,7 +135,7 @@ pref("dom.serviceWorkers.enabled", false);
pref("dom.enable_performance", true); pref("dom.enable_performance", true);
// Whether resource timing will be gathered and returned by performance.GetEntries* // Whether resource timing will be gathered and returned by performance.GetEntries*
pref("dom.enable_resource_timing", false); pref("dom.enable_resource_timing", true);
// Whether the Gamepad API is enabled // Whether the Gamepad API is enabled
pref("dom.gamepad.enabled", true); pref("dom.gamepad.enabled", true);
@ -341,7 +341,6 @@ pref("media.peerconnection.video.max_bitrate", 2000);
#endif #endif
pref("media.navigator.permission.disabled", false); pref("media.navigator.permission.disabled", false);
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]"); pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
pref("media.peerconnection.trickle_ice", true);
pref("media.peerconnection.use_document_iceservers", true); pref("media.peerconnection.use_document_iceservers", true);
// Do not enable identity before ensuring that the UX cannot be spoofed // Do not enable identity before ensuring that the UX cannot be spoofed
// see Bug 884573 for details // see Bug 884573 for details

Просмотреть файл

@ -96,25 +96,6 @@ Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) {
#ifdef JNI_STUBS #ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t)(JNIEnv *, jclass, jobject);
static Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient;
extern "C" NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv * arg0, jclass arg1, jobject arg2) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_setLayerClient", &f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onResume_t)(JNIEnv *, jclass); typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onResume_t)(JNIEnv *, jclass);
static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume; static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume;
extern "C" NS_EXPORT void JNICALL extern "C" NS_EXPORT void JNICALL

Просмотреть файл

@ -615,6 +615,10 @@ class MochitestOptions(optparse.OptionParser):
"tab": 10000, # See dependencies of bug 1051230. "tab": 10000, # See dependencies of bug 1051230.
} }
# Bug 1051230 - Leak logging does not yet work for tab processes on desktop.
# Bug 1065098 - The geckomediaplugin process fails to produce a leak log for some reason.
options.ignoreMissingLeaks = ["tab", "geckomediaplugin"]
return options return options
@ -819,6 +823,12 @@ class B2GOptions(MochitestOptions):
options.sslPort = tempSSL options.sslPort = tempSSL
options.httpPort = tempPort options.httpPort = tempPort
# Bug 1071866 - B2G Mochitests do not always produce a leak log.
options.ignoreMissingLeaks.append("default")
# Bug 1070068 - Leak logging does not work for tab processes on B2G.
assert "tab" in options.ignoreMissingLeaks, "Ignore failures for tab processes on B2G"
return options return options
def elf_arm(self, filename): def elf_arm(self, filename):

Просмотреть файл

@ -1842,7 +1842,7 @@ class Mochitest(MochitestUtilsMixin):
self.stopVMwareRecording(); self.stopVMwareRecording();
self.stopServers() self.stopServers()
processLeakLog(self.leak_report_file, options.leakThresholds) processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks)
if self.nsprLogs: if self.nsprLogs:
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip: with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:

Просмотреть файл

@ -202,7 +202,7 @@ class B2GMochitest(MochitestUtilsMixin):
self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name) self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
self.app_ctx.dm.removeFile(self.leak_report_file) self.app_ctx.dm.removeFile(self.leak_report_file)
processLeakLog(local_leak_file.name, options.leakThresholds) processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks)
except KeyboardInterrupt: except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n"); self.log.info("runtests.py | Received keyboard interrupt.\n");
status = -1 status = -1

Просмотреть файл

@ -231,8 +231,11 @@ class RemoteB2GVersion(B2GVersion):
self._info[desired_props[key]] = value self._info[desired_props[key]] = value
if self._info.get('device_id', '').lower() == 'flame': if self._info.get('device_id', '').lower() == 'flame':
self._info['device_firmware_version_base'] = dm._runCmd( for prop in ['ro.boot.bootloader', 't2m.sw.version']:
['shell', 'getprop', 't2m.sw.version']).output[0] value = dm.shellCheckOutput(['getprop', prop])
if value:
self._info['device_firmware_version_base'] = value
break
def get_version(binary=None, sources=None, dm_type=None, host=None, def get_version(binary=None, sources=None, dm_type=None, host=None,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше