зеркало из 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.
|
# Simply copy the log.
|
||||||
log.info(leakReport.rstrip("\n"))
|
log.info(leakReport.rstrip("\n"))
|
||||||
|
|
||||||
def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMissingLeaks):
|
||||||
"""Process a single leak log.
|
"""Process a single leak log.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -273,11 +273,14 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
||||||
if crashedOnPurpose:
|
if crashedOnPurpose:
|
||||||
log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log"
|
log.info("TEST-INFO | leakcheck | %s deliberate crash and thus no leak log"
|
||||||
% processString)
|
% processString)
|
||||||
else:
|
elif ignoreMissingLeaks:
|
||||||
# TODO: This should be a TEST-UNEXPECTED-FAIL, but was changed to a warning
|
log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
|
||||||
# due to too many intermittent failures (see bug 831223).
|
|
||||||
log.info("WARNING | leakcheck | %s missing output line for total leaks!"
|
|
||||||
% processString)
|
% processString)
|
||||||
|
else:
|
||||||
|
log.info("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!"
|
||||||
|
% processString)
|
||||||
|
log.info("TEST-INFO | leakcheck | missing output line from log file %s"
|
||||||
|
% leakLogFileName)
|
||||||
return
|
return
|
||||||
|
|
||||||
if totalBytesLeaked == 0:
|
if totalBytesLeaked == 0:
|
||||||
|
@ -306,7 +309,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold):
|
||||||
log.info("%s | leakcheck | %s %d bytes leaked (%s)"
|
log.info("%s | leakcheck | %s %d bytes leaked (%s)"
|
||||||
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
|
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
|
||||||
|
|
||||||
def processLeakLog(leakLogFile, leakThresholds):
|
def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
|
||||||
"""Process the leak log, including separate leak logs created
|
"""Process the leak log, including separate leak logs created
|
||||||
by child processes.
|
by child processes.
|
||||||
|
|
||||||
|
@ -363,7 +366,8 @@ def processLeakLog(leakLogFile, leakThresholds):
|
||||||
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
|
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
|
||||||
% processType)
|
% processType)
|
||||||
leakThreshold = leakThresholds.get(processType, 0)
|
leakThreshold = leakThresholds.get(processType, 0)
|
||||||
processSingleLeakFile(thisFile, processType, leakThreshold)
|
processSingleLeakFile(thisFile, processType, leakThreshold,
|
||||||
|
processType in ignoreMissingLeaks)
|
||||||
|
|
||||||
def replaceBackSlashes(input):
|
def replaceBackSlashes(input):
|
||||||
return input.replace('\\', '/')
|
return input.replace('\\', '/')
|
||||||
|
|
|
@ -31,7 +31,7 @@ gyp_vars = {
|
||||||
'use_openssl': 0,
|
'use_openssl': 0,
|
||||||
|
|
||||||
# saves 4MB when webrtc_trace is off
|
# saves 4MB when webrtc_trace is off
|
||||||
'enable_lazy_trace_alloc': 0,
|
'enable_lazy_trace_alloc': 1 if CONFIG['RELEASE_BUILD'] else 0,
|
||||||
|
|
||||||
'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
|
'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
|
||||||
'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
|
'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
|
||||||
|
|
|
@ -9178,14 +9178,6 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
||||||
nsresult rv = clone->Init();
|
nsresult rv = clone->Init();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Set URI/principal
|
|
||||||
clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
|
|
||||||
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
|
|
||||||
// Must set the principal first, since SetBaseURI checks it.
|
|
||||||
clone->SetPrincipal(NodePrincipal());
|
|
||||||
clone->mDocumentBaseURI = mDocumentBaseURI;
|
|
||||||
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
|
|
||||||
|
|
||||||
if (mCreatingStaticClone) {
|
if (mCreatingStaticClone) {
|
||||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||||
|
|
||||||
|
@ -9210,6 +9202,18 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
|
||||||
clone->SetContainer(mDocumentContainer);
|
clone->SetContainer(mDocumentContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now ensure that our clone has the same URI, base URI, and principal as us.
|
||||||
|
// We do this after the mCreatingStaticClone block above, because that block
|
||||||
|
// can set the base URI to an incorrect value in cases when base URI
|
||||||
|
// information came from the channel. So we override explicitly, and do it
|
||||||
|
// for all these properties, in case ResetToURI messes with any of the rest of
|
||||||
|
// them.
|
||||||
|
clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
|
||||||
|
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
|
||||||
|
clone->SetPrincipal(NodePrincipal());
|
||||||
|
clone->mDocumentBaseURI = mDocumentBaseURI;
|
||||||
|
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
|
||||||
|
|
||||||
// Set scripting object
|
// Set scripting object
|
||||||
bool hasHadScriptObject = true;
|
bool hasHadScriptObject = true;
|
||||||
nsIScriptGlobalObject* scriptObject =
|
nsIScriptGlobalObject* scriptObject =
|
||||||
|
|
|
@ -1090,7 +1090,7 @@ nsXMLHttpRequest::GetResponseURL(nsAString& aUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoCString temp;
|
nsAutoCString temp;
|
||||||
responseUrl->GetSpec(temp);
|
responseUrl->GetSpecIgnoringRef(temp);
|
||||||
CopyUTF8toUTF16(temp, aUrl);
|
CopyUTF8toUTF16(temp, aUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,11 @@ function testSuccessResponse() {
|
||||||
skip: isInWorker(),
|
skip: isInWorker(),
|
||||||
reason: "cross-origin redirect request not works on Workers, see bug 882458"
|
reason: "cross-origin redirect request not works on Workers, see bug 882458"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
message: "request URL has fragment",
|
||||||
|
requestURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text#fragment",
|
||||||
|
responseURL: "http://mochi.test:8888/tests/content/base/test/file_XHRResponseURL.text"
|
||||||
|
},
|
||||||
|
|
||||||
// tests for non-http(s) URL
|
// tests for non-http(s) URL
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,7 +63,7 @@ PRLogModuleInfo* gMediaStreamGraphLog;
|
||||||
/**
|
/**
|
||||||
* The singleton graph instance.
|
* The singleton graph instance.
|
||||||
*/
|
*/
|
||||||
static MediaStreamGraphImpl* gGraph;
|
static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
|
||||||
|
|
||||||
MediaStreamGraphImpl::~MediaStreamGraphImpl()
|
MediaStreamGraphImpl::~MediaStreamGraphImpl()
|
||||||
{
|
{
|
||||||
|
@ -1633,9 +1633,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
|
||||||
NS_DispatchToMainThread(event);
|
NS_DispatchToMainThread(event);
|
||||||
|
|
||||||
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
|
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
|
||||||
if (this == gGraph) {
|
MediaStreamGraphImpl* graph;
|
||||||
|
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
|
||||||
// null out gGraph if that's the graph being shut down
|
// null out gGraph if that's the graph being shut down
|
||||||
gGraph = nullptr;
|
gGraphs.Remove(mAudioChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1786,9 +1787,12 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
|
||||||
delete aMessage;
|
delete aMessage;
|
||||||
if (IsEmpty() &&
|
if (IsEmpty() &&
|
||||||
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
|
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
|
||||||
if (gGraph == this) {
|
|
||||||
gGraph = nullptr;
|
MediaStreamGraphImpl* graph;
|
||||||
|
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
|
||||||
|
gGraphs.Remove(mAudioChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2736,6 +2740,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mCanRunMessagesSynchronously(false)
|
, mCanRunMessagesSynchronously(false)
|
||||||
#endif
|
#endif
|
||||||
|
, mAudioChannel(static_cast<uint32_t>(aChannel))
|
||||||
{
|
{
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
if (!gMediaStreamGraphLog) {
|
if (!gMediaStreamGraphLog) {
|
||||||
|
@ -2774,15 +2779,26 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
|
||||||
|
|
||||||
static bool gShutdownObserverRegistered = false;
|
static bool gShutdownObserverRegistered = false;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
PLDHashOperator
|
||||||
|
ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
|
||||||
|
MediaStreamGraphImpl* aGraph,
|
||||||
|
void* /* aUnused */)
|
||||||
|
{
|
||||||
|
aGraph->ForceShutDown();
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
|
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
|
||||||
const char *aTopic,
|
const char *aTopic,
|
||||||
const char16_t *aData)
|
const char16_t *aData)
|
||||||
{
|
{
|
||||||
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||||
if (gGraph) {
|
gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
|
||||||
gGraph->ForceShutDown();
|
|
||||||
}
|
|
||||||
nsContentUtils::UnregisterShutdownObserver(this);
|
nsContentUtils::UnregisterShutdownObserver(this);
|
||||||
gShutdownObserverRegistered = false;
|
gShutdownObserverRegistered = false;
|
||||||
}
|
}
|
||||||
|
@ -2794,7 +2810,10 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
||||||
|
|
||||||
if (!gGraph) {
|
uint32_t channel = static_cast<uint32_t>(aChannel);
|
||||||
|
MediaStreamGraphImpl* graph = nullptr;
|
||||||
|
|
||||||
|
if (!gGraphs.Get(channel, &graph)) {
|
||||||
if (!gShutdownObserverRegistered) {
|
if (!gShutdownObserverRegistered) {
|
||||||
gShutdownObserverRegistered = true;
|
gShutdownObserverRegistered = true;
|
||||||
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
|
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
|
||||||
|
@ -2802,12 +2821,13 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
|
||||||
|
|
||||||
CubebUtils::InitPreferredSampleRate();
|
CubebUtils::InitPreferredSampleRate();
|
||||||
|
|
||||||
gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
|
graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
|
||||||
|
gGraphs.Put(channel, graph);
|
||||||
|
|
||||||
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
|
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
|
||||||
}
|
}
|
||||||
|
|
||||||
return gGraph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaStreamGraph*
|
MediaStreamGraph*
|
||||||
|
@ -2978,7 +2998,10 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
|
||||||
bool
|
bool
|
||||||
MediaStreamGraph::IsNonRealtime() const
|
MediaStreamGraph::IsNonRealtime() const
|
||||||
{
|
{
|
||||||
return this != gGraph;
|
const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
|
||||||
|
MediaStreamGraphImpl* graph;
|
||||||
|
|
||||||
|
return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -654,6 +654,8 @@ public:
|
||||||
nsRefPtr<AudioOutputObserver> mFarendObserverRef;
|
nsRefPtr<AudioOutputObserver> mFarendObserverRef;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uint32_t AudioChannel() const { return mAudioChannel; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~MediaStreamGraphImpl();
|
virtual ~MediaStreamGraphImpl();
|
||||||
|
|
||||||
|
@ -687,6 +689,9 @@ private:
|
||||||
bool mCanRunMessagesSynchronously;
|
bool mCanRunMessagesSynchronously;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// We use uint32_t instead AudioChannel because this is just used as key for
|
||||||
|
// the hashtable gGraphs.
|
||||||
|
uint32_t mAudioChannel;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,9 +168,11 @@ static const int32_t MAX_VIDEO_HEIGHT = 3000;
|
||||||
void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
|
void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
|
||||||
|
|
||||||
// The amount of virtual memory reserved for thread stacks.
|
// The amount of virtual memory reserved for thread stacks.
|
||||||
#if (defined(XP_WIN) || defined(LINUX)) && !defined(MOZ_ASAN)
|
#if defined(MOZ_ASAN)
|
||||||
#define MEDIA_THREAD_STACK_SIZE (128 * 1024)
|
// Use the system default in ASAN builds, because the default is assumed to be
|
||||||
#elif defined(XP_MACOSX) && !defined(MOZ_ASAN)
|
// larger than the size we want to use and is hopefully sufficient for ASAN.
|
||||||
|
#define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
|
||||||
|
#elif defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
|
||||||
#define MEDIA_THREAD_STACK_SIZE (256 * 1024)
|
#define MEDIA_THREAD_STACK_SIZE (256 * 1024)
|
||||||
#else
|
#else
|
||||||
// All other platforms use their system defaults.
|
// All other platforms use their system defaults.
|
||||||
|
|
|
@ -263,8 +263,12 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
|
||||||
|
|
||||||
// Enable sandboxing here -- we know the plugin file's path, but
|
// Enable sandboxing here -- we know the plugin file's path, but
|
||||||
// this process's execution hasn't been affected by its content yet.
|
// this process's execution hasn't been affected by its content yet.
|
||||||
MOZ_ASSERT(mozilla::CanSandboxMediaPlugin());
|
if (mozilla::CanSandboxMediaPlugin()) {
|
||||||
mozilla::SetMediaPluginSandbox(nativePath.get());
|
mozilla::SetMediaPluginSandbox(nativePath.get());
|
||||||
|
} else {
|
||||||
|
printf_stderr("GMPChild::LoadPluginLibrary: Loading media plugin %s unsandboxed.\n",
|
||||||
|
nativePath.get());
|
||||||
|
}
|
||||||
#endif // XP_LINUX && MOZ_GMP_SANDBOX
|
#endif // XP_LINUX && MOZ_GMP_SANDBOX
|
||||||
|
|
||||||
libFile->Load(&mLib);
|
libFile->Load(&mLib);
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
#include "GMPTimerParent.h"
|
#include "GMPTimerParent.h"
|
||||||
#include "runnable_utils.h"
|
#include "runnable_utils.h"
|
||||||
|
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||||
|
#include "mozilla/Sandbox.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mozilla/dom/CrashReporterParent.h"
|
#include "mozilla/dom/CrashReporterParent.h"
|
||||||
using mozilla::dom::CrashReporterParent;
|
using mozilla::dom::CrashReporterParent;
|
||||||
|
@ -852,6 +855,17 @@ GMPParent::ReadGMPMetaData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||||
|
if (cap->mAPIName.EqualsLiteral("eme-decrypt") &&
|
||||||
|
!mozilla::CanSandboxMediaPlugin()) {
|
||||||
|
printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
|
||||||
|
" but this system can't sandbox it; not loading.\n",
|
||||||
|
mDisplayName.get());
|
||||||
|
delete cap;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
mCapabilities.AppendElement(cap);
|
mCapabilities.AppendElement(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,14 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||||
const nsAString& aOrigin,
|
const nsAString& aOrigin,
|
||||||
GMPDecryptorProxy** aDecryptor)
|
GMPDecryptorProxy** aDecryptor)
|
||||||
{
|
{
|
||||||
|
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||||
|
if (!mozilla::CanSandboxMediaPlugin()) {
|
||||||
|
NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
|
||||||
|
"EME decryption not available without sandboxing support.");
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||||
NS_ENSURE_ARG(aDecryptor);
|
NS_ENSURE_ARG(aDecryptor);
|
||||||
|
@ -625,11 +633,6 @@ NS_IMETHODIMP
|
||||||
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
|
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
|
||||||
if (!mozilla::CanSandboxMediaPlugin()) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
nsCOMPtr<nsIThread> thread;
|
nsCOMPtr<nsIThread> thread;
|
||||||
nsresult rv = GetThread(getter_AddRefs(thread));
|
nsresult rv = GetThread(getter_AddRefs(thread));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
|
@ -240,8 +240,7 @@ static int webm_read(void* aBuffer, size_t aLength, void* aUserData)
|
||||||
|
|
||||||
// Check the read length.
|
// Check the read length.
|
||||||
if (aLength > ioData->data.Length()) {
|
if (aLength > ioData->data.Length()) {
|
||||||
NS_ERROR("Invalid read length");
|
return 0;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check eos.
|
// Check eos.
|
||||||
|
@ -292,7 +291,7 @@ static int webm_seek(int64_t aOffset, int aWhence, void* aUserData)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t webm_tell(void* aUserData)
|
static int64_t webm_tell(void* aUserData)
|
||||||
|
|
|
@ -289,7 +289,15 @@ void
|
||||||
SourceBuffer::StopUpdating()
|
SourceBuffer::StopUpdating()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mUpdating);
|
if (!mUpdating) {
|
||||||
|
// The buffer append algorithm has been interrupted by abort().
|
||||||
|
//
|
||||||
|
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
|
||||||
|
// the first StopUpdating() runnable runs, then a second StopUpdating()
|
||||||
|
// runnable will be scheduled, but still only one (the first) will queue
|
||||||
|
// events.
|
||||||
|
return;
|
||||||
|
}
|
||||||
mUpdating = false;
|
mUpdating = false;
|
||||||
QueueAsyncSimpleEvent("update");
|
QueueAsyncSimpleEvent("update");
|
||||||
QueueAsyncSimpleEvent("updateend");
|
QueueAsyncSimpleEvent("updateend");
|
||||||
|
|
|
@ -648,12 +648,6 @@ AudioContext::MozAudioChannelType() const
|
||||||
return mDestination->MozAudioChannelType();
|
return mDestination->MozAudioChannelType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
|
|
||||||
{
|
|
||||||
mDestination->SetMozAudioChannelType(aValue, aRv);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioChannel
|
AudioChannel
|
||||||
AudioContext::TestAudioChannelInAudioNodeStream()
|
AudioContext::TestAudioChannelInAudioNodeStream()
|
||||||
{
|
{
|
||||||
|
|
|
@ -222,7 +222,6 @@ public:
|
||||||
JSObject* GetGlobalJSObject() const;
|
JSObject* GetGlobalJSObject() const;
|
||||||
|
|
||||||
AudioChannel MozAudioChannelType() const;
|
AudioChannel MozAudioChannelType() const;
|
||||||
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
|
|
||||||
|
|
||||||
AudioChannel TestAudioChannelInAudioNodeStream();
|
AudioChannel TestAudioChannelInAudioNodeStream();
|
||||||
|
|
||||||
|
|
|
@ -376,16 +376,17 @@ public:
|
||||||
float* higherWaveData = nullptr;
|
float* higherWaveData = nullptr;
|
||||||
float* lowerWaveData = nullptr;
|
float* lowerWaveData = nullptr;
|
||||||
float tableInterpolationFactor;
|
float tableInterpolationFactor;
|
||||||
float rate = 1.0 / mSource->SampleRate();
|
// Phase increment at frequency of 1 Hz.
|
||||||
|
// mPhase runs [0,periodicWaveSize) here instead of [0,2*M_PI).
|
||||||
|
float basePhaseIncrement =
|
||||||
|
static_cast<float>(periodicWaveSize) / mSource->SampleRate();
|
||||||
|
|
||||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||||
UpdateParametersIfNeeded(ticks, i);
|
UpdateParametersIfNeeded(ticks, i);
|
||||||
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
|
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
|
||||||
lowerWaveData,
|
lowerWaveData,
|
||||||
higherWaveData,
|
higherWaveData,
|
||||||
tableInterpolationFactor);
|
tableInterpolationFactor);
|
||||||
// mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
|
|
||||||
mPhase += periodicWaveSize * mFinalFrequency * rate;
|
|
||||||
mPhase = fmod(mPhase, periodicWaveSize);
|
mPhase = fmod(mPhase, periodicWaveSize);
|
||||||
// Bilinear interpolation between adjacent samples in each table.
|
// Bilinear interpolation between adjacent samples in each table.
|
||||||
uint32_t j1 = floor(mPhase);
|
uint32_t j1 = floor(mPhase);
|
||||||
|
@ -394,12 +395,14 @@ public:
|
||||||
j2 -= periodicWaveSize;
|
j2 -= periodicWaveSize;
|
||||||
}
|
}
|
||||||
float sampleInterpolationFactor = mPhase - j1;
|
float sampleInterpolationFactor = mPhase - j1;
|
||||||
float lower = sampleInterpolationFactor * lowerWaveData[j1] +
|
float lower = (1.0f - sampleInterpolationFactor) * lowerWaveData[j1] +
|
||||||
(1 - sampleInterpolationFactor) * lowerWaveData[j2];
|
sampleInterpolationFactor * lowerWaveData[j2];
|
||||||
float higher = sampleInterpolationFactor * higherWaveData[j1] +
|
float higher = (1.0f - sampleInterpolationFactor) * higherWaveData[j1] +
|
||||||
(1 - sampleInterpolationFactor) * higherWaveData[j2];
|
sampleInterpolationFactor * higherWaveData[j2];
|
||||||
aOutput[i] = tableInterpolationFactor * lower +
|
aOutput[i] = (1.0f - tableInterpolationFactor) * lower +
|
||||||
(1 - tableInterpolationFactor) * higher;
|
tableInterpolationFactor * higher;
|
||||||
|
|
||||||
|
mPhase += basePhaseIncrement * mFinalFrequency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,27 +18,23 @@ function test_basic() {
|
||||||
// Default
|
// Default
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
// random wrong channel
|
|
||||||
ac.mozAudioChannelType = "foo";
|
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
|
||||||
|
|
||||||
// Unpermitted channels
|
// Unpermitted channels
|
||||||
ac.mozAudioChannelType = "content";
|
ac = new AudioContext("content");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
ac.mozAudioChannelType = "notification";
|
ac = new AudioContext("notification");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
ac.mozAudioChannelType = "alarm";
|
ac = new AudioContext("alarm");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
ac.mozAudioChannelType = "telephony";
|
ac = new AudioContext("telephony");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
ac.mozAudioChannelType = "ringer";
|
ac = new AudioContext("ringer");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
ac.mozAudioChannelType = "publicnotification";
|
ac = new AudioContext("publicnotification");
|
||||||
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
|
||||||
|
|
||||||
runTest();
|
runTest();
|
||||||
|
@ -56,7 +52,7 @@ function test_permission(aChannel) {
|
||||||
SpecialPowers.pushPermissions(
|
SpecialPowers.pushPermissions(
|
||||||
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
|
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
|
||||||
function() {
|
function() {
|
||||||
ac.mozAudioChannelType = aChannel;
|
var ac = new AudioContext(aChannel);
|
||||||
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
|
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
|
||||||
|
|
||||||
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
|
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
|
||||||
|
|
|
@ -11,11 +11,26 @@
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
// real and imag are used in separate PeriodicWaves to make their peak values
|
||||||
|
// easy to determine.
|
||||||
|
const realMax = 99;
|
||||||
|
var real = new Float32Array(realMax + 1);
|
||||||
|
real[1] = 2.0; // fundamental
|
||||||
|
real[realMax] = 3.0;
|
||||||
|
const realPeak = real[1] + real[realMax];
|
||||||
|
const realFundamental = 19.0;
|
||||||
|
var imag = new Float32Array(4);
|
||||||
|
imag[0] = 6.0; // should be ignored.
|
||||||
|
imag[3] = 0.5;
|
||||||
|
const imagPeak = imag[3];
|
||||||
|
const imagFundamental = 551.0;
|
||||||
|
|
||||||
|
const testLength = 4096;
|
||||||
|
|
||||||
addLoadEvent(function() {
|
addLoadEvent(function() {
|
||||||
var ac = new AudioContext();
|
var ac = new AudioContext();
|
||||||
var real = new Float32Array(4096);
|
ac.createPeriodicWave(new Float32Array(4096), new Float32Array(4096));
|
||||||
var imag = new Float32Array(4096);
|
|
||||||
var table = ac.createPeriodicWave(real, imag);
|
|
||||||
expectException(function() {
|
expectException(function() {
|
||||||
ac.createPeriodicWave(new Float32Array(512), imag);
|
ac.createPeriodicWave(new Float32Array(512), imag);
|
||||||
}, DOMException.NOT_SUPPORTED_ERR);
|
}, DOMException.NOT_SUPPORTED_ERR);
|
||||||
|
@ -25,9 +40,54 @@ addLoadEvent(function() {
|
||||||
expectException(function() {
|
expectException(function() {
|
||||||
ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097));
|
ac.createPeriodicWave(new Float32Array(4097), new Float32Array(4097));
|
||||||
}, DOMException.NOT_SUPPORTED_ERR);
|
}, DOMException.NOT_SUPPORTED_ERR);
|
||||||
SimpleTest.finish();
|
|
||||||
|
runTest();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var gTest = {
|
||||||
|
createGraph: function(context) {
|
||||||
|
var merger = context.createChannelMerger();
|
||||||
|
|
||||||
|
var osc0 = context.createOscillator();
|
||||||
|
var osc1 = context.createOscillator();
|
||||||
|
|
||||||
|
osc0.setPeriodicWave(context.
|
||||||
|
createPeriodicWave(real,
|
||||||
|
new Float32Array(real.length)));
|
||||||
|
osc1.setPeriodicWave(context.
|
||||||
|
createPeriodicWave(new Float32Array(imag.length),
|
||||||
|
imag));
|
||||||
|
|
||||||
|
osc0.frequency.value = realFundamental;
|
||||||
|
osc1.frequency.value = imagFundamental;
|
||||||
|
|
||||||
|
osc0.start();
|
||||||
|
osc1.start();
|
||||||
|
|
||||||
|
osc0.connect(merger, 0, 0);
|
||||||
|
osc1.connect(merger, 0, 1);
|
||||||
|
|
||||||
|
return merger;
|
||||||
|
},
|
||||||
|
createExpectedBuffers: function(context) {
|
||||||
|
var buffer = context.createBuffer(2, testLength, context.sampleRate);
|
||||||
|
|
||||||
|
for (var i = 0; i < buffer.length; ++i) {
|
||||||
|
|
||||||
|
buffer.getChannelData(0)[i] = 1.0 / realPeak *
|
||||||
|
(real[1] * Math.cos(2 * Math.PI * realFundamental * i /
|
||||||
|
context.sampleRate) +
|
||||||
|
real[realMax] * Math.cos(2 * Math.PI * realMax * realFundamental * i /
|
||||||
|
context.sampleRate));
|
||||||
|
|
||||||
|
buffer.getChannelData(1)[i] = 1.0 / imagPeak *
|
||||||
|
imag[3] * Math.sin(2 * Math.PI * 3 * imagFundamental * i /
|
||||||
|
context.sampleRate);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -56,6 +56,9 @@ TestInterfaceJS.prototype = {
|
||||||
get cachedAttr() { return this._cachedAttr; },
|
get cachedAttr() { return this._cachedAttr; },
|
||||||
setCachedAttr: function(n) { this._cachedAttr = n; },
|
setCachedAttr: function(n) { this._cachedAttr = n; },
|
||||||
clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
|
clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
|
||||||
|
|
||||||
|
testSequenceOverload: function(arg) {},
|
||||||
|
testSequenceUnion: function(arg) {},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
||||||
|
|
|
@ -50,3 +50,5 @@ skip-if = debug == false
|
||||||
[test_throwing_method_noDCE.html]
|
[test_throwing_method_noDCE.html]
|
||||||
[test_treat_non_object_as_null.html]
|
[test_treat_non_object_as_null.html]
|
||||||
[test_traceProtos.html]
|
[test_traceProtos.html]
|
||||||
|
[test_sequence_detection.html]
|
||||||
|
skip-if = debug == false
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1066432
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1066432</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 1066432 **/
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
|
||||||
|
var testInterfaceJS = new TestInterfaceJS();
|
||||||
|
ok(testInterfaceJS, "got a TestInterfaceJS object");
|
||||||
|
try {
|
||||||
|
testInterfaceJS.testSequenceOverload(
|
||||||
|
{ "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
|
||||||
|
ok(false, "Should have thrown in the overload case");
|
||||||
|
} catch (e) {
|
||||||
|
ise(e.name, "TypeError", "Should get a TypeError for the overload case");
|
||||||
|
ok(e.message.contains("not iterable"),
|
||||||
|
"Should have a message about being non-iterable in the overload case");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
testInterfaceJS.testSequenceUnion(
|
||||||
|
{ "@@iterator": 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] });
|
||||||
|
ok(false, "Should have thrown in the union case");
|
||||||
|
} catch (e) {
|
||||||
|
ise(e.name, "TypeError", "Should get a TypeError for the union case");
|
||||||
|
ok(e.message.contains("not iterable"),
|
||||||
|
"Should have a message about being non-iterable in the union case");
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1066432">Mozilla Bug 1066432</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -824,7 +824,7 @@ private:
|
||||||
param.data = (unsigned char*) &oaepParams;
|
param.data = (unsigned char*) &oaepParams;
|
||||||
param.len = sizeof(oaepParams);
|
param.len = sizeof(oaepParams);
|
||||||
|
|
||||||
uint32_t outLen;
|
uint32_t outLen = 0;
|
||||||
if (mEncrypt) {
|
if (mEncrypt) {
|
||||||
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too
|
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too
|
||||||
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
|
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
|
||||||
|
@ -841,9 +841,9 @@ private:
|
||||||
mResult.Elements(), &outLen, mResult.Length(),
|
mResult.Elements(), &outLen, mResult.Length(),
|
||||||
mData.Elements(), mData.Length()));
|
mData.Elements(), mData.Length()));
|
||||||
}
|
}
|
||||||
mResult.SetLength(outLen);
|
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||||
|
|
||||||
|
mResult.SetLength(outLen);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -342,6 +342,7 @@ namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
int32_t ContentParent::sNuwaPid = 0;
|
||||||
bool ContentParent::sNuwaReady = false;
|
bool ContentParent::sNuwaReady = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -587,6 +588,7 @@ ContentParent::RunNuwaProcess()
|
||||||
/* aIsNuwaProcess = */ true);
|
/* aIsNuwaProcess = */ true);
|
||||||
nuwaProcess->Init();
|
nuwaProcess->Init();
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
sNuwaPid = nuwaProcess->Pid();
|
||||||
sNuwaReady = false;
|
sNuwaReady = false;
|
||||||
#endif
|
#endif
|
||||||
return nuwaProcess.forget();
|
return nuwaProcess.forget();
|
||||||
|
@ -1990,6 +1992,7 @@ ContentParent::~ContentParent()
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
if (IsNuwaProcess()) {
|
if (IsNuwaProcess()) {
|
||||||
sNuwaReady = false;
|
sNuwaReady = false;
|
||||||
|
sNuwaPid = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -3699,6 +3702,12 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
|
||||||
if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
if (IsNuwaProcess() && IsNuwaReady()) {
|
||||||
|
// Nuwa won't receive frame messages after it is frozen.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
|
return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,10 @@ class ContentParent MOZ_FINAL : public PContentParent
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
static int32_t NuwaPid() {
|
||||||
|
return sNuwaPid;
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsNuwaReady() {
|
static bool IsNuwaReady() {
|
||||||
return sNuwaReady;
|
return sNuwaReady;
|
||||||
}
|
}
|
||||||
|
@ -725,6 +729,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
static int32_t sNuwaPid;
|
||||||
static bool sNuwaReady;
|
static bool sNuwaReady;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -301,7 +301,6 @@ function RTCPeerConnection() {
|
||||||
|
|
||||||
this._localType = null;
|
this._localType = null;
|
||||||
this._remoteType = null;
|
this._remoteType = null;
|
||||||
this._trickleIce = false;
|
|
||||||
this._peerIdentity = null;
|
this._peerIdentity = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -326,7 +325,6 @@ RTCPeerConnection.prototype = {
|
||||||
init: function(win) { this._win = win; },
|
init: function(win) { this._win = win; },
|
||||||
|
|
||||||
__init: function(rtcConfig) {
|
__init: function(rtcConfig) {
|
||||||
this._trickleIce = Services.prefs.getBoolPref("media.peerconnection.trickle_ice");
|
|
||||||
if (!rtcConfig.iceServers ||
|
if (!rtcConfig.iceServers ||
|
||||||
!Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
|
!Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
|
||||||
rtcConfig.iceServers =
|
rtcConfig.iceServers =
|
||||||
|
@ -365,8 +363,7 @@ RTCPeerConnection.prototype = {
|
||||||
this._queueOrRun({
|
this._queueOrRun({
|
||||||
func: this._initialize,
|
func: this._initialize,
|
||||||
args: [rtcConfig],
|
args: [rtcConfig],
|
||||||
// If not trickling, suppress start.
|
wait: false
|
||||||
wait: !this._trickleIce
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -500,7 +497,11 @@ RTCPeerConnection.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
dispatchEvent: function(event) {
|
dispatchEvent: function(event) {
|
||||||
this.__DOM_IMPL__.dispatchEvent(event);
|
// PC can close while events are firing if there is an async dispatch
|
||||||
|
// in c++ land
|
||||||
|
if (!this._closed) {
|
||||||
|
this.__DOM_IMPL__.dispatchEvent(event);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Log error message to web console and window.onerror, if present.
|
// Log error message to web console and window.onerror, if present.
|
||||||
|
|
|
@ -1937,6 +1937,10 @@ PeerConnectionWrapper.prototype = {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._remote_ice_candidates.push(candidate);
|
self._remote_ice_candidates.push(candidate);
|
||||||
|
if (self.signalingstate === 'closed') {
|
||||||
|
info("Received ICE candidate for closed PeerConnection - discarding");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (self.remoteDescriptionSet) {
|
if (self.remoteDescriptionSet) {
|
||||||
self.addIceCandidate(candidate);
|
self.addIceCandidate(candidate);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2566,15 +2570,9 @@ PeerConnectionWrapper.prototype = {
|
||||||
* Closes the connection
|
* Closes the connection
|
||||||
*/
|
*/
|
||||||
close : function PCW_close() {
|
close : function PCW_close() {
|
||||||
// It might be that a test has already closed the pc. In those cases
|
this._ice_candidates_to_add = [];
|
||||||
// we should not fail.
|
this._pc.close();
|
||||||
try {
|
info(this + ": Closed connection.");
|
||||||
this._pc.close();
|
|
||||||
info(this + ": Closed connection.");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
info(this + ": Failure in closing connection - " + e.message);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -589,8 +589,15 @@ DOMStorageDBParent::Observe(const char* aTopic,
|
||||||
const nsACString& aScopePrefix)
|
const nsACString& aScopePrefix)
|
||||||
{
|
{
|
||||||
if (mIPCOpen) {
|
if (mIPCOpen) {
|
||||||
mozilla::unused << SendObserve(nsDependentCString(aTopic),
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
nsCString(aScopePrefix));
|
if (!(static_cast<ContentParent*>(Manager())->IsNuwaProcess() &&
|
||||||
|
ContentParent::IsNuwaReady())) {
|
||||||
|
#endif
|
||||||
|
mozilla::unused << SendObserve(nsDependentCString(aTopic),
|
||||||
|
nsCString(aScopePrefix));
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -78,8 +78,8 @@ interface AudioContext : EventTarget {
|
||||||
// Mozilla extensions
|
// Mozilla extensions
|
||||||
partial interface AudioContext {
|
partial interface AudioContext {
|
||||||
// Read AudioChannel.webidl for more information about this attribute.
|
// Read AudioChannel.webidl for more information about this attribute.
|
||||||
[Pref="media.useAudioChannelService", SetterThrows]
|
[Pref="media.useAudioChannelService"]
|
||||||
attribute AudioChannel mozAudioChannelType;
|
readonly attribute AudioChannel mozAudioChannelType;
|
||||||
|
|
||||||
// These 2 events are dispatched when the AudioContext object is muted by
|
// These 2 events are dispatched when the AudioContext object is muted by
|
||||||
// the AudioChannelService. It's call 'interrupt' because when this event is
|
// the AudioChannelService. It's call 'interrupt' because when this event is
|
||||||
|
|
|
@ -42,4 +42,10 @@ interface TestInterfaceJS {
|
||||||
readonly attribute short cachedAttr;
|
readonly attribute short cachedAttr;
|
||||||
void setCachedAttr(short n);
|
void setCachedAttr(short n);
|
||||||
void clearCachedAttrCache();
|
void clearCachedAttrCache();
|
||||||
|
|
||||||
|
// Test for sequence overloading and union behavior
|
||||||
|
void testSequenceOverload(sequence<DOMString> arg);
|
||||||
|
void testSequenceOverload(DOMString arg);
|
||||||
|
|
||||||
|
void testSequenceUnion((sequence<DOMString> or DOMString) arg);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2205,7 +2205,7 @@ RuntimeService::CancelWorkersForWindow(nsPIDOMWindow* aWindow)
|
||||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||||
WorkerPrivate*& worker = workers[index];
|
WorkerPrivate*& worker = workers[index];
|
||||||
|
|
||||||
if (worker->IsSharedWorker()) {
|
if (worker->IsSharedWorker() || worker->IsServiceWorker()) {
|
||||||
worker->CloseSharedWorkersForWindow(aWindow);
|
worker->CloseSharedWorkersForWindow(aWindow);
|
||||||
} else if (!worker->Cancel(cx)) {
|
} else if (!worker->Cancel(cx)) {
|
||||||
JS_ReportPendingException(cx);
|
JS_ReportPendingException(cx);
|
||||||
|
|
|
@ -128,7 +128,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
||||||
endFrame = aImportedBy->mFirstNotImported;
|
endFrame = aImportedBy->mFirstNotImported;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#if defined(PR_LOGGING) && defined(TX_TO_STRING)
|
||||||
txPattern* match = 0;
|
txPattern* match = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
||||||
if (templ.mMatch->matches(aNode, aContext)) {
|
if (templ.mMatch->matches(aNode, aContext)) {
|
||||||
matchTemplate = templ.mFirstInstruction;
|
matchTemplate = templ.mFirstInstruction;
|
||||||
*aImportFrame = frame;
|
*aImportFrame = frame;
|
||||||
#ifdef PR_LOGGING
|
#if defined(PR_LOGGING) && defined(TX_TO_STRING)
|
||||||
match = templ.mMatch;
|
match = templ.mMatch;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,7 @@ MOZ_END_ENUM_CLASS(BufferMode)
|
||||||
|
|
||||||
MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t)
|
MOZ_BEGIN_ENUM_CLASS(DrawRegionClip, int8_t)
|
||||||
DRAW,
|
DRAW,
|
||||||
DRAW_SNAPPED,
|
NONE
|
||||||
CLIP_NONE
|
|
||||||
MOZ_END_ENUM_CLASS(DrawRegionClip)
|
MOZ_END_ENUM_CLASS(DrawRegionClip)
|
||||||
|
|
||||||
MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t)
|
MOZ_BEGIN_ENUM_CLASS(SurfaceMode, int8_t)
|
||||||
|
|
|
@ -695,7 +695,7 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
|
||||||
nsIntRegion invalidate;
|
nsIntRegion invalidate;
|
||||||
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
|
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
|
||||||
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
|
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
|
||||||
result.mClip = DrawRegionClip::DRAW_SNAPPED;
|
result.mClip = DrawRegionClip::DRAW;
|
||||||
result.mMode = mode;
|
result.mMode = mode;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -229,7 +229,7 @@ public:
|
||||||
: mRegionToDraw()
|
: mRegionToDraw()
|
||||||
, mRegionToInvalidate()
|
, mRegionToInvalidate()
|
||||||
, mMode(SurfaceMode::SURFACE_NONE)
|
, mMode(SurfaceMode::SURFACE_NONE)
|
||||||
, mClip(DrawRegionClip::CLIP_NONE)
|
, mClip(DrawRegionClip::NONE)
|
||||||
, mContentType(gfxContentType::SENTINEL)
|
, mContentType(gfxContentType::SENTINEL)
|
||||||
, mDidSelfCopy(false)
|
, mDidSelfCopy(false)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -91,7 +91,7 @@ BasicPaintedLayer::PaintThebes(gfxContext* aContext,
|
||||||
groupContext = aContext;
|
groupContext = aContext;
|
||||||
}
|
}
|
||||||
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
|
SetAntialiasingFlags(this, groupContext->GetDrawTarget());
|
||||||
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
|
aCallback(this, groupContext, toDraw, DrawRegionClip::NONE, nsIntRegion(), aCallbackData);
|
||||||
if (needsGroup) {
|
if (needsGroup) {
|
||||||
aContext->PopGroupToSource();
|
aContext->PopGroupToSource();
|
||||||
if (needsClipToVisibleRegion) {
|
if (needsClipToVisibleRegion) {
|
||||||
|
|
|
@ -443,7 +443,17 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
||||||
}
|
}
|
||||||
if (mWidget) {
|
if (mWidget) {
|
||||||
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
|
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
|
||||||
|
// The compositor doesn't draw to a different sized surface
|
||||||
|
// when there's a rotation. Instead we rotate the result
|
||||||
|
// when drawing into dt
|
||||||
|
nsIntRect outerBounds;
|
||||||
|
mWidget->GetBounds(outerBounds);
|
||||||
|
|
||||||
nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
|
nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
|
||||||
|
if (mTargetRotation) {
|
||||||
|
bounds = RotateRect(bounds, outerBounds, mTargetRotation);
|
||||||
|
}
|
||||||
|
|
||||||
SurfaceDescriptor inSnapshot;
|
SurfaceDescriptor inSnapshot;
|
||||||
if (!bounds.IsEmpty() &&
|
if (!bounds.IsEmpty() &&
|
||||||
mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
|
mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
|
||||||
|
@ -452,11 +462,18 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
||||||
remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
|
remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
|
||||||
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
|
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
|
||||||
DrawTarget* dt = mShadowTarget->GetDrawTarget();
|
DrawTarget* dt = mShadowTarget->GetDrawTarget();
|
||||||
|
|
||||||
Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||||
Rect srcRect(0, 0, bounds.width, bounds.height);
|
Rect srcRect(0, 0, bounds.width, bounds.height);
|
||||||
|
|
||||||
|
gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);
|
||||||
|
|
||||||
|
gfx::Matrix oldMatrix = dt->GetTransform();
|
||||||
|
dt->SetTransform(oldMatrix * rotate);
|
||||||
dt->DrawSurface(surf, dstRect, srcRect,
|
dt->DrawSurface(surf, dstRect, srcRect,
|
||||||
DrawSurfaceOptions(),
|
DrawSurfaceOptions(),
|
||||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||||
|
dt->SetTransform(oldMatrix);
|
||||||
}
|
}
|
||||||
mForwarder->DestroySharedSurface(&inSnapshot);
|
mForwarder->DestroySharedSurface(&inSnapshot);
|
||||||
}
|
}
|
||||||
|
|
|
@ -934,7 +934,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||||
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
|
PROFILER_LABEL("ClientTiledLayerBuffer", "PaintThebesSingleBufferDraw",
|
||||||
js::ProfileEntry::Category::GRAPHICS);
|
js::ProfileEntry::Category::GRAPHICS);
|
||||||
|
|
||||||
mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData);
|
mCallback(mPaintedLayer, ctxt, aPaintRegion, DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||||
|
@ -1304,7 +1304,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||||
Scale(mResolution, mResolution));
|
Scale(mResolution, mResolution));
|
||||||
mCallback(mPaintedLayer, ctxt,
|
mCallback(mPaintedLayer, ctxt,
|
||||||
tileRegion.GetBounds(),
|
tileRegion.GetBounds(),
|
||||||
DrawRegionClip::CLIP_NONE,
|
DrawRegionClip::NONE,
|
||||||
nsIntRegion(), mCallbackData);
|
nsIntRegion(), mCallbackData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -537,7 +537,7 @@ PaintedLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
||||||
|
|
||||||
context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y));
|
context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y));
|
||||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||||
cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData);
|
cbInfo.Callback(this, context, aRegion, DrawRegionClip::NONE, nsIntRegion(), cbInfo.CallbackData);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
|
for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
|
||||||
NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,
|
NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifdef MOZ_NUWA_PROCESS
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
#include "ipc/Nuwa.h"
|
#include "ipc/Nuwa.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
|
@ -70,6 +71,9 @@ ProcessLink::ProcessLink(MessageChannel *aChan)
|
||||||
, mTransport(nullptr)
|
, mTransport(nullptr)
|
||||||
, mIOLoop(nullptr)
|
, mIOLoop(nullptr)
|
||||||
, mExistingListener(nullptr)
|
, mExistingListener(nullptr)
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
, mIsToNuwaProcess(false)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +172,26 @@ ProcessLink::SendMessage(Message *msg)
|
||||||
mChan->AssertWorkerThread();
|
mChan->AssertWorkerThread();
|
||||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||||
|
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
|
||||||
|
switch (msg->type()) {
|
||||||
|
case mozilla::dom::PContent::Msg_NuwaFork__ID:
|
||||||
|
case mozilla::dom::PContent::Reply_AddNewProcess__ID:
|
||||||
|
case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
|
||||||
|
case GOODBYE_MESSAGE_TYPE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_CRASH();
|
||||||
|
#else
|
||||||
|
// In optimized build, message will be dropped.
|
||||||
|
printf_stderr("Sending message to frozen Nuwa");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
mIOLoop->PostTask(
|
mIOLoop->PostTask(
|
||||||
FROM_HERE,
|
FROM_HERE,
|
||||||
NewRunnableMethod(mTransport, &Transport::Send, msg));
|
NewRunnableMethod(mTransport, &Transport::Send, msg));
|
||||||
|
@ -360,6 +384,10 @@ ProcessLink::OnChannelConnected(int32_t peer_pid)
|
||||||
if (mExistingListener)
|
if (mExistingListener)
|
||||||
mExistingListener->OnChannelConnected(peer_pid);
|
mExistingListener->OnChannelConnected(peer_pid);
|
||||||
|
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid());
|
||||||
|
#endif
|
||||||
|
|
||||||
if (notifyChannel) {
|
if (notifyChannel) {
|
||||||
mChan->OnChannelConnected(peer_pid);
|
mChan->OnChannelConnected(peer_pid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,9 @@ class ProcessLink
|
||||||
Transport* mTransport;
|
Transport* mTransport;
|
||||||
MessageLoop* mIOLoop; // thread where IO happens
|
MessageLoop* mIOLoop; // thread where IO happens
|
||||||
Transport::Listener* mExistingListener; // channel's previous listener
|
Transport::Listener* mExistingListener; // channel's previous listener
|
||||||
|
#ifdef MOZ_NUWA_PROCESS
|
||||||
|
bool mIsToNuwaProcess;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadLink : public MessageLink
|
class ThreadLink : public MessageLink
|
||||||
|
|
|
@ -2016,6 +2016,12 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
|
||||||
*answer = true;
|
*answer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pn->isHoistedLetUse()) {
|
||||||
|
// Hoisted uses of lexical bindings throw on access.
|
||||||
|
*answer = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (pn->isKind(PNK_DOT)) {
|
if (pn->isKind(PNK_DOT)) {
|
||||||
/* Dotted property references in general can call getters. */
|
/* Dotted property references in general can call getters. */
|
||||||
*answer = true;
|
*answer = true;
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
function assertThrowsReferenceError(f) {
|
||||||
|
var e = null;
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
} catch (ex) {
|
||||||
|
e = ex;
|
||||||
|
}
|
||||||
|
assertEq(e instanceof ReferenceError, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThrowsReferenceError(function () { delete x; let x; });
|
||||||
|
|
||||||
|
// FIXME do this unconditionally once bug 611388 lands.
|
||||||
|
function constIsLexical() {
|
||||||
|
try {
|
||||||
|
(function () { z++; const z; })();
|
||||||
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (constIsLexical())
|
||||||
|
assertThrowsReferenceError(function () { delete x; const x; });
|
|
@ -0,0 +1,24 @@
|
||||||
|
function assertThrowsReferenceError(f) {
|
||||||
|
var e = null;
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
} catch (ex) {
|
||||||
|
e = ex;
|
||||||
|
}
|
||||||
|
assertEq(e instanceof ReferenceError, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TDZ is effectful, don't optimize out x.
|
||||||
|
assertThrowsReferenceError(function () { x; let x; });
|
||||||
|
|
||||||
|
// FIXME do this unconditionally once bug 611388 lands.
|
||||||
|
function constIsLexical() {
|
||||||
|
try {
|
||||||
|
(function () { z++; const z; })();
|
||||||
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (constIsLexical())
|
||||||
|
assertThrowsReferenceError(function () { x; const x; });
|
|
@ -0,0 +1,5 @@
|
||||||
|
// |jit-test| error: ReferenceError
|
||||||
|
{
|
||||||
|
while (x && 0) {}
|
||||||
|
let x
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
try {
|
||||||
|
let x = ((function f(y) {
|
||||||
|
if (y > 0) {
|
||||||
|
f(-1)
|
||||||
|
}
|
||||||
|
x
|
||||||
|
})(1))
|
||||||
|
} catch (e) {
|
||||||
|
assertEq(e instanceof ReferenceError, true);
|
||||||
|
}
|
|
@ -7911,13 +7911,28 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
|
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
|
||||||
masm.storePtr(scratch, shapeAddr);
|
masm.storePtr(scratch, shapeAddr);
|
||||||
|
|
||||||
// Change the object's type if required.
|
// Try to change the object's type.
|
||||||
Label noTypeChange;
|
Label noTypeChange;
|
||||||
|
|
||||||
|
// Check if the cache has a new type to change to.
|
||||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
|
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
|
||||||
masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange);
|
masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noTypeChange);
|
||||||
|
|
||||||
|
// Check if the old type still has a newScript.
|
||||||
|
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch);
|
||||||
|
masm.branchPtr(Assembler::Equal,
|
||||||
|
Address(scratch, types::TypeObject::offsetOfNewScript()),
|
||||||
|
ImmWord(0),
|
||||||
|
&noTypeChange);
|
||||||
|
|
||||||
|
// Reload the new type from the cache.
|
||||||
|
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewType()), scratch);
|
||||||
|
|
||||||
|
// Change the object's type.
|
||||||
Address typeAddr(objReg, JSObject::offsetOfType());
|
Address typeAddr(objReg, JSObject::offsetOfType());
|
||||||
EmitPreBarrier(masm, typeAddr, MIRType_TypeObject);
|
EmitPreBarrier(masm, typeAddr, MIRType_TypeObject);
|
||||||
masm.storePtr(scratch, typeAddr);
|
masm.storePtr(scratch, typeAddr);
|
||||||
|
|
||||||
masm.bind(&noTypeChange);
|
masm.bind(&noTypeChange);
|
||||||
|
|
||||||
Register holderReg;
|
Register holderReg;
|
||||||
|
|
|
@ -2583,11 +2583,27 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
|
||||||
|
|
||||||
if (oldType != obj->type()) {
|
if (oldType != obj->type()) {
|
||||||
// Changing object's type from a partially to fully initialized type,
|
// Changing object's type from a partially to fully initialized type,
|
||||||
// per the acquired properties analysis.
|
// per the acquired properties analysis. Only change the type if the
|
||||||
|
// old type still has a newScript.
|
||||||
|
Label noTypeChange, skipPop;
|
||||||
|
|
||||||
|
masm.push(object);
|
||||||
|
masm.loadPtr(Address(object, JSObject::offsetOfType()), object);
|
||||||
|
masm.branchPtr(Assembler::Equal,
|
||||||
|
Address(object, types::TypeObject::offsetOfNewScript()),
|
||||||
|
ImmWord(0),
|
||||||
|
&noTypeChange);
|
||||||
|
masm.pop(object);
|
||||||
|
|
||||||
Address typeAddr(object, JSObject::offsetOfType());
|
Address typeAddr(object, JSObject::offsetOfType());
|
||||||
if (cx->zone()->needsIncrementalBarrier())
|
if (cx->zone()->needsIncrementalBarrier())
|
||||||
masm.callPreBarrier(typeAddr, MIRType_TypeObject);
|
masm.callPreBarrier(typeAddr, MIRType_TypeObject);
|
||||||
masm.storePtr(ImmGCPtr(obj->type()), typeAddr);
|
masm.storePtr(ImmGCPtr(obj->type()), typeAddr);
|
||||||
|
|
||||||
|
masm.jump(&skipPop);
|
||||||
|
masm.bind(&noTypeChange);
|
||||||
|
masm.pop(object);
|
||||||
|
masm.bind(&skipPop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the value on the object. Since this is an add, obj->lastProperty()
|
// Set the value on the object. Since this is an add, obj->lastProperty()
|
||||||
|
|
|
@ -573,6 +573,13 @@ jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *
|
||||||
return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::ObjectType(obj));
|
return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::ObjectType(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static types::TemporaryTypeSet *
|
||||||
|
MakeUnknownTypeSet()
|
||||||
|
{
|
||||||
|
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
|
||||||
|
return alloc->new_<types::TemporaryTypeSet>(alloc, types::Type::UnknownType());
|
||||||
|
}
|
||||||
|
|
||||||
MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
|
MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
|
||||||
: value_(vp)
|
: value_(vp)
|
||||||
{
|
{
|
||||||
|
@ -582,6 +589,16 @@ MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constra
|
||||||
// other types as the result type encodes all needed information.
|
// other types as the result type encodes all needed information.
|
||||||
setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
|
setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
|
||||||
}
|
}
|
||||||
|
if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
|
||||||
|
// JS_UNINITIALIZED_LEXICAL does not escape to script and is not
|
||||||
|
// observed in type sets. However, it may flow around freely during
|
||||||
|
// Ion compilation. Give it an unknown typeset to poison any type sets
|
||||||
|
// it merges with.
|
||||||
|
//
|
||||||
|
// TODO We could track uninitialized lexicals more precisely by tracking
|
||||||
|
// them in type sets.
|
||||||
|
setResultTypeSet(MakeUnknownTypeSet());
|
||||||
|
}
|
||||||
|
|
||||||
setMovable();
|
setMovable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,19 @@ The tests in this directory exercise the JSAPI.
|
||||||
|
|
||||||
If you built JS, you already built the tests.
|
If you built JS, you already built the tests.
|
||||||
|
|
||||||
If you did `make check` in your JS objdir, you already ran them.
|
|
||||||
|
|
||||||
The tests are built by default when you build JS. All the tests are compiled
|
The tests are built by default when you build JS. All the tests are compiled
|
||||||
into a single binary named jsapi-tests. They all run in a single process.
|
into a single binary named jsapi-tests. They all run in a single process.
|
||||||
|
|
||||||
|
To run the tests:
|
||||||
|
|
||||||
|
cd $OBJDIR/dist/bin
|
||||||
|
./jsapi-tests
|
||||||
|
|
||||||
To run the tests in a debugger:
|
To run the tests in a debugger:
|
||||||
|
|
||||||
cd $OBJDIR/jsapi-tests
|
cd $OBJDIR/dist/bin
|
||||||
gdb ./jsapi-tests
|
gdb ./jsapi-tests
|
||||||
|
|
||||||
|
|
||||||
--- Creating new tests
|
--- Creating new tests
|
||||||
|
|
||||||
1. You can either add to an existing test*.cpp file or make a new one.
|
1. You can either add to an existing test*.cpp file or make a new one.
|
||||||
|
|
|
@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
|
||||||
'testException.cpp',
|
'testException.cpp',
|
||||||
'testExternalStrings.cpp',
|
'testExternalStrings.cpp',
|
||||||
'testFindSCCs.cpp',
|
'testFindSCCs.cpp',
|
||||||
|
'testForOfIterator.cpp',
|
||||||
'testFreshGlobalEvalRedefinition.cpp',
|
'testFreshGlobalEvalRedefinition.cpp',
|
||||||
'testFuncCallback.cpp',
|
'testFuncCallback.cpp',
|
||||||
'testFunctionProperties.cpp',
|
'testFunctionProperties.cpp',
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
*/
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "jsapi-tests/tests.h"
|
||||||
|
|
||||||
|
BEGIN_TEST(testForOfIterator_basicNonIterable)
|
||||||
|
{
|
||||||
|
JS::RootedValue v(cx);
|
||||||
|
// Hack to make it simple to produce an object that has a property
|
||||||
|
// named Symbol.iterator.
|
||||||
|
EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
|
||||||
|
JS::ForOfIterator iter(cx);
|
||||||
|
bool ok = iter.init(v);
|
||||||
|
CHECK(!ok);
|
||||||
|
JS_ClearPendingException(cx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testForOfIterator_basicNonIterable)
|
||||||
|
|
||||||
|
BEGIN_TEST(testForOfIterator_bug515273_part1)
|
||||||
|
{
|
||||||
|
JS::RootedValue v(cx);
|
||||||
|
|
||||||
|
// Hack to make it simple to produce an object that has a property
|
||||||
|
// named Symbol.iterator.
|
||||||
|
EVAL("var obj = { '@@iterator': 5, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; obj;", &v);
|
||||||
|
|
||||||
|
JS::ForOfIterator iter(cx);
|
||||||
|
bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
|
||||||
|
CHECK(!ok);
|
||||||
|
JS_ClearPendingException(cx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testForOfIterator_bug515273_part1)
|
||||||
|
|
||||||
|
BEGIN_TEST(testForOfIterator_bug515273_part2)
|
||||||
|
{
|
||||||
|
JS::RootedObject obj(cx,
|
||||||
|
JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
|
||||||
|
CHECK(obj);
|
||||||
|
JS::RootedValue v(cx, JS::ObjectValue(*obj));
|
||||||
|
|
||||||
|
JS::ForOfIterator iter(cx);
|
||||||
|
bool ok = iter.init(v, JS::ForOfIterator::AllowNonIterable);
|
||||||
|
CHECK(ok);
|
||||||
|
CHECK(!iter.valueIsIterable());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
END_TEST(testForOfIterator_bug515273_part2)
|
|
@ -5191,10 +5191,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the iterator. If AllowNonIterable is passed then if iterable
|
* Initialize the iterator. If AllowNonIterable is passed then if getting
|
||||||
* does not have a callable @@iterator init() will just return true instead
|
* the @@iterator property from iterable returns undefined init() will just
|
||||||
* of throwing. Callers should then check valueIsIterable() before
|
* return true instead of throwing. Callers must then check
|
||||||
* continuing with the iteration.
|
* valueIsIterable() before continuing with the iteration.
|
||||||
*/
|
*/
|
||||||
bool init(JS::HandleValue iterable,
|
bool init(JS::HandleValue iterable,
|
||||||
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
|
NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable);
|
||||||
|
|
|
@ -1236,6 +1236,10 @@ struct TypeObject : public gc::TenuredCell
|
||||||
return offsetof(TypeObject, proto_);
|
return offsetof(TypeObject, proto_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t offsetOfNewScript() {
|
||||||
|
return offsetof(TypeObject, newScript_);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline uint32_t basePropertyCount() const;
|
inline uint32_t basePropertyCount() const;
|
||||||
inline void setBasePropertyCount(uint32_t count);
|
inline void setBasePropertyCount(uint32_t count);
|
||||||
|
|
|
@ -1366,13 +1366,17 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
|
||||||
if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
|
if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Throw if obj[@@iterator] isn't callable if we were asked to do so.
|
// If obj[@@iterator] is undefined and we were asked to allow non-iterables,
|
||||||
|
// bail out now without setting iterator. This will make valueIsIterable(),
|
||||||
|
// which our caller should check, return false.
|
||||||
|
if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Throw if obj[@@iterator] isn't callable.
|
||||||
// js::Invoke is about to check for this kind of error anyway, but it would
|
// js::Invoke is about to check for this kind of error anyway, but it would
|
||||||
// throw an inscrutable error message about |method| rather than this nice
|
// throw an inscrutable error message about |method| rather than this nice
|
||||||
// one about |obj|.
|
// one about |obj|.
|
||||||
if (!callee.isObject() || !callee.toObject().isCallable()) {
|
if (!callee.isObject() || !callee.toObject().isCallable()) {
|
||||||
if (nonIterableBehavior == AllowNonIterable)
|
|
||||||
return true;
|
|
||||||
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
|
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -254,7 +254,10 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
// NAME operations are the slow paths already, so unconditionally check
|
||||||
|
// for uninitialized lets.
|
||||||
|
return CheckUninitializedLexical(cx, name, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -264,7 +267,7 @@ FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vp.set(pobj->nativeGetSlot(shape->slot()));
|
vp.set(pobj->nativeGetSlot(shape->slot()));
|
||||||
return true;
|
return !IsUninitializedLexical(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
|
|
@ -298,17 +298,9 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle
|
||||||
|
|
||||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||||
JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
|
JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
|
||||||
if (op2 == JSOP_TYPEOF) {
|
if (op2 == JSOP_TYPEOF)
|
||||||
if (!FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
|
return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||||
return false;
|
return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||||
} else {
|
|
||||||
if (!FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NAME operations are the slow paths already, so unconditionally check
|
|
||||||
// for uninitialized lets.
|
|
||||||
return CheckUninitializedLexical(cx, nameRoot, vp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
|
@ -3564,7 +3556,7 @@ js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name
|
||||||
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// See note in NameOperation.
|
// See note in FetchName.
|
||||||
return CheckUninitializedLexical(cx, name, vp);
|
return CheckUninitializedLexical(cx, name, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3589,7 +3581,7 @@ js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandleProperty
|
||||||
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
if (!JSObject::getProperty(cx, obj, obj, name, vp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// See note in NameOperation.
|
// See note in FetchName.
|
||||||
return CheckUninitializedLexical(cx, name, vp);
|
return CheckUninitializedLexical(cx, name, vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3874,6 +3866,13 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NAME operations are the slow paths already, so unconditionally check
|
||||||
|
// for uninitialized lets.
|
||||||
|
if (pobj == scope && IsUninitializedLexicalSlot(scope, shape)) {
|
||||||
|
ReportUninitializedLexical(cx, name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool succeeded;
|
bool succeeded;
|
||||||
RootedId id(cx, NameToId(name));
|
RootedId id(cx, NameToId(name));
|
||||||
if (!JSObject::deleteGeneric(cx, scope, id, &succeeded))
|
if (!JSObject::deleteGeneric(cx, scope, id, &succeeded))
|
||||||
|
|
|
@ -4371,7 +4371,7 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
||||||
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
|
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
|
||||||
{
|
{
|
||||||
if (!gfxPrefs::LayoutPaintRectsSeparately() ||
|
if (!gfxPrefs::LayoutPaintRectsSeparately() ||
|
||||||
aClip == DrawRegionClip::CLIP_NONE) {
|
aClip == DrawRegionClip::NONE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4453,9 +4453,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
||||||
bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
|
bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
|
||||||
|
|
||||||
if (!shouldDrawRectsSeparately) {
|
if (!shouldDrawRectsSeparately) {
|
||||||
if (aClip == DrawRegionClip::DRAW_SNAPPED) {
|
if (aClip == DrawRegionClip::DRAW) {
|
||||||
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
|
|
||||||
} else if (aClip == DrawRegionClip::DRAW) {
|
|
||||||
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4486,7 +4484,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
||||||
while (const nsIntRect* iterRect = it.Next()) {
|
while (const nsIntRect* iterRect = it.Next()) {
|
||||||
gfxContextAutoSaveRestore save(aContext);
|
gfxContextAutoSaveRestore save(aContext);
|
||||||
aContext->NewPath();
|
aContext->NewPath();
|
||||||
aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED);
|
aContext->Rectangle(*iterRect);
|
||||||
aContext->Clip();
|
aContext->Clip();
|
||||||
|
|
||||||
DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
|
DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
|
||||||
|
@ -4522,9 +4520,7 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
||||||
if (presContext->GetPaintFlashing() && isActiveLayerManager) {
|
if (presContext->GetPaintFlashing() && isActiveLayerManager) {
|
||||||
gfxContextAutoSaveRestore save(aContext);
|
gfxContextAutoSaveRestore save(aContext);
|
||||||
if (shouldDrawRectsSeparately) {
|
if (shouldDrawRectsSeparately) {
|
||||||
if (aClip == DrawRegionClip::DRAW_SNAPPED) {
|
if (aClip == DrawRegionClip::DRAW) {
|
||||||
gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
|
|
||||||
} else if (aClip == DrawRegionClip::DRAW) {
|
|
||||||
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
gfxUtils::ClipToRegion(aContext, aRegionToDraw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3069,6 +3069,16 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||||
oldContext.get(), newContext.get());
|
oldContext.get(), newContext.get());
|
||||||
oldContext->SwapStyleData(newContext, equalStructs);
|
oldContext->SwapStyleData(newContext, equalStructs);
|
||||||
*aSwappedStructs |= equalStructs;
|
*aSwappedStructs |= equalStructs;
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
|
||||||
|
if (structs) {
|
||||||
|
LOG_RESTYLE_INDENT();
|
||||||
|
LOG_RESTYLE("old style context now has: %s",
|
||||||
|
oldContext->GetCachedStyleDataAsString(structs).get());
|
||||||
|
LOG_RESTYLE("new style context now has: %s",
|
||||||
|
newContext->GetCachedStyleDataAsString(structs).get());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
LOG_RESTYLE("setting new style context");
|
LOG_RESTYLE("setting new style context");
|
||||||
aSelf->SetStyleContext(newContext);
|
aSelf->SetStyleContext(newContext);
|
||||||
|
@ -3636,6 +3646,39 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
uint32_t
|
||||||
|
RestyleManager::StructsToLog()
|
||||||
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
static uint32_t structs;
|
||||||
|
if (!initialized) {
|
||||||
|
structs = 0;
|
||||||
|
const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
|
||||||
|
if (value) {
|
||||||
|
nsCString s(value);
|
||||||
|
while (!s.IsEmpty()) {
|
||||||
|
int32_t index = s.FindChar(',');
|
||||||
|
nsStyleStructID sid;
|
||||||
|
bool found;
|
||||||
|
if (index == -1) {
|
||||||
|
found = nsStyleContext::LookupStruct(s, sid);
|
||||||
|
s.Truncate();
|
||||||
|
} else {
|
||||||
|
found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
|
||||||
|
s = Substring(s, index + 1);
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
structs |= nsCachedStyleData::GetBitForSID(sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
return structs;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* static */ nsCString
|
/* static */ nsCString
|
||||||
RestyleManager::RestyleHintToString(nsRestyleHint aHint)
|
RestyleManager::RestyleHintToString(nsRestyleHint aHint)
|
||||||
|
|
|
@ -386,6 +386,13 @@ public:
|
||||||
return animations;
|
return animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
|
||||||
|
// style struct names -- such as "Font,SVGReset" -- to log the style context
|
||||||
|
// tree and those cached struct pointers before each restyle. This
|
||||||
|
// function returns a bitfield of the structs named in the
|
||||||
|
// environment variable.
|
||||||
|
static uint32_t StructsToLog();
|
||||||
|
|
||||||
static nsCString StructNamesToString(uint32_t aSIDs);
|
static nsCString StructNamesToString(uint32_t aSIDs);
|
||||||
int32_t& LoggingDepth() { return mLoggingDepth; }
|
int32_t& LoggingDepth() { return mLoggingDepth; }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -162,7 +162,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||||
RestyleManager::ChangeHintToString(aChangeHint).get());
|
RestyleManager::ChangeHintToString(aChangeHint).get());
|
||||||
|
|
||||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||||
|
|
||||||
if (aRestyleHint & ~eRestyle_LaterSiblings) {
|
if (aRestyleHint & ~eRestyle_LaterSiblings) {
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
if (ShouldLogRestyle() && primaryFrame &&
|
||||||
|
RestyleManager::StructsToLog() != 0) {
|
||||||
|
LOG_RESTYLE("style context tree before restyle:");
|
||||||
|
LOG_RESTYLE_INDENT();
|
||||||
|
primaryFrame->StyleContext()->LogStyleContextTree(
|
||||||
|
LoggingDepth(), RestyleManager::StructsToLog());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
|
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
|
||||||
*this, aRestyleHint);
|
*this, aRestyleHint);
|
||||||
} else if (aChangeHint &&
|
} else if (aChangeHint &&
|
||||||
|
|
|
@ -1224,7 +1224,8 @@ void
|
||||||
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
||||||
int32_t aNumFramesOnLine,
|
int32_t aNumFramesOnLine,
|
||||||
WritingMode aLineWM,
|
WritingMode aLineWM,
|
||||||
nscoord& aLineWidth)
|
nscoord& aLineWidth,
|
||||||
|
nscoord aStart)
|
||||||
{
|
{
|
||||||
// If this line consists of a line frame, reorder the line frame's children.
|
// If this line consists of a line frame, reorder the line frame's children.
|
||||||
if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
|
if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
|
||||||
|
@ -1237,7 +1238,7 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
||||||
}
|
}
|
||||||
|
|
||||||
BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
|
BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
|
||||||
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth);
|
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
|
@ -1279,6 +1280,7 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame)
|
||||||
void
|
void
|
||||||
nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
||||||
nsContinuationStates* aContinuationStates,
|
nsContinuationStates* aContinuationStates,
|
||||||
|
bool aSpanDirMatchesLineDir,
|
||||||
bool& aIsFirst /* out */,
|
bool& aIsFirst /* out */,
|
||||||
bool& aIsLast /* out */)
|
bool& aIsLast /* out */)
|
||||||
{
|
{
|
||||||
|
@ -1293,6 +1295,7 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
||||||
* chain on this line.
|
* chain on this line.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool firstInLineOrder, lastInLineOrder;
|
||||||
nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
|
nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
|
||||||
nsFrameContinuationState* firstFrameState;
|
nsFrameContinuationState* firstFrameState;
|
||||||
|
|
||||||
|
@ -1327,16 +1330,30 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
||||||
}
|
}
|
||||||
frameState->mHasContOnNextLines = (frame != nullptr);
|
frameState->mHasContOnNextLines = (frame != nullptr);
|
||||||
|
|
||||||
aIsFirst = !frameState->mHasContOnPrevLines;
|
firstInLineOrder = true;
|
||||||
firstFrameState = frameState;
|
firstFrameState = frameState;
|
||||||
} else {
|
} else {
|
||||||
// aFrame is not the first visual frame of its continuation chain
|
// aFrame is not the first visual frame of its continuation chain
|
||||||
aIsFirst = false;
|
firstInLineOrder = false;
|
||||||
firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
|
firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
aIsLast = (firstFrameState->mFrameCount == 1 &&
|
lastInLineOrder = (firstFrameState->mFrameCount == 1);
|
||||||
!firstFrameState->mHasContOnNextLines);
|
|
||||||
|
if (aSpanDirMatchesLineDir) {
|
||||||
|
aIsFirst = firstInLineOrder;
|
||||||
|
aIsLast = lastInLineOrder;
|
||||||
|
} else {
|
||||||
|
aIsFirst = lastInLineOrder;
|
||||||
|
aIsLast = firstInLineOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameState->mHasContOnPrevLines) {
|
||||||
|
aIsFirst = false;
|
||||||
|
}
|
||||||
|
if (firstFrameState->mHasContOnNextLines) {
|
||||||
|
aIsLast = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((aIsFirst || aIsLast) &&
|
if ((aIsFirst || aIsLast) &&
|
||||||
(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
|
(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
|
||||||
|
@ -1356,6 +1373,24 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame* aFrame,
|
||||||
|
|
||||||
// Reduce number of remaining frames of the continuation chain on the line.
|
// Reduce number of remaining frames of the continuation chain on the line.
|
||||||
firstFrameState->mFrameCount--;
|
firstFrameState->mFrameCount--;
|
||||||
|
|
||||||
|
nsInlineFrame* testFrame = do_QueryFrame(aFrame);
|
||||||
|
|
||||||
|
if (testFrame) {
|
||||||
|
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
|
||||||
|
|
||||||
|
if (aIsFirst) {
|
||||||
|
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
|
||||||
|
} else {
|
||||||
|
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aIsLast) {
|
||||||
|
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
|
||||||
|
} else {
|
||||||
|
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1363,55 +1398,46 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
|
||||||
bool aIsEvenLevel,
|
bool aIsEvenLevel,
|
||||||
nscoord& aStart,
|
nscoord& aStart,
|
||||||
nsContinuationStates* aContinuationStates,
|
nsContinuationStates* aContinuationStates,
|
||||||
WritingMode aLineWM,
|
WritingMode aContainerWM,
|
||||||
nscoord& aLineWidth)
|
nscoord& aContainerWidth)
|
||||||
{
|
{
|
||||||
if (!aFrame)
|
if (!aFrame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isFirst, isLast;
|
bool isFirst, isLast;
|
||||||
|
WritingMode frameWM = aFrame->GetWritingMode();
|
||||||
IsFirstOrLast(aFrame,
|
IsFirstOrLast(aFrame,
|
||||||
aContinuationStates,
|
aContinuationStates,
|
||||||
|
aContainerWM.IsBidiLTR() == frameWM.IsBidiLTR(),
|
||||||
isFirst /* out */,
|
isFirst /* out */,
|
||||||
isLast /* out */);
|
isLast /* out */);
|
||||||
|
|
||||||
WritingMode frameWM = aFrame->GetWritingMode();
|
// We only need the margin if the frame is first or last in its own
|
||||||
nsInlineFrame* testFrame = do_QueryFrame(aFrame);
|
// writing mode, but we're traversing the frames in the order of the
|
||||||
|
// container's writing mode. To get the right values, we set start and
|
||||||
|
// end margins on a logical margin in the frame's writing mode, and
|
||||||
|
// then convert the margin to the container's writing mode to set the
|
||||||
|
// coordinates.
|
||||||
|
|
||||||
if (testFrame) {
|
|
||||||
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
|
|
||||||
|
|
||||||
if (isFirst) {
|
|
||||||
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
|
|
||||||
} else {
|
|
||||||
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLast) {
|
|
||||||
aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
|
|
||||||
} else {
|
|
||||||
aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This method is called from nsBlockFrame::PlaceLine via the call to
|
// This method is called from nsBlockFrame::PlaceLine via the call to
|
||||||
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
|
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
|
||||||
// have been reflowed, which is required for GetUsedMargin/Border/Padding
|
// have been reflowed, which is required for GetUsedMargin/Border/Padding
|
||||||
LogicalMargin margin(aLineWM, aFrame->GetUsedMargin());
|
LogicalMargin frameMargin = aFrame->GetLogicalUsedMargin(frameWM);
|
||||||
if (isFirst) {
|
LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(frameWM);
|
||||||
aStart += margin.IStart(aLineWM);
|
if (!isFirst) {
|
||||||
|
frameMargin.IStart(frameWM) = 0;
|
||||||
|
borderPadding.IStart(frameWM) = 0;
|
||||||
}
|
}
|
||||||
|
if (!isLast) {
|
||||||
|
frameMargin.IEnd(frameWM) = 0;
|
||||||
|
borderPadding.IEnd(frameWM) = 0;
|
||||||
|
}
|
||||||
|
LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM);
|
||||||
|
aStart += margin.IStart(aContainerWM);
|
||||||
|
|
||||||
nscoord start = aStart;
|
nscoord start = aStart;
|
||||||
nscoord frameISize = aFrame->ISize(aLineWM);
|
|
||||||
|
|
||||||
if (!IsBidiLeaf(aFrame))
|
|
||||||
{
|
|
||||||
nscoord iCoord = 0;
|
|
||||||
LogicalMargin borderPadding(frameWM, aFrame->GetUsedBorderAndPadding());
|
|
||||||
if (isFirst) {
|
|
||||||
iCoord += borderPadding.IStart(frameWM);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!IsBidiLeaf(aFrame)) {
|
||||||
// If the resolved direction of the container is different from the
|
// If the resolved direction of the container is different from the
|
||||||
// direction of the frame, we need to traverse the child list in reverse
|
// direction of the frame, we need to traverse the child list in reverse
|
||||||
// order, to make it O(n) we store the list locally and iterate the list
|
// order, to make it O(n) we store the list locally and iterate the list
|
||||||
|
@ -1430,35 +1456,33 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
|
||||||
|
|
||||||
// Reposition the child frames
|
// Reposition the child frames
|
||||||
int32_t index = 0;
|
int32_t index = 0;
|
||||||
|
nscoord iCoord = borderPadding.IStart(frameWM);
|
||||||
|
|
||||||
while (frame) {
|
while (frame) {
|
||||||
RepositionFrame(frame,
|
RepositionFrame(frame,
|
||||||
aIsEvenLevel,
|
aIsEvenLevel,
|
||||||
iCoord,
|
iCoord,
|
||||||
aContinuationStates,
|
aContinuationStates,
|
||||||
frameWM,
|
frameWM,
|
||||||
frameISize);
|
aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
|
||||||
index++;
|
index++;
|
||||||
frame = reverseOrder ?
|
frame = reverseOrder ?
|
||||||
childList[childList.Length() - index - 1] :
|
childList[childList.Length() - index - 1] :
|
||||||
frame->GetNextSibling();
|
frame->GetNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLast) {
|
aStart += iCoord + borderPadding.IEnd(frameWM);
|
||||||
iCoord += borderPadding.IEnd(frameWM);
|
|
||||||
}
|
|
||||||
aStart += iCoord;
|
|
||||||
} else {
|
} else {
|
||||||
aStart += frameISize;
|
aStart += aFrame->ISize(aContainerWM);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth);
|
LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
|
||||||
logicalRect.IStart(aLineWM) = start;
|
aContainerWidth);
|
||||||
logicalRect.ISize(aLineWM) = aStart - start;
|
logicalRect.IStart(aContainerWM) = start;
|
||||||
aFrame->SetRect(aLineWM, logicalRect, aLineWidth);
|
logicalRect.ISize(aContainerWM) = aStart - start;
|
||||||
|
aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
|
||||||
|
|
||||||
if (isLast) {
|
aStart += margin.IEnd(aContainerWM);
|
||||||
aStart += margin.IEnd(aLineWM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1485,20 +1509,10 @@ void
|
||||||
nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
|
nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
|
||||||
nsIFrame* aFirstChild,
|
nsIFrame* aFirstChild,
|
||||||
WritingMode aLineWM,
|
WritingMode aLineWM,
|
||||||
nscoord& aLineWidth)
|
nscoord& aLineWidth,
|
||||||
|
nscoord& aStart)
|
||||||
{
|
{
|
||||||
nscoord startSpace = 0;
|
nscoord start = aStart;
|
||||||
|
|
||||||
// This method is called from nsBlockFrame::PlaceLine via the call to
|
|
||||||
// bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
|
|
||||||
// have been reflowed, which is required for GetUsedMargin/Border/Padding
|
|
||||||
LogicalMargin margin(aLineWM, aFirstChild->GetUsedMargin());
|
|
||||||
if (!aFirstChild->GetPrevContinuation() &&
|
|
||||||
!aFirstChild->FrameIsNonFirstInIBSplit())
|
|
||||||
startSpace = margin.IStart(aLineWM);
|
|
||||||
|
|
||||||
nscoord start = LogicalRect(aLineWM, aFirstChild->GetRect(),
|
|
||||||
aLineWidth).IStart(aLineWM) - startSpace;
|
|
||||||
nsIFrame* frame;
|
nsIFrame* frame;
|
||||||
int32_t count = aBld->mVisualFrames.Length();
|
int32_t count = aBld->mVisualFrames.Length();
|
||||||
int32_t index;
|
int32_t index;
|
||||||
|
|
|
@ -160,7 +160,8 @@ public:
|
||||||
static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
||||||
int32_t aNumFramesOnLine,
|
int32_t aNumFramesOnLine,
|
||||||
mozilla::WritingMode aLineWM,
|
mozilla::WritingMode aLineWM,
|
||||||
nscoord& aLineWidth);
|
nscoord& aLineWidth,
|
||||||
|
nscoord aStart);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format Unicode text, taking into account bidi capabilities
|
* Format Unicode text, taking into account bidi capabilities
|
||||||
|
@ -397,8 +398,8 @@ private:
|
||||||
bool aIsEvenLevel,
|
bool aIsEvenLevel,
|
||||||
nscoord& aStart,
|
nscoord& aStart,
|
||||||
nsContinuationStates* aContinuationStates,
|
nsContinuationStates* aContinuationStates,
|
||||||
mozilla::WritingMode aLineWM,
|
mozilla::WritingMode aContainerWM,
|
||||||
nscoord& aLineWidth);
|
nscoord& aContainerWidth);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the continuation state(nsFrameContinuationState) to
|
* Initialize the continuation state(nsFrameContinuationState) to
|
||||||
|
@ -412,22 +413,32 @@ private:
|
||||||
nsContinuationStates* aContinuationStates);
|
nsContinuationStates* aContinuationStates);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
|
* Determine if aFrame is first or last, and set aIsFirst and
|
||||||
* aIsRightMost values. Also set continuation states of aContinuationStates.
|
* aIsLast values. Also set continuation states of
|
||||||
|
* aContinuationStates.
|
||||||
*
|
*
|
||||||
* A frame is leftmost if it's the first appearance of its continuation chain
|
* A frame is first if it's the first appearance of its continuation
|
||||||
* on the line and the chain is on its first line if it's LTR or the chain is
|
* chain on the line and the chain is on its first line.
|
||||||
* on its last line if it's RTL.
|
* A frame is last if it's the last appearance of its continuation
|
||||||
* A frame is rightmost if it's the last appearance of its continuation chain
|
* chain on the line and the chain is on its last line.
|
||||||
* on the line and the chain is on its first line if it's RTL or the chain is
|
|
||||||
* on its last line if it's LTR.
|
|
||||||
*
|
*
|
||||||
* @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
|
* N.B: "First appearance" and "Last appearance" in the previous
|
||||||
* @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation
|
* paragraph refer to the frame's inline direction, not necessarily
|
||||||
* @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation
|
* the line's.
|
||||||
|
*
|
||||||
|
* @param aContinuationStates A map from nsIFrame* to
|
||||||
|
* nsFrameContinuationState
|
||||||
|
* @param[in] aSpanDirMatchesLineDir TRUE means that the inline
|
||||||
|
* direction of aFrame is the same
|
||||||
|
* as its container
|
||||||
|
* @param[out] aIsFirst TRUE means aFrame is first frame
|
||||||
|
* or continuation
|
||||||
|
* @param[out] aIsLast TRUE means aFrame is last frame
|
||||||
|
* or continuation
|
||||||
*/
|
*/
|
||||||
static void IsFirstOrLast(nsIFrame* aFrame,
|
static void IsFirstOrLast(nsIFrame* aFrame,
|
||||||
nsContinuationStates* aContinuationStates,
|
nsContinuationStates* aContinuationStates,
|
||||||
|
bool aSpanInLineOrder /* in */,
|
||||||
bool& aIsFirst /* out */,
|
bool& aIsFirst /* out */,
|
||||||
bool& aIsLast /* out */);
|
bool& aIsLast /* out */);
|
||||||
|
|
||||||
|
@ -441,7 +452,8 @@ private:
|
||||||
static void RepositionInlineFrames(BidiLineData* aBld,
|
static void RepositionInlineFrames(BidiLineData* aBld,
|
||||||
nsIFrame* aFirstChild,
|
nsIFrame* aFirstChild,
|
||||||
mozilla::WritingMode aLineWM,
|
mozilla::WritingMode aLineWM,
|
||||||
nscoord& aLineWidth);
|
nscoord& aLineWidth,
|
||||||
|
nscoord& aStart);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for Resolve()
|
* Helper method for Resolve()
|
||||||
|
|
|
@ -2598,20 +2598,22 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dx) {
|
if (mPresContext->BidiEnabled() &&
|
||||||
|
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
|
||||||
|
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
|
||||||
|
aLine->GetChildCount(),
|
||||||
|
lineWM, mContainerWidth,
|
||||||
|
psd->mIStart + mTextIndent + dx);
|
||||||
|
if (dx) {
|
||||||
|
aLine->IndentBy(dx, mContainerWidth);
|
||||||
|
}
|
||||||
|
} else if (dx) {
|
||||||
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
||||||
pfd->mBounds.IStart(lineWM) += dx;
|
pfd->mBounds.IStart(lineWM) += dx;
|
||||||
pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
|
pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
|
||||||
}
|
}
|
||||||
aLine->IndentBy(dx, mContainerWidth);
|
aLine->IndentBy(dx, mContainerWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPresContext->BidiEnabled() &&
|
|
||||||
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
|
|
||||||
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
|
|
||||||
aLine->GetChildCount(),
|
|
||||||
lineWM, mContainerWidth);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for bug 1069941 -- borders</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div dir="ltr">
|
||||||
|
<span dir="ltr" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
|
||||||
|
</div>
|
||||||
|
<div dir="ltr">
|
||||||
|
<span dir="ltr" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for bug 1069941 -- borders</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div dir="ltr">
|
||||||
|
<span dir="rtl" style="color:transparent;background:gray;border-left:10px solid teal;">+٥</span>
|
||||||
|
</div>
|
||||||
|
<div dir="ltr">
|
||||||
|
<span dir="rtl" style="color:transparent;background:gray;border-right:10px solid teal;">+٥</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for bug 1069941 -- margins</title>
|
||||||
|
<style type="text/css">
|
||||||
|
.outer {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid lime;
|
||||||
|
}
|
||||||
|
.inner {
|
||||||
|
color:transparent;
|
||||||
|
margin-left: 50px;
|
||||||
|
border: 2px solid teal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<span class="outer"><span class="inner">(12]</span></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for bug 1069941 -- margins</title>
|
||||||
|
<style type="text/css">
|
||||||
|
.outer {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid lime;
|
||||||
|
}
|
||||||
|
.inner {
|
||||||
|
color:transparent;
|
||||||
|
margin-left: 50px;
|
||||||
|
border: 2px solid teal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<span class="outer"><span class="inner" dir="rtl">[12)</span></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -142,3 +142,6 @@ skip-if(B2G) == 726420-1.html 726420-1-ref.html
|
||||||
skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul
|
skip-if(B2G&&browserIsRemote) == 869833-1.xul 869833-1-ref.xul
|
||||||
== 922530-1.html 922530-1-ref.html
|
== 922530-1.html 922530-1-ref.html
|
||||||
== 922550-1.html 922550-1-ref.html
|
== 922550-1.html 922550-1-ref.html
|
||||||
|
== 1069941-inline-bidi-border-1.html 1069941-inline-bidi-border-1-ref.html
|
||||||
|
== 1069941-inline-bidi-margin-1.html 1069941-inline-bidi-margin-1-ref.html
|
||||||
|
|
||||||
|
|
|
@ -1048,6 +1048,21 @@ nsStyleContext::StructName(nsStyleStructID aSID)
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
|
||||||
|
{
|
||||||
|
if (false)
|
||||||
|
;
|
||||||
|
#define STYLE_STRUCT(name_, checkdata_cb_) \
|
||||||
|
else if (aName.EqualsLiteral(#name_)) \
|
||||||
|
aResult = eStyleStruct_##name_;
|
||||||
|
#include "nsStyleStructList.h"
|
||||||
|
#undef STYLE_STRUCT
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1162,3 +1177,96 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
|
||||||
|
|
||||||
ClearCachedInheritedStyleDataOnDescendants(aStructs);
|
ClearCachedInheritedStyleDataOnDescendants(aStructs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
nsCString
|
||||||
|
nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
|
||||||
|
{
|
||||||
|
nsCString structs;
|
||||||
|
for (nsStyleStructID i = nsStyleStructID(0);
|
||||||
|
i < nsStyleStructID_Length;
|
||||||
|
i = nsStyleStructID(i + 1)) {
|
||||||
|
if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
|
||||||
|
const void* data = GetCachedStyleData(i);
|
||||||
|
if (!structs.IsEmpty()) {
|
||||||
|
structs.Append(' ');
|
||||||
|
}
|
||||||
|
structs.AppendPrintf("%s=%p", StructName(i), data);
|
||||||
|
if (HasCachedInheritedStyleData(i)) {
|
||||||
|
structs.AppendLiteral("(dependent)");
|
||||||
|
} else {
|
||||||
|
structs.AppendLiteral("(owned)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return structs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t&
|
||||||
|
nsStyleContext::LoggingDepth()
|
||||||
|
{
|
||||||
|
static int32_t depth = 0;
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
|
||||||
|
{
|
||||||
|
LoggingDepth() = aLoggingDepth;
|
||||||
|
LogStyleContextTree(true, aStructs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
|
||||||
|
{
|
||||||
|
nsCString structs = GetCachedStyleDataAsString(aStructs);
|
||||||
|
if (!structs.IsEmpty()) {
|
||||||
|
structs.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString pseudo;
|
||||||
|
if (mPseudoTag) {
|
||||||
|
nsAutoString pseudoTag;
|
||||||
|
mPseudoTag->ToString(pseudoTag);
|
||||||
|
AppendUTF16toUTF8(pseudoTag, pseudo);
|
||||||
|
pseudo.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString flags;
|
||||||
|
if (IsStyleIfVisited()) {
|
||||||
|
flags.AppendLiteral("IS_STYLE_IF_VISITED ");
|
||||||
|
}
|
||||||
|
if (UsesGrandancestorStyle()) {
|
||||||
|
flags.AppendLiteral("USES_GRANDANCESTOR_STYLE ");
|
||||||
|
}
|
||||||
|
if (IsShared()) {
|
||||||
|
flags.AppendLiteral("IS_SHARED ");
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString parent;
|
||||||
|
if (aFirst) {
|
||||||
|
parent.AppendPrintf("parent=%p ", mParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_RESTYLE("%p(%d) %s%s%s%s",
|
||||||
|
this, mRefCnt,
|
||||||
|
structs.get(), pseudo.get(), flags.get(), parent.get());
|
||||||
|
|
||||||
|
LOG_RESTYLE_INDENT();
|
||||||
|
|
||||||
|
if (nullptr != mChild) {
|
||||||
|
nsStyleContext* child = mChild;
|
||||||
|
do {
|
||||||
|
child->LogStyleContextTree(false, aStructs);
|
||||||
|
child = child->mNextSibling;
|
||||||
|
} while (mChild != child);
|
||||||
|
}
|
||||||
|
if (nullptr != mEmptyChild) {
|
||||||
|
nsStyleContext* child = mEmptyChild;
|
||||||
|
do {
|
||||||
|
child->LogStyleContextTree(false, aStructs);
|
||||||
|
child = child->mNextSibling;
|
||||||
|
} while (mEmptyChild != child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#ifndef _nsStyleContext_h_
|
#ifndef _nsStyleContext_h_
|
||||||
#define _nsStyleContext_h_
|
#define _nsStyleContext_h_
|
||||||
|
|
||||||
|
#include "mozilla/RestyleLogging.h"
|
||||||
#include "nsRuleNode.h"
|
#include "nsRuleNode.h"
|
||||||
#include "nsCSSPseudoElements.h"
|
#include "nsCSSPseudoElements.h"
|
||||||
|
|
||||||
|
@ -397,6 +398,13 @@ public:
|
||||||
void List(FILE* out, int32_t aIndent);
|
void List(FILE* out, int32_t aIndent);
|
||||||
static void AssertStyleStructMaxDifferenceValid();
|
static void AssertStyleStructMaxDifferenceValid();
|
||||||
static const char* StructName(nsStyleStructID aSID);
|
static const char* StructName(nsStyleStructID aSID);
|
||||||
|
static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
nsCString GetCachedStyleDataAsString(uint32_t aStructs);
|
||||||
|
void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
|
||||||
|
int32_t& LoggingDepth();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -450,6 +458,15 @@ private:
|
||||||
int32_t aLevels) const;
|
int32_t aLevels) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef RESTYLE_LOGGING
|
||||||
|
void LogStyleContextTree(bool aFirst, uint32_t aStructs);
|
||||||
|
|
||||||
|
// This only gets called under call trees where we've already checked
|
||||||
|
// that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
|
||||||
|
// It exists here just to satisfy LOG_RESTYLE's expectations.
|
||||||
|
bool ShouldLogRestyle() { return true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
nsStyleContext* mParent; // STRONG
|
nsStyleContext* mParent; // STRONG
|
||||||
|
|
||||||
// Children are kept in two circularly-linked lists. The list anchor
|
// Children are kept in two circularly-linked lists. The list anchor
|
||||||
|
|
|
@ -164,6 +164,7 @@ class RemoteOptions(ReftestOptions):
|
||||||
|
|
||||||
# Android does not run leak tests, but set some reasonable defaults to avoid errors.
|
# Android does not run leak tests, but set some reasonable defaults to avoid errors.
|
||||||
options.leakThresholds = {}
|
options.leakThresholds = {}
|
||||||
|
options.ignoreMissingLeaks = []
|
||||||
|
|
||||||
# TODO: Copied from main, but I think these are no longer used in a post xulrunner world
|
# TODO: Copied from main, but I think these are no longer used in a post xulrunner world
|
||||||
#options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
|
#options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
|
||||||
|
|
|
@ -344,7 +344,7 @@ class RefTest(object):
|
||||||
# give the JS harness 30 seconds to deal
|
# give the JS harness 30 seconds to deal
|
||||||
# with its own timeouts
|
# with its own timeouts
|
||||||
timeout=options.timeout + 30.0)
|
timeout=options.timeout + 30.0)
|
||||||
processLeakLog(self.leakLogFile, options.leakThresholds)
|
processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks)
|
||||||
self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
|
self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
|
||||||
finally:
|
finally:
|
||||||
self.cleanup(profileDir)
|
self.cleanup(profileDir)
|
||||||
|
@ -513,6 +513,8 @@ class ReftestOptions(OptionParser):
|
||||||
|
|
||||||
options.leakThresholds = {"default": options.defaultLeakThreshold}
|
options.leakThresholds = {"default": options.defaultLeakThreshold}
|
||||||
|
|
||||||
|
options.ignoreMissingLeaks = []
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
[![Build Status](https://travis-ci.org/kinetiknz/nestegg.svg?branch=master)](https://travis-ci.org/kinetiknz/nestegg)
|
||||||
|
|
||||||
See INSTALL for build instructions.
|
See INSTALL for build instructions.
|
||||||
|
|
||||||
Licensed under an ISC-style license. See LICENSE for details.
|
Licensed under an ISC-style license. See LICENSE for details.
|
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
||||||
|
|
||||||
The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
|
The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
|
||||||
|
|
||||||
The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284.
|
The git commit ID used was 59220ae3e801cbad0f8160129c4df315469af671.
|
||||||
|
|
|
@ -381,8 +381,11 @@ int nestegg_sniff(unsigned char const * buffer, size_t length);
|
||||||
* Set the underlying allocation function for library allocations.
|
* Set the underlying allocation function for library allocations.
|
||||||
*
|
*
|
||||||
* @param realloc_func The desired function.
|
* @param realloc_func The desired function.
|
||||||
|
* @retval 0 realloc_func(p, 0) does not act as free()
|
||||||
|
* @retval 1 realloc_func(p, 0) acts as free()
|
||||||
|
* @retval -1 malloc failed during realloc_func test
|
||||||
*/
|
*/
|
||||||
void nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
|
int nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ realloc_t halloc_allocator = NULL;
|
||||||
/*
|
/*
|
||||||
* static methods
|
* static methods
|
||||||
*/
|
*/
|
||||||
static void _set_allocator(void);
|
int halloc_set_allocator(realloc_t realloc_func);
|
||||||
static void * _realloc(void * ptr, size_t n);
|
static void * _realloc(void * ptr, size_t n);
|
||||||
|
|
||||||
static int _relate(hblock_t * b, hblock_t * p);
|
static int _relate(hblock_t * b, hblock_t * p);
|
||||||
|
@ -62,7 +62,10 @@ void * halloc(void * ptr, size_t len)
|
||||||
/* set up default allocator */
|
/* set up default allocator */
|
||||||
if (! allocator)
|
if (! allocator)
|
||||||
{
|
{
|
||||||
_set_allocator();
|
if (halloc_set_allocator(realloc) == 0)
|
||||||
|
{
|
||||||
|
halloc_set_allocator(_realloc);
|
||||||
|
}
|
||||||
assert(allocator);
|
assert(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +175,7 @@ char * h_strdup(const char * str)
|
||||||
/*
|
/*
|
||||||
* static stuff
|
* static stuff
|
||||||
*/
|
*/
|
||||||
static void _set_allocator(void)
|
int halloc_set_allocator(realloc_t realloc_func)
|
||||||
{
|
{
|
||||||
void * p;
|
void * p;
|
||||||
assert(! allocator);
|
assert(! allocator);
|
||||||
|
@ -187,17 +190,17 @@ static void _set_allocator(void)
|
||||||
*
|
*
|
||||||
* Thanks to Stan Tobias for pointing this tricky part out.
|
* Thanks to Stan Tobias for pointing this tricky part out.
|
||||||
*/
|
*/
|
||||||
allocator = realloc;
|
if (! (p = realloc_func(NULL, 1)))
|
||||||
if (! (p = malloc(1)))
|
|
||||||
/* hmm */
|
/* hmm */
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
if ((p = realloc(p, 0)))
|
if ((p = realloc_func(p, 0)))
|
||||||
{
|
{
|
||||||
/* realloc cannot be used as free() */
|
/* realloc_func cannot be used as free() */
|
||||||
allocator = _realloc;
|
return 0;
|
||||||
free(p);
|
|
||||||
}
|
}
|
||||||
|
allocator = realloc_func;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void * _realloc(void * ptr, size_t n)
|
static void * _realloc(void * ptr, size_t n)
|
||||||
|
|
|
@ -321,9 +321,18 @@ struct block_additional {
|
||||||
struct block_additional * next;
|
struct block_additional * next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NE_IO_BUFSZ 16384
|
||||||
|
|
||||||
|
struct nestegg_io_buf {
|
||||||
|
nestegg_io io;
|
||||||
|
unsigned char buffer[NE_IO_BUFSZ];
|
||||||
|
size_t bufsz;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
/* Public (opaque) Structures */
|
/* Public (opaque) Structures */
|
||||||
struct nestegg {
|
struct nestegg {
|
||||||
nestegg_io * io;
|
struct nestegg_io_buf * io;
|
||||||
nestegg_log log;
|
nestegg_log log;
|
||||||
struct pool_ctx * alloc_pool;
|
struct pool_ctx * alloc_pool;
|
||||||
uint64_t last_id;
|
uint64_t last_id;
|
||||||
|
@ -546,19 +555,99 @@ ne_alloc(size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_io_read(nestegg_io * io, void * buffer, size_t length)
|
ne_io_read(struct nestegg_io_buf * io, void * buffer, size_t length)
|
||||||
{
|
{
|
||||||
return io->read(buffer, length, io->userdata);
|
int64_t off;
|
||||||
|
int r;
|
||||||
|
size_t avail;
|
||||||
|
|
||||||
|
assert(io->offset == -1 || (io->offset >= 0 && (unsigned int) io->offset < io->bufsz));
|
||||||
|
|
||||||
|
/* Too big to buffer, invalidate buffer and read through */
|
||||||
|
if (length > io->bufsz) {
|
||||||
|
if (io->offset != -1) {
|
||||||
|
r = io->io.seek(-(io->bufsz - io->offset), NESTEGG_SEEK_CUR, io->io.userdata);
|
||||||
|
if (r != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io->offset = -1;
|
||||||
|
return io->io.read(buffer, length, io->io.userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer invalid */
|
||||||
|
if (io->offset == -1) {
|
||||||
|
off = io->io.tell(io->io.userdata);
|
||||||
|
if (off == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Refill buffer */
|
||||||
|
r = io->io.read(io->buffer, io->bufsz, io->io.userdata);
|
||||||
|
if (r != 1) {
|
||||||
|
/* Read truncated due to being within io->bufsz of EOS, reset read
|
||||||
|
position and switch to read through mode */
|
||||||
|
io->offset = -1;
|
||||||
|
io->bufsz = 0;
|
||||||
|
if (r == 0) {
|
||||||
|
r = io->io.seek(off, NESTEGG_SEEK_SET, io->io.userdata);
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
return io->io.read(buffer, length, io->io.userdata);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (r == 1) {
|
||||||
|
io->offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service request with what we have */
|
||||||
|
avail = length;
|
||||||
|
if (io->bufsz - io->offset < length) {
|
||||||
|
avail = io->bufsz - io->offset;
|
||||||
|
}
|
||||||
|
memcpy(buffer, io->buffer + io->offset, avail);
|
||||||
|
io->offset += avail;
|
||||||
|
|
||||||
|
if ((unsigned int) io->offset == io->bufsz) {
|
||||||
|
io->offset = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Still more to read, invalidate buffer and read more */
|
||||||
|
if (length - avail > 0) {
|
||||||
|
return ne_io_read(io, (char *) buffer + avail, length - avail);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_io_seek(nestegg_io * io, int64_t offset, int whence)
|
ne_io_seek(struct nestegg_io_buf * io, int64_t offset, int whence)
|
||||||
{
|
{
|
||||||
return io->seek(offset, whence, io->userdata);
|
/* Invalidate buffer */
|
||||||
|
io->offset = -1;
|
||||||
|
|
||||||
|
return io->io.seek(offset, whence, io->io.userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
ne_io_tell(struct nestegg_io_buf * io)
|
||||||
|
{
|
||||||
|
int64_t off;
|
||||||
|
|
||||||
|
off = io->io.tell(io->io.userdata);
|
||||||
|
if (off == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (io->offset == -1) {
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
assert(off >= (int64_t) io->bufsz - io->offset);
|
||||||
|
return off - io->bufsz + (unsigned int) io->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_io_read_skip(nestegg_io * io, size_t length)
|
ne_io_read_skip(struct nestegg_io_buf * io, size_t length)
|
||||||
{
|
{
|
||||||
size_t get;
|
size_t get;
|
||||||
unsigned char buf[8192];
|
unsigned char buf[8192];
|
||||||
|
@ -575,14 +664,8 @@ ne_io_read_skip(nestegg_io * io, size_t length)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
|
||||||
ne_io_tell(nestegg_io * io)
|
|
||||||
{
|
|
||||||
return io->tell(io->userdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag)
|
ne_bare_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
|
@ -619,19 +702,19 @@ ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vin
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length)
|
ne_read_id(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
|
||||||
{
|
{
|
||||||
return ne_bare_read_vint(io, value, length, MASK_NONE);
|
return ne_bare_read_vint(io, value, length, MASK_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length)
|
ne_read_vint(struct nestegg_io_buf * io, uint64_t * value, uint64_t * length)
|
||||||
{
|
{
|
||||||
return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
|
return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
|
ne_read_svint(struct nestegg_io_buf * io, int64_t * value, uint64_t * length)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint64_t uvalue;
|
uint64_t uvalue;
|
||||||
|
@ -653,7 +736,7 @@ ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
|
ne_read_uint(struct nestegg_io_buf * io, uint64_t * val, uint64_t length)
|
||||||
{
|
{
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
int r;
|
int r;
|
||||||
|
@ -675,7 +758,7 @@ ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
|
ne_read_int(struct nestegg_io_buf * io, int64_t * val, uint64_t length)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint64_t uval, base;
|
uint64_t uval, base;
|
||||||
|
@ -688,8 +771,8 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
|
||||||
base = 1;
|
base = 1;
|
||||||
base <<= length * 8 - 1;
|
base <<= length * 8 - 1;
|
||||||
if (uval >= base) {
|
if (uval >= base) {
|
||||||
base = 1;
|
base = 1;
|
||||||
base <<= length * 8;
|
base <<= length * 8;
|
||||||
} else {
|
} else {
|
||||||
base = 0;
|
base = 0;
|
||||||
}
|
}
|
||||||
|
@ -702,7 +785,7 @@ ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_float(nestegg_io * io, double * val, uint64_t length)
|
ne_read_float(struct nestegg_io_buf * io, double * val, uint64_t length)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
|
@ -736,9 +819,9 @@ ne_read_string(nestegg * ctx, char ** val, uint64_t length)
|
||||||
if (!str)
|
if (!str)
|
||||||
return -1;
|
return -1;
|
||||||
if (length) {
|
if (length) {
|
||||||
r = ne_io_read(ctx->io, (unsigned char *) str, length);
|
r = ne_io_read(ctx->io, (unsigned char *) str, length);
|
||||||
if (r != 1)
|
if (r != 1)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
str[length] = '\0';
|
str[length] = '\0';
|
||||||
*val = str;
|
*val = str;
|
||||||
|
@ -1018,8 +1101,9 @@ ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
|
||||||
break;
|
break;
|
||||||
case TYPE_MASTER:
|
case TYPE_MASTER:
|
||||||
case TYPE_UNKNOWN:
|
case TYPE_UNKNOWN:
|
||||||
assert(0);
|
default:
|
||||||
r = 0;
|
r = 0;
|
||||||
|
assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1136,7 +1220,7 @@ ne_xiph_lace_value(unsigned char ** np)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
|
ne_read_xiph_lace_value(struct nestegg_io_buf * io, uint64_t * value, size_t * consumed)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint64_t lace;
|
uint64_t lace;
|
||||||
|
@ -1159,7 +1243,7 @@ ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
|
ne_read_xiph_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -1182,7 +1266,7 @@ ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
|
ne_read_ebml_lacing(struct nestegg_io_buf * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint64_t lace, sum, length;
|
uint64_t lace, sum, length;
|
||||||
|
@ -1792,9 +1876,9 @@ struct sniff_buffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_buffer_read(void * buffer, size_t length, void * user_data)
|
ne_buffer_read(void * buffer, size_t length, void * userdata)
|
||||||
{
|
{
|
||||||
struct sniff_buffer * sb = user_data;
|
struct sniff_buffer * sb = userdata;
|
||||||
|
|
||||||
int rv = 1;
|
int rv = 1;
|
||||||
size_t available = sb->length - sb->offset;
|
size_t available = sb->length - sb->offset;
|
||||||
|
@ -1809,21 +1893,21 @@ ne_buffer_read(void * buffer, size_t length, void * user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ne_buffer_seek(int64_t offset, int whence, void * user_data)
|
ne_buffer_seek(int64_t offset, int whence, void * userdata)
|
||||||
{
|
{
|
||||||
struct sniff_buffer * sb = user_data;
|
struct sniff_buffer * sb = userdata;
|
||||||
int64_t o = sb->offset;
|
int64_t o = sb->offset;
|
||||||
|
|
||||||
switch(whence) {
|
switch(whence) {
|
||||||
case NESTEGG_SEEK_SET:
|
case NESTEGG_SEEK_SET:
|
||||||
o = offset;
|
o = offset;
|
||||||
break;
|
break;
|
||||||
case NESTEGG_SEEK_CUR:
|
case NESTEGG_SEEK_CUR:
|
||||||
o += offset;
|
o += offset;
|
||||||
break;
|
break;
|
||||||
case NESTEGG_SEEK_END:
|
case NESTEGG_SEEK_END:
|
||||||
o = sb->length + offset;
|
o = sb->length + offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o < 0 || o > (int64_t) sb->length)
|
if (o < 0 || o > (int64_t) sb->length)
|
||||||
|
@ -1834,9 +1918,9 @@ ne_buffer_seek(int64_t offset, int whence, void * user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
ne_buffer_tell(void * user_data)
|
ne_buffer_tell(void * userdata)
|
||||||
{
|
{
|
||||||
struct sniff_buffer * sb = user_data;
|
struct sniff_buffer * sb = userdata;
|
||||||
return sb->offset;
|
return sb->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1860,7 +1944,9 @@ ne_match_webm(nestegg_io io, int64_t max_offset)
|
||||||
nestegg_destroy(ctx);
|
nestegg_destroy(ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*ctx->io = io;
|
ctx->io->io = io;
|
||||||
|
ctx->io->bufsz = NE_IO_BUFSZ;
|
||||||
|
ctx->io->offset = -1;
|
||||||
ctx->alloc_pool = ne_pool_init();
|
ctx->alloc_pool = ne_pool_init();
|
||||||
if (!ctx->alloc_pool) {
|
if (!ctx->alloc_pool) {
|
||||||
nestegg_destroy(ctx);
|
nestegg_destroy(ctx);
|
||||||
|
@ -1918,7 +2004,9 @@ nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t ma
|
||||||
nestegg_destroy(ctx);
|
nestegg_destroy(ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*ctx->io = io;
|
ctx->io->io = io;
|
||||||
|
ctx->io->bufsz = NE_IO_BUFSZ;
|
||||||
|
ctx->io->offset = -1;
|
||||||
ctx->log = callback;
|
ctx->log = callback;
|
||||||
ctx->alloc_pool = ne_pool_init();
|
ctx->alloc_pool = ne_pool_init();
|
||||||
if (!ctx->alloc_pool) {
|
if (!ctx->alloc_pool) {
|
||||||
|
@ -2264,35 +2352,35 @@ nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item,
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
|
if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
|
||||||
&& nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
|
&& nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ne_get_binary(entry->codec_private, &codec_private) != 0)
|
if (ne_get_binary(entry->codec_private, &codec_private) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
|
if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
|
||||||
p = codec_private.data;
|
p = codec_private.data;
|
||||||
count = *p++ + 1;
|
count = *p++ + 1;
|
||||||
|
|
||||||
if (count > 3)
|
if (count > 3)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
total = 0;
|
||||||
|
while (--count) {
|
||||||
|
sizes[i] = ne_xiph_lace_value(&p);
|
||||||
|
total += sizes[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
sizes[i] = codec_private.length - total - (p - codec_private.data);
|
||||||
|
|
||||||
|
for (i = 0; i < item; ++i) {
|
||||||
|
if (sizes[i] > LIMIT_FRAME)
|
||||||
return -1;
|
return -1;
|
||||||
|
p += sizes[i];
|
||||||
i = 0;
|
}
|
||||||
total = 0;
|
*data = p;
|
||||||
while (--count) {
|
*length = sizes[item];
|
||||||
sizes[i] = ne_xiph_lace_value(&p);
|
|
||||||
total += sizes[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
sizes[i] = codec_private.length - total - (p - codec_private.data);
|
|
||||||
|
|
||||||
for (i = 0; i < item; ++i) {
|
|
||||||
if (sizes[i] > LIMIT_FRAME)
|
|
||||||
return -1;
|
|
||||||
p += sizes[i];
|
|
||||||
}
|
|
||||||
*data = p;
|
|
||||||
*length = sizes[item];
|
|
||||||
} else {
|
} else {
|
||||||
*data = codec_private.data;
|
*data = codec_private.data;
|
||||||
*length = codec_private.length;
|
*length = codec_private.length;
|
||||||
|
@ -2494,7 +2582,7 @@ nestegg_free_packet(nestegg_packet * pkt)
|
||||||
free(block_additional);
|
free(block_additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(pkt);
|
free(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2588,28 +2676,31 @@ int
|
||||||
nestegg_has_cues(nestegg * ctx)
|
nestegg_has_cues(nestegg * ctx)
|
||||||
{
|
{
|
||||||
return ctx->segment.cues.cue_point.head ||
|
return ctx->segment.cues.cue_point.head ||
|
||||||
ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
|
ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nestegg_sniff(unsigned char const * buffer, size_t length)
|
nestegg_sniff(unsigned char const * buffer, size_t length)
|
||||||
{
|
{
|
||||||
nestegg_io io;
|
nestegg_io io;
|
||||||
struct sniff_buffer user_data;
|
struct sniff_buffer userdata;
|
||||||
|
|
||||||
user_data.buffer = buffer;
|
userdata.buffer = buffer;
|
||||||
user_data.length = length;
|
userdata.length = length;
|
||||||
user_data.offset = 0;
|
userdata.offset = 0;
|
||||||
|
|
||||||
io.read = ne_buffer_read;
|
io.read = ne_buffer_read;
|
||||||
io.seek = ne_buffer_seek;
|
io.seek = ne_buffer_seek;
|
||||||
io.tell = ne_buffer_tell;
|
io.tell = ne_buffer_tell;
|
||||||
io.userdata = &user_data;
|
io.userdata = &userdata;
|
||||||
return ne_match_webm(io, length);
|
return ne_match_webm(io, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/* From halloc.c */
|
||||||
|
int halloc_set_allocator(realloc_t realloc_func);
|
||||||
|
|
||||||
|
int
|
||||||
nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t))
|
nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t))
|
||||||
{
|
{
|
||||||
halloc_allocator = realloc_func;
|
return halloc_set_allocator(realloc_func);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ cp $1/halloc/src/halloc.c src
|
||||||
cp $1/halloc/src/hlist.h src
|
cp $1/halloc/src/hlist.h src
|
||||||
cp $1/halloc/src/macros.h src
|
cp $1/halloc/src/macros.h src
|
||||||
cp $1/LICENSE .
|
cp $1/LICENSE .
|
||||||
cp $1/README .
|
cp $1/README.md .
|
||||||
cp $1/AUTHORS .
|
cp $1/AUTHORS .
|
||||||
if [ -d $1/.git ]; then
|
if [ -d $1/.git ]; then
|
||||||
rev=$(cd $1 && git rev-parse --verify HEAD)
|
rev=$(cd $1 && git rev-parse --verify HEAD)
|
||||||
|
|
|
@ -2549,12 +2549,12 @@ cc_boolean vcmCheckAttribs(cc_uint32_t media_type, void *sdp_p, int level,
|
||||||
rcap->max_cpb = t_uint;
|
rcap->max_cpb = t_uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
|
if ( ccsdpAttrGetFmtpMaxDpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
|
||||||
{
|
{
|
||||||
rcap->max_dpb = t_uint;
|
rcap->max_dpb = t_uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ccsdpAttrGetFmtpMaxCpb(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
|
if ( ccsdpAttrGetFmtpMaxBr(sdp_p, level, 0, fmtp_inst, &t_uint) == SDP_SUCCESS )
|
||||||
{
|
{
|
||||||
rcap->max_br = t_uint;
|
rcap->max_br = t_uint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1124,6 +1124,7 @@ public abstract class GeckoApp
|
||||||
mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
|
mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
|
||||||
|
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
|
final String action = intent.getAction();
|
||||||
final String args = intent.getStringExtra("args");
|
final String args = intent.getStringExtra("args");
|
||||||
|
|
||||||
earlyStartJavaSampler(intent);
|
earlyStartJavaSampler(intent);
|
||||||
|
@ -1163,7 +1164,13 @@ public abstract class GeckoApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserDB.initialize(getProfile().getName());
|
// Speculatively pre-fetch the profile in the background.
|
||||||
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
getProfile();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
|
// Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
|
||||||
try {
|
try {
|
||||||
|
@ -1205,6 +1212,30 @@ public abstract class GeckoApp
|
||||||
// without killing the entire application (see Bug 769269).
|
// without killing the entire application (see Bug 769269).
|
||||||
mIsRestoringActivity = true;
|
mIsRestoringActivity = true;
|
||||||
Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1);
|
Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
final String uri = getURIFromIntent(intent);
|
||||||
|
|
||||||
|
GeckoThread.setArgs(args);
|
||||||
|
GeckoThread.setAction(action);
|
||||||
|
GeckoThread.setUri(TextUtils.isEmpty(uri) ? null : uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ACTION_DEBUG.equals(action) &&
|
||||||
|
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching,
|
||||||
|
GeckoThread.LaunchState.Launched)) {
|
||||||
|
GeckoThread.createAndStart();
|
||||||
|
|
||||||
|
} else if (ACTION_DEBUG.equals(action) &&
|
||||||
|
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching,
|
||||||
|
GeckoThread.LaunchState.WaitForDebugger)) {
|
||||||
|
ThreadUtils.getUiHandler().postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GeckoThread.setLaunchState(GeckoThread.LaunchState.Launched);
|
||||||
|
GeckoThread.createAndStart();
|
||||||
|
}
|
||||||
|
}, 1000 * 5 /* 5 seconds */);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
|
Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
|
||||||
|
@ -1368,6 +1399,9 @@ public abstract class GeckoApp
|
||||||
layerView.initializeView(EventDispatcher.getInstance());
|
layerView.initializeView(EventDispatcher.getInstance());
|
||||||
mLayerView = layerView;
|
mLayerView = layerView;
|
||||||
GeckoAppShell.setLayerView(layerView);
|
GeckoAppShell.setLayerView(layerView);
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
|
||||||
|
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, layerView.getLayerClientObject()));
|
||||||
|
|
||||||
// bind the GeckoEditable instance to the new LayerView
|
// bind the GeckoEditable instance to the new LayerView
|
||||||
GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", "");
|
GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", "");
|
||||||
}
|
}
|
||||||
|
@ -1425,6 +1459,8 @@ public abstract class GeckoApp
|
||||||
|
|
||||||
initializeChrome();
|
initializeChrome();
|
||||||
|
|
||||||
|
BrowserDB.initialize(getProfile().getName());
|
||||||
|
|
||||||
// If we are doing a restore, read the session data and send it to Gecko
|
// If we are doing a restore, read the session data and send it to Gecko
|
||||||
if (!mIsRestoringActivity) {
|
if (!mIsRestoringActivity) {
|
||||||
String restoreMessage = null;
|
String restoreMessage = null;
|
||||||
|
@ -1467,25 +1503,6 @@ public abstract class GeckoApp
|
||||||
|
|
||||||
Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal());
|
Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal());
|
||||||
|
|
||||||
if (!mIsRestoringActivity) {
|
|
||||||
GeckoThread.setArgs(intent.getStringExtra("args"));
|
|
||||||
GeckoThread.setAction(intent.getAction());
|
|
||||||
GeckoThread.setUri(passedUri);
|
|
||||||
}
|
|
||||||
if (!ACTION_DEBUG.equals(action) &&
|
|
||||||
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
|
|
||||||
GeckoThread.createAndStart();
|
|
||||||
} else if (ACTION_DEBUG.equals(action) &&
|
|
||||||
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) {
|
|
||||||
ThreadUtils.getUiHandler().postDelayed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching);
|
|
||||||
GeckoThread.createAndStart();
|
|
||||||
}
|
|
||||||
}, 1000 * 5 /* 5 seconds */);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if launched from data reporting notification.
|
// Check if launched from data reporting notification.
|
||||||
if (ACTION_LAUNCH_SETTINGS.equals(action)) {
|
if (ACTION_LAUNCH_SETTINGS.equals(action)) {
|
||||||
Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
|
Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
|
||||||
|
@ -1580,7 +1597,6 @@ public abstract class GeckoApp
|
||||||
if (selectedTab != null)
|
if (selectedTab != null)
|
||||||
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
||||||
geckoConnected();
|
geckoConnected();
|
||||||
GeckoAppShell.setLayerClient(mLayerView.getLayerClientObject());
|
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1647,7 +1663,7 @@ public abstract class GeckoApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeckoProfile getProfile() {
|
public synchronized GeckoProfile getProfile() {
|
||||||
// fall back to default profile if we didn't load a specific one
|
// fall back to default profile if we didn't load a specific one
|
||||||
if (mProfile == null) {
|
if (mProfile == null) {
|
||||||
mProfile = GeckoProfile.get(this);
|
mProfile = GeckoProfile.get(this);
|
||||||
|
|
|
@ -205,8 +205,6 @@ public class GeckoAppShell
|
||||||
public static native void nativeInit();
|
public static native void nativeInit();
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
// public static native void setSurfaceView(GeckoSurfaceView sv);
|
|
||||||
public static native void setLayerClient(Object client);
|
|
||||||
public static native void onResume();
|
public static native void onResume();
|
||||||
public static void callObserver(String observerKey, String topic, String data) {
|
public static void callObserver(String observerKey, String topic, String data) {
|
||||||
sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
|
sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
|
||||||
|
@ -342,9 +340,6 @@ public class GeckoAppShell
|
||||||
// run gecko -- it will spawn its own thread
|
// run gecko -- it will spawn its own thread
|
||||||
GeckoAppShell.nativeInit();
|
GeckoAppShell.nativeInit();
|
||||||
|
|
||||||
if (sLayerView != null)
|
|
||||||
GeckoAppShell.setLayerClient(sLayerView.getLayerClientObject());
|
|
||||||
|
|
||||||
// First argument is the .apk path
|
// First argument is the .apk path
|
||||||
String combinedArgs = apkPath + " -greomni " + apkPath;
|
String combinedArgs = apkPath + " -greomni " + apkPath;
|
||||||
if (args != null)
|
if (args != null)
|
||||||
|
|
|
@ -76,6 +76,7 @@ public class GeckoEvent {
|
||||||
KEY_EVENT(1),
|
KEY_EVENT(1),
|
||||||
MOTION_EVENT(2),
|
MOTION_EVENT(2),
|
||||||
SENSOR_EVENT(3),
|
SENSOR_EVENT(3),
|
||||||
|
PROCESS_OBJECT(4),
|
||||||
LOCATION_EVENT(5),
|
LOCATION_EVENT(5),
|
||||||
IME_EVENT(6),
|
IME_EVENT(6),
|
||||||
SIZE_CHANGED(8),
|
SIZE_CHANGED(8),
|
||||||
|
@ -183,6 +184,8 @@ public class GeckoEvent {
|
||||||
public static final int ACTION_GAMEPAD_BUTTON = 1;
|
public static final int ACTION_GAMEPAD_BUTTON = 1;
|
||||||
public static final int ACTION_GAMEPAD_AXES = 2;
|
public static final int ACTION_GAMEPAD_AXES = 2;
|
||||||
|
|
||||||
|
public static final int ACTION_OBJECT_LAYER_CLIENT = 1;
|
||||||
|
|
||||||
private final int mType;
|
private final int mType;
|
||||||
private int mAction;
|
private int mAction;
|
||||||
private boolean mAckNeeded;
|
private boolean mAckNeeded;
|
||||||
|
@ -245,6 +248,8 @@ public class GeckoEvent {
|
||||||
|
|
||||||
private String[] mPrefNames;
|
private String[] mPrefNames;
|
||||||
|
|
||||||
|
private Object mObject;
|
||||||
|
|
||||||
private GeckoEvent(NativeGeckoEvent event) {
|
private GeckoEvent(NativeGeckoEvent event) {
|
||||||
mType = event.value;
|
mType = event.value;
|
||||||
}
|
}
|
||||||
|
@ -597,6 +602,13 @@ public class GeckoEvent {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GeckoEvent createObjectEvent(final int action, final Object object) {
|
||||||
|
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PROCESS_OBJECT);
|
||||||
|
event.mAction = action;
|
||||||
|
event.mObject = object;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
public static GeckoEvent createLocationEvent(Location l) {
|
public static GeckoEvent createLocationEvent(Location l) {
|
||||||
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT);
|
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT);
|
||||||
event.mLocation = l;
|
event.mLocation = l;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import java.util.Hashtable;
|
||||||
|
|
||||||
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
|
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
|
||||||
import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
|
import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
|
||||||
import org.mozilla.gecko.db.BrowserDB;
|
import org.mozilla.gecko.db.LocalBrowserDB;
|
||||||
import org.mozilla.gecko.distribution.Distribution;
|
import org.mozilla.gecko.distribution.Distribution;
|
||||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||||
import org.mozilla.gecko.util.INIParser;
|
import org.mozilla.gecko.util.INIParser;
|
||||||
|
@ -209,7 +209,7 @@ public final class GeckoProfile {
|
||||||
* Now do the things that createProfileDirectory normally does --
|
* Now do the things that createProfileDirectory normally does --
|
||||||
* right now that's kicking off DB init.
|
* right now that's kicking off DB init.
|
||||||
*/
|
*/
|
||||||
profile.enqueueInitialization();
|
profile.enqueueInitialization(profile.getDir());
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -650,7 +650,7 @@ public final class GeckoProfile {
|
||||||
|
|
||||||
// Trigger init for non-webapp profiles.
|
// Trigger init for non-webapp profiles.
|
||||||
if (!mIsWebAppProfile) {
|
if (!mIsWebAppProfile) {
|
||||||
enqueueInitialization();
|
enqueueInitialization(profileDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out profile creation time, mirroring the logic in nsToolkitProfileService.
|
// Write out profile creation time, mirroring the logic in nsToolkitProfileService.
|
||||||
|
@ -684,7 +684,7 @@ public final class GeckoProfile {
|
||||||
* This is public for use *from tests only*!
|
* This is public for use *from tests only*!
|
||||||
*/
|
*/
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
public void enqueueInitialization() {
|
public void enqueueInitialization(final File profileDir) {
|
||||||
Log.i(LOGTAG, "Enqueuing profile init.");
|
Log.i(LOGTAG, "Enqueuing profile init.");
|
||||||
final Context context = mApplicationContext;
|
final Context context = mApplicationContext;
|
||||||
|
|
||||||
|
@ -697,13 +697,24 @@ public final class GeckoProfile {
|
||||||
|
|
||||||
final ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
|
|
||||||
// We pass the number of added bookmarks to ensure that the
|
// Because we are running in the background, we want to synchronize on the
|
||||||
// indices of the distribution and default bookmarks are
|
// GeckoProfile instance so that we don't race with main thread operations
|
||||||
// contiguous. Because there are always at least as many
|
// such as locking/unlocking/removing the profile.
|
||||||
// bookmarks as there are favicons, we can also guarantee that
|
synchronized (GeckoProfile.this) {
|
||||||
// the favicon IDs won't overlap.
|
// Skip initialization if the profile directory has been removed.
|
||||||
final int offset = BrowserDB.addDistributionBookmarks(cr, distribution, 0);
|
if (!profileDir.exists()) {
|
||||||
BrowserDB.addDefaultBookmarks(context, cr, offset);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We pass the number of added bookmarks to ensure that the
|
||||||
|
// indices of the distribution and default bookmarks are
|
||||||
|
// contiguous. Because there are always at least as many
|
||||||
|
// bookmarks as there are favicons, we can also guarantee that
|
||||||
|
// the favicon IDs won't overlap.
|
||||||
|
final LocalBrowserDB db = new LocalBrowserDB(getName());
|
||||||
|
final int offset = db.addDistributionBookmarks(cr, distribution, 0);
|
||||||
|
db.addDefaultBookmarks(context, cr, offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,25 +136,29 @@ public class GeckoThread extends Thread implements GeckoEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String addCustomProfileArg(String args) {
|
private String addCustomProfileArg(String args) {
|
||||||
String profile = "";
|
String profileArg = "";
|
||||||
String guest = "";
|
String guestArg = "";
|
||||||
if (GeckoAppShell.getGeckoInterface() != null) {
|
if (GeckoAppShell.getGeckoInterface() != null) {
|
||||||
if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) {
|
final GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile();
|
||||||
|
|
||||||
|
if (profile.inGuestMode()) {
|
||||||
try {
|
try {
|
||||||
profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath();
|
profileArg = " -profile " + profile.getDir().getCanonicalPath();
|
||||||
} catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); }
|
} catch (final IOException ioe) {
|
||||||
|
Log.e(LOGTAG, "error getting guest profile path", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) {
|
if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) {
|
||||||
guest = " " + BrowserApp.GUEST_BROWSING_ARG;
|
guestArg = " " + BrowserApp.GUEST_BROWSING_ARG;
|
||||||
}
|
}
|
||||||
} else if (!GeckoProfile.sIsUsingCustomProfile) {
|
} else if (!GeckoProfile.sIsUsingCustomProfile) {
|
||||||
// If nothing was passed in in the intent, force Gecko to use the default profile for
|
// If nothing was passed in the intent, make sure the default profile exists and
|
||||||
// for this activity
|
// force Gecko to use the default profile for this activity
|
||||||
profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName();
|
profileArg = " -P " + profile.forceCreate().getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (args != null ? args : "") + profile + guest;
|
return (args != null ? args : "") + profileArg + guestArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -174,6 +174,8 @@ public class GeckoView extends LayerView
|
||||||
BrowserDB.initialize(profile.getName());
|
BrowserDB.initialize(profile.getName());
|
||||||
|
|
||||||
GeckoAppShell.setLayerView(this);
|
GeckoAppShell.setLayerView(this);
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
|
||||||
|
GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject()));
|
||||||
GeckoThread.createAndStart();
|
GeckoThread.createAndStart();
|
||||||
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
||||||
// If Gecko is already running, that means the Activity was
|
// If Gecko is already running, that means the Activity was
|
||||||
|
@ -247,7 +249,6 @@ public class GeckoView extends LayerView
|
||||||
if (selectedTab != null)
|
if (selectedTab != null)
|
||||||
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
|
||||||
geckoConnected();
|
geckoConnected();
|
||||||
GeckoAppShell.setLayerClient(getLayerClientObject());
|
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class SuggestedSites {
|
||||||
|
|
||||||
final Context context;
|
final Context context;
|
||||||
final Distribution distribution;
|
final Distribution distribution;
|
||||||
final File file;
|
private File cachedFile;
|
||||||
private Map<String, Site> cachedSites;
|
private Map<String, Site> cachedSites;
|
||||||
private Set<String> cachedBlacklist;
|
private Set<String> cachedBlacklist;
|
||||||
|
|
||||||
|
@ -166,14 +166,20 @@ public class SuggestedSites {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuggestedSites(Context appContext, Distribution distribution) {
|
public SuggestedSites(Context appContext, Distribution distribution) {
|
||||||
this(appContext, distribution,
|
this(appContext, distribution, null);
|
||||||
GeckoProfile.get(appContext).getFile(FILENAME));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuggestedSites(Context appContext, Distribution distribution, File file) {
|
public SuggestedSites(Context appContext, Distribution distribution, File file) {
|
||||||
this.context = appContext;
|
this.context = appContext;
|
||||||
this.distribution = distribution;
|
this.distribution = distribution;
|
||||||
this.file = file;
|
this.cachedFile = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized File getFile() {
|
||||||
|
if (cachedFile == null) {
|
||||||
|
cachedFile = GeckoProfile.get(context).getFile(FILENAME);
|
||||||
|
}
|
||||||
|
return cachedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNewLocale(Context context, Locale requestedLocale) {
|
private static boolean isNewLocale(Context context, Locale requestedLocale) {
|
||||||
|
@ -306,6 +312,7 @@ public class SuggestedSites {
|
||||||
setCachedSites(sites);
|
setCachedSites(sites);
|
||||||
|
|
||||||
// Save the result to disk.
|
// Save the result to disk.
|
||||||
|
final File file = getFile();
|
||||||
synchronized (file) {
|
synchronized (file) {
|
||||||
saveSites(file, sites);
|
saveSites(file, sites);
|
||||||
}
|
}
|
||||||
|
@ -349,6 +356,7 @@ public class SuggestedSites {
|
||||||
|
|
||||||
private Map<String, Site> loadFromProfile() {
|
private Map<String, Site> loadFromProfile() {
|
||||||
try {
|
try {
|
||||||
|
final File file = getFile();
|
||||||
synchronized (file) {
|
synchronized (file) {
|
||||||
return loadSites(file);
|
return loadSites(file);
|
||||||
}
|
}
|
||||||
|
@ -462,7 +470,7 @@ public class SuggestedSites {
|
||||||
// Force the suggested sites file in profile dir to be re-generated
|
// Force the suggested sites file in profile dir to be re-generated
|
||||||
// if the locale has changed.
|
// if the locale has changed.
|
||||||
if (isNewLocale) {
|
if (isNewLocale) {
|
||||||
file.delete();
|
getFile().delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cachedSites == null || isNewLocale) {
|
if (cachedSites == null || isNewLocale) {
|
||||||
|
|
|
@ -133,7 +133,7 @@ abstract class BaseTest extends BaseRobocopTest {
|
||||||
|
|
||||||
// In Robocop tests, we typically don't get initialized correctly, because
|
// In Robocop tests, we typically don't get initialized correctly, because
|
||||||
// GeckoProfile doesn't create the profile directory.
|
// GeckoProfile doesn't create the profile directory.
|
||||||
profile.enqueueInitialization();
|
profile.enqueueInitialization(profile.getDir());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -12,44 +12,65 @@ import java.util.concurrent.SynchronousQueue;
|
||||||
final class GeckoBackgroundThread extends Thread {
|
final class GeckoBackgroundThread extends Thread {
|
||||||
private static final String LOOPER_NAME = "GeckoBackgroundThread";
|
private static final String LOOPER_NAME = "GeckoBackgroundThread";
|
||||||
|
|
||||||
// Guarded by 'this'.
|
// Guarded by 'GeckoBackgroundThread.class'.
|
||||||
private static Handler sHandler;
|
private static Handler handler;
|
||||||
private SynchronousQueue<Handler> mHandlerQueue = new SynchronousQueue<Handler>();
|
private static Thread thread;
|
||||||
|
|
||||||
|
// The initial Runnable to run on the new thread. Its purpose
|
||||||
|
// is to avoid us having to wait for the new thread to start.
|
||||||
|
private Runnable initialRunnable;
|
||||||
|
|
||||||
// Singleton, so private constructor.
|
// Singleton, so private constructor.
|
||||||
private GeckoBackgroundThread() {
|
private GeckoBackgroundThread(final Runnable initialRunnable) {
|
||||||
super();
|
this.initialRunnable = initialRunnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
setName(LOOPER_NAME);
|
setName(LOOPER_NAME);
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
try {
|
|
||||||
mHandlerQueue.put(new Handler());
|
synchronized (GeckoBackgroundThread.class) {
|
||||||
} catch (InterruptedException ie) {}
|
handler = new Handler();
|
||||||
|
GeckoBackgroundThread.class.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialRunnable != null) {
|
||||||
|
initialRunnable.run();
|
||||||
|
initialRunnable = null;
|
||||||
|
}
|
||||||
|
|
||||||
Looper.loop();
|
Looper.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a Handler for a looper thread, or create one if it doesn't yet exist.
|
private static void startThread(final Runnable initialRunnable) {
|
||||||
/*package*/ static synchronized Handler getHandler() {
|
thread = new GeckoBackgroundThread(initialRunnable);
|
||||||
if (sHandler == null) {
|
ThreadUtils.setBackgroundThread(thread);
|
||||||
GeckoBackgroundThread lt = new GeckoBackgroundThread();
|
|
||||||
ThreadUtils.setBackgroundThread(lt);
|
thread.setDaemon(true);
|
||||||
lt.start();
|
thread.start();
|
||||||
try {
|
|
||||||
sHandler = lt.mHandlerQueue.take();
|
|
||||||
} catch (InterruptedException ie) {}
|
|
||||||
}
|
|
||||||
return sHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ static void post(Runnable runnable) {
|
// Get a Handler for a looper thread, or create one if it doesn't yet exist.
|
||||||
Handler handler = getHandler();
|
/*package*/ static synchronized Handler getHandler() {
|
||||||
if (handler == null) {
|
if (thread == null) {
|
||||||
throw new IllegalStateException("No handler! Must have been interrupted. Not posting.");
|
startThread(null);
|
||||||
}
|
}
|
||||||
handler.post(runnable);
|
|
||||||
|
while (handler == null) {
|
||||||
|
try {
|
||||||
|
GeckoBackgroundThread.class.wait();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ static synchronized void post(final Runnable runnable) {
|
||||||
|
if (thread == null) {
|
||||||
|
startThread(runnable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getHandler().post(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ public final class ThreadUtils {
|
||||||
return isOnThread(getUiThread());
|
return isOnThread(getUiThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RobocopTarget
|
||||||
public static boolean isOnBackgroundThread() {
|
public static boolean isOnBackgroundThread() {
|
||||||
if (sBackgroundThread == null) {
|
if (sBackgroundThread == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -197,6 +198,7 @@ public final class ThreadUtils {
|
||||||
return isOnThread(sBackgroundThread);
|
return isOnThread(sBackgroundThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RobocopTarget
|
||||||
public static boolean isOnThread(Thread thread) {
|
public static boolean isOnThread(Thread thread) {
|
||||||
return (Thread.currentThread().getId() == thread.getId());
|
return (Thread.currentThread().getId() == thread.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const Cu = Components.utils;
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
|
||||||
if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
|
if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
document.body.setAttribute("class", "normal");
|
document.body.setAttribute("class", "normal");
|
||||||
}, false);
|
}, false);
|
||||||
|
|
|
@ -98,6 +98,8 @@ if test ! "$RELEASE_BUILD"; then
|
||||||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
|
MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Enable generational GC on mobile.
|
# Enable generational GC on mobile.
|
||||||
JSGC_GENERATIONAL=1
|
JSGC_GENERATIONAL=1
|
||||||
|
|
||||||
|
# Use the low-memory GC tuning.
|
||||||
|
JS_GC_SMALL_CHUNK_SIZE=1
|
||||||
|
|
|
@ -12,6 +12,9 @@ jar.sources += [
|
||||||
'src/harness/BrowserInstrumentationTestRunner.java',
|
'src/harness/BrowserInstrumentationTestRunner.java',
|
||||||
'src/harness/BrowserTestListener.java',
|
'src/harness/BrowserTestListener.java',
|
||||||
'src/TestDistribution.java',
|
'src/TestDistribution.java',
|
||||||
|
'src/TestGeckoBackgroundThread.java',
|
||||||
|
'src/TestGeckoMenu.java',
|
||||||
|
'src/TestGeckoProfilesProvider.java',
|
||||||
'src/TestGeckoSharedPrefs.java',
|
'src/TestGeckoSharedPrefs.java',
|
||||||
'src/TestImageDownloader.java',
|
'src/TestImageDownloader.java',
|
||||||
'src/TestJarReader.java',
|
'src/TestJarReader.java',
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
|
public class TestGeckoBackgroundThread extends BrowserTestCase {
|
||||||
|
|
||||||
|
private boolean finishedTest;
|
||||||
|
private boolean ranFirstRunnable;
|
||||||
|
|
||||||
|
public void testGeckoBackgroundThread() throws InterruptedException {
|
||||||
|
|
||||||
|
final Thread testThread = Thread.currentThread();
|
||||||
|
|
||||||
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Must *not* be on thread that posted the Runnable.
|
||||||
|
assertFalse(ThreadUtils.isOnThread(testThread));
|
||||||
|
|
||||||
|
// Must be on background thread.
|
||||||
|
assertTrue(ThreadUtils.isOnBackgroundThread());
|
||||||
|
|
||||||
|
ranFirstRunnable = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Post a second Runnable to make sure it still runs on the background thread,
|
||||||
|
// and it only runs after the first Runnable has run.
|
||||||
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Must still be on background thread.
|
||||||
|
assertTrue(ThreadUtils.isOnBackgroundThread());
|
||||||
|
|
||||||
|
// This Runnable must be run after the first Runnable had finished.
|
||||||
|
assertTrue(ranFirstRunnable);
|
||||||
|
|
||||||
|
synchronized (TestGeckoBackgroundThread.this) {
|
||||||
|
finishedTest = true;
|
||||||
|
TestGeckoBackgroundThread.this.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
while (!finishedTest) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,7 +135,7 @@ pref("dom.serviceWorkers.enabled", false);
|
||||||
pref("dom.enable_performance", true);
|
pref("dom.enable_performance", true);
|
||||||
|
|
||||||
// Whether resource timing will be gathered and returned by performance.GetEntries*
|
// Whether resource timing will be gathered and returned by performance.GetEntries*
|
||||||
pref("dom.enable_resource_timing", false);
|
pref("dom.enable_resource_timing", true);
|
||||||
|
|
||||||
// Whether the Gamepad API is enabled
|
// Whether the Gamepad API is enabled
|
||||||
pref("dom.gamepad.enabled", true);
|
pref("dom.gamepad.enabled", true);
|
||||||
|
@ -341,7 +341,6 @@ pref("media.peerconnection.video.max_bitrate", 2000);
|
||||||
#endif
|
#endif
|
||||||
pref("media.navigator.permission.disabled", false);
|
pref("media.navigator.permission.disabled", false);
|
||||||
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
|
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
|
||||||
pref("media.peerconnection.trickle_ice", true);
|
|
||||||
pref("media.peerconnection.use_document_iceservers", true);
|
pref("media.peerconnection.use_document_iceservers", true);
|
||||||
// Do not enable identity before ensuring that the UX cannot be spoofed
|
// Do not enable identity before ensuring that the UX cannot be spoofed
|
||||||
// see Bug 884573 for details
|
// see Bug 884573 for details
|
||||||
|
|
|
@ -96,25 +96,6 @@ Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) {
|
||||||
|
|
||||||
#ifdef JNI_STUBS
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t)(JNIEnv *, jclass, jobject);
|
|
||||||
static Java_org_mozilla_gecko_GeckoAppShell_setLayerClient_t f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient;
|
|
||||||
extern "C" NS_EXPORT void JNICALL
|
|
||||||
Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv * arg0, jclass arg1, jobject arg2) {
|
|
||||||
if (!f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient) {
|
|
||||||
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
|
||||||
"JNI Function called before it was loaded");
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(arg0, arg1, arg2);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JNI_BINDINGS
|
|
||||||
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_setLayerClient", &f_Java_org_mozilla_gecko_GeckoAppShell_setLayerClient);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JNI_STUBS
|
|
||||||
|
|
||||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onResume_t)(JNIEnv *, jclass);
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onResume_t)(JNIEnv *, jclass);
|
||||||
static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume;
|
static Java_org_mozilla_gecko_GeckoAppShell_onResume_t f_Java_org_mozilla_gecko_GeckoAppShell_onResume;
|
||||||
extern "C" NS_EXPORT void JNICALL
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
|
|
@ -615,6 +615,10 @@ class MochitestOptions(optparse.OptionParser):
|
||||||
"tab": 10000, # See dependencies of bug 1051230.
|
"tab": 10000, # See dependencies of bug 1051230.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bug 1051230 - Leak logging does not yet work for tab processes on desktop.
|
||||||
|
# Bug 1065098 - The geckomediaplugin process fails to produce a leak log for some reason.
|
||||||
|
options.ignoreMissingLeaks = ["tab", "geckomediaplugin"]
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
@ -819,6 +823,12 @@ class B2GOptions(MochitestOptions):
|
||||||
options.sslPort = tempSSL
|
options.sslPort = tempSSL
|
||||||
options.httpPort = tempPort
|
options.httpPort = tempPort
|
||||||
|
|
||||||
|
# Bug 1071866 - B2G Mochitests do not always produce a leak log.
|
||||||
|
options.ignoreMissingLeaks.append("default")
|
||||||
|
|
||||||
|
# Bug 1070068 - Leak logging does not work for tab processes on B2G.
|
||||||
|
assert "tab" in options.ignoreMissingLeaks, "Ignore failures for tab processes on B2G"
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def elf_arm(self, filename):
|
def elf_arm(self, filename):
|
||||||
|
|
|
@ -1842,7 +1842,7 @@ class Mochitest(MochitestUtilsMixin):
|
||||||
self.stopVMwareRecording();
|
self.stopVMwareRecording();
|
||||||
self.stopServers()
|
self.stopServers()
|
||||||
|
|
||||||
processLeakLog(self.leak_report_file, options.leakThresholds)
|
processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks)
|
||||||
|
|
||||||
if self.nsprLogs:
|
if self.nsprLogs:
|
||||||
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
|
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
|
||||||
|
|
|
@ -202,7 +202,7 @@ class B2GMochitest(MochitestUtilsMixin):
|
||||||
self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
|
self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
|
||||||
self.app_ctx.dm.removeFile(self.leak_report_file)
|
self.app_ctx.dm.removeFile(self.leak_report_file)
|
||||||
|
|
||||||
processLeakLog(local_leak_file.name, options.leakThresholds)
|
processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
self.log.info("runtests.py | Received keyboard interrupt.\n");
|
self.log.info("runtests.py | Received keyboard interrupt.\n");
|
||||||
status = -1
|
status = -1
|
||||||
|
|
|
@ -231,8 +231,11 @@ class RemoteB2GVersion(B2GVersion):
|
||||||
self._info[desired_props[key]] = value
|
self._info[desired_props[key]] = value
|
||||||
|
|
||||||
if self._info.get('device_id', '').lower() == 'flame':
|
if self._info.get('device_id', '').lower() == 'flame':
|
||||||
self._info['device_firmware_version_base'] = dm._runCmd(
|
for prop in ['ro.boot.bootloader', 't2m.sw.version']:
|
||||||
['shell', 'getprop', 't2m.sw.version']).output[0]
|
value = dm.shellCheckOutput(['getprop', prop])
|
||||||
|
if value:
|
||||||
|
self._info['device_firmware_version_base'] = value
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def get_version(binary=None, sources=None, dm_type=None, host=None,
|
def get_version(binary=None, sources=None, dm_type=None, host=None,
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче