зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
bcd85e4b9f
|
@ -196,7 +196,7 @@ def dumpLeakLog(leakLogFile, filter = False):
|
|||
# Simply copy the log.
|
||||
log.info(leakReport.rstrip("\n"))
|
||||
|
||||
def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
||||
def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMissingLeaks):
|
||||
"""Process a single leak log.
|
||||
"""
|
||||
|
||||
|
@ -273,11 +273,14 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
|||
if crashedOnPurpose:
|
||||
log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log"
|
||||
% processString)
|
||||
else:
|
||||
# TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning
|
||||
# due to too many intermittent failures (see bug 831223).
|
||||
log.info("WARNING | leakcheck | %s missing output line for total leaks!"
|
||||
elif ignoreMissingLeaks:
|
||||
log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
|
||||
% 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
|
||||
|
||||
if totalBytesLeaked == 0:
|
||||
|
@ -306,7 +309,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
|||
log.info("%s | leakcheck | %s %d bytes leaked (%s)"
|
||||
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
|
||||
|
||||
def processLeakLog(leakLogFile, leakThresholds):
|
||||
def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
|
||||
"""Process the leak log, including separate leak logs created
|
||||
by child processes.
|
||||
|
||||
|
@ -363,7 +366,8 @@ def processLeakLog(leakLogFile, leakThresholds):
|
|||
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
|
||||
% processType)
|
||||
leakThreshold = leakThresholds.get(processType, 0)
|
||||
processSingleLeakFile(thisFile, processType, leakThreshold)
|
||||
processSingleLeakFile(thisFile, processType, leakThreshold,
|
||||
processType in ignoreMissingLeaks)
|
||||
|
||||
def replaceBackSlashes(input):
|
||||
return input.replace('\\', '/')
|
||||
|
|
|
@ -31,7 +31,7 @@ gyp_vars = {
|
|||
'use_openssl': 0,
|
||||
|
||||
# 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_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
|
||||
|
|
|
@ -9178,14 +9178,6 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
|||
nsresult rv = clone->Init();
|
||||
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) {
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
|
||||
|
@ -9210,6 +9202,18 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
|||
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
|
||||
bool hasHadScriptObject = true;
|
||||
nsIScriptGlobalObject* scriptObject =
|
||||
|
|
|
@ -1090,7 +1090,7 @@ nsXMLHttpRequest::GetResponseURL(nsAString& aUrl)
|
|||
}
|
||||
|
||||
nsAutoCString temp;
|
||||
responseUrl->GetSpec(temp);
|
||||
responseUrl->GetSpecIgnoringRef(temp);
|
||||
CopyUTF8toUTF16(temp, aUrl);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,11 @@ function testSuccessResponse() {
|
|||
skip: isInWorker(),
|
||||
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
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ PRLogModuleInfo* gMediaStreamGraphLog;
|
|||
/**
|
||||
* The singleton graph instance.
|
||||
*/
|
||||
static MediaStreamGraphImpl* gGraph;
|
||||
static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
|
||||
|
||||
MediaStreamGraphImpl::~MediaStreamGraphImpl()
|
||||
{
|
||||
|
@ -1633,9 +1633,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
|
|||
NS_DispatchToMainThread(event);
|
||||
|
||||
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
|
||||
gGraph = nullptr;
|
||||
gGraphs.Remove(mAudioChannel);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1786,9 +1787,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
|
|||
delete aMessage;
|
||||
if (IsEmpty() &&
|
||||
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
|
||||
if (gGraph == this) {
|
||||
gGraph = nullptr;
|
||||
|
||||
MediaStreamGraphImpl* graph;
|
||||
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
|
||||
gGraphs.Remove(mAudioChannel);
|
||||
}
|
||||
|
||||
Destroy();
|
||||
}
|
||||
return;
|
||||
|
@ -2736,6 +2740,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
|
|||
#ifdef DEBUG
|
||||
, mCanRunMessagesSynchronously(false)
|
||||
#endif
|
||||
, mAudioChannel(static_cast<uint32_t>(aChannel))
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gMediaStreamGraphLog) {
|
||||
|
@ -2774,15 +2779,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
|
|||
|
||||
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
|
||||
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
if (gGraph) {
|
||||
gGraph->ForceShutDown();
|
||||
}
|
||||
gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
|
||||
nsContentUtils::UnregisterShutdownObserver(this);
|
||||
gShutdownObserverRegistered = false;
|
||||
}
|
||||
|
@ -2794,7 +2810,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
|
|||
{
|
||||
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) {
|
||||
gShutdownObserverRegistered = true;
|
||||
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
|
||||
|
@ -2802,12 +2821,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
|
|||
|
||||
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*
|
||||
|
@ -2978,7 +2998,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
|
|||
bool
|
||||
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
|
||||
|
|
|
@ -654,6 +654,8 @@ public:
|
|||
nsRefPtr<AudioOutputObserver> mFarendObserverRef;
|
||||
#endif
|
||||
|
||||
uint32_t AudioChannel() const { return mAudioChannel; }
|
||||
|
||||
private:
|
||||
virtual ~MediaStreamGraphImpl();
|
||||
|
||||
|
@ -687,6 +689,9 @@ private:
|
|||
bool mCanRunMessagesSynchronously;
|
||||
#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);
|
||||
|
||||
// The amount of virtual memory reserved for thread stacks.
|
||||
#if (defined(XP_WIN) || defined(LINUX)) && !defined(MOZ_ASAN)
|
||||
#define MEDIA_THREAD_STACK_SIZE (128 * 1024)
|
||||
#elif defined(XP_MACOSX) && !defined(MOZ_ASAN)
|
||||
#if defined(MOZ_ASAN)
|
||||
// Use the system default in ASAN builds, because the default is assumed to be
|
||||
// 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)
|
||||
#else
|
||||
// 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
|
||||
// this process's execution hasn't been affected by its content yet.
|
||||
MOZ_ASSERT(mozilla::CanSandboxMediaPlugin());
|
||||
if (mozilla::CanSandboxMediaPlugin()) {
|
||||
mozilla::SetMediaPluginSandbox(nativePath.get());
|
||||
} else {
|
||||
printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
|
||||
nativePath.get());
|
||||
}
|
||||
#endif // XP_LINUX && MOZ_GMP_SANDBOX
|
||||
|
||||
libFile->Load(&mLib);
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include "nsIObserverService.h"
|
||||
#include "GMPTimerParent.h"
|
||||
#include "runnable_utils.h"
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/dom/CrashReporterParent.h"
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -435,6 +435,14 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
|||
const nsAString& aOrigin,
|
||||
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);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aDecryptor);
|
||||
|
@ -625,11 +633,6 @@ NS_IMETHODIMP
|
|||
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
if (!mozilla::CanSandboxMediaPlugin()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
#endif
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = GetThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -240,8 +240,7 @@ static int webm_read(void* aBuffer, size_t aLength, void* aUserData)
|
|||
|
||||
// Check the read length.
|
||||
if (aLength > ioData->data.Length()) {
|
||||
NS_ERROR("Invalid read length");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check eos.
|
||||
|
@ -292,7 +291,7 @@ static int webm_seek(int64_t aOffset, int aWhence, void* aUserData)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t webm_tell(void* aUserData)
|
||||
|
|
|
@ -289,7 +289,15 @@ void
|
|||
SourceBuffer::StopUpdating()
|
||||
{
|
||||
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;
|
||||
QueueAsyncSimpleEvent("update");
|
||||
QueueAsyncSimpleEvent("updateend");
|
||||
|
|
|
@ -648,12 +648,6 @@ AudioContext::MozAudioChannelType() const
|
|||
return mDestination->MozAudioChannelType();
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
|
||||
{
|
||||
mDestination->SetMozAudioChannelType(aValue, aRv);
|
||||
}
|
||||
|
||||
AudioChannel
|
||||
AudioContext::TestAudioChannelInAudioNodeStream()
|
||||
{
|
||||
|
|
|
@ -222,7 +222,6 @@ public:
|
|||
JSObject* GetGlobalJSObject() const;
|
||||
|
||||
AudioChannel MozAudioChannelType() const;
|
||||
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
|
||||
|
||||
AudioChannel TestAudioChannelInAudioNodeStream();
|
||||
|
||||
|
|
|
@ -376,7 +376,10 @@ public:
|
|||
float* higherWaveData = nullptr;
|
||||
float* lowerWaveData = nullptr;
|
||||
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) {
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
|
@ -384,8 +387,6 @@ public:
|
|||
lowerWaveData,
|
||||
higherWaveData,
|
||||
tableInterpolationFactor);
|
||||
// mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
|
||||
mPhase += periodicWaveSize * mFinalFrequency * rate;
|
||||
mPhase = fmod(mPhase, periodicWaveSize);
|
||||
// Bilinear interpolation between adjacent samples in each table.
|
||||
uint32_t j1 = floor(mPhase);
|
||||
|
@ -394,12 +395,14 @@ public:
|
|||
j2 -= periodicWaveSize;
|
||||
}
|
||||
float sampleInterpolationFactor = mPhase - j1;
|
||||
float lower = sampleInterpolationFactor * lowerWaveData[j1] +
|
||||
(1 - sampleInterpolationFactor) * lowerWaveData[j2];
|
||||
float higher = sampleInterpolationFactor * higherWaveData[j1] +
|
||||
(1 - sampleInterpolationFactor) * higherWaveData[j2];
|
||||
aOutput[i] = tableInterpolationFactor * lower +
|
||||
(1 - tableInterpolationFactor) * higher;
|
||||
float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
|
||||
sampleInterpolationFactor * lowerWaveData[j2];
|
||||
float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
|
||||
sampleInterpolationFactor * higherWaveData[j2];
|
||||
aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
|
||||
tableInterpolationFactor * higher;
|
||||
|
||||
mPhase += basePhaseIncrement * mFinalFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,27 +18,23 @@ function test_basic() {
|
|||
// Default
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
// random wrong channel
|
||||
ac.mozAudioChannelType = "foo";
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
// Unpermitted channels
|
||||
ac.mozAudioChannelType = "content";
|
||||
ac = new AudioContext("content");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "notification";
|
||||
ac = new AudioContext("notification");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "alarm";
|
||||
ac = new AudioContext("alarm");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "telephony";
|
||||
ac = new AudioContext("telephony");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "ringer";
|
||||
ac = new AudioContext("ringer");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
ac.mozAudioChannelType = "publicnotification";
|
||||
ac = new AudioContext("publicnotification");
|
||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||
|
||||
runTest();
|
||||
|
@ -56,7 +52,7 @@ function test_permission(aChannel) {
|
|||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
|
||||
function() {
|
||||
ac.mozAudioChannelType = aChannel;
|
||||
var ac = new AudioContext(aChannel);
|
||||
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
|
||||
|
||||
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
|
||||
|
|
|
@ -11,11 +11,26 @@
|
|||
<script class="testbody" type="text/javascript">
|
||||
|
||||
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() {
|
||||
var ac = new AudioContext();
|
||||
var real = new Float32Array(4096);
|
||||
var imag = new Float32Array(4096);
|
||||
var table = ac.createPeriodicWave(real, imag);
|
||||
ac.createPeriodicWave(new Float32Array(4096), new Float32Array(4096));
|
||||
expectException(function() {
|
||||
ac.createPeriodicWave(new Float32Array(512), imag);
|
||||
}, DOMException.NOT_SUPPORTED_ERR);
|
||||
|
@ -25,9 +40,54 @@ addLoadEvent(function() {
|
|||
expectException(function() {
|
||||
ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097));
|
||||
}, 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>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -56,6 +56,9 @@ TestInterfaceJS.prototype = {
|
|||
get cachedAttr() { return this._cachedAttr; },
|
||||
setCachedAttr: function(n) { this._cachedAttr = n; },
|
||||
clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
|
||||
|
||||
testSequenceOverload: function(arg) {},
|
||||
testSequenceUnion: function(arg) {},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
||||
|
|
|
@ -50,3 +50,5 @@ skip-if = debug == false
|
|||
[test_throwing_method_noDCE.html]
|
||||
[test_treat_non_object_as_null.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.len = sizeof(oaepParams);
|
||||
|
||||
uint32_t outLen;
|
||||
uint32_t outLen = 0;
|
||||
if (mEncrypt) {
|
||||
// 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'
|
||||
|
@ -841,9 +841,9 @@ private:
|
|||
mResult.Elements(), &outLen, mResult.Length(),
|
||||
mData.Elements(), mData.Length()));
|
||||
}
|
||||
mResult.SetLength(outLen);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
mResult.SetLength(outLen);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -342,6 +342,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
int32_t ContentParent::sNuwaPid = 0;
|
||||
bool ContentParent::sNuwaReady = false;
|
||||
#endif
|
||||
|
||||
|
@ -587,6 +588,7 @@ ContentParent::RunNuwaProcess()
|
|||
/* aIsNuwaProcess = */ true);
|
||||
nuwaProcess->Init();
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
sNuwaPid = nuwaProcess->Pid();
|
||||
sNuwaReady = false;
|
||||
#endif
|
||||
return nuwaProcess.forget();
|
||||
|
@ -1990,6 +1992,7 @@ ContentParent::~ContentParent()
|
|||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
sNuwaReady = false;
|
||||
sNuwaPid = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -3699,6 +3702,12 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
|
|||
if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,10 @@ class ContentParent MOZ_FINAL : public PContentParent
|
|||
|
||||
public:
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static int32_t NuwaPid() {
|
||||
return sNuwaPid;
|
||||
}
|
||||
|
||||
static bool IsNuwaReady() {
|
||||
return sNuwaReady;
|
||||
}
|
||||
|
@ -725,6 +729,7 @@ private:
|
|||
#endif
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static int32_t sNuwaPid;
|
||||
static bool sNuwaReady;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -301,7 +301,6 @@ function RTCPeerConnection() {
|
|||
|
||||
this._localType = null;
|
||||
this._remoteType = null;
|
||||
this._trickleIce = false;
|
||||
this._peerIdentity = null;
|
||||
|
||||
/**
|
||||
|
@ -326,7 +325,6 @@ RTCPeerConnection.prototype = {
|
|||
init: function(win) { this._win = win; },
|
||||
|
||||
__init: function(rtcConfig) {
|
||||
this._trickleIce = Services.prefs.getBoolPref("media.peerconnection.trickle_ice");
|
||||
if (!rtcConfig.iceServers ||
|
||||
!Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
|
||||
rtcConfig.iceServers =
|
||||
|
@ -365,8 +363,7 @@ RTCPeerConnection.prototype = {
|
|||
this._queueOrRun({
|
||||
func: this._initialize,
|
||||
args: [rtcConfig],
|
||||
// If not trickling, suppress start.
|
||||
wait: !this._trickleIce
|
||||
wait: false
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -500,7 +497,11 @@ RTCPeerConnection.prototype = {
|
|||
},
|
||||
|
||||
dispatchEvent: function(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.
|
||||
|
|
|
@ -1937,6 +1937,10 @@ PeerConnectionWrapper.prototype = {
|
|||
var self = this;
|
||||
|
||||
self._remote_ice_candidates.push(candidate);
|
||||
if (self.signalingstate === 'closed') {
|
||||
info("Received ICE candidate for closed PeerConnection - discarding");
|
||||
return;
|
||||
}
|
||||
if (self.remoteDescriptionSet) {
|
||||
self.addIceCandidate(candidate);
|
||||
} else {
|
||||
|
@ -2566,15 +2570,9 @@ PeerConnectionWrapper.prototype = {
|
|||
* Closes the connection
|
||||
*/
|
||||
close : function PCW_close() {
|
||||
// It might be that a test has already closed the pc. In those cases
|
||||
// we should not fail.
|
||||
try {
|
||||
this._ice_candidates_to_add = [];
|
||||
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)
|
||||
{
|
||||
if (mIPCOpen) {
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!(static_cast<ContentParent*>(Manager())->IsNuwaProcess() &&
|
||||
ContentParent::IsNuwaReady())) {
|
||||
#endif
|
||||
mozilla::unused << SendObserve(nsDependentCString(aTopic),
|
||||
nsCString(aScopePrefix));
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -78,8 +78,8 @@ interface AudioContext : EventTarget {
|
|||
// Mozilla extensions
|
||||
partial interface AudioContext {
|
||||
// Read AudioChannel.webidl for more information about this attribute.
|
||||
[Pref="media.useAudioChannelService", SetterThrows]
|
||||
attribute AudioChannel mozAudioChannelType;
|
||||
[Pref="media.useAudioChannelService"]
|
||||
readonly attribute AudioChannel mozAudioChannelType;
|
||||
|
||||
// These 2 events are dispatched when the AudioContext object is muted by
|
||||
// the AudioChannelService. It's call 'interrupt' because when this event is
|
||||
|
|
|
@ -42,4 +42,10 @@ interface TestInterfaceJS {
|
|||
readonly attribute short cachedAttr;
|
||||
void setCachedAttr(short n);
|
||||
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++) {
|
||||
WorkerPrivate*& worker = workers[index];
|
||||
|
||||
if (worker->IsSharedWorker()) {
|
||||
if (worker->IsSharedWorker() || worker->IsServiceWorker()) {
|
||||
worker->CloseSharedWorkersForWindow(aWindow);
|
||||
} else if (!worker->Cancel(cx)) {
|
||||
JS_ReportPendingException(cx);
|
||||
|
|
|
@ -128,7 +128,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
endFrame = aImportedBy->mFirstNotImported;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
#if defined(PR_LOGGING) && defined(TX_TO_STRING)
|
||||
txPattern* match = 0;
|
||||
#endif
|
||||
|
||||
|
@ -149,7 +149,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
if (templ.mMatch->matches(aNode, aContext)) {
|
||||
matchTemplate = templ.mFirstInstruction;
|
||||
*aImportFrame = frame;
|
||||
#ifdef PR_LOGGING
|
||||
#if defined(PR_LOGGING) && defined(TX_TO_STRING)
|
||||
match = templ.mMatch;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -64,8 +64,7 @@ MOZ_END_ENUM_CLASS(BufferMode)
|
|||
|
||||
MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t)
|
||||
DRAW,
|
||||
DRAW_SNAPPED,
|
||||
CLIP_NONE
|
||||
NONE
|
||||
MOZ_END_ENUM_CLASS(DrawRegionClip)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t)
|
||||
|
|
|
@ -695,7 +695,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
|
|||
nsIntRegion invalidate;
|
||||
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
|
||||
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
|
||||
result.mClip = DrawRegionClip::DRAW_SNAPPED;
|
||||
result.mClip = DrawRegionClip::DRAW;
|
||||
result.mMode = mode;
|
||||
|
||||
return result;
|
||||
|
|
|
@ -229,7 +229,7 @@ public:
|
|||
: mRegionToDraw()
|
||||
, mRegionToInvalidate()
|
||||
, mMode(SurfaceMode::SURFACE_NONE)
|
||||
, mClip(DrawRegionClip::CLIP_NONE)
|
||||
, mClip(DrawRegionClip::NONE)
|
||||
, mContentType(gfxContentType::SENTINEL)
|
||||
, mDidSelfCopy(false)
|
||||
{}
|
||||
|
|
|
@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext,
|
|||
groupContext = aContext;
|
||||
}
|
||||
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
|
||||
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
|
||||
aCallback(this, groupContext, toDraw, DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
|
||||
if (needsGroup) {
|
||||
aContext->PopGroupToSource();
|
||||
if (needsClipToVisibleRegion) {
|
||||
|
|
|
@ -443,7 +443,17 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
|||
}
|
||||
if (mWidget) {
|
||||
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());
|
||||
if (mTargetRotation) {
|
||||
bounds = RotateRect(bounds, outerBounds, mTargetRotation);
|
||||
}
|
||||
|
||||
SurfaceDescriptor inSnapshot;
|
||||
if (!bounds.IsEmpty() &&
|
||||
mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
|
||||
|
@ -452,11 +462,18 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
|||
remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
|
||||
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
|
||||
DrawTarget* dt = mShadowTarget->GetDrawTarget();
|
||||
|
||||
Rect dstRect(bounds.x, bounds.y, 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,
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
dt->SetTransform(oldMatrix);
|
||||
}
|
||||
mForwarder->DestroySharedSurface(&inSnapshot);
|
||||
}
|
||||
|
|
|
@ -934,7 +934,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
|
||||
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
|
||||
|
@ -1304,7 +1304,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
|||
Scale(mResolution, mResolution));
|
||||
mCallback(mPaintedLayer, ctxt,
|
||||
tileRegion.GetBounds(),
|
||||
DrawRegionClip::CLIP_NONE,
|
||||
DrawRegionClip::NONE,
|
||||
nsIntRegion(), mCallbackData);
|
||||
|
||||
}
|
||||
|
|
|
@ -537,7 +537,7 @@ PaintedLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
|
||||
context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y));
|
||||
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) {
|
||||
NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
@ -70,6 +71,9 @@ ProcessLink::ProcessLink(MessageChannel *aChan)
|
|||
, mTransport(nullptr)
|
||||
, mIOLoop(nullptr)
|
||||
, mExistingListener(nullptr)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
, mIsToNuwaProcess(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -168,6 +172,26 @@ ProcessLink::SendMessage(Message *msg)
|
|||
mChan->AssertWorkerThread();
|
||||
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(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(mTransport, &Transport::Send, msg));
|
||||
|
@ -360,6 +384,10 @@ ProcessLink::OnChannelConnected(int32_t peer_pid)
|
|||
if (mExistingListener)
|
||||
mExistingListener->OnChannelConnected(peer_pid);
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid());
|
||||
#endif
|
||||
|
||||
if (notifyChannel) {
|
||||
mChan->OnChannelConnected(peer_pid);
|
||||
}
|
||||
|
|
|
@ -170,6 +170,9 @@ class ProcessLink
|
|||
Transport* mTransport;
|
||||
MessageLoop* mIOLoop; // thread where IO happens
|
||||
Transport::Listener* mExistingListener; // channel's previous listener
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
bool mIsToNuwaProcess;
|
||||
#endif
|
||||
};
|
||||
|
||||
class ThreadLink : public MessageLink
|
||||
|
|
|
@ -2016,6 +2016,12 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
|
|||
*answer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pn->isHoistedLetUse()) {
|
||||
// Hoisted uses of lexical bindings throw on access.
|
||||
*answer = true;
|
||||
}
|
||||
|
||||
if (pn->isKind(PNK_DOT)) {
|
||||
/* Dotted property references in general can call getters. */
|
||||
*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.storePtr(scratch, shapeAddr);
|
||||
|
||||
// Change the object's type if required.
|
||||
// Try to change the object's type.
|
||||
Label noTypeChange;
|
||||
|
||||
// Check if the cache has a new type to change to.
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
|
||||
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());
|
||||
EmitPreBarrier(masm, typeAddr, MIRType_TypeObject);
|
||||
masm.storePtr(scratch, typeAddr);
|
||||
|
||||
masm.bind(&noTypeChange);
|
||||
|
||||
Register holderReg;
|
||||
|
|
|
@ -2583,11 +2583,27 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
|
|||
|
||||
if (oldType != obj->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());
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
masm.callPreBarrier(typeAddr, MIRType_TypeObject);
|
||||
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()
|
||||
|
|
|
@ -573,6 +573,13 @@ jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *
|
|||
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)
|
||||
: 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.
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -7,17 +7,19 @@ The tests in this directory exercise the JSAPI.
|
|||
|
||||
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
|
||||
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:
|
||||
|
||||
cd $OBJDIR/jsapi-tests
|
||||
cd $OBJDIR/dist/bin
|
||||
gdb ./jsapi-tests
|
||||
|
||||
|
||||
--- Creating new tests
|
||||
|
||||
1. You can either add to an existing test*.cpp file or make a new one.
|
||||
|
|
|
@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
|
|||
'testException.cpp',
|
||||
'testExternalStrings.cpp',
|
||||
'testFindSCCs.cpp',
|
||||
'testForOfIterator.cpp',
|
||||
'testFreshGlobalEvalRedefinition.cpp',
|
||||
'testFuncCallback.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
|
||||
* does not have a callable @@iterator init() will just return true instead
|
||||
* of throwing. Callers should then check valueIsIterable() before
|
||||
* continuing with the iteration.
|
||||
* Initialize the iterator. If AllowNonIterable is passed then if getting
|
||||
* the @@iterator property from iterable returns undefined init() will just
|
||||
* return true instead of throwing. Callers must then check
|
||||
* valueIsIterable() before continuing with the iteration.
|
||||
*/
|
||||
bool init(JS::HandleValue iterable,
|
||||
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
|
||||
|
|
|
@ -1236,6 +1236,10 @@ struct TypeObject : public gc::TenuredCell
|
|||
return offsetof(TypeObject, proto_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfNewScript() {
|
||||
return offsetof(TypeObject, newScript_);
|
||||
}
|
||||
|
||||
private:
|
||||
inline uint32_t basePropertyCount() const;
|
||||
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))
|
||||
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
|
||||
// throw an inscrutable error message about |method| rather than this nice
|
||||
// one about |obj|.
|
||||
if (!callee.isObject() || !callee.toObject().isCallable()) {
|
||||
if (nonIterableBehavior == AllowNonIterable)
|
||||
return true;
|
||||
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
|
||||
if (!bytes)
|
||||
return false;
|
||||
|
|
|
@ -254,7 +254,10 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// NAME operations are the slow paths already, so unconditionally check
|
||||
// for uninitialized lets.
|
||||
return CheckUninitializedLexical(cx, name, vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -264,7 +267,7 @@ FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp)
|
|||
return false;
|
||||
|
||||
vp.set(pobj->nativeGetSlot(shape->slot()));
|
||||
return true;
|
||||
return !IsUninitializedLexical(vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -298,17 +298,9 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle
|
|||
|
||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||
JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
|
||||
if (op2 == JSOP_TYPEOF) {
|
||||
if (!FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
|
||||
return false;
|
||||
} 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);
|
||||
if (op2 == JSOP_TYPEOF)
|
||||
return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||
return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -3564,7 +3556,7 @@ js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name
|
|||
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
||||
return false;
|
||||
|
||||
// See note in NameOperation.
|
||||
// See note in FetchName.
|
||||
return CheckUninitializedLexical(cx, name, vp);
|
||||
}
|
||||
|
||||
|
@ -3589,7 +3581,7 @@ js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandleProperty
|
|||
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
||||
return false;
|
||||
|
||||
// See note in NameOperation.
|
||||
// See note in FetchName.
|
||||
return CheckUninitializedLexical(cx, name, vp);
|
||||
}
|
||||
|
||||
|
@ -3874,6 +3866,13 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco
|
|||
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;
|
||||
RootedId id(cx, NameToId(name));
|
||||
if (!JSObject::deleteGeneric(cx, scope, id, &succeeded))
|
||||
|
|
|
@ -4371,7 +4371,7 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
|||
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
|
||||
{
|
||||
if (!gfxPrefs::LayoutPaintRectsSeparately() ||
|
||||
aClip == DrawRegionClip::CLIP_NONE) {
|
||||
aClip == DrawRegionClip::NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4453,9 +4453,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
|||
bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
|
||||
|
||||
if (!shouldDrawRectsSeparately) {
|
||||
if (aClip == DrawRegionClip::DRAW_SNAPPED) {
|
||||
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
|
||||
} else if (aClip == DrawRegionClip::DRAW) {
|
||||
if (aClip == DrawRegionClip::DRAW) {
|
||||
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
||||
}
|
||||
|
||||
|
@ -4486,7 +4484,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
|||
while (const nsIntRect* iterRect = it.Next()) {
|
||||
gfxContextAutoSaveRestore save(aContext);
|
||||
aContext->NewPath();
|
||||
aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED);
|
||||
aContext->Rectangle(*iterRect);
|
||||
aContext->Clip();
|
||||
|
||||
DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
|
||||
|
@ -4522,9 +4520,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
|||
if (presContext->GetPaintFlashing() && isActiveLayerManager) {
|
||||
gfxContextAutoSaveRestore save(aContext);
|
||||
if (shouldDrawRectsSeparately) {
|
||||
if (aClip == DrawRegionClip::DRAW_SNAPPED) {
|
||||
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
|
||||
} else if (aClip == DrawRegionClip::DRAW) {
|
||||
if (aClip == DrawRegionClip::DRAW) {
|
||||
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3069,6 +3069,16 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
|||
oldContext.get(), newContext.get());
|
||||
oldContext->SwapStyleData(newContext, 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");
|
||||
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
|
||||
/* static */ nsCString
|
||||
RestyleManager::RestyleHintToString(nsRestyleHint aHint)
|
||||
|
|
|
@ -386,6 +386,13 @@ public:
|
|||
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);
|
||||
int32_t& LoggingDepth() { return mLoggingDepth; }
|
||||
#endif
|
||||
|
|
|
@ -162,7 +162,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
|
|||
RestyleManager::ChangeHintToString(aChangeHint).get());
|
||||
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
|
||||
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,
|
||||
*this, aRestyleHint);
|
||||
} else if (aChangeHint &&
|
||||
|
|
|
@ -1224,7 +1224,8 @@ void
|
|||
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
||||
int32_t aNumFramesOnLine,
|
||||
WritingMode aLineWM,
|
||||
nscoord& aLineWidth)
|
||||
nscoord& aLineWidth,
|
||||
nscoord aStart)
|
||||
{
|
||||
// If this line consists of a line frame, reorder the line frame's children.
|
||||
if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
|
||||
|
@ -1237,7 +1238,7 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
|||
}
|
||||
|
||||
BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
|
||||
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth);
|
||||
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
|
@ -1279,6 +1280,7 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame)
|
|||
void
|
||||
nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
||||
nsContinuationStates* aContinuationStates,
|
||||
bool aSpanDirMatchesLineDir,
|
||||
bool& aIsFirst /* out */,
|
||||
bool& aIsLast /* out */)
|
||||
{
|
||||
|
@ -1293,6 +1295,7 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
|||
* chain on this line.
|
||||
*/
|
||||
|
||||
bool firstInLineOrder, lastInLineOrder;
|
||||
nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
|
||||
nsFrameContinuationState* firstFrameState;
|
||||
|
||||
|
@ -1327,16 +1330,30 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
|||
}
|
||||
frameState->mHasContOnNextLines = (frame != nullptr);
|
||||
|
||||
aIsFirst = !frameState->mHasContOnPrevLines;
|
||||
firstInLineOrder = true;
|
||||
firstFrameState = frameState;
|
||||
} else {
|
||||
// aFrame is not the first visual frame of its continuation chain
|
||||
aIsFirst = false;
|
||||
firstInLineOrder = false;
|
||||
firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
|
||||
}
|
||||
|
||||
aIsLast = (firstFrameState->mFrameCount == 1 &&
|
||||
!firstFrameState->mHasContOnNextLines);
|
||||
lastInLineOrder = (firstFrameState->mFrameCount == 1);
|
||||
|
||||
if (aSpanDirMatchesLineDir) {
|
||||
aIsFirst = firstInLineOrder;
|
||||
aIsLast = lastInLineOrder;
|
||||
} else {
|
||||
aIsFirst = lastInLineOrder;
|
||||
aIsLast = firstInLineOrder;
|
||||
}
|
||||
|
||||
if (frameState->mHasContOnPrevLines) {
|
||||
aIsFirst = false;
|
||||
}
|
||||
if (firstFrameState->mHasContOnNextLines) {
|
||||
aIsLast = false;
|
||||
}
|
||||
|
||||
if ((aIsFirst || aIsLast) &&
|
||||
(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.
|
||||
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
|
||||
|
@ -1363,55 +1398,46 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
|
|||
bool aIsEvenLevel,
|
||||
nscoord& aStart,
|
||||
nsContinuationStates* aContinuationStates,
|
||||
WritingMode aLineWM,
|
||||
nscoord& aLineWidth)
|
||||
WritingMode aContainerWM,
|
||||
nscoord& aContainerWidth)
|
||||
{
|
||||
if (!aFrame)
|
||||
return;
|
||||
|
||||
bool isFirst, isLast;
|
||||
WritingMode frameWM = aFrame->GetWritingMode();
|
||||
IsFirstOrLast(aFrame,
|
||||
aContinuationStates,
|
||||
aContainerWM.IsBidiLTR() == frameWM.IsBidiLTR(),
|
||||
isFirst /* out */,
|
||||
isLast /* out */);
|
||||
|
||||
WritingMode frameWM = aFrame->GetWritingMode();
|
||||
nsInlineFrame* testFrame = do_QueryFrame(aFrame);
|
||||
// We only need the margin if the frame is first or last in its own
|
||||
// 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
|
||||
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
|
||||
// have been reflowed, which is required for GetUsedMargin/Border/Padding
|
||||
LogicalMargin margin(aLineWM, aFrame->GetUsedMargin());
|
||||
if (isFirst) {
|
||||
aStart += margin.IStart(aLineWM);
|
||||
LogicalMargin frameMargin = aFrame->GetLogicalUsedMargin(frameWM);
|
||||
LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(frameWM);
|
||||
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 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
|
||||
// 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
|
||||
|
@ -1430,35 +1456,33 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
|
|||
|
||||
// Reposition the child frames
|
||||
int32_t index = 0;
|
||||
nscoord iCoord = borderPadding.IStart(frameWM);
|
||||
|
||||
while (frame) {
|
||||
RepositionFrame(frame,
|
||||
aIsEvenLevel,
|
||||
iCoord,
|
||||
aContinuationStates,
|
||||
frameWM,
|
||||
frameISize);
|
||||
aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
|
||||
index++;
|
||||
frame = reverseOrder ?
|
||||
childList[childList.Length() - index - 1] :
|
||||
frame->GetNextSibling();
|
||||
}
|
||||
|
||||
if (isLast) {
|
||||
iCoord += borderPadding.IEnd(frameWM);
|
||||
}
|
||||
aStart += iCoord;
|
||||
aStart += iCoord + borderPadding.IEnd(frameWM);
|
||||
} else {
|
||||
aStart += frameISize;
|
||||
aStart += aFrame->ISize(aContainerWM);
|
||||
}
|
||||
|
||||
LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth);
|
||||
logicalRect.IStart(aLineWM) = start;
|
||||
logicalRect.ISize(aLineWM) = aStart - start;
|
||||
aFrame->SetRect(aLineWM, logicalRect, aLineWidth);
|
||||
LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
|
||||
aContainerWidth);
|
||||
logicalRect.IStart(aContainerWM) = start;
|
||||
logicalRect.ISize(aContainerWM) = aStart - start;
|
||||
aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
|
||||
|
||||
if (isLast) {
|
||||
aStart += margin.IEnd(aLineWM);
|
||||
}
|
||||
aStart += margin.IEnd(aContainerWM);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1485,20 +1509,10 @@ void
|
|||
nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
|
||||
nsIFrame* aFirstChild,
|
||||
WritingMode aLineWM,
|
||||
nscoord& aLineWidth)
|
||||
nscoord& aLineWidth,
|
||||
nscoord& aStart)
|
||||
{
|
||||
nscoord startSpace = 0;
|
||||
|
||||
// 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;
|
||||
nscoord start = aStart;
|
||||
nsIFrame* frame;
|
||||
int32_t count = aBld->mVisualFrames.Length();
|
||||
int32_t index;
|
||||
|
|
|
@ -160,7 +160,8 @@ public:
|
|||
static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
||||
int32_t aNumFramesOnLine,
|
||||
mozilla::WritingMode aLineWM,
|
||||
nscoord& aLineWidth);
|
||||
nscoord& aLineWidth,
|
||||
nscoord aStart);
|
||||
|
||||
/**
|
||||
* Format Unicode text, taking into account bidi capabilities
|
||||
|
@ -397,8 +398,8 @@ private:
|
|||
bool aIsEvenLevel,
|
||||
nscoord& aStart,
|
||||
nsContinuationStates* aContinuationStates,
|
||||
mozilla::WritingMode aLineWM,
|
||||
nscoord& aLineWidth);
|
||||
mozilla::WritingMode aContainerWM,
|
||||
nscoord& aContainerWidth);
|
||||
|
||||
/*
|
||||
* Initialize the continuation state(nsFrameContinuationState) to
|
||||
|
@ -412,22 +413,32 @@ private:
|
|||
nsContinuationStates* aContinuationStates);
|
||||
|
||||
/*
|
||||
* Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
|
||||
* aIsRightMost values. Also set continuation states of aContinuationStates.
|
||||
* Determine if aFrame is first or last, and set aIsFirst and
|
||||
* aIsLast values. Also set continuation states of
|
||||
* aContinuationStates.
|
||||
*
|
||||
* A frame is leftmost if it's the first appearance of its continuation chain
|
||||
* on the line and the chain is on its first line if it's LTR or the chain is
|
||||
* on its last line if it's RTL.
|
||||
* A frame is rightmost if it's the last appearance of its continuation chain
|
||||
* 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.
|
||||
* A frame is first if it's the first appearance of its continuation
|
||||
* chain on the line and the chain is on its first line.
|
||||
* A frame is last if it's the last appearance of its continuation
|
||||
* chain on the line and the chain is on its last line.
|
||||
*
|
||||
* @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
|
||||
* @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation
|
||||
* @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation
|
||||
* N.B: "First appearance" and "Last appearance" in the previous
|
||||
* paragraph refer to the frame's inline direction, not necessarily
|
||||
* 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,
|
||||
nsContinuationStates* aContinuationStates,
|
||||
bool aSpanInLineOrder /* in */,
|
||||
bool& aIsFirst /* out */,
|
||||
bool& aIsLast /* out */);
|
||||
|
||||
|
@ -441,7 +452,8 @@ private:
|
|||
static void RepositionInlineFrames(BidiLineData* aBld,
|
||||
nsIFrame* aFirstChild,
|
||||
mozilla::WritingMode aLineWM,
|
||||
nscoord& aLineWidth);
|
||||
nscoord& aLineWidth,
|
||||
nscoord& aStart);
|
||||
|
||||
/**
|
||||
* Helper method for Resolve()
|
||||
|
|
|
@ -2598,20 +2598,22 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
pfd->mBounds.IStart(lineWM) += dx;
|
||||
pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
|
||||
}
|
||||
aLine->IndentBy(dx, mContainerWidth);
|
||||
}
|
||||
|
||||
if (mPresContext->BidiEnabled() &&
|
||||
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
|
||||
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
|
||||
aLine->GetChildCount(),
|
||||
lineWM, mContainerWidth);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
== 922530-1.html 922530-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";
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
bool
|
||||
|
@ -1162,3 +1177,96 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t 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_
|
||||
#define _nsStyleContext_h_
|
||||
|
||||
#include "mozilla/RestyleLogging.h"
|
||||
#include "nsRuleNode.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
|
||||
|
@ -397,6 +398,13 @@ public:
|
|||
void List(FILE* out, int32_t aIndent);
|
||||
static void AssertStyleStructMaxDifferenceValid();
|
||||
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
|
||||
|
||||
private:
|
||||
|
@ -450,6 +458,15 @@ private:
|
|||
int32_t aLevels) const;
|
||||
#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
|
||||
|
||||
// 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.
|
||||
options.leakThresholds = {}
|
||||
options.ignoreMissingLeaks = []
|
||||
|
||||
# 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'
|
||||
|
|
|
@ -344,7 +344,7 @@ class RefTest(object):
|
|||
# give the JS harness 30 seconds to deal
|
||||
# with its own timeouts
|
||||
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.")
|
||||
finally:
|
||||
self.cleanup(profileDir)
|
||||
|
@ -513,6 +513,8 @@ class ReftestOptions(OptionParser):
|
|||
|
||||
options.leakThresholds = {"default": options.defaultLeakThreshold}
|
||||
|
||||
options.ignoreMissingLeaks = []
|
||||
|
||||
return options
|
||||
|
||||
def main():
|
||||
|
|
|
@ -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.
|
||||
|
||||
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 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.
|
||||
*
|
||||
* @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)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ realloc_t halloc_allocator = NULL;
|
|||
/*
|
||||
* static methods
|
||||
*/
|
||||
static void _set_allocator(void);
|
||||
int halloc_set_allocator(realloc_t realloc_func);
|
||||
static void * _realloc(void * ptr, size_t n);
|
||||
|
||||
static int _relate(hblock_t * b, hblock_t * p);
|
||||
|
@ -62,7 +62,10 @@ void * halloc(void * ptr, size_t len)
|
|||
/* set up default allocator */
|
||||
if (! allocator)
|
||||
{
|
||||
_set_allocator();
|
||||
if (halloc_set_allocator(realloc) == 0)
|
||||
{
|
||||
halloc_set_allocator(_realloc);
|
||||
}
|
||||
assert(allocator);
|
||||
}
|
||||
|
||||
|
@ -172,7 +175,7 @@ char * h_strdup(const char * str)
|
|||
/*
|
||||
* static stuff
|
||||
*/
|
||||
static void _set_allocator(void)
|
||||
int halloc_set_allocator(realloc_t realloc_func)
|
||||
{
|
||||
void * p;
|
||||
assert(! allocator);
|
||||
|
@ -187,17 +190,17 @@ static void _set_allocator(void)
|
|||
*
|
||||
* Thanks to Stan Tobias for pointing this tricky part out.
|
||||
*/
|
||||
allocator = realloc;
|
||||
if (! (p = malloc(1)))
|
||||
if (! (p = realloc_func(NULL, 1)))
|
||||
/* hmm */
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if ((p = realloc(p, 0)))
|
||||
if ((p = realloc_func(p, 0)))
|
||||
{
|
||||
/* realloc cannot be used as free() */
|
||||
allocator = _realloc;
|
||||
free(p);
|
||||
/* realloc_func cannot be used as free() */
|
||||
return 0;
|
||||
}
|
||||
allocator = realloc_func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void * _realloc(void * ptr, size_t n)
|
||||
|
|
|
@ -321,9 +321,18 @@ struct block_additional {
|
|||
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 */
|
||||
struct nestegg {
|
||||
nestegg_io * io;
|
||||
struct nestegg_io_buf * io;
|
||||
nestegg_log log;
|
||||
struct pool_ctx * alloc_pool;
|
||||
uint64_t last_id;
|
||||
|
@ -546,19 +555,99 @@ ne_alloc(size_t size)
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
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;
|
||||
unsigned char buf[8192];
|
||||
|
@ -575,14 +664,8 @@ ne_io_read_skip(nestegg_io * io, size_t length)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
ne_io_tell(nestegg_io * io)
|
||||
{
|
||||
return io->tell(io->userdata);
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned char b;
|
||||
|
@ -619,19 +702,19 @@ ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vin
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
uint64_t uvalue;
|
||||
|
@ -653,7 +736,7 @@ ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
|
|||
}
|
||||
|
||||
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;
|
||||
int r;
|
||||
|
@ -675,7 +758,7 @@ ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
|
|||
}
|
||||
|
||||
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;
|
||||
uint64_t uval, base;
|
||||
|
@ -702,7 +785,7 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
|
|||
}
|
||||
|
||||
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 {
|
||||
uint64_t u;
|
||||
|
@ -1018,8 +1101,9 @@ ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
|
|||
break;
|
||||
case TYPE_MASTER:
|
||||
case TYPE_UNKNOWN:
|
||||
assert(0);
|
||||
default:
|
||||
r = 0;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1220,7 @@ ne_xiph_lace_value(unsigned char ** np)
|
|||
}
|
||||
|
||||
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;
|
||||
uint64_t lace;
|
||||
|
@ -1159,7 +1243,7 @@ ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
|
|||
}
|
||||
|
||||
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;
|
||||
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
|
||||
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;
|
||||
uint64_t lace, sum, length;
|
||||
|
@ -1792,9 +1876,9 @@ struct sniff_buffer {
|
|||
};
|
||||
|
||||
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;
|
||||
size_t available = sb->length - sb->offset;
|
||||
|
@ -1809,9 +1893,9 @@ ne_buffer_read(void * buffer, size_t length, void * user_data)
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
switch(whence) {
|
||||
|
@ -1834,9 +1918,9 @@ ne_buffer_seek(int64_t offset, int whence, void * user_data)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1860,7 +1944,9 @@ ne_match_webm(nestegg_io io, int64_t max_offset)
|
|||
nestegg_destroy(ctx);
|
||||
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();
|
||||
if (!ctx->alloc_pool) {
|
||||
nestegg_destroy(ctx);
|
||||
|
@ -1918,7 +2004,9 @@ nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t ma
|
|||
nestegg_destroy(ctx);
|
||||
return -1;
|
||||
}
|
||||
*ctx->io = io;
|
||||
ctx->io->io = io;
|
||||
ctx->io->bufsz = NE_IO_BUFSZ;
|
||||
ctx->io->offset = -1;
|
||||
ctx->log = callback;
|
||||
ctx->alloc_pool = ne_pool_init();
|
||||
if (!ctx->alloc_pool) {
|
||||
|
@ -2595,21 +2683,24 @@ int
|
|||
nestegg_sniff(unsigned char const * buffer, size_t length)
|
||||
{
|
||||
nestegg_io io;
|
||||
struct sniff_buffer user_data;
|
||||
struct sniff_buffer userdata;
|
||||
|
||||
user_data.buffer = buffer;
|
||||
user_data.length = length;
|
||||
user_data.offset = 0;
|
||||
userdata.buffer = buffer;
|
||||
userdata.length = length;
|
||||
userdata.offset = 0;
|
||||
|
||||
io.read = ne_buffer_read;
|
||||
io.seek = ne_buffer_seek;
|
||||
io.tell = ne_buffer_tell;
|
||||
io.userdata = &user_data;
|
||||
io.userdata = &userdata;
|
||||
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))
|
||||
{
|
||||
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/macros.h src
|
||||
cp $1/LICENSE .
|
||||
cp $1/README .
|
||||
cp $1/README.md .
|
||||
cp $1/AUTHORS .
|
||||
if [ -d $1/.git ]; then
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1124,6 +1124,7 @@ public abstract class GeckoApp
|
|||
mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final String action = intent.getAction();
|
||||
final String args = intent.getStringExtra("args");
|
||||
|
||||
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>.
|
||||
try {
|
||||
|
@ -1205,6 +1212,30 @@ public abstract class GeckoApp
|
|||
// without killing the entire application (see Bug 769269).
|
||||
mIsRestoringActivity = true;
|
||||
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);
|
||||
|
@ -1368,6 +1399,9 @@ public abstract class GeckoApp
|
|||
layerView.initializeView(EventDispatcher.getInstance());
|
||||
mLayerView = layerView;
|
||||
GeckoAppShell.setLayerView(layerView);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
|
||||
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, layerView.getLayerClientObject()));
|
||||
|
||||
// bind the GeckoEditable instance to the new LayerView
|
||||
GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", "");
|
||||
}
|
||||
|
@ -1425,6 +1459,8 @@ public abstract class GeckoApp
|
|||
|
||||
initializeChrome();
|
||||
|
||||
BrowserDB.initialize(getProfile().getName());
|
||||
|
||||
// If we are doing a restore, read the session data and send it to Gecko
|
||||
if (!mIsRestoringActivity) {
|
||||
String restoreMessage = null;
|
||||
|
@ -1467,25 +1503,6 @@ public abstract class GeckoApp
|
|||
|
||||
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.
|
||||
if (ACTION_LAUNCH_SETTINGS.equals(action)) {
|
||||
Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
|
||||
|
@ -1580,7 +1597,6 @@ public abstract class GeckoApp
|
|||
if (selectedTab != null)
|
||||
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
||||
geckoConnected();
|
||||
GeckoAppShell.setLayerClient(mLayerView.getLayerClientObject());
|
||||
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
|
||||
if (mProfile == null) {
|
||||
mProfile = GeckoProfile.get(this);
|
||||
|
|
|
@ -205,8 +205,6 @@ public class GeckoAppShell
|
|||
public static native void nativeInit();
|
||||
|
||||
// helper methods
|
||||
// public static native void setSurfaceView(GeckoSurfaceView sv);
|
||||
public static native void setLayerClient(Object client);
|
||||
public static native void onResume();
|
||||
public static void callObserver(String observerKey, String topic, String data) {
|
||||
sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
|
||||
|
@ -342,9 +340,6 @@ public class GeckoAppShell
|
|||
// run gecko -- it will spawn its own thread
|
||||
GeckoAppShell.nativeInit();
|
||||
|
||||
if (sLayerView != null)
|
||||
GeckoAppShell.setLayerClient(sLayerView.getLayerClientObject());
|
||||
|
||||
// First argument is the .apk path
|
||||
String combinedArgs = apkPath + " -greomni " + apkPath;
|
||||
if (args != null)
|
||||
|
|
|
@ -76,6 +76,7 @@ public class GeckoEvent {
|
|||
KEY_EVENT(1),
|
||||
MOTION_EVENT(2),
|
||||
SENSOR_EVENT(3),
|
||||
PROCESS_OBJECT(4),
|
||||
LOCATION_EVENT(5),
|
||||
IME_EVENT(6),
|
||||
SIZE_CHANGED(8),
|
||||
|
@ -183,6 +184,8 @@ public class GeckoEvent {
|
|||
public static final int ACTION_GAMEPAD_BUTTON = 1;
|
||||
public static final int ACTION_GAMEPAD_AXES = 2;
|
||||
|
||||
public static final int ACTION_OBJECT_LAYER_CLIENT = 1;
|
||||
|
||||
private final int mType;
|
||||
private int mAction;
|
||||
private boolean mAckNeeded;
|
||||
|
@ -245,6 +248,8 @@ public class GeckoEvent {
|
|||
|
||||
private String[] mPrefNames;
|
||||
|
||||
private Object mObject;
|
||||
|
||||
private GeckoEvent(NativeGeckoEvent event) {
|
||||
mType = event.value;
|
||||
}
|
||||
|
@ -597,6 +602,13 @@ public class GeckoEvent {
|
|||
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) {
|
||||
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT);
|
||||
event.mLocation = l;
|
||||
|
|
|
@ -17,7 +17,7 @@ import java.util.Hashtable;
|
|||
|
||||
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
|
||||
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.mozglue.RobocopTarget;
|
||||
import org.mozilla.gecko.util.INIParser;
|
||||
|
@ -209,7 +209,7 @@ public final class GeckoProfile {
|
|||
* Now do the things that createProfileDirectory normally does --
|
||||
* right now that's kicking off DB init.
|
||||
*/
|
||||
profile.enqueueInitialization();
|
||||
profile.enqueueInitialization(profile.getDir());
|
||||
|
||||
return profile;
|
||||
} catch (Exception ex) {
|
||||
|
@ -650,7 +650,7 @@ public final class GeckoProfile {
|
|||
|
||||
// Trigger init for non-webapp profiles.
|
||||
if (!mIsWebAppProfile) {
|
||||
enqueueInitialization();
|
||||
enqueueInitialization(profileDir);
|
||||
}
|
||||
|
||||
// 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*!
|
||||
*/
|
||||
@RobocopTarget
|
||||
public void enqueueInitialization() {
|
||||
public void enqueueInitialization(final File profileDir) {
|
||||
Log.i(LOGTAG, "Enqueuing profile init.");
|
||||
final Context context = mApplicationContext;
|
||||
|
||||
|
@ -697,13 +697,24 @@ public final class GeckoProfile {
|
|||
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
|
||||
// Because we are running in the background, we want to synchronize on the
|
||||
// GeckoProfile instance so that we don't race with main thread operations
|
||||
// such as locking/unlocking/removing the profile.
|
||||
synchronized (GeckoProfile.this) {
|
||||
// Skip initialization if the profile directory has been removed.
|
||||
if (!profileDir.exists()) {
|
||||
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 int offset = BrowserDB.addDistributionBookmarks(cr, distribution, 0);
|
||||
BrowserDB.addDefaultBookmarks(context, cr, offset);
|
||||
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) {
|
||||
String profile = "";
|
||||
String guest = "";
|
||||
String profileArg = "";
|
||||
String guestArg = "";
|
||||
if (GeckoAppShell.getGeckoInterface() != null) {
|
||||
if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) {
|
||||
final GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile();
|
||||
|
||||
if (profile.inGuestMode()) {
|
||||
try {
|
||||
profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath();
|
||||
} catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); }
|
||||
profileArg = " -profile " + profile.getDir().getCanonicalPath();
|
||||
} catch (final IOException ioe) {
|
||||
Log.e(LOGTAG, "error getting guest profile path", ioe);
|
||||
}
|
||||
|
||||
if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) {
|
||||
guest = " " + BrowserApp.GUEST_BROWSING_ARG;
|
||||
guestArg = " " + BrowserApp.GUEST_BROWSING_ARG;
|
||||
}
|
||||
} else if (!GeckoProfile.sIsUsingCustomProfile) {
|
||||
// If nothing was passed in in the intent, force Gecko to use the default profile for
|
||||
// for this activity
|
||||
profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName();
|
||||
// If nothing was passed in the intent, make sure the default profile exists and
|
||||
// force Gecko to use the default profile for this activity
|
||||
profileArg = " -P " + profile.forceCreate().getName();
|
||||
}
|
||||
}
|
||||
|
||||
return (args != null ? args : "") + profile + guest;
|
||||
return (args != null ? args : "") + profileArg + guestArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -174,6 +174,8 @@ public class GeckoView extends LayerView
|
|||
BrowserDB.initialize(profile.getName());
|
||||
|
||||
GeckoAppShell.setLayerView(this);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
|
||||
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject()));
|
||||
GeckoThread.createAndStart();
|
||||
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
||||
// If Gecko is already running, that means the Activity was
|
||||
|
@ -247,7 +249,6 @@ public class GeckoView extends LayerView
|
|||
if (selectedTab != null)
|
||||
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
||||
geckoConnected();
|
||||
GeckoAppShell.setLayerClient(getLayerClientObject());
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ public class SuggestedSites {
|
|||
|
||||
final Context context;
|
||||
final Distribution distribution;
|
||||
final File file;
|
||||
private File cachedFile;
|
||||
private Map<String, Site> cachedSites;
|
||||
private Set<String> cachedBlacklist;
|
||||
|
||||
|
@ -166,14 +166,20 @@ public class SuggestedSites {
|
|||
}
|
||||
|
||||
public SuggestedSites(Context appContext, Distribution distribution) {
|
||||
this(appContext, distribution,
|
||||
GeckoProfile.get(appContext).getFile(FILENAME));
|
||||
this(appContext, distribution, null);
|
||||
}
|
||||
|
||||
public SuggestedSites(Context appContext, Distribution distribution, File file) {
|
||||
this.context = appContext;
|
||||
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) {
|
||||
|
@ -306,6 +312,7 @@ public class SuggestedSites {
|
|||
setCachedSites(sites);
|
||||
|
||||
// Save the result to disk.
|
||||
final File file = getFile();
|
||||
synchronized (file) {
|
||||
saveSites(file, sites);
|
||||
}
|
||||
|
@ -349,6 +356,7 @@ public class SuggestedSites {
|
|||
|
||||
private Map<String, Site> loadFromProfile() {
|
||||
try {
|
||||
final File file = getFile();
|
||||
synchronized (file) {
|
||||
return loadSites(file);
|
||||
}
|
||||
|
@ -462,7 +470,7 @@ public class SuggestedSites {
|
|||
// Force the suggested sites file in profile dir to be re-generated
|
||||
// if the locale has changed.
|
||||
if (isNewLocale) {
|
||||
file.delete();
|
||||
getFile().delete();
|
||||
}
|
||||
|
||||
if (cachedSites == null || isNewLocale) {
|
||||
|
|
|
@ -133,7 +133,7 @@ abstract class BaseTest extends BaseRobocopTest {
|
|||
|
||||
// In Robocop tests, we typically don't get initialized correctly, because
|
||||
// GeckoProfile doesn't create the profile directory.
|
||||
profile.enqueueInitialization();
|
||||
profile.enqueueInitialization(profile.getDir());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,44 +12,65 @@ import java.util.concurrent.SynchronousQueue;
|
|||
final class GeckoBackgroundThread extends Thread {
|
||||
private static final String LOOPER_NAME = "GeckoBackgroundThread";
|
||||
|
||||
// Guarded by 'this'.
|
||||
private static Handler sHandler;
|
||||
private SynchronousQueue<Handler> mHandlerQueue = new SynchronousQueue<Handler>();
|
||||
// Guarded by 'GeckoBackgroundThread.class'.
|
||||
private static Handler 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.
|
||||
private GeckoBackgroundThread() {
|
||||
super();
|
||||
private GeckoBackgroundThread(final Runnable initialRunnable) {
|
||||
this.initialRunnable = initialRunnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
setName(LOOPER_NAME);
|
||||
Looper.prepare();
|
||||
try {
|
||||
mHandlerQueue.put(new Handler());
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
synchronized (GeckoBackgroundThread.class) {
|
||||
handler = new Handler();
|
||||
GeckoBackgroundThread.class.notify();
|
||||
}
|
||||
|
||||
if (initialRunnable != null) {
|
||||
initialRunnable.run();
|
||||
initialRunnable = null;
|
||||
}
|
||||
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
// Get a Handler for a looper thread, or create one if it doesn't yet exist.
|
||||
/*package*/ static synchronized Handler getHandler() {
|
||||
if (sHandler == null) {
|
||||
GeckoBackgroundThread lt = new GeckoBackgroundThread();
|
||||
ThreadUtils.setBackgroundThread(lt);
|
||||
lt.start();
|
||||
try {
|
||||
sHandler = lt.mHandlerQueue.take();
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
return sHandler;
|
||||
private static void startThread(final Runnable initialRunnable) {
|
||||
thread = new GeckoBackgroundThread(initialRunnable);
|
||||
ThreadUtils.setBackgroundThread(thread);
|
||||
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/*package*/ static void post(Runnable runnable) {
|
||||
Handler handler = getHandler();
|
||||
if (handler == null) {
|
||||
throw new IllegalStateException("No handler! Must have been interrupted. Not posting.");
|
||||
// Get a Handler for a looper thread, or create one if it doesn't yet exist.
|
||||
/*package*/ static synchronized Handler getHandler() {
|
||||
if (thread == null) {
|
||||
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());
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static boolean isOnBackgroundThread() {
|
||||
if (sBackgroundThread == null) {
|
||||
return false;
|
||||
|
@ -197,6 +198,7 @@ public final class ThreadUtils {
|
|||
return isOnThread(sBackgroundThread);
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static boolean isOnThread(Thread thread) {
|
||||
return (Thread.currentThread().getId() == thread.getId());
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ const Cu = Components.utils;
|
|||
|
||||
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.body.setAttribute("class", "normal");
|
||||
}, false);
|
||||
|
|
|
@ -98,6 +98,8 @@ if test ! "$RELEASE_BUILD"; then
|
|||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
|
||||
fi
|
||||
|
||||
|
||||
# Enable generational GC on mobile.
|
||||
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/BrowserTestListener.java',
|
||||
'src/TestDistribution.java',
|
||||
'src/TestGeckoBackgroundThread.java',
|
||||
'src/TestGeckoMenu.java',
|
||||
'src/TestGeckoProfilesProvider.java',
|
||||
'src/TestGeckoSharedPrefs.java',
|
||||
'src/TestImageDownloader.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);
|
||||
|
||||
// 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
|
||||
pref("dom.gamepad.enabled", true);
|
||||
|
@ -341,7 +341,6 @@ pref("media.peerconnection.video.max_bitrate", 2000);
|
|||
#endif
|
||||
pref("media.navigator.permission.disabled", false);
|
||||
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
|
||||
pref("media.peerconnection.trickle_ice", true);
|
||||
pref("media.peerconnection.use_document_iceservers", true);
|
||||
// Do not enable identity before ensuring that the UX cannot be spoofed
|
||||
// see Bug 884573 for details
|
||||
|
|
|
@ -96,25 +96,6 @@ Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) {
|
|||
|
||||
#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);
|
||||
static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume;
|
||||
extern "C" NS_EXPORT void JNICALL
|
||||
|
|
|
@ -615,6 +615,10 @@ class MochitestOptions(optparse.OptionParser):
|
|||
"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
|
||||
|
||||
|
||||
|
@ -819,6 +823,12 @@ class B2GOptions(MochitestOptions):
|
|||
options.sslPort = tempSSL
|
||||
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
|
||||
|
||||
def elf_arm(self, filename):
|
||||
|
|
|
@ -1842,7 +1842,7 @@ class Mochitest(MochitestUtilsMixin):
|
|||
self.stopVMwareRecording();
|
||||
self.stopServers()
|
||||
|
||||
processLeakLog(self.leak_report_file, options.leakThresholds)
|
||||
processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks)
|
||||
|
||||
if self.nsprLogs:
|
||||
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.removeFile(self.leak_report_file)
|
||||
|
||||
processLeakLog(local_leak_file.name, options.leakThresholds)
|
||||
processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks)
|
||||
except KeyboardInterrupt:
|
||||
self.log.info("runtests.py | Received keyboard interrupt.\n");
|
||||
status = -1
|
||||
|
|
|
@ -231,8 +231,11 @@ class RemoteB2GVersion(B2GVersion):
|
|||
self._info[desired_props[key]] = value
|
||||
|
||||
if self._info.get('device_id', '').lower() == 'flame':
|
||||
self._info['device_firmware_version_base'] = dm._runCmd(
|
||||
['shell', 'getprop', 't2m.sw.version']).output[0]
|
||||
for prop in ['ro.boot.bootloader', 't2m.sw.version']:
|
||||
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,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче