diff --git a/CLOBBER b/CLOBBER index d4cdfaff33d..3da13ded390 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,5 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Merge day clobber \ No newline at end of file +Hitting failures with Taskcluster-based jobs that seem like needs-clobber. + diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 86fd4577a3f..c937cd5fd8f 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -552,8 +552,7 @@ nsContextMenu.prototype = { const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; if (aNode.namespaceURI == xulNS || - aNode.nodeType == Node.DOCUMENT_NODE || - this.isDisabledForEvents(aNode)) { + aNode.nodeType == Node.DOCUMENT_NODE) { this.shouldDisplay = false; return; } @@ -1534,16 +1533,6 @@ nsContextMenu.prototype = { "contextMenu.hasBGImage = " + this.hasBGImage + "\n"; }, - isDisabledForEvents: function(aNode) { - let ownerDoc = aNode.ownerDocument; - return - ownerDoc.defaultView && - ownerDoc.defaultView - .QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindowUtils) - .isNodeDisabledForEvents(aNode); - }, - isTargetATextBox: function(node) { if (node instanceof HTMLInputElement) return node.mozIsTextField(false); diff --git a/configure.in b/configure.in index 9a2dcbd67b7..6066e66dd1a 100644 --- a/configure.in +++ b/configure.in @@ -50,7 +50,7 @@ _SUBDIR_CONFIG_ARGS="$ac_configure_args" dnl Set the version number of the libs included with mozilla dnl ======================================================== MOZJPEG=62 -MOZPNG=10616 +MOZPNG=10617 NSPR_VERSION=4 NSPR_MINVER=4.10.8 NSS_VERSION=3 diff --git a/dom/apps/OfflineCacheInstaller.jsm b/dom/apps/OfflineCacheInstaller.jsm index 06c9fea5667..6bfe89c4cbd 100644 --- a/dom/apps/OfflineCacheInstaller.jsm +++ b/dom/apps/OfflineCacheInstaller.jsm @@ -46,32 +46,43 @@ function enableOfflineCacheForApp(aPrincipal) { } -function storeCache(applicationCache, url, file, itemType) { +function storeCache(applicationCache, url, file, itemType, metadata) { let storage = Services.cache2.appCacheStorage(LoadContextInfo.default, applicationCache); let uri = Services.io.newURI(url, null, null); + let nowGMT = new Date().toGMTString(); + metadata = metadata || {}; + metadata.lastFetched = metadata.lastFetched || nowGMT; + metadata.lastModified = metadata.lastModified || nowGMT; storage.asyncOpenURI(uri, "", nsICacheStorage.OPEN_TRUNCATE, { onCacheEntryAvailable: function (cacheEntry, isNew, appCache, result) { - cacheEntry.setMetaDataElement('request-method', 'GET'); - cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n'); + cacheEntry.setMetaDataElement("request-method", "GET"); + cacheEntry.setMetaDataElement("response-head", + "HTTP/1.1 200 OK\r\n" + + "Date: " + metadata.lastFetched + "\r\n" + + "Last-Modified: " + metadata.lastModified + "\r\n" + + "Cache-Control: no-cache\r\n"); let outputStream = cacheEntry.openOutputStream(0); - // Input-Output stream machinery in order to push nsIFile content into cache - let inputStream = Cc['@mozilla.org/network/file-input-stream;1'] + // Input-Output stream machinery in order to push nsIFile content into + // cache + let inputStream = Cc["@mozilla.org/network/file-input-stream;1"] .createInstance(Ci.nsIFileInputStream); inputStream.init(file, 1, -1, null); - let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1'] - .createInstance(Ci.nsIBufferedOutputStream); + let bufferedOutputStream = + Cc["@mozilla.org/network/buffered-output-stream;1"] + .createInstance(Ci.nsIBufferedOutputStream); bufferedOutputStream.init(outputStream, 1024); bufferedOutputStream.writeFrom(inputStream, inputStream.available()); bufferedOutputStream.flush(); bufferedOutputStream.close(); inputStream.close(); + cacheEntry.setExpirationTime(0); cacheEntry.markValid(); - debug (file.path + ' -> ' + url + ' (' + itemType + ')'); + debug (file.path + " -> " + url + " (" + itemType + ")"); applicationCache.markEntry(url, itemType); cacheEntry.close(); } @@ -206,8 +217,12 @@ function installCache(app) { return; } - let cacheDir = makeFile(app.cachePath) + let cacheDir = makeFile(app.cachePath); cacheDir.append(app.appId); + + let resourcesMetadata = cacheDir.clone(); + resourcesMetadata.append('resources_metadata.json'); + cacheDir.append('cache'); if (!cacheDir.exists()) return; @@ -218,55 +233,72 @@ function installCache(app) { return; let principal = Services.scriptSecurityManager.getAppCodebasePrincipal( - app.origin, app.localId, false); + app.origin, app.localId, false); - enableOfflineCacheForApp(principal); + // If the build has been correctly configured, this should not happen! + // If we install the cache anyway, it won't be updateable. If we don't install + // it, the application won't be useable offline. + let metadataLoaded; + if (!resourcesMetadata.exists()) { + // Not debug, since this is something that should be logged always! + dump("OfflineCacheInstaller: App " + app.appId + " does have an app cache" + + " but does not have a resources_metadata.json file!"); + metadataLoaded = Promise.resolve({}); + } else { + metadataLoaded = new Promise( + (resolve, reject) => + readFile(resourcesMetadata, principal, content => resolve(JSON.parse(content)))); + } - // Get the url for the manifest. - let appcacheURL = app.appcache_path; + metadataLoaded.then(function(metadata) { + enableOfflineCacheForApp(principal); - // The group ID contains application id and 'f' for not being hosted in - // a browser element, but a mozbrowser iframe. - // See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier - let groupID = appcacheURL + '#' + app.localId+ '+f'; - let applicationCache = applicationCacheService.createApplicationCache(groupID); - applicationCache.activate(); + // Get the url for the manifest. + let appcacheURL = app.appcache_path; - readFile(cacheManifest, principal, function readAppCache(content) { - let entries = parseAppCache(app, cacheManifest.path, content); + // The group ID contains application id and 'f' for not being hosted in + // a browser element, but a mozbrowser iframe. + // See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier + let groupID = appcacheURL + '#' + app.localId+ '+f'; + let applicationCache = applicationCacheService.createApplicationCache(groupID); + applicationCache.activate(); - entries.urls.forEach(function processCachedFile(url) { - // Get this nsIFile from cache folder for this URL - // We have absolute urls, so remove the origin part to locate the - // files. - let path = url.replace(app.origin.spec, ''); - let file = cacheDir.clone(); - let paths = path.split('/'); - paths.forEach(file.append); + readFile(cacheManifest, principal, function readAppCache(content) { + let entries = parseAppCache(app, cacheManifest.path, content); - if (!file.exists()) { - let msg = 'File ' + file.path + ' exists in the manifest but does ' + - 'not points to a real file.'; - throw new Error(msg); - } + entries.urls.forEach(function processCachedFile(url) { + // Get this nsIFile from cache folder for this URL + // We have absolute urls, so remove the origin part to locate the + // files. + let path = url.replace(app.origin.spec, ''); + let file = cacheDir.clone(); + let paths = path.split('/'); + paths.forEach(file.append); - let itemType = nsIApplicationCache.ITEM_EXPLICIT; - if (entries.fallbacks.indexOf(url) > -1) { - debug('add fallback: ' + url + '\n'); - itemType |= nsIApplicationCache.ITEM_FALLBACK; - } - storeCache(applicationCache, url, file, itemType); + if (!file.exists()) { + let msg = 'File ' + file.path + ' exists in the manifest but does ' + + 'not points to a real file.'; + throw new Error(msg); + } + + let itemType = nsIApplicationCache.ITEM_EXPLICIT; + if (entries.fallbacks.indexOf(url) > -1) { + debug('add fallback: ' + url + '\n'); + itemType |= nsIApplicationCache.ITEM_FALLBACK; + } + storeCache(applicationCache, url, file, itemType, metadata[path]); + }); + + let array = new MutableArray(); + entries.namespaces.forEach(function processNamespace([type, spec, data]) { + debug('add namespace: ' + type + ' - ' + spec + ' - ' + data + '\n'); + array.appendElement(new Namespace(type, spec, data), false); + }); + applicationCache.addNamespaces(array); + + storeCache(applicationCache, appcacheURL, cacheManifest, + nsIApplicationCache.ITEM_MANIFEST); }); - - let array = new MutableArray(); - entries.namespaces.forEach(function processNamespace([type, spec, data]) { - debug('add namespace: ' + type + ' - ' + spec + ' - ' + data + '\n'); - array.appendElement(new Namespace(type, spec, data), false); - }); - applicationCache.addNamespaces(array); - - storeCache(applicationCache, appcacheURL, cacheManifest, - nsIApplicationCache.ITEM_MANIFEST); }); } diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index e3162da51ef..db7e7cd2082 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -125,8 +125,7 @@ public: void FailConnection(uint16_t reasonCode, const nsACString& aReasonString = EmptyCString()); nsresult CloseConnection(uint16_t reasonCode, - const nsACString& aReasonString = EmptyCString(), - bool aCanceling = false); + const nsACString& aReasonString = EmptyCString()); nsresult Disconnect(); void DisconnectInternal(); @@ -385,38 +384,6 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI, namespace { -class CloseRunnable final : public WorkerMainThreadRunnable -{ -public: - CloseRunnable(WebSocketImpl* aImpl, uint16_t aReasonCode, - const nsACString& aReasonString) - : WorkerMainThreadRunnable(aImpl->mWorkerPrivate) - , mImpl(aImpl) - , mReasonCode(aReasonCode) - , mReasonString(aReasonString) - , mRv(NS_ERROR_FAILURE) - { } - - bool MainThreadRun() override - { - mRv = mImpl->mChannel->Close(mReasonCode, mReasonString); - return true; - } - - nsresult ErrorCode() const - { - return mRv; - } - -private: - // A raw pointer because this runnable is sync. - WebSocketImpl* mImpl; - - uint16_t mReasonCode; - const nsACString& mReasonString; - nsresult mRv; -}; - class CancelWebSocketRunnable final : public nsRunnable { public: @@ -469,11 +436,9 @@ private: nsresult WebSocketImpl::CloseConnection(uint16_t aReasonCode, - const nsACString& aReasonString, - bool aCanceling) + const nsACString& aReasonString) { AssertIsOnTargetThread(); - MOZ_ASSERT(!NS_IsMainThread() || !aCanceling); if (mDisconnectingOrDisconnected) { return NS_OK; @@ -500,16 +465,9 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode, return mChannel->Close(aReasonCode, aReasonString); } - if (aCanceling) { - nsRefPtr runnable = - new CancelWebSocketRunnable(mChannel, aReasonCode, aReasonString); - return NS_DispatchToMainThread(runnable); - } - - nsRefPtr runnable = - new CloseRunnable(this, aReasonCode, aReasonString); - runnable->Dispatch(mWorkerPrivate->GetJSContext()); - return runnable->ErrorCode(); + nsRefPtr runnable = + new CancelWebSocketRunnable(mChannel, aReasonCode, aReasonString); + return NS_DispatchToMainThread(runnable); } // No channel, but not disconnected: canceled or failed early @@ -2033,7 +1991,7 @@ public: } mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY, - EmptyCString(), true); + EmptyCString()); } return true; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 32710efbe26..207bc5a215f 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -340,19 +340,18 @@ nsFrameLoader::ReallyStartLoadingInternal() } if (mRemoteFrame) { - if (!mRemoteBrowser) { - TryRemoteBrowser(); - - if (!mRemoteBrowser) { + if (!mRemoteBrowser && !TryRemoteBrowser()) { NS_WARNING("Couldn't create child process for iframe."); return NS_ERROR_FAILURE; - } } - if (mRemoteBrowserShown || ShowRemoteFrame(ScreenIntSize(0, 0))) { - // FIXME get error codes from child - mRemoteBrowser->LoadURL(mURIToLoad); - } else { + // Execute pending frame scripts before loading URL + EnsureMessageManager(); + + // FIXME get error codes from child + mRemoteBrowser->LoadURL(mURIToLoad); + + if (!mRemoteBrowserShown && !ShowRemoteFrame(ScreenIntSize(0, 0))) { NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n"); } @@ -832,13 +831,9 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size, { NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames."); - if (!mRemoteBrowser) { - TryRemoteBrowser(); - - if (!mRemoteBrowser) { - NS_ERROR("Couldn't create child process."); - return false; - } + if (!mRemoteBrowser && !TryRemoteBrowser()) { + NS_ERROR("Couldn't create child process."); + return false; } // FIXME/bug 589337: Show()/Hide() is pretty expensive for @@ -2262,28 +2257,31 @@ nsFrameLoader::TryRemoteBrowser() nsCOMPtr ownerElement = mOwnerContent; mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement, openerContentParent); - if (mRemoteBrowser) { - mChildID = mRemoteBrowser->Manager()->ChildID(); - nsCOMPtr rootItem; - parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem)); - nsCOMPtr rootWin = rootItem->GetWindow(); - nsCOMPtr rootChromeWin = do_QueryInterface(rootWin); - - if (rootChromeWin) { - nsCOMPtr browserDOMWin; - rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin)); - mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin); - } - - mContentParent = mRemoteBrowser->Manager(); - - if (mOwnerContent->AttrValueIs(kNameSpaceID_None, - nsGkAtoms::mozpasspointerevents, - nsGkAtoms::_true, - eCaseMatters)) { - unused << mRemoteBrowser->SendSetUpdateHitRegion(true); - } + if (!mRemoteBrowser) { + return false; } + + mContentParent = mRemoteBrowser->Manager(); + mChildID = mRemoteBrowser->Manager()->ChildID(); + + nsCOMPtr rootItem; + parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem)); + nsCOMPtr rootWin = rootItem->GetWindow(); + nsCOMPtr rootChromeWin = do_QueryInterface(rootWin); + + if (rootChromeWin) { + nsCOMPtr browserDOMWin; + rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin)); + mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin); + } + + if (mOwnerContent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::mozpasspointerevents, + nsGkAtoms::_true, + eCaseMatters)) { + unused << mRemoteBrowser->SendSetUpdateHitRegion(true); + } + return true; } @@ -2528,7 +2526,7 @@ nsFrameLoader::EnsureMessageManager() bool useRemoteProcess = ShouldUseRemoteProcess(); if (mMessageManager) { - if (useRemoteProcess && mRemoteBrowserShown) { + if (useRemoteProcess && mRemoteBrowser) { mMessageManager->InitWithCallback(this); } return NS_OK; @@ -2553,7 +2551,7 @@ nsFrameLoader::EnsureMessageManager() } if (useRemoteProcess) { - mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr, + mMessageManager = new nsFrameMessageManager(mRemoteBrowser ? this : nullptr, static_cast(parentManager.get()), MM_CHROME); } else { diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp index 06e7b9468eb..2738664b636 100644 --- a/dom/base/nsInProcessTabChildGlobal.cpp +++ b/dom/base/nsInProcessTabChildGlobal.cpp @@ -260,6 +260,7 @@ nsInProcessTabChildGlobal::GetOwnerContent() nsresult nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor) { + aVisitor.mForceContentDispatch = true; aVisitor.mCanHandle = true; #ifdef DEBUG diff --git a/dom/canvas/CanvasImageCache.cpp b/dom/canvas/CanvasImageCache.cpp index 2dc049293b8..bf3fafafed5 100644 --- a/dom/canvas/CanvasImageCache.cpp +++ b/dom/canvas/CanvasImageCache.cpp @@ -299,7 +299,7 @@ CanvasImageCache::Lookup(Element* aImage, gImageCache->MarkUsed(entry->mData); - *aSize = gfx::ToIntSize(entry->mData->mSize); + *aSize = entry->mData->mSize; return entry->mData->mSourceSurface; } diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 76f9cb05ab4..b4448c14eda 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4320,7 +4320,7 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image return; } - imgSize = gfx::ToIntSize(res.mSize); + imgSize = res.mSize; // Scale sw/sh based on aspect ratio if (image.IsHTMLVideoElement()) { diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 1cc64f9221e..3074924399b 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -55,7 +55,6 @@ #if defined(XP_WIN) #define TARGET_SANDBOX_EXPORTS #include "mozilla/sandboxTarget.h" -#include "nsDirectoryServiceDefs.h" #elif defined(XP_LINUX) #include "mozilla/Sandbox.h" #include "mozilla/SandboxInfo.h" @@ -1080,76 +1079,6 @@ ContentChild::AllocPProcessHangMonitorChild(Transport* aTransport, return CreateHangMonitorChild(aTransport, aOtherProcess); } -#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) -static void -SetUpSandboxEnvironment() -{ - // Set up a low integrity temp directory. This only makes sense if the - // delayed integrity level for the content process is INTEGRITY_LEVEL_LOW. - nsresult rv; - nsCOMPtr directoryService = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr lowIntegrityTemp; - rv = directoryService->Get(NS_WIN_LOW_INTEGRITY_TEMP, NS_GET_IID(nsIFile), - getter_AddRefs(lowIntegrityTemp)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - // Undefine returns a failure if the property is not already set. - unused << directoryService->Undefine(NS_OS_TEMP_DIR); - rv = directoryService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - // Set TEMP and TMP environment variables. - nsAutoString lowIntegrityTempPath; - rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get()); - NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path"); - setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get()); - NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path"); -} - -void -ContentChild::CleanUpSandboxEnvironment() -{ - // Sandbox environment is only currently a low integrity temp, which only - // makes sense for sandbox pref level 1 (and will eventually not be needed - // at all, once all file access is via chrome/broker process). - if (Preferences::GetInt("security.sandbox.content.level") != 1) { - return; - } - - nsresult rv; - nsCOMPtr directoryService = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr lowIntegrityTemp; - rv = directoryService->Get(NS_WIN_LOW_INTEGRITY_TEMP, NS_GET_IID(nsIFile), - getter_AddRefs(lowIntegrityTemp)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - // Don't check the return value as the directory will only have been created - // if it has been used. - unused << lowIntegrityTemp->Remove(/* aRecursive */ true); -} -#endif - #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX) #include @@ -1268,12 +1197,6 @@ ContentChild::RecvSetProcessSandbox() SetContentProcessSandbox(); #elif defined(XP_WIN) mozilla::SandboxTarget::Instance()->StartSandbox(); - // Sandbox environment is only currently a low integrity temp, which only - // makes sense for sandbox pref level 1 (and will eventually not be needed - // at all, once all file access is via chrome/broker process). - if (Preferences::GetInt("security.sandbox.content.level") == 1) { - SetUpSandboxEnvironment(); - } #elif defined(XP_MACOSX) StartMacOSContentSandbox(); #endif diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 76efe546599..8f83fc716e5 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -135,11 +135,6 @@ public: AllocPProcessHangMonitorChild(Transport* aTransport, ProcessId aOtherProcess) override; -#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) - // Cleans up any resources used by the process when sandboxed. - void CleanUpSandboxEnvironment(); -#endif - virtual bool RecvSetProcessSandbox() override; PBackgroundChild* diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp index 2aa55e57182..cf1f1913e75 100644 --- a/dom/ipc/ContentProcess.cpp +++ b/dom/ipc/ContentProcess.cpp @@ -8,11 +8,87 @@ #include "ContentProcess.h" +#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) +#include "mozilla/Preferences.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#endif + using mozilla::ipc::IOThreadChild; namespace mozilla { namespace dom { +#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) +static already_AddRefed +GetLowIntegrityTemp() +{ + MOZ_ASSERT(nsDirectoryService::gService, + "GetLowIntegrityTemp relies on nsDirectoryService being initialized"); + + // A low integrity temp only currently makes sense for sandbox pref level 1. + if (Preferences::GetInt("security.sandbox.content.level") != 1) { + return nullptr; + } + + nsCOMPtr lowIntegrityTemp; + nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP, + NS_GET_IID(nsIFile), + getter_AddRefs(lowIntegrityTemp)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + return lowIntegrityTemp.forget(); +} + +static void +SetUpSandboxEnvironment() +{ + MOZ_ASSERT(nsDirectoryService::gService, + "SetUpSandboxEnvironment relies on nsDirectoryService being initialized"); + + // Setup to use a low integrity temp if available. + nsCOMPtr lowIntegrityTemp = GetLowIntegrityTemp(); + if (!lowIntegrityTemp) { + return; + } + + // Undefine returns a failure if the property is not already set. + unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR); + nsresult rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + // Set TEMP and TMP environment variables. + nsAutoString lowIntegrityTempPath; + rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get()); + NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path"); + setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get()); + NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path"); +} + +static void +CleanUpSandboxEnvironment() +{ + // Remove low integrity temp if it exists. + nsCOMPtr lowIntegrityTemp = GetLowIntegrityTemp(); + if (!lowIntegrityTemp) { + return; + } + + // Don't check the return value as the directory will only have been created + // if it has been used. + unused << lowIntegrityTemp->Remove(/* aRecursive */ true); +} +#endif + void ContentProcess::SetAppDir(const nsACString& aPath) { @@ -27,6 +103,10 @@ ContentProcess::Init() IOThreadChild::channel()); mXREEmbed.Start(); mContent.InitXPCOM(); + +#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) + SetUpSandboxEnvironment(); +#endif return true; } @@ -35,7 +115,7 @@ void ContentProcess::CleanUp() { #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) - mContent.CleanUpSandboxEnvironment(); + CleanUpSandboxEnvironment(); #endif mXREEmbed.Stop(); } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index eda4992b210..eb7fdae5dea 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1693,6 +1693,10 @@ bool TabChild::RecvLoadURL(const nsCString& aURI, const BrowserConfiguration& aConfiguration) { + if (!InitTabChildGlobal()) { + return false; + } + SetProcessNameToAppName(); nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(), diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 2515602fb2b..de7bd92a297 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -266,7 +266,6 @@ TabParent::TabParent(nsIContentParent* aManager, , mOrientation(0) , mDPI(0) , mDefaultScale(0) - , mShown(false) , mUpdatedDimensions(false) , mChromeOffset(0, 0) , mManager(aManager) @@ -754,13 +753,6 @@ TabParent::LoadURL(nsIURI* aURI) return; } - if (!mShown) { - NS_WARNING(nsPrintfCString("TabParent::LoadURL(%s) called before " - "Show(). Ignoring LoadURL.\n", - spec.get()).get()); - return; - } - uint32_t appId = OwnOrContainingAppId(); if (mSendOfflineStatus && NS_IsAppOffline(appId)) { // If the app is offline in the parent process @@ -824,8 +816,6 @@ TabParent::LoadURL(nsIURI* aURI) void TabParent::Show(const ScreenIntSize& size, bool aParentIsActive) { - // sigh - mShown = true; mDimensions = size; if (mIsDestroyed) { return; diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index b1c4c061d53..2f843f3c382 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -429,7 +429,6 @@ protected: ScreenOrientation mOrientation; float mDPI; CSSToLayoutDeviceScale mDefaultScale; - bool mShown; bool mUpdatedDimensions; nsIntPoint mChromeOffset; diff --git a/dom/media/fmp4/AVCCDecoderModule.cpp b/dom/media/fmp4/AVCCDecoderModule.cpp deleted file mode 100644 index 1e2ab895875..00000000000 --- a/dom/media/fmp4/AVCCDecoderModule.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "AVCCDecoderModule.h" -#include "ImageContainer.h" -#include "MediaTaskQueue.h" -#include "mp4_demuxer/DecoderData.h" -#include "mp4_demuxer/AnnexB.h" -#include "mp4_demuxer/H264.h" - -namespace mozilla -{ - -class AVCCMediaDataDecoder : public MediaDataDecoder { -public: - - AVCCMediaDataDecoder(PlatformDecoderModule* aPDM, - const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableMediaTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback); - - virtual ~AVCCMediaDataDecoder(); - - virtual nsresult Init() override; - virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override; - virtual nsresult Flush() override; - virtual nsresult Drain() override; - virtual nsresult Shutdown() override; - virtual bool IsWaitingMediaResources() override; - virtual bool IsDormantNeeded() override; - virtual void AllocateMediaResources() override; - virtual void ReleaseMediaResources() override; - virtual bool IsHardwareAccelerated() const override; - -private: - // Will create the required MediaDataDecoder if we have a AVC SPS. - // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and - // will set mError accordingly. - nsresult CreateDecoder(); - nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample); - nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample); - void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData); - - nsRefPtr mPDM; - mp4_demuxer::VideoDecoderConfig mCurrentConfig; - layers::LayersBackend mLayersBackend; - nsRefPtr mImageContainer; - nsRefPtr mVideoTaskQueue; - MediaDataDecoderCallback* mCallback; - nsRefPtr mDecoder; - nsresult mLastError; -}; - -AVCCMediaDataDecoder::AVCCMediaDataDecoder(PlatformDecoderModule* aPDM, - const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableMediaTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) - : mPDM(aPDM) - , mCurrentConfig(aConfig) - , mLayersBackend(aLayersBackend) - , mImageContainer(aImageContainer) - , mVideoTaskQueue(aVideoTaskQueue) - , mCallback(aCallback) - , mDecoder(nullptr) - , mLastError(NS_OK) -{ - CreateDecoder(); -} - -AVCCMediaDataDecoder::~AVCCMediaDataDecoder() -{ -} - -nsresult -AVCCMediaDataDecoder::Init() -{ - if (mDecoder) { - return mDecoder->Init(); - } - return mLastError; -} - -nsresult -AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) -{ - if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) { - return NS_ERROR_FAILURE; - } - nsresult rv; - if (!mDecoder) { - // It is not possible to create an AVCC H264 decoder without SPS. - // As such, creation will fail if the extra_data just extracted doesn't - // contain a SPS. - rv = CreateDecoderAndInit(aSample); - if (rv == NS_ERROR_NOT_INITIALIZED) { - // We are missing the required SPS to create the decoder. - // Ignore for the time being, the MP4Sample will be dropped. - return NS_OK; - } - } else { - rv = CheckForSPSChange(aSample); - } - NS_ENSURE_SUCCESS(rv, rv); - - aSample->extra_data = mCurrentConfig.extra_data; - - return mDecoder->Input(aSample); -} - -nsresult -AVCCMediaDataDecoder::Flush() -{ - if (mDecoder) { - return mDecoder->Flush(); - } - return mLastError; -} - -nsresult -AVCCMediaDataDecoder::Drain() -{ - if (mDecoder) { - return mDecoder->Drain(); - } - return mLastError; -} - -nsresult -AVCCMediaDataDecoder::Shutdown() -{ - if (mDecoder) { - nsresult rv = mDecoder->Shutdown(); - mDecoder = nullptr; - return rv; - } - return NS_OK; -} - -bool -AVCCMediaDataDecoder::IsWaitingMediaResources() -{ - if (mDecoder) { - return mDecoder->IsWaitingMediaResources(); - } - return MediaDataDecoder::IsWaitingMediaResources(); -} - -bool -AVCCMediaDataDecoder::IsDormantNeeded() -{ - return true; -} - -void -AVCCMediaDataDecoder::AllocateMediaResources() -{ - // Nothing to do, decoder will be allocated on the fly when required. -} - -void -AVCCMediaDataDecoder::ReleaseMediaResources() -{ - Shutdown(); -} - -nsresult -AVCCMediaDataDecoder::CreateDecoder() -{ - if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) { - // nothing found yet, will try again later - return NS_ERROR_NOT_INITIALIZED; - } - UpdateConfigFromExtraData(mCurrentConfig.extra_data); - - mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig, - mLayersBackend, - mImageContainer, - mVideoTaskQueue, - mCallback); - if (!mDecoder) { - mLastError = NS_ERROR_FAILURE; - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult -AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample) -{ - nsRefPtr extra_data = - mp4_demuxer::AnnexB::ExtractExtraData(aSample); - if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) { - return NS_ERROR_NOT_INITIALIZED; - } - UpdateConfigFromExtraData(extra_data); - - nsresult rv = CreateDecoder(); - NS_ENSURE_SUCCESS(rv, rv); - return Init(); -} - -bool -AVCCMediaDataDecoder::IsHardwareAccelerated() const -{ - if (mDecoder) { - return mDecoder->IsHardwareAccelerated(); - } - return MediaDataDecoder::IsHardwareAccelerated(); -} - -nsresult -AVCCMediaDataDecoder::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample) -{ - nsRefPtr extra_data = - mp4_demuxer::AnnexB::ExtractExtraData(aSample); - if (!mp4_demuxer::AnnexB::HasSPS(extra_data) || - mp4_demuxer::AnnexB::CompareExtraData(extra_data, - mCurrentConfig.extra_data)) { - return NS_OK; - } - // The SPS has changed, signal to flush the current decoder and create a - // new one. - mDecoder->Flush(); - ReleaseMediaResources(); - return CreateDecoderAndInit(aSample); -} - -void -AVCCMediaDataDecoder::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData) -{ - mp4_demuxer::SPSData spsdata; - if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) && - spsdata.pic_width > 0 && spsdata.pic_height > 0) { - mp4_demuxer::H264::EnsureSPSIsSane(spsdata); - mCurrentConfig.image_width = spsdata.pic_width; - mCurrentConfig.image_height = spsdata.pic_height; - mCurrentConfig.display_width = spsdata.display_width; - mCurrentConfig.display_height = spsdata.display_height; - } - mCurrentConfig.extra_data = aExtraData; -} - -// AVCCDecoderModule - -AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM) -: mPDM(aPDM) -{ - MOZ_ASSERT(aPDM); -} - -AVCCDecoderModule::~AVCCDecoderModule() -{ -} - -nsresult -AVCCDecoderModule::Startup() -{ - return mPDM->Startup(); -} - -already_AddRefed -AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableMediaTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) -{ - nsRefPtr decoder; - - if ((!aConfig.mime_type.EqualsLiteral("video/avc") && - !aConfig.mime_type.EqualsLiteral("video/mp4")) || - !mPDM->DecoderNeedsAVCC(aConfig)) { - // There is no need for an AVCC wrapper for non-AVC content. - decoder = mPDM->CreateVideoDecoder(aConfig, - aLayersBackend, - aImageContainer, - aVideoTaskQueue, - aCallback); - } else { - decoder = new AVCCMediaDataDecoder(mPDM, - aConfig, - aLayersBackend, - aImageContainer, - aVideoTaskQueue, - aCallback); - } - return decoder.forget(); -} - -already_AddRefed -AVCCDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, - FlushableMediaTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) -{ - return mPDM->CreateAudioDecoder(aConfig, - aAudioTaskQueue, - aCallback); -} - -bool -AVCCDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) -{ - return mPDM->SupportsAudioMimeType(aMimeType); -} - -bool -AVCCDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType) -{ - return mPDM->SupportsVideoMimeType(aMimeType); -} - -} // namespace mozilla diff --git a/dom/media/fmp4/AVCCDecoderModule.h b/dom/media/fmp4/AVCCDecoderModule.h deleted file mode 100644 index 5e3d6ec0472..00000000000 --- a/dom/media/fmp4/AVCCDecoderModule.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifndef mozilla_AVCCDecoderModule_h -#define mozilla_AVCCDecoderModule_h - -#include "PlatformDecoderModule.h" - -namespace mozilla { - -class AVCCMediaDataDecoder; - -// AVCCDecoderModule is a PlatformDecoderModule wrapper used to ensure that -// only AVCC format is fed to the underlying PlatformDecoderModule. -// The AVCCDecoderModule allows playback of content where the SPS NAL may not be -// provided in the init segment (e.g. AVC3 or Annex B) -// AVCCDecoderModule will monitor the input data, and will delay creation of the -// MediaDataDecoder until a SPS and PPS NALs have been extracted. -// -// AVCC-only decoder modules are AppleVideoDecoder and EMEH264Decoder. - -class AVCCDecoderModule : public PlatformDecoderModule { -public: - explicit AVCCDecoderModule(PlatformDecoderModule* aPDM); - virtual ~AVCCDecoderModule(); - - virtual nsresult Startup() override; - - virtual already_AddRefed - CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableMediaTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) override; - - virtual already_AddRefed - CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, - FlushableMediaTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) override; - - virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override; - virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override; - -private: - nsRefPtr mPDM; -}; - -} // namespace mozilla - -#endif // mozilla_AVCCDecoderModule_h diff --git a/dom/media/fmp4/BlankDecoderModule.cpp b/dom/media/fmp4/BlankDecoderModule.cpp index 8ce03235b6d..ccb22cdf925 100644 --- a/dom/media/fmp4/BlankDecoderModule.cpp +++ b/dom/media/fmp4/BlankDecoderModule.cpp @@ -238,11 +238,17 @@ public: } virtual bool - SupportsAudioMimeType(const nsACString& aMimeType) override + SupportsMimeType(const nsACString& aMimeType) override { return true; } + ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const + { + return kNeedNone; + } + }; already_AddRefed CreateBlankDecoderModule() diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index 33af6dc3167..1436ede1014 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -158,6 +158,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder) , mIsEncrypted(false) , mAreDecodersSetup(false) , mIndexReady(false) + , mLastSeenEnd(-1) , mDemuxerMonitor("MP4 Demuxer") #if defined(MP4_READER_DORMANT_HEURISTIC) , mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)) @@ -343,7 +344,7 @@ MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType) { return (aMimeType.EqualsLiteral("audio/mpeg") || aMimeType.EqualsLiteral("audio/mp4a-latm")) && - mPlatform->SupportsAudioMimeType(aMimeType); + mPlatform->SupportsMimeType(aMimeType); } bool @@ -352,7 +353,7 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType) return (aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/avc") || aMimeType.EqualsLiteral("video/x-vnd.on2.vp6")) && - mPlatform->SupportsVideoMimeType(aMimeType); + mPlatform->SupportsMimeType(aMimeType); } void @@ -513,9 +514,10 @@ MP4Reader::EnsureDecodersSetup() NS_ENSURE_TRUE(IsSupportedAudioMimeType(mDemuxer->AudioConfig().mime_type), false); - mAudio.mDecoder = mPlatform->CreateAudioDecoder(mDemuxer->AudioConfig(), - mAudio.mTaskQueue, - mAudio.mCallback); + mAudio.mDecoder = + mPlatform->CreateDecoder(mDemuxer->AudioConfig(), + mAudio.mTaskQueue, + mAudio.mCallback); NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, false); nsresult rv = mAudio.mDecoder->Init(); NS_ENSURE_SUCCESS(rv, false); @@ -534,11 +536,12 @@ MP4Reader::EnsureDecodersSetup() mVideo.mTaskQueue, mVideo.mCallback); } else { - mVideo.mDecoder = mPlatform->CreateVideoDecoder(mDemuxer->VideoConfig(), - mLayersBackendType, - mDecoder->GetImageContainer(), - mVideo.mTaskQueue, - mVideo.mCallback); + mVideo.mDecoder = + mPlatform->CreateDecoder(mDemuxer->VideoConfig(), + mVideo.mTaskQueue, + mVideo.mCallback, + mLayersBackendType, + mDecoder->GetImageContainer()); } NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false); nsresult rv = mVideo.mDecoder->Init(); @@ -600,7 +603,7 @@ MP4Reader::DisableHardwareAcceleration() mSharedDecoderManager->DisableHardwareAcceleration(); const VideoDecoderConfig& video = mDemuxer->VideoConfig(); - if (!mSharedDecoderManager->Recreate(video, mLayersBackendType, mDecoder->GetImageContainer())) { + if (!mSharedDecoderManager->Recreate(video)) { MonitorAutoLock mon(mVideo.mMonitor); mVideo.mError = true; if (mVideo.HasPromise()) { @@ -1158,4 +1161,39 @@ MP4Reader::VideoIsHardwareAccelerated() const return mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(); } +void +MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (mShutdown) { + return; + } + + if (mLastSeenEnd < 0) { + MonitorAutoLock mon(mDemuxerMonitor); + mLastSeenEnd = mDecoder->GetResource()->GetLength(); + if (mLastSeenEnd < 0) { + // We dont have a length. Demuxer would have been blocking already. + return; + } + } + int64_t end = aOffset + aLength; + if (end <= mLastSeenEnd) { + return; + } + mLastSeenEnd = end; + + if (HasVideo()) { + auto& decoder = GetDecoderData(kVideo); + MonitorAutoLock lock(decoder.mMonitor); + decoder.mDemuxEOS = false; + } + if (HasAudio()) { + auto& decoder = GetDecoderData(kAudio); + MonitorAutoLock lock(decoder.mMonitor); + decoder.mDemuxEOS = false; + } +} + } // namespace mozilla diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index 1519c772d2d..87e18630b2c 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -77,6 +77,7 @@ public: virtual bool IsMediaSeekable() override; virtual int64_t GetEvictionOffset(double aTime) override; + virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override; virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override; @@ -287,6 +288,7 @@ private: bool mAreDecodersSetup; bool mIndexReady; + int64_t mLastSeenEnd; Monitor mDemuxerMonitor; nsRefPtr mSharedDecoderManager; diff --git a/dom/media/fmp4/PlatformDecoderModule.cpp b/dom/media/fmp4/PlatformDecoderModule.cpp index 1c81b03c51c..b34525df983 100644 --- a/dom/media/fmp4/PlatformDecoderModule.cpp +++ b/dom/media/fmp4/PlatformDecoderModule.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PlatformDecoderModule.h" -#include "AVCCDecoderModule.h" #ifdef XP_WIN #include "WMFDecoderModule.h" @@ -32,6 +31,9 @@ #include "SharedThreadPool.h" #include "MediaTaskQueue.h" +#include "mp4_demuxer/DecoderData.h" +#include "H264Converter.h" + namespace mozilla { extern already_AddRefed CreateBlankDecoderModule(); @@ -107,10 +109,7 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy, } nsRefPtr emepdm( - new AVCCDecoderModule(new EMEDecoderModule(aProxy, - pdm, - cdmDecodesAudio, - cdmDecodesVideo))); + new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo)); return emepdm.forget(); } #endif @@ -151,13 +150,12 @@ PlatformDecoderModule::CreatePDM() if (sFFmpegDecoderEnabled) { nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); if (m) { - nsRefPtr m2(new AVCCDecoderModule(m)); - return m2.forget(); + return m.forget(); } } #endif #ifdef MOZ_APPLEMEDIA - nsRefPtr m(new AVCCDecoderModule(new AppleDecoderModule())); + nsRefPtr m(new AppleDecoderModule()); return m.forget(); #endif #ifdef MOZ_GONK_MEDIACODEC @@ -173,28 +171,55 @@ PlatformDecoderModule::CreatePDM() } #endif if (sGMPDecoderEnabled) { - nsRefPtr m(new AVCCDecoderModule(new GMPDecoderModule())); + nsRefPtr m(new GMPDecoderModule()); return m.forget(); } return nullptr; } -bool -PlatformDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) +already_AddRefed +PlatformDecoderModule::CreateDecoder(const mp4_demuxer::TrackConfig& aConfig, + FlushableMediaTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) { - return aMimeType.EqualsLiteral("audio/mp4a-latm"); + nsRefPtr m; + + if (aConfig.IsAudioConfig()) { + m = CreateAudioDecoder(static_cast(aConfig), + aTaskQueue, + aCallback); + return m.forget(); + } + + if (!aConfig.IsVideoConfig()) { + return nullptr; + } + + if (H264Converter::IsH264(aConfig)) { + m = new H264Converter(this, + static_cast(aConfig), + aLayersBackend, + aImageContainer, + aTaskQueue, + aCallback); + } else { + m = CreateVideoDecoder(static_cast(aConfig), + aLayersBackend, + aImageContainer, + aTaskQueue, + aCallback); + } + return m.forget(); } bool -PlatformDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType) +PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) { - return aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/avc"); -} - -bool -PlatformDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) -{ - return false; + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); } } // namespace mozilla diff --git a/dom/media/fmp4/PlatformDecoderModule.h b/dom/media/fmp4/PlatformDecoderModule.h index 836d939ff81..97d50659083 100644 --- a/dom/media/fmp4/PlatformDecoderModule.h +++ b/dom/media/fmp4/PlatformDecoderModule.h @@ -14,6 +14,7 @@ #include namespace mp4_demuxer { +class TrackConfig; class VideoDecoderConfig; class AudioDecoderConfig; class MP4Sample; @@ -86,7 +87,44 @@ public: bool aHasVideo); #endif - // Creates an H.264 decoder. The layers backend is passed in so that + // Creates a decoder. + // See CreateVideoDecoder and CreateAudioDecoder for implementation details. + virtual already_AddRefed + CreateDecoder(const mp4_demuxer::TrackConfig& aConfig, + FlushableMediaTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, + layers::ImageContainer* aImageContainer = nullptr); + + // An audio decoder module must support AAC by default. + // A video decoder must support H264 by default. + // If more codecs are to be supported, SupportsMimeType will have + // to be extended + virtual bool SupportsMimeType(const nsACString& aMimeType); + + enum ConversionRequired { + kNeedNone, + kNeedAVCC, + kNeedAnnexB, + }; + + // Indicates that the decoder requires a specific format. + // The PlatformDecoderModule will convert the demuxed data accordingly before + // feeding it to MediaDataDecoder::Input. + virtual ConversionRequired DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const = 0; + + virtual void DisableHardwareAcceleration() {} + + virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const { + return true; + } + +protected: + PlatformDecoderModule() {} + virtual ~PlatformDecoderModule() {} + + friend class H264Converter; + // Creates a Video decoder. The layers backend is passed in so that // decoders can determine whether hardware accelerated decoding can be used. // Asynchronous decoding of video should be done in runnables dispatched // to aVideoTaskQueue. If the task queue isn't needed, the decoder should @@ -99,10 +137,10 @@ public: // This is called on the decode task queue. virtual already_AddRefed CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableMediaTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) = 0; + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableMediaTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) = 0; // Creates an Audio decoder with the specified properties. // Asynchronous decoding of audio should be done in runnables dispatched to @@ -119,24 +157,6 @@ public: FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) = 0; - // An audio decoder module must support AAC by default. - // If more audio codec is to be supported, SupportsAudioMimeType will have - // to be extended - virtual bool SupportsAudioMimeType(const nsACString& aMimeType); - virtual bool SupportsVideoMimeType(const nsACString& aMimeType); - - // Indicates if the video decoder requires AVCC format. - virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig); - - virtual void DisableHardwareAcceleration() {} - - virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const { - return true; - } - -protected: - PlatformDecoderModule() {} - virtual ~PlatformDecoderModule() {} // Caches pref media.fragmented-mp4.use-blank-decoder static bool sUseBlankDecoder; static bool sFFmpegDecoderEnabled; @@ -213,7 +233,6 @@ public: // The MP4Reader will not call Input() while it's calling Flush(). virtual nsresult Flush() = 0; - // Causes all complete samples in the pipeline that can be decoded to be // output. If the decoder can't produce samples from the current output, // it drops the input samples. The decoder may be holding onto samples @@ -244,6 +263,15 @@ public: virtual void AllocateMediaResources() {} virtual void ReleaseMediaResources() {} virtual bool IsHardwareAccelerated() const { return false; } + + // ConfigurationChanged will be called to inform the video or audio decoder + // that the format of the next input sample is about to change. + // If video decoder, aConfig will be a VideoDecoderConfig object. + // If audio decoder, aConfig will be a AudioDecoderConfig object. + virtual nsresult ConfigurationChanged(const mp4_demuxer::TrackConfig& aConfig) + { + return NS_OK; + } }; } // namespace mozilla diff --git a/dom/media/fmp4/SharedDecoderManager.cpp b/dom/media/fmp4/SharedDecoderManager.cpp index f256f89e94f..a4acd02a91f 100644 --- a/dom/media/fmp4/SharedDecoderManager.cpp +++ b/dom/media/fmp4/SharedDecoderManager.cpp @@ -83,15 +83,18 @@ SharedDecoderManager::CreateVideoDecoder( MediaDataDecoderCallback* aCallback) { if (!mDecoder) { + mLayersBackend = aLayersBackend; + mImageContainer = aImageContainer; // We use the manager's task queue for the decoder, rather than the one // passed in, so that none of the objects sharing the decoder can shutdown // the task queue while we're potentially still using it for a *different* // object also sharing the decoder. - mDecoder = aPDM->CreateVideoDecoder(aConfig, - aLayersBackend, - aImageContainer, - mTaskQueue, - mCallback); + mDecoder = + aPDM->CreateDecoder(aConfig, + mTaskQueue, + mCallback, + mLayersBackend, + mImageContainer); if (!mDecoder) { mPDM = nullptr; return nullptr; @@ -113,17 +116,15 @@ SharedDecoderManager::DisableHardwareAcceleration() } bool -SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) +SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig) { mDecoder->Flush(); mDecoder->Shutdown(); - mDecoder = mPDM->CreateVideoDecoder(aConfig, - aLayersBackend, - aImageContainer, - mTaskQueue, - mCallback); + mDecoder = mPDM->CreateDecoder(aConfig, + mTaskQueue, + mCallback, + mLayersBackend, + mImageContainer); if (!mDecoder) { return false; } diff --git a/dom/media/fmp4/SharedDecoderManager.h b/dom/media/fmp4/SharedDecoderManager.h index 56199bc74e1..b79610ea1f5 100644 --- a/dom/media/fmp4/SharedDecoderManager.h +++ b/dom/media/fmp4/SharedDecoderManager.h @@ -42,9 +42,7 @@ public: friend class SharedDecoderCallback; void DisableHardwareAcceleration(); - bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer); + bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig); private: virtual ~SharedDecoderManager(); @@ -52,6 +50,8 @@ private: nsRefPtr mPDM; nsRefPtr mDecoder; + layers::LayersBackend mLayersBackend; + nsRefPtr mImageContainer; nsRefPtr mTaskQueue; SharedDecoderProxy* mActiveProxy; MediaDataDecoderCallback* mActiveCallback; diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index 81ab97191a0..546bc97bd6f 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -63,10 +63,6 @@ public: } virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override { - if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) { - return NS_ERROR_OUT_OF_MEMORY; - } - return MediaCodecDataDecoder::Input(aSample); } @@ -248,8 +244,13 @@ public: }; -bool AndroidDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) { - return static_cast(CreateDecoder(aMimeType)); +bool AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType) +{ + if (aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc")) { + return true; + } + return static_cast(mozilla::CreateDecoder(aMimeType)); } already_AddRefed @@ -296,6 +297,16 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& } +PlatformDecoderModule::ConversionRequired +AndroidDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const +{ + if (aConfig.IsVideoConfig()) { + return kNeedAnnexB; + } else { + return kNeedNone; + } +} + MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType, const nsACString& aMimeType, MediaFormat::Param aFormat, diff --git a/dom/media/fmp4/android/AndroidDecoderModule.h b/dom/media/fmp4/android/AndroidDecoderModule.h index 7804f387817..8115912b395 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.h +++ b/dom/media/fmp4/android/AndroidDecoderModule.h @@ -35,7 +35,10 @@ public: AndroidDecoderModule() {} virtual ~AndroidDecoderModule() {} - virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override; + virtual bool SupportsMimeType(const nsACString& aMimeType) override; + + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; }; class MediaCodecDataDecoder : public MediaDataDecoder { diff --git a/dom/media/fmp4/apple/AppleDecoderModule.cpp b/dom/media/fmp4/apple/AppleDecoderModule.cpp index ee7ae69056c..adcf9791f08 100644 --- a/dom/media/fmp4/apple/AppleDecoderModule.cpp +++ b/dom/media/fmp4/apple/AppleDecoderModule.cpp @@ -192,15 +192,20 @@ AppleDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aC } bool -AppleDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) +AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType) { - return aMimeType.EqualsLiteral("audio/mp4a-latm") || aMimeType.EqualsLiteral("audio/mpeg"); + return aMimeType.EqualsLiteral("audio/mpeg") || + PlatformDecoderModule::SupportsMimeType(aMimeType); } -bool -AppleDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) +PlatformDecoderModule::ConversionRequired +AppleDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const { - return true; + if (aConfig.IsVideoConfig()) { + return kNeedAVCC; + } else { + return kNeedNone; + } } } // namespace mozilla diff --git a/dom/media/fmp4/apple/AppleDecoderModule.h b/dom/media/fmp4/apple/AppleDecoderModule.h index 2ee205b4ddf..e90d926df4d 100644 --- a/dom/media/fmp4/apple/AppleDecoderModule.h +++ b/dom/media/fmp4/apple/AppleDecoderModule.h @@ -32,9 +32,10 @@ public: FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) override; - virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override; - virtual bool - DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override; + virtual bool SupportsMimeType(const nsACString& aMimeType) override; + + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; static void Init(); static nsresult CanDecode(); diff --git a/dom/media/fmp4/eme/EMEDecoderModule.cpp b/dom/media/fmp4/eme/EMEDecoderModule.cpp index 9e8a254d619..220c03c3e69 100644 --- a/dom/media/fmp4/eme/EMEDecoderModule.cpp +++ b/dom/media/fmp4/eme/EMEDecoderModule.cpp @@ -253,11 +253,12 @@ EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig, return wrapper.forget(); } - nsRefPtr decoder(mPDM->CreateVideoDecoder(aConfig, - aLayersBackend, - aImageContainer, - aVideoTaskQueue, - aCallback)); + nsRefPtr decoder( + mPDM->CreateDecoder(aConfig, + aVideoTaskQueue, + aCallback, + aLayersBackend, + aImageContainer)); if (!decoder) { return nullptr; } @@ -286,9 +287,8 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig, return wrapper.forget(); } - nsRefPtr decoder(mPDM->CreateAudioDecoder(aConfig, - aAudioTaskQueue, - aCallback)); + nsRefPtr decoder( + mPDM->CreateDecoder(aConfig, aAudioTaskQueue, aCallback)); if (!decoder) { return nullptr; } @@ -303,10 +303,14 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig, return emeDecoder.forget(); } -bool -EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) +PlatformDecoderModule::ConversionRequired +EMEDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const { - return mCDMDecodesVideo && aConfig.crypto.valid; + if (aConfig.IsVideoConfig()) { + return kNeedAVCC; + } else { + return kNeedNone; + } } } // namespace mozilla diff --git a/dom/media/fmp4/eme/EMEDecoderModule.h b/dom/media/fmp4/eme/EMEDecoderModule.h index e83d5576b01..c6fee6d0cf1 100644 --- a/dom/media/fmp4/eme/EMEDecoderModule.h +++ b/dom/media/fmp4/eme/EMEDecoderModule.h @@ -42,8 +42,8 @@ public: FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) override; - virtual bool - DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override; + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; private: nsRefPtr mProxy; diff --git a/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h b/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h index 7b157edff73..2b63850226e 100644 --- a/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h @@ -51,19 +51,22 @@ public: return decoder.forget(); } - virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override + virtual bool SupportsMimeType(const nsACString& aMimeType) override { - return FFmpegAudioDecoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; + return FFmpegAudioDecoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE || + FFmpegH264Decoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; } - virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override { - return FFmpegH264Decoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; - } - - virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override - { - return true; + if (aConfig.IsVideoConfig() && + (aConfig.mime_type.EqualsLiteral("video/avc") || + aConfig.mime_type.EqualsLiteral("video/mp4"))) { + return PlatformDecoderModule::kNeedAVCC; + } else { + return kNeedNone; + } } }; diff --git a/dom/media/fmp4/gmp/GMPDecoderModule.cpp b/dom/media/fmp4/gmp/GMPDecoderModule.cpp index 8ccbbff22ce..208ac235d89 100644 --- a/dom/media/fmp4/gmp/GMPDecoderModule.cpp +++ b/dom/media/fmp4/gmp/GMPDecoderModule.cpp @@ -75,11 +75,15 @@ GMPDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCon return wrapper.forget(); } -bool -GMPDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) +PlatformDecoderModule::ConversionRequired +GMPDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const { // GMPVideoCodecType::kGMPVideoCodecH264 specifies that encoded frames must be in AVCC format. - return true; + if (aConfig.IsVideoConfig()) { + return kNeedAVCC; + } else { + return kNeedNone; + } } } // namespace mozilla diff --git a/dom/media/fmp4/gmp/GMPDecoderModule.h b/dom/media/fmp4/gmp/GMPDecoderModule.h index fd88157a77f..60876e7db94 100644 --- a/dom/media/fmp4/gmp/GMPDecoderModule.h +++ b/dom/media/fmp4/gmp/GMPDecoderModule.h @@ -31,7 +31,8 @@ public: FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) override; - virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override; + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; }; } // namespace mozilla diff --git a/dom/media/fmp4/gonk/GonkDecoderModule.cpp b/dom/media/fmp4/gonk/GonkDecoderModule.cpp index 55185a9e19b..fea5778b896 100644 --- a/dom/media/fmp4/gonk/GonkDecoderModule.cpp +++ b/dom/media/fmp4/gonk/GonkDecoderModule.cpp @@ -51,4 +51,14 @@ GonkDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCo return decoder.forget(); } +PlatformDecoderModule::ConversionRequired +GonkDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const +{ + if (aConfig.IsVideoConfig()) { + return kNeedAVCC; + } else { + return kNeedNone; + } +} + } // namespace mozilla diff --git a/dom/media/fmp4/gonk/GonkDecoderModule.h b/dom/media/fmp4/gonk/GonkDecoderModule.h index 9afc221b3e6..eb0d4989d72 100644 --- a/dom/media/fmp4/gonk/GonkDecoderModule.h +++ b/dom/media/fmp4/gonk/GonkDecoderModule.h @@ -31,6 +31,9 @@ public: MediaDataDecoderCallback* aCallback) override; static void Init(); + + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; }; } // namespace mozilla diff --git a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp index 27b587b0563..f700ed3a992 100644 --- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp @@ -452,20 +452,6 @@ GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) 0); } -bool -GonkVideoDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) -{ - if (aSample != nullptr) { - // We must prepare samples in AVC Annex B. - if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) { - GVDM_LOG("Failed to convert sample to annex B!"); - return false; - } - } - - return true; -} - void GonkVideoDecoderManager::ClearQueueFrameTime() { diff --git a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h index ab95441347f..1519c5d5206 100644 --- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h +++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h @@ -58,8 +58,6 @@ public: static void RecycleCallback(TextureClient* aClient, void* aClosure); protected: - virtual bool PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) override; - virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) override; private: diff --git a/dom/media/fmp4/moz.build b/dom/media/fmp4/moz.build index 2b74fad737c..0e19cc128ed 100644 --- a/dom/media/fmp4/moz.build +++ b/dom/media/fmp4/moz.build @@ -5,21 +5,21 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ - 'AVCCDecoderModule.h', 'MP4Decoder.h', 'MP4Reader.h', 'MP4Stream.h', 'PlatformDecoderModule.h', 'SharedDecoderManager.h', + 'wrappers/H264Converter.h' ] UNIFIED_SOURCES += [ - 'AVCCDecoderModule.cpp', 'BlankDecoderModule.cpp', 'MP4Decoder.cpp', 'MP4Stream.cpp', 'PlatformDecoderModule.cpp', 'SharedDecoderManager.cpp', + 'wrappers/H264Converter.cpp' ] SOURCES += [ diff --git a/dom/media/fmp4/wmf/WMFDecoderModule.cpp b/dom/media/fmp4/wmf/WMFDecoderModule.cpp index a12b4e8228e..bd7f639ff9f 100644 --- a/dom/media/fmp4/wmf/WMFDecoderModule.cpp +++ b/dom/media/fmp4/wmf/WMFDecoderModule.cpp @@ -121,19 +121,26 @@ WMFDecoderModule::SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& } bool -WMFDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType) +WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/avc") || aMimeType.EqualsLiteral("video/webm; codecs=vp8") || - aMimeType.EqualsLiteral("video/webm; codecs=vp9"); + aMimeType.EqualsLiteral("video/webm; codecs=vp9") || + aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("audio/mpeg"); } -bool -WMFDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) +PlatformDecoderModule::ConversionRequired +WMFDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const { - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("audio/mpeg"); + if (aConfig.IsVideoConfig() && + (aConfig.mime_type.EqualsLiteral("video/avc") || + aConfig.mime_type.EqualsLiteral("video/mp4"))) { + return kNeedAnnexB; + } else { + return kNeedNone; + } } static bool diff --git a/dom/media/fmp4/wmf/WMFDecoderModule.h b/dom/media/fmp4/wmf/WMFDecoderModule.h index da2c2e3a3f4..84dacbda3bb 100644 --- a/dom/media/fmp4/wmf/WMFDecoderModule.h +++ b/dom/media/fmp4/wmf/WMFDecoderModule.h @@ -31,8 +31,7 @@ public: FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) override; - bool SupportsVideoMimeType(const nsACString& aMimeType) override; - bool SupportsAudioMimeType(const nsACString& aMimeType) override; + bool SupportsMimeType(const nsACString& aMimeType) override; virtual void DisableHardwareAcceleration() override { @@ -41,6 +40,9 @@ public: virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const override; + virtual ConversionRequired + DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override; + // Accessors that report whether we have the required MFTs available // on the system to play various codecs. Windows Vista doesn't have the // H.264/AAC decoders if the "Platform Update Supplement for Windows Vista" diff --git a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp index 97992d85533..b5c19e94a6b 100644 --- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp @@ -241,12 +241,6 @@ WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample) // This can happen during shutdown. return E_FAIL; } - if (mStreamType != VP8 && mStreamType != VP9) { - // We must prepare samples in AVC Annex B. - if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) { - return E_FAIL; - } - } // Forward sample data to the decoder. const uint8_t* data = reinterpret_cast(aSample->data); uint32_t length = aSample->size; diff --git a/dom/media/fmp4/wrappers/H264Converter.cpp b/dom/media/fmp4/wrappers/H264Converter.cpp new file mode 100644 index 00000000000..ab2b6c52a2d --- /dev/null +++ b/dom/media/fmp4/wrappers/H264Converter.cpp @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "H264Converter.h" +#include "ImageContainer.h" +#include "MediaTaskQueue.h" +#include "mp4_demuxer/DecoderData.h" +#include "mp4_demuxer/AnnexB.h" +#include "mp4_demuxer/H264.h" + +namespace mozilla +{ + + // H264 AnnexB or AVCC handler +#include "mp4_demuxer/DecoderData.h" +#include "mp4_demuxer/AnnexB.h" +#include "mp4_demuxer/H264.h" + +H264Converter::H264Converter(PlatformDecoderModule* aPDM, + const mp4_demuxer::VideoDecoderConfig& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableMediaTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) + : mPDM(aPDM) + , mCurrentConfig(aConfig) + , mLayersBackend(aLayersBackend) + , mImageContainer(aImageContainer) + , mVideoTaskQueue(aVideoTaskQueue) + , mCallback(aCallback) + , mDecoder(nullptr) + , mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC) + , mLastError(NS_OK) +{ + CreateDecoder(); +} + +H264Converter::~H264Converter() +{ +} + +nsresult +H264Converter::Init() +{ + if (mDecoder) { + return mDecoder->Init(); + } + return mLastError; +} + +nsresult +H264Converter::Input(mp4_demuxer::MP4Sample* aSample) +{ + if (!mNeedAVCC) { + if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) { + return NS_ERROR_FAILURE; + } + } else { + if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) { + return NS_ERROR_FAILURE; + } + } + nsresult rv; + if (!mDecoder) { + // It is not possible to create an AVCC H264 decoder without SPS. + // As such, creation will fail if the extra_data just extracted doesn't + // contain a SPS. + rv = CreateDecoderAndInit(aSample); + if (rv == NS_ERROR_NOT_INITIALIZED) { + // We are missing the required SPS to create the decoder. + // Ignore for the time being, the MP4Sample will be dropped. + return NS_OK; + } + } else { + rv = CheckForSPSChange(aSample); + } + NS_ENSURE_SUCCESS(rv, rv); + + aSample->extra_data = mCurrentConfig.extra_data; + + return mDecoder->Input(aSample); +} + +nsresult +H264Converter::Flush() +{ + if (mDecoder) { + return mDecoder->Flush(); + } + return mLastError; +} + +nsresult +H264Converter::Drain() +{ + if (mDecoder) { + return mDecoder->Drain(); + } + return mLastError; +} + +nsresult +H264Converter::Shutdown() +{ + if (mDecoder) { + nsresult rv = mDecoder->Shutdown(); + mDecoder = nullptr; + return rv; + } + return NS_OK; +} + +bool +H264Converter::IsWaitingMediaResources() +{ + if (mDecoder) { + return mDecoder->IsWaitingMediaResources(); + } + return MediaDataDecoder::IsWaitingMediaResources(); +} + +bool +H264Converter::IsDormantNeeded() +{ + if (mNeedAVCC) { + return true; + } + return mDecoder ? + mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded(); +} + +void +H264Converter::AllocateMediaResources() +{ + if (mNeedAVCC) { + // Nothing to do, decoder will be allocated on the fly when required. + return; + } + if (mDecoder) { + mDecoder->AllocateMediaResources(); + } +} + +void +H264Converter::ReleaseMediaResources() +{ + if (mNeedAVCC) { + Shutdown(); + return; + } + if (mDecoder) { + mDecoder->ReleaseMediaResources(); + } +} + +bool +H264Converter::IsHardwareAccelerated() const +{ + if (mDecoder) { + return mDecoder->IsHardwareAccelerated(); + } + return MediaDataDecoder::IsHardwareAccelerated(); +} + +nsresult +H264Converter::CreateDecoder() +{ + if (mNeedAVCC && !mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) { + // nothing found yet, will try again later + return NS_ERROR_NOT_INITIALIZED; + } + UpdateConfigFromExtraData(mCurrentConfig.extra_data); + + mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig, + mLayersBackend, + mImageContainer, + mVideoTaskQueue, + mCallback); + if (!mDecoder) { + mLastError = NS_ERROR_FAILURE; + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +nsresult +H264Converter::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample) +{ + nsRefPtr extra_data = + mp4_demuxer::AnnexB::ExtractExtraData(aSample); + if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) { + return NS_ERROR_NOT_INITIALIZED; + } + UpdateConfigFromExtraData(extra_data); + + nsresult rv = CreateDecoder(); + NS_ENSURE_SUCCESS(rv, rv); + return Init(); +} + +nsresult +H264Converter::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample) +{ + nsRefPtr extra_data = + mp4_demuxer::AnnexB::ExtractExtraData(aSample); + if (!mp4_demuxer::AnnexB::HasSPS(extra_data) || + mp4_demuxer::AnnexB::CompareExtraData(extra_data, + mCurrentConfig.extra_data)) { + return NS_OK; + } + if (!mNeedAVCC) { + UpdateConfigFromExtraData(extra_data); + mDecoder->ConfigurationChanged(mCurrentConfig); + return NS_OK; + } + // The SPS has changed, signal to flush the current decoder and create a + // new one. + mDecoder->Flush(); + ReleaseMediaResources(); + return CreateDecoderAndInit(aSample); +} + +void +H264Converter::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData) +{ + mp4_demuxer::SPSData spsdata; + if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) && + spsdata.pic_width > 0 && spsdata.pic_height > 0) { + mp4_demuxer::H264::EnsureSPSIsSane(spsdata); + mCurrentConfig.image_width = spsdata.pic_width; + mCurrentConfig.image_height = spsdata.pic_height; + mCurrentConfig.display_width = spsdata.display_width; + mCurrentConfig.display_height = spsdata.display_height; + } + mCurrentConfig.extra_data = aExtraData; +} + +/* static */ +bool +H264Converter::IsH264(const mp4_demuxer::TrackConfig& aConfig) +{ + return aConfig.mime_type.EqualsLiteral("video/avc") || + aConfig.mime_type.EqualsLiteral("video/mp4"); +} + +} // namespace mozilla diff --git a/dom/media/fmp4/wrappers/H264Converter.h b/dom/media/fmp4/wrappers/H264Converter.h new file mode 100644 index 00000000000..b21fad19931 --- /dev/null +++ b/dom/media/fmp4/wrappers/H264Converter.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#ifndef mozilla_H264Converter_h +#define mozilla_H264Converter_h + +#include "PlatformDecoderModule.h" + +namespace mozilla { + +// H264Converter is a MediaDataDecoder wrapper used to ensure that +// only AVCC or AnnexB is fed to the underlying MediaDataDecoder. +// The H264Converter allows playback of content where the SPS NAL may not be +// provided in the init segment (e.g. AVC3 or Annex B) +// H264Converter will monitor the input data, and will delay creation of the +// MediaDataDecoder until a SPS and PPS NALs have been extracted. + +class H264Converter : public MediaDataDecoder { +public: + + H264Converter(PlatformDecoderModule* aPDM, + const mp4_demuxer::VideoDecoderConfig& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableMediaTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback); + virtual ~H264Converter(); + + virtual nsresult Init() override; + virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override; + virtual nsresult Flush() override; + virtual nsresult Drain() override; + virtual nsresult Shutdown() override; + virtual bool IsWaitingMediaResources() override; + virtual bool IsDormantNeeded() override; + virtual void AllocateMediaResources() override; + virtual void ReleaseMediaResources() override; + virtual bool IsHardwareAccelerated() const override; + + // Return true if mimetype is H.264. + static bool IsH264(const mp4_demuxer::TrackConfig& aConfig); + +private: + // Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL. + // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and + // will set mError accordingly. + nsresult CreateDecoder(); + nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample); + nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample); + void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData); + + nsRefPtr mPDM; + mp4_demuxer::VideoDecoderConfig mCurrentConfig; + layers::LayersBackend mLayersBackend; + nsRefPtr mImageContainer; + nsRefPtr mVideoTaskQueue; + MediaDataDecoderCallback* mCallback; + nsRefPtr mDecoder; + bool mNeedAVCC; + nsresult mLastError; +}; + +} // namespace mozilla + +#endif // mozilla_H264Converter_h diff --git a/dom/media/gtest/TestGMPCrossOrigin.cpp b/dom/media/gtest/TestGMPCrossOrigin.cpp index 336cd405d5c..bbb034ffb5c 100644 --- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -565,8 +565,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(IsGMPStorageIsEmpty()); - const nsString origin1 = NS_LITERAL_STRING("example1.com"); - const nsString origin2 = NS_LITERAL_STRING("example2.org"); + const nsString origin1 = NS_LITERAL_STRING("http://example1.com"); + const nsString origin2 = NS_LITERAL_STRING("http://example2.org"); nsCString PBnodeId1 = GetNodeId(origin1, origin2, true); nsCString PBnodeId2 = GetNodeId(origin1, origin2, true); @@ -602,8 +602,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // Once we clear storage, the node ids generated for the same origin-pair // should be different. - const nsString origin1 = NS_LITERAL_STRING("example1.com"); - const nsString origin2 = NS_LITERAL_STRING("example2.org"); + const nsString origin1 = NS_LITERAL_STRING("http://example1.com"); + const nsString origin2 = NS_LITERAL_STRING("http://example2.org"); nsCString nodeId3 = GetNodeId(origin1, origin2, false); EXPECT_TRUE(!aNodeId1.Equals(nodeId3)); @@ -707,8 +707,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(NS_LITERAL_CSTRING("test-storage complete"), NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("example1.com"), - NS_LITERAL_STRING("example2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), + NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -728,8 +728,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback this, &GMPStorageTest::TestForgetThisSite_AnotherSite); Expect(NS_LITERAL_CSTRING("test-storage complete"), r); - CreateDecryptor(NS_LITERAL_STRING("example1.com"), - NS_LITERAL_STRING("example2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), + NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -742,8 +742,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback this, &GMPStorageTest::TestForgetThisSite_CollectSiteInfo); Expect(NS_LITERAL_CSTRING("test-storage complete"), r); - CreateDecryptor(NS_LITERAL_STRING("example3.com"), - NS_LITERAL_STRING("example4.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example3.com"), + NS_LITERAL_STRING("http://example4.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -771,7 +771,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback void TestForgetThisSite_CollectSiteInfo() { nsAutoPtr siteInfo( - new NodeInfo(NS_LITERAL_CSTRING("example1.com"))); + new NodeInfo(NS_LITERAL_CSTRING("http://example1.com"))); // Collect nodeIds that are expected to remain for later comparison. EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo)); // Invoke "Forget this site" on the main thread. @@ -861,8 +861,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback this, &GMPStorageTest::TestClearRecentHistory1_Clear); Expect(NS_LITERAL_CSTRING("test-storage complete"), r); - CreateDecryptor(NS_LITERAL_STRING("example1.com"), - NS_LITERAL_STRING("example2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), + NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -883,8 +883,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback this, &GMPStorageTest::TestClearRecentHistory2_Clear); Expect(NS_LITERAL_CSTRING("test-storage complete"), r); - CreateDecryptor(NS_LITERAL_STRING("example1.com"), - NS_LITERAL_STRING("example2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), + NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -905,8 +905,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback this, &GMPStorageTest::TestClearRecentHistory3_Clear); Expect(NS_LITERAL_CSTRING("test-storage complete"), r); - CreateDecryptor(NS_LITERAL_STRING("example1.com"), - NS_LITERAL_STRING("example2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), + NS_LITERAL_STRING("http://example2.com"), false, NS_LITERAL_CSTRING("test-storage")); } @@ -1019,8 +1019,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // Open decryptor on one, origin, write a record, and test that that // record can't be read on another origin. - CreateDecryptor(NS_LITERAL_STRING("example3.com"), - NS_LITERAL_STRING("example4.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example3.com"), + NS_LITERAL_STRING("http://example4.com"), false, update); } @@ -1033,8 +1033,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId succeeded (length 0 bytes)"), NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("example5.com"), - NS_LITERAL_STRING("example6.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example5.com"), + NS_LITERAL_STRING("http://example6.com"), false, NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId")); } @@ -1050,8 +1050,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // open another, and test that record can be read, close decryptor, // then send pb-last-context-closed notification, then open decryptor // and check that it can't read that data; it should have been purged. - CreateDecryptor(NS_LITERAL_STRING("pb1.com"), - NS_LITERAL_STRING("pb2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"), + NS_LITERAL_STRING("http://pb2.com"), true, NS_LITERAL_CSTRING("store pbdata test-pb-data")); } @@ -1063,8 +1063,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback NS_NewRunnableMethod(this, &GMPStorageTest::TestPBStorage_RecordRetrievedContinuation)); - CreateDecryptor(NS_LITERAL_STRING("pb1.com"), - NS_LITERAL_STRING("pb2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"), + NS_LITERAL_STRING("http://pb2.com"), true, NS_LITERAL_CSTRING("retrieve pbdata")); } @@ -1077,8 +1077,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("pb1.com"), - NS_LITERAL_STRING("pb2.com"), + CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"), + NS_LITERAL_STRING("http://pb2.com"), true, NS_LITERAL_CSTRING("retrieve pbdata")); } @@ -1108,20 +1108,20 @@ class GMPStorageTest : public GMPDecryptorProxyCallback void TestAsyncShutdownTimeout() { // Create decryptors that timeout in their async shutdown. // If the gtest hangs on shutdown, test fails! - CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example7.com"), - NS_LITERAL_STRING("example8.com"), + CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example7.com"), + NS_LITERAL_STRING("http://example8.com"), &GMPStorageTest::TestAsyncShutdownTimeout2); }; void TestAsyncShutdownTimeout2() { - CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example9.com"), - NS_LITERAL_STRING("example10.com"), + CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example9.com"), + NS_LITERAL_STRING("http://example10.com"), &GMPStorageTest::TestAsyncShutdownTimeout3); }; void TestAsyncShutdownTimeout3() { - CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example11.com"), - NS_LITERAL_STRING("example12.com"), + CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example11.com"), + NS_LITERAL_STRING("http://example12.com"), &GMPStorageTest::SetFinished); }; @@ -1144,8 +1144,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // Test that a GMP can write to storage during shutdown, and retrieve // that written data in a subsequent session. - CreateDecryptor(NS_LITERAL_STRING("example13.com"), - NS_LITERAL_STRING("example14.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example13.com"), + NS_LITERAL_STRING("http://example14.com"), false, update); } @@ -1163,8 +1163,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(response, NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("example13.com"), - NS_LITERAL_STRING("example14.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example13.com"), + NS_LITERAL_STRING("http://example14.com"), false, NS_LITERAL_CSTRING("retrieve-shutdown-token")); } @@ -1176,8 +1176,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(NS_LITERAL_CSTRING("OP tests completed"), NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("example15.com"), - NS_LITERAL_STRING("example16.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example15.com"), + NS_LITERAL_STRING("http://example16.com"), false, NS_LITERAL_CSTRING("test-op-apis")); } @@ -1187,8 +1187,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"), NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); - CreateDecryptor(NS_LITERAL_STRING("example17.com"), - NS_LITERAL_STRING("example18.com"), + CreateDecryptor(NS_LITERAL_STRING("http://example17.com"), + NS_LITERAL_STRING("http://example18.com"), false, NS_LITERAL_CSTRING("retrieve-plugin-voucher")); } @@ -1237,8 +1237,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Expect(response, continuation); } - CreateDecryptor(NS_LITERAL_STRING("foo.com"), - NS_LITERAL_STRING("bar.com"), + CreateDecryptor(NS_LITERAL_STRING("http://foo.com"), + NS_LITERAL_STRING("http://bar.com"), aPrivateBrowsing, Move(updates)); } @@ -1290,8 +1290,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback update.Append(longRecordName); update.AppendLiteral(" "); update.Append(data); - CreateDecryptor(NS_LITERAL_STRING("fuz.com"), - NS_LITERAL_STRING("baz.com"), + CreateDecryptor(NS_LITERAL_STRING("http://fuz.com"), + NS_LITERAL_STRING("http://baz.com"), false, update); } diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index 7402c4d2ca1..4393c9ca37e 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -168,12 +168,16 @@ MediaSourceReader::RequestAudioData() &MediaSourceReader::CompleteAudioSeekAndRejectPromise)); break; case SOURCE_NONE: - if (mLastAudioTime) { + if (!mLastAudioTime) { + // This is the first call to RequestAudioData. + // Fallback to using decoder with earliest data. + mAudioSourceDecoder = FirstDecoder(MediaData::AUDIO_DATA); + } + if (mLastAudioTime || !mAudioSourceDecoder) { CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime); break; } - // Fallback to using first reader - mAudioSourceDecoder = mAudioTrack->Decoders()[0]; + // Fallback to getting first frame from first decoder. default: DoAudioRequest(); break; @@ -338,12 +342,16 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres &MediaSourceReader::CompleteVideoSeekAndRejectPromise)); break; case SOURCE_NONE: - if (mLastVideoTime) { + if (!mLastVideoTime) { + // This is the first call to RequestVideoData. + // Fallback to using decoder with earliest data. + mVideoSourceDecoder = FirstDecoder(MediaData::VIDEO_DATA); + } + if (mLastVideoTime || !mVideoSourceDecoder) { CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime); break; } - // Fallback to using first reader. - mVideoSourceDecoder = mVideoTrack->Decoders()[0]; + // Fallback to getting first frame from first decoder. default: DoVideoRequest(); break; @@ -1033,6 +1041,36 @@ MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered) return NS_OK; } +already_AddRefed +MediaSourceReader::FirstDecoder(MediaData::Type aType) +{ + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + TrackBuffer* trackBuffer = + aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack; + MOZ_ASSERT(trackBuffer); + const nsTArray>& decoders = trackBuffer->Decoders(); + if (decoders.IsEmpty()) { + return nullptr; + } + + nsRefPtr firstDecoder; + double lowestStartTime = PositiveInfinity(); + + for (uint32_t i = 0; i < decoders.Length(); ++i) { + nsRefPtr r = new TimeRanges(); + decoders[i]->GetBuffered(r); + double start = r->GetStartTime(); + if (start < 0) { + continue; + } + if (start < lowestStartTime) { + firstDecoder = decoders[i]; + lowestStartTime = start; + } + } + return firstDecoder.forget(); +} + nsRefPtr MediaSourceReader::WaitForData(MediaData::Type aType) { @@ -1053,13 +1091,23 @@ MediaSourceReader::MaybeNotifyHaveData() // The next Request*Data will handle END_OF_STREAM or going back into waiting // mode. if (!IsSeeking() && mAudioTrack) { - haveAudio = HaveData(mLastAudioTime, MediaData::AUDIO_DATA); + if (!mLastAudioTime) { + nsRefPtr d = FirstDecoder(MediaData::AUDIO_DATA); + haveAudio = !!d; + } else { + haveAudio = HaveData(mLastAudioTime, MediaData::AUDIO_DATA); + } if (ended || haveAudio) { WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__); } } if (!IsSeeking() && mVideoTrack) { - haveVideo = HaveData(mLastVideoTime, MediaData::VIDEO_DATA); + if (!mLastVideoTime) { + nsRefPtr d = FirstDecoder(MediaData::VIDEO_DATA); + haveVideo = !!d; + } else { + haveVideo = HaveData(mLastVideoTime, MediaData::VIDEO_DATA); + } if (ended || haveVideo) { WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__); } diff --git a/dom/media/mediasource/MediaSourceReader.h b/dom/media/mediasource/MediaSourceReader.h index a61cc1d5cc7..4ba4e6c8f8e 100644 --- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -223,6 +223,7 @@ private: int64_t aTolerance /* microseconds */, const nsTArray>& aTrackDecoders); bool HaveData(int64_t aTarget, MediaData::Type aType); + already_AddRefed FirstDecoder(MediaData::Type aType); void AttemptSeek(); bool IsSeeking() { return mPendingSeekTime != -1; } diff --git a/dom/media/webm/IntelWebMVideoDecoder.cpp b/dom/media/webm/IntelWebMVideoDecoder.cpp index 809ade33458..c7513d6f0ae 100644 --- a/dom/media/webm/IntelWebMVideoDecoder.cpp +++ b/dom/media/webm/IntelWebMVideoDecoder.cpp @@ -116,7 +116,7 @@ IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType) { return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") || aMimeType.EqualsLiteral("video/webm; codecs=vp9")) && - mPlatform->SupportsVideoMimeType(aMimeType); + mPlatform->SupportsMimeType(aMimeType); } nsresult @@ -147,11 +147,12 @@ IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) if (!IsSupportedVideoMimeType(video.mime_type)) { return NS_ERROR_FAILURE; } - mMediaDataDecoder = mPlatform->CreateVideoDecoder(video, - mReader->GetLayersBackendType(), - mReader->GetDecoder()->GetImageContainer(), - mTaskQueue, - this); + mMediaDataDecoder = + mPlatform->CreateDecoder(video, + mTaskQueue, + this, + mReader->GetLayersBackendType(), + mReader->GetDecoder()->GetImageContainer()); if (!mMediaDataDecoder) { return NS_ERROR_FAILURE; } diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index 8b352560422..81e10958e99 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -470,8 +470,9 @@ MediaEngineGonkVideoSource::StartImpl(webrtc::CaptureCapability aCapability) { config.mMode = ICameraControl::kPictureMode; config.mPreviewSize.width = aCapability.width; config.mPreviewSize.height = aCapability.height; + config.mPictureSize.width = aCapability.width; + config.mPictureSize.height = aCapability.height; mCameraControl->Start(&config); - mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, config.mPreviewSize); hal::RegisterScreenConfigurationObserver(this); } diff --git a/dom/network/tests/test_udpsocket.html b/dom/network/tests/test_udpsocket.html index 42720eee8dd..67478b76eda 100644 --- a/dom/network/tests/test_udpsocket.html +++ b/dom/network/tests/test_udpsocket.html @@ -321,6 +321,9 @@ function testOpenWithoutClose() { closed.push(socket.closed); } + SpecialPowers.gc(); + info('all unrefereced socket should be closed right after GC'); + return Promise.all(closed); } diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index f31df6c3c0c..967294af1c3 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -113,7 +113,7 @@ CreateDrawTargetForSurface(gfxASurface *aSurface) } RefPtr drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), - ToIntSize(gfxIntSize(aSurface->GetSize())), + aSurface->GetSize(), &format); aSurface->SetData(&kDrawTarget, drawTarget, nullptr); return drawTarget; diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 769175b024d..ccad537c7f1 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -1441,35 +1441,13 @@ PromiseWorkerProxy::StoreISupports(nsISupports* aSupports) mSupportsArray.AppendElement(supports); } -namespace { - -class PromiseWorkerProxyControlRunnable final - : public WorkerControlRunnable +bool +PromiseWorkerProxyControlRunnable::WorkerRun(JSContext* aCx, + WorkerPrivate* aWorkerPrivate) { - nsRefPtr mProxy; - -public: - PromiseWorkerProxyControlRunnable(WorkerPrivate* aWorkerPrivate, - PromiseWorkerProxy* aProxy) - : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) - , mProxy(aProxy) - { - MOZ_ASSERT(aProxy); - } - - virtual bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override - { - mProxy->CleanUp(aCx); - return true; - } - -private: - ~PromiseWorkerProxyControlRunnable() - {} -}; - -} // anonymous namespace + mProxy->CleanUp(aCx); + return true; +} void PromiseWorkerProxy::RunCallback(JSContext* aCx, diff --git a/dom/promise/PromiseWorkerProxy.h b/dom/promise/PromiseWorkerProxy.h index c3d08d92c50..9c0933452fc 100644 --- a/dom/promise/PromiseWorkerProxy.h +++ b/dom/promise/PromiseWorkerProxy.h @@ -11,6 +11,8 @@ #include "mozilla/dom/workers/bindings/WorkerFeature.h" #include "nsProxyRelease.h" +#include "WorkerRunnable.h" + namespace mozilla { namespace dom { @@ -53,8 +55,12 @@ class WorkerPrivate; // dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the // worker. This might be null! In the WorkerRunnable's WorkerRun() use // GetWorkerPromise() to access the Promise and resolve/reject it. Then call -// CleanUp() on the worker -// thread. +// CleanUp() on the worker thread. +// +// IMPORTANT: Dispatching the runnable to the worker thread may fail causing +// the promise to leak. To successfully release the promise on the +// worker thread in this case, use |PromiseWorkerProxyControlRunnable| to +// dispatch a control runnable that will deref the object on the correct thread. class PromiseWorkerProxy : public PromiseNativeHandler, public workers::WorkerFeature @@ -78,6 +84,17 @@ public: void CleanUp(JSContext* aCx); + Mutex& GetCleanUpLock() + { + return mCleanUpLock; + } + + bool IsClean() const + { + mCleanUpLock.AssertCurrentThreadOwns(); + return mCleanedUp; + } + protected: virtual void ResolvedCallback(JSContext* aCx, JS::Handle aValue) override; @@ -119,6 +136,30 @@ private: Mutex mCleanUpLock; }; +// Helper runnable used for releasing the proxied promise when the worker +// is not accepting runnables and the promise object would leak. +// See the instructions above. +class PromiseWorkerProxyControlRunnable final : public workers::WorkerControlRunnable +{ + nsRefPtr mProxy; + +public: + PromiseWorkerProxyControlRunnable(workers::WorkerPrivate* aWorkerPrivate, + PromiseWorkerProxy* aProxy) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) + , mProxy(aProxy) + { + MOZ_ASSERT(aProxy); + } + + virtual bool + WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override; + +private: + ~PromiseWorkerProxyControlRunnable() + {} +}; + } // namespace dom } // namespace mozilla diff --git a/dom/webidl/Client.webidl b/dom/webidl/Client.webidl index b09d0b9b434..a2111a8d612 100644 --- a/dom/webidl/Client.webidl +++ b/dom/webidl/Client.webidl @@ -22,6 +22,8 @@ interface WindowClient : Client { readonly attribute VisibilityState visibilityState; readonly attribute boolean focused; readonly attribute FrameType frameType; + + [Throws] Promise focus(); }; diff --git a/dom/workers/ServiceWorkerClient.h b/dom/workers/ServiceWorkerClient.h index 090512d3a16..cf273dd16ae 100644 --- a/dom/workers/ServiceWorkerClient.h +++ b/dom/workers/ServiceWorkerClient.h @@ -50,10 +50,10 @@ public: ServiceWorkerClient(nsISupports* aOwner, const ServiceWorkerClientInfo& aClientInfo) - : mOwner(aOwner), - mId(aClientInfo.mClientId), - mWindowId(aClientInfo.mWindowId), - mUrl(aClientInfo.mUrl) + : mOwner(aOwner) + , mId(aClientInfo.mClientId) + , mUrl(aClientInfo.mUrl) + , mWindowId(aClientInfo.mWindowId) { MOZ_ASSERT(aOwner); } @@ -89,8 +89,10 @@ protected: private: nsCOMPtr mOwner; nsString mId; - uint64_t mWindowId; nsString mUrl; + +protected: + uint64_t mWindowId; }; } // namespace workers diff --git a/dom/workers/ServiceWorkerClients.cpp b/dom/workers/ServiceWorkerClients.cpp index a49a31a45b6..6c34ee95907 100644 --- a/dom/workers/ServiceWorkerClients.cpp +++ b/dom/workers/ServiceWorkerClients.cpp @@ -4,6 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseWorkerProxy.h" #include "ServiceWorkerClient.h" #include "ServiceWorkerClients.h" @@ -41,96 +42,17 @@ ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle aGivenPro namespace { -// Helper class used for passing the promise between threads while -// keeping the worker alive. -class PromiseHolder final : public WorkerFeature -{ - friend class MatchAllRunnable; - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseHolder) - -public: - PromiseHolder(WorkerPrivate* aWorkerPrivate, - Promise* aPromise) - : mWorkerPrivate(aWorkerPrivate), - mPromise(aPromise), - mCleanUpLock("promiseHolderCleanUpLock"), - mClean(false) - { - MOZ_ASSERT(mWorkerPrivate); - mWorkerPrivate->AssertIsOnWorkerThread(); - MOZ_ASSERT(mPromise); - - if (NS_WARN_IF(!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this))) { - // Worker has been canceled and will go away. - // The ResolvePromiseWorkerRunnable won't run, so we can set mPromise to - // nullptr. - mPromise = nullptr; - mClean = true; - } - } - - Promise* - GetPromise() const - { - return mPromise; - } - - void - Clean() - { - mWorkerPrivate->AssertIsOnWorkerThread(); - - MutexAutoLock lock(mCleanUpLock); - if (mClean) { - return; - } - - mPromise = nullptr; - mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this); - mClean = true; - } - - bool - Notify(JSContext* aCx, Status aStatus) - { - mWorkerPrivate->AssertIsOnWorkerThread(); - - if (aStatus > Running) { - Clean(); - } - - return true; - } - -private: - ~PromiseHolder() - { - MOZ_ASSERT(mClean); - } - - WorkerPrivate* mWorkerPrivate; - nsRefPtr mPromise; - - // Used to prevent race conditions on |mClean| and to ensure that either a - // Notify() call or a dispatch back to the worker thread occurs before - // this object is released. - Mutex mCleanUpLock; - - bool mClean; -}; - class ResolvePromiseWorkerRunnable final : public WorkerRunnable { - nsRefPtr mPromiseHolder; + nsRefPtr mPromiseProxy; nsTArray mValue; public: ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate, - PromiseHolder* aPromiseHolder, + PromiseWorkerProxy* aPromiseProxy, nsTArray& aValue) : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount), - mPromiseHolder(aPromiseHolder) + mPromiseProxy(aPromiseProxy) { AssertIsOnMainThread(); mValue.SwapElements(aValue); @@ -142,7 +64,7 @@ public: MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); - Promise* promise = mPromiseHolder->GetPromise(); + Promise* promise = mPromiseProxy->GetWorkerPromise(); MOZ_ASSERT(promise); nsTArray> ret; @@ -154,51 +76,23 @@ public: promise->MaybeResolve(ret); // release the reference on the worker thread. - mPromiseHolder->Clean(); + mPromiseProxy->CleanUp(aCx); return true; } }; -class ReleasePromiseRunnable final : public MainThreadWorkerControlRunnable -{ - nsRefPtr mPromiseHolder; - -public: - ReleasePromiseRunnable(WorkerPrivate* aWorkerPrivate, - PromiseHolder* aPromiseHolder) - : MainThreadWorkerControlRunnable(aWorkerPrivate), - mPromiseHolder(aPromiseHolder) - { } - -private: - ~ReleasePromiseRunnable() - { } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - MOZ_ASSERT(aWorkerPrivate); - aWorkerPrivate->AssertIsOnWorkerThread(); - - mPromiseHolder->Clean(); - - return true; - } - -}; - class MatchAllRunnable final : public nsRunnable { WorkerPrivate* mWorkerPrivate; - nsRefPtr mPromiseHolder; + nsRefPtr mPromiseProxy; nsCString mScope; public: MatchAllRunnable(WorkerPrivate* aWorkerPrivate, - PromiseHolder* aPromiseHolder, + PromiseWorkerProxy* aPromiseProxy, const nsCString& aScope) : mWorkerPrivate(aWorkerPrivate), - mPromiseHolder(aPromiseHolder), + mPromiseProxy(aPromiseProxy), mScope(aScope) { MOZ_ASSERT(aWorkerPrivate); @@ -210,8 +104,8 @@ public: { AssertIsOnMainThread(); - MutexAutoLock lock(mPromiseHolder->mCleanUpLock); - if (mPromiseHolder->mClean) { + MutexAutoLock lock(mPromiseProxy->GetCleanUpLock()); + if (mPromiseProxy->IsClean()) { // Don't resolve the promise if it was already released. return NS_OK; } @@ -221,7 +115,7 @@ public: swm->GetAllClients(mScope, result); nsRefPtr r = - new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseHolder, result); + new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseProxy, result); AutoSafeJSContext cx; if (r->Dispatch(cx)) { @@ -230,11 +124,11 @@ public: // Dispatch to worker thread failed because the worker is shutting down. // Use a control runnable to release the runnable on the worker thread. - nsRefPtr releaseRunnable = - new ReleasePromiseRunnable(mWorkerPrivate, mPromiseHolder); + nsRefPtr releaseRunnable = + new PromiseWorkerProxyControlRunnable(mWorkerPrivate, mPromiseProxy); if (!releaseRunnable->Dispatch(cx)) { - NS_RUNTIMEABORT("Failed to dispatch PromiseHolder control runnable."); + NS_RUNTIMEABORT("Failed to dispatch MatchAll promise control runnable."); } return NS_OK; @@ -264,16 +158,16 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions, return nullptr; } - nsRefPtr promiseHolder = new PromiseHolder(workerPrivate, - promise); - if (!promiseHolder->GetPromise()) { + nsRefPtr promiseProxy = + PromiseWorkerProxy::Create(workerPrivate, promise); + if (!promiseProxy->GetWorkerPromise()) { // Don't dispatch if adding the worker feature failed. return promise.forget(); } nsRefPtr r = new MatchAllRunnable(workerPrivate, - promiseHolder, + promiseProxy, NS_ConvertUTF16toUTF8(scope)); nsresult rv = NS_DispatchToMainThread(r); diff --git a/dom/workers/ServiceWorkerWindowClient.cpp b/dom/workers/ServiceWorkerWindowClient.cpp index e55a972f8df..8c2708a43b5 100644 --- a/dom/workers/ServiceWorkerWindowClient.cpp +++ b/dom/workers/ServiceWorkerWindowClient.cpp @@ -7,6 +7,7 @@ #include "ServiceWorkerWindowClient.h" #include "mozilla/dom/ClientBinding.h" +#include "mozilla/dom/PromiseWorkerProxy.h" using namespace mozilla::dom; using namespace mozilla::dom::workers; @@ -17,18 +18,135 @@ ServiceWorkerWindowClient::WrapObject(JSContext* aCx, JS::Handle aGiv return WindowClientBinding::Wrap(aCx, this, aGivenProto); } -already_AddRefed -ServiceWorkerWindowClient::Focus() const +namespace { + +// Passing a null clientInfo will reject the promise with InvalidAccessError. +class ResolveOrRejectPromiseRunnable final : public WorkerRunnable { - ErrorResult result; + nsRefPtr mPromiseProxy; + UniquePtr mClientInfo; + +public: + ResolveOrRejectPromiseRunnable(WorkerPrivate* aWorkerPrivate, + PromiseWorkerProxy* aPromiseProxy, + UniquePtr&& aClientInfo) + : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) + , mPromiseProxy(aPromiseProxy) + , mClientInfo(Move(aClientInfo)) + { + AssertIsOnMainThread(); + } + + bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + Promise* promise = mPromiseProxy->GetWorkerPromise(); + MOZ_ASSERT(promise); + + if (mClientInfo) { + nsRefPtr client = + new ServiceWorkerWindowClient(promise->GetParentObject(), *mClientInfo); + promise->MaybeResolve(client); + } else { + promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); + } + + // Release the reference on the worker thread. + mPromiseProxy->CleanUp(aCx); + + return true; + } +}; + +class ClientFocusRunnable final : public nsRunnable +{ + uint64_t mWindowId; + nsRefPtr mPromiseProxy; + +public: + ClientFocusRunnable(uint64_t aWindowId, PromiseWorkerProxy* aPromiseProxy) + : mWindowId(aWindowId) + , mPromiseProxy(aPromiseProxy) + { + MOZ_ASSERT(mPromiseProxy); + MOZ_ASSERT(mPromiseProxy->GetWorkerPromise()); + } + + NS_IMETHOD + Run() override + { + AssertIsOnMainThread(); + nsGlobalWindow* window = nsGlobalWindow::GetOuterWindowWithId(mWindowId); + UniquePtr clientInfo; + + if (window) { + ErrorResult result; + //FIXME(catalinb): Bug 1144660 - check if we are allowed to focus here. + window->Focus(result); + clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument())); + } + + DispatchResult(Move(clientInfo)); + return NS_OK; + } + +private: + void + DispatchResult(UniquePtr&& aClientInfo) + { + WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + nsRefPtr resolveRunnable = + new ResolveOrRejectPromiseRunnable(workerPrivate, mPromiseProxy, + Move(aClientInfo)); + + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + if (!resolveRunnable->Dispatch(cx)) { + nsRefPtr controlRunnable = + new PromiseWorkerProxyControlRunnable(workerPrivate, mPromiseProxy); + if (!controlRunnable->Dispatch(cx)) { + NS_RUNTIMEABORT("Failed to dispatch Focus promise control runnable."); + } + } + } +}; + +} // anonymous namespace + +already_AddRefed +ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const +{ + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + nsCOMPtr global = do_QueryInterface(GetParentObject()); MOZ_ASSERT(global); - nsRefPtr promise = Promise::Create(global, result); - if (NS_WARN_IF(result.Failed())) { + nsRefPtr promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - promise->MaybeReject(NS_ERROR_NOT_AVAILABLE); + nsRefPtr promiseProxy = + PromiseWorkerProxy::Create(workerPrivate, promise); + if (!promiseProxy->GetWorkerPromise()) { + // Don't dispatch if adding the worker feature failed. + return promise.forget(); + } + + nsRefPtr r = new ClientFocusRunnable(mWindowId, + promiseProxy); + aRv = NS_DispatchToMainThread(r); + if (NS_WARN_IF(aRv.Failed())) { + promise->MaybeReject(aRv.ErrorCode()); + } + return promise.forget(); } diff --git a/dom/workers/ServiceWorkerWindowClient.h b/dom/workers/ServiceWorkerWindowClient.h index 06dd1125834..b60bcfaf7ca 100644 --- a/dom/workers/ServiceWorkerWindowClient.h +++ b/dom/workers/ServiceWorkerWindowClient.h @@ -47,7 +47,7 @@ public: } already_AddRefed - Focus() const; + Focus(ErrorResult& aRv) const; private: ~ServiceWorkerWindowClient() diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index f591724687d..b43514e0cf7 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -5898,11 +5898,10 @@ WorkerPrivate::NotifyFeatures(JSContext* aCx, Status aStatus) CancelAllTimeouts(aCx); } - nsAutoTArray features; - features.AppendElements(mFeatures); - - for (uint32_t index = 0; index < features.Length(); index++) { - if (!features[index]->Notify(aCx, aStatus)) { + nsTObserverArray::ForwardIterator iter(mFeatures); + while (iter.HasMore()) { + WorkerFeature* feature = iter.GetNext(); + if (!feature->Notify(aCx, aStatus)) { NS_WARNING("Failed to notify feature!"); } } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index acf7d87edff..a816c10d491 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -25,6 +25,7 @@ #include "nsString.h" #include "nsTArray.h" #include "nsThreadUtils.h" +#include "nsTObserverArray.h" #include "mozilla/dom/StructuredCloneTags.h" #include "Queue.h" @@ -852,7 +853,7 @@ class WorkerPrivate : public WorkerPrivateParent nsRefPtr mScope; nsRefPtr mDebuggerScope; nsTArray mChildWorkers; - nsTArray mFeatures; + nsTObserverArray mFeatures; nsTArray> mTimeouts; uint32_t mDebuggerEventLoopLevel; diff --git a/dom/workers/test/serviceworkers/client_focus_worker.js b/dom/workers/test/serviceworkers/client_focus_worker.js new file mode 100644 index 00000000000..944ebf224b0 --- /dev/null +++ b/dom/workers/test/serviceworkers/client_focus_worker.js @@ -0,0 +1,15 @@ +onmessage = function(e) { + if (!e.source) { + dump("ERROR: message doesn't have a source."); + } + + // The client should be a window client + if (e.source instanceof WindowClient) { + // this will dispatch a focus event on the client + e.source.focus().then(function(client) { + client.postMessage(client.focused); + }); + } else { + dump("ERROR: client should be a WindowClient"); + } +}; diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index 702106c373e..21007a1a0d2 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -17,6 +17,7 @@ support-files = workerUpdate/update.html sw_clients/simple.html sw_clients/service_worker_controlled.html + sw_clients/focus_stealing_client.html match_all_worker.js match_all_advanced_worker.js worker_unregister.js @@ -63,6 +64,7 @@ support-files = redirect_serviceworker.sjs importscript.sjs importscript_worker.js + client_focus_worker.js [test_unregister.html] [test_installation_simple.html] @@ -89,3 +91,4 @@ skip-if = true # Bug 1136780 [test_sandbox_intercept.html] [test_request_context.html] [test_importscript.html] +[test_client_focus.html] diff --git a/dom/workers/test/serviceworkers/sw_clients/focus_stealing_client.html b/dom/workers/test/serviceworkers/sw_clients/focus_stealing_client.html new file mode 100644 index 00000000000..e0831ae02ad --- /dev/null +++ b/dom/workers/test/serviceworkers/sw_clients/focus_stealing_client.html @@ -0,0 +1,33 @@ + + + + + Bug 1130686 - Test service worker client.focus: client + + + + +/ +

+ +

+
+
+
+
+
diff --git a/dom/workers/test/serviceworkers/test_client_focus.html b/dom/workers/test/serviceworkers/test_client_focus.html
new file mode 100644
index 00000000000..81a3c73ea78
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_client_focus.html
@@ -0,0 +1,94 @@
+
+
+
+
+  Bug 1130686 - Test service worker client.focus 
+  
+  
+
+
+
+

+
+

+
+
+
+
+
diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm
index a5c3a9baf3e..74953f923d7 100644
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -296,7 +296,7 @@ GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
                                       bool requireCompatProfile)
 {
     nsRefPtr glContext = CreateHeadless(requireCompatProfile);
-    if (!glContext->InitOffscreen(ToIntSize(size), caps))
+    if (!glContext->InitOffscreen(size, caps))
         return nullptr;
 
     return glContext.forget();
diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp
index b946167fa66..e25a4cab860 100644
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -904,7 +904,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
     if (!glContext)
         return nullptr;
 
-    if (!glContext->InitOffscreen(ToIntSize(size), caps))
+    if (!glContext->InitOffscreen(size, caps))
         return nullptr;
 
     return glContext.forget();
diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp
index f95ae85dafa..b1f514c01a0 100644
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -1234,7 +1234,7 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
     if (!glContext)
         return nullptr;
 
-    if (!glContext->InitOffscreen(ToIntSize(size), caps))
+    if (!glContext->InitOffscreen(size, caps))
         return nullptr;
 
     return glContext.forget();
diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp
index bf605c057e9..ce2f31f4b10 100644
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -640,7 +640,7 @@ GLContextProviderWGL::CreateHeadless(bool)
 }
 
 already_AddRefed
-GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
+GLContextProviderWGL::CreateOffscreen(const IntSize& size,
                                       const SurfaceCaps& caps,
                                       bool requireCompatProfile)
 {
@@ -648,7 +648,7 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
     if (!glContext)
         return nullptr;
 
-    if (!glContext->InitOffscreen(ToIntSize(size), caps))
+    if (!glContext->InitOffscreen(size, caps))
         return nullptr;
 
     return glContext.forget();
diff --git a/gfx/layers/TextureDIB.cpp b/gfx/layers/TextureDIB.cpp
index 5ce945a55ab..0a1fea7908f 100644
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -126,7 +126,7 @@ DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
     dont_AddRef(reinterpret_cast(aDescriptor.surface()));
   MOZ_ASSERT(mSurface);
 
-  mSize = ToIntSize(mSurface->GetSize());
+  mSize = mSurface->GetSize();
   mFormat = ImageFormatToSurfaceFormat(
     gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
 }
diff --git a/gfx/layers/YCbCrImageDataSerializer.cpp b/gfx/layers/YCbCrImageDataSerializer.cpp
index 3670ac54e18..f47d2415cf8 100644
--- a/gfx/layers/YCbCrImageDataSerializer.cpp
+++ b/gfx/layers/YCbCrImageDataSerializer.cpp
@@ -5,7 +5,6 @@
 
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include                      // for memcpy
-#include "gfx2DGlue.h"                  // for ToIntSize
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Logging.h"        // for gfxDebug
diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp
index 619070ed72d..bc38a2f2cb8 100644
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -639,7 +639,7 @@ Transform(const gfxImageSurface* aDest,
     return;
   }
 
-  IntSize destSize = ToIntSize(aDest->GetSize());
+  IntSize destSize = aDest->GetSize();
   SkImageInfo destInfo = SkImageInfo::Make(destSize.width,
                                            destSize.height,
                                            kBGRA_8888_SkColorType,
@@ -697,7 +697,7 @@ Transform(const gfxImageSurface* aDest,
           const gfx3DMatrix& aTransform,
           gfxPoint aDestOffset)
 {
-  IntSize destSize = ToIntSize(aDest->GetSize());
+  IntSize destSize = aDest->GetSize();
   pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
                                                   destSize.width,
                                                   destSize.height,
diff --git a/gfx/layers/basic/TextureClientX11.cpp b/gfx/layers/basic/TextureClientX11.cpp
index 6d752b82cbb..40c64c250c9 100644
--- a/gfx/layers/basic/TextureClientX11.cpp
+++ b/gfx/layers/basic/TextureClientX11.cpp
@@ -144,7 +144,7 @@ TextureClientX11::BorrowDrawTarget()
   }
 
   if (!mDrawTarget) {
-    IntSize size = ToIntSize(mSurface->GetSize());
+    IntSize size = mSurface->GetSize();
     mDrawTarget = Factory::CreateDrawTargetForCairoSurface(mSurface->CairoSurface(), size);
   }
 
diff --git a/gfx/layers/basic/X11TextureSourceBasic.cpp b/gfx/layers/basic/X11TextureSourceBasic.cpp
index 4eb06890829..62b09b4b97b 100644
--- a/gfx/layers/basic/X11TextureSourceBasic.cpp
+++ b/gfx/layers/basic/X11TextureSourceBasic.cpp
@@ -21,7 +21,7 @@ X11TextureSourceBasic::X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXl
 IntSize
 X11TextureSourceBasic::GetSize() const
 {
-  return ToIntSize(mSurface->GetSize());
+  return mSurface->GetSize();
 }
 
 SurfaceFormat
diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp
index 78481e7cde1..7371eef18a9 100644
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -258,17 +258,15 @@ ClientTiledPaintedLayer::UseProgressiveDraw() {
     return false;
   }
 
-  // XXX We probably want to disable progressive drawing for non active APZ layers in the future
-  //     but we should wait for a proper test case before making this change.
-#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
-  LayerMetricsWrapper scrollAncestor;
-  GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
-  MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
-  const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
-  if (!IsScrollingOnCompositor(parentMetrics)) {
-    return false;
+  if (gfxPrefs::AsyncPanZoomEnabled()) {
+    LayerMetricsWrapper scrollAncestor;
+    GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
+    MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
+    const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
+    if (!IsScrollingOnCompositor(parentMetrics)) {
+      return false;
+    }
   }
-#endif
 
   return true;
 }
diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp
index 89a1d069b24..fd0d5f753c7 100644
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -805,7 +805,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
     scrollbarTransform.PostTranslate(xTranslation, 0, 0);
   }
 
-  Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
+  Matrix4x4 transform = aScrollbar->GetLocalTransform() * scrollbarTransform;
 
   if (aScrollbarIsDescendant) {
     // If the scrollbar layer is a child of the content it is a scrollbar for,
diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp
index a2f612f4604..fef39072c1a 100755
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -344,7 +344,8 @@ RenderLayers(ContainerT* aContainer,
     Layer* layer = layerToRender->GetLayer();
 
     gfxRGBA color;
-    if (LayerHasCheckerboardingAPZC(layer, &color)) {
+    if ((layer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+        LayerHasCheckerboardingAPZC(layer, &color)) {
       // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
       // and only fill in that area. However the layer bounds takes into account the base translation
       // for the painted layer whereas the checkerboard region does not. One does not simply
diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp
index 62da13c243e..2f7d4dda64b 100644
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -7,7 +7,6 @@
 
 #include "CompositableHost.h"           // for CompositableHost
 #include "LayersLogging.h"              // for AppendToString
-#include "gfx2DGlue.h"                  // for ToIntSize
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
diff --git a/gfx/layers/composite/X11TextureHost.cpp b/gfx/layers/composite/X11TextureHost.cpp
index 240e4ac1b08..a63e6e148a3 100644
--- a/gfx/layers/composite/X11TextureHost.cpp
+++ b/gfx/layers/composite/X11TextureHost.cpp
@@ -83,7 +83,7 @@ X11TextureHost::GetFormat() const
 IntSize
 X11TextureHost::GetSize() const
 {
-  return ToIntSize(mSurface->GetSize());
+  return mSurface->GetSize();
 }
 
 }
diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp
index 5832ba87564..6b19cf62436 100644
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1458,18 +1458,24 @@ CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
   if (SUCCEEDED(hr)) {
     return;
   }
-  // XXX - It would be nice to use gfxCriticalError, but it needs to
-  // be made to work off the main thread first.
-  //MOZ_ASSERT(aSeverity != DebugAssert);
 
   if (aSeverity == Critical) {
     MOZ_CRASH("Unrecoverable D3D11 error");
   }
 
-  if (mDevice && hr == DXGI_ERROR_DEVICE_REMOVED) {
+  bool deviceRemoved = hr == DXGI_ERROR_DEVICE_REMOVED;
+
+  if (deviceRemoved && mDevice) {
     hr = mDevice->GetDeviceRemovedReason();
   }
 
+  // Device reset may not be an error on our side, but can mess things up so
+  // it's useful to see it in the reports.
+  gfxCriticalError(CriticalLog::DefaultOptions(!deviceRemoved))
+    << (deviceRemoved ? "[CompositorD3D11] device removed with error code: "
+                      : "[CompositorD3D11] error code: ")
+    << hexa(hr);
+
   // Always crash if we are making invalid calls
   if (hr == DXGI_ERROR_INVALID_CALL) {
     MOZ_CRASH("Invalid D3D11 api call");
diff --git a/gfx/layers/d3d11/CompositorD3D11.h b/gfx/layers/d3d11/CompositorD3D11.h
index 31fa25a9e78..e40f21aad47 100644
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -167,7 +167,7 @@ private:
   void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
   void PaintToTarget();
 
-  virtual gfx::IntSize GetWidgetSize() const override { return gfx::ToIntSize(mSize); }
+  virtual gfx::IntSize GetWidgetSize() const override { return mSize; }
 
   RefPtr mContext;
   RefPtr mDevice;
@@ -179,7 +179,7 @@ private:
 
   nsIWidget* mWidget;
 
-  nsIntSize mSize;
+  gfx::IntSize mSize;
 
   HWND mHwnd;
 
diff --git a/gfx/layers/d3d9/CompositorD3D9.h b/gfx/layers/d3d9/CompositorD3D9.h
index 9568f42e6e5..c4e41c485ee 100644
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -152,7 +152,7 @@ private:
 
   virtual gfx::IntSize GetWidgetSize() const override
   {
-    return gfx::ToIntSize(mSize);
+    return mSize;
   }
 
   /* Device manager instance for this compositor */
diff --git a/gfx/layers/d3d9/DeviceManagerD3D9.cpp b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
index 3dbfb264171..75750e68ca2 100644
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -240,7 +240,7 @@ DeviceManagerD3D9::Init()
     mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION));
 
     if (!mD3D9) {
-      gfxCriticalError() << "[D3D9] Failed to create the device";
+      gfxCriticalError() << "[D3D9] Failed to create the IDirect3D9 object";
       return false;
     }
   }
@@ -249,7 +249,7 @@ DeviceManagerD3D9::Init()
   hr = mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident);
 
   if (FAILED(hr)) {
-    gfxCriticalError() << "[D3D9] Failed to create the environment";
+    gfxCriticalError() << "[D3D9] Failed to create the environment code: " << gfx::hexa(hr);
     return false;
   }
 
@@ -331,13 +331,13 @@ DeviceManagerD3D9::Init()
     mNv3DVUtils->SetDeviceInfo(devUnknown); 
   } 
 
-  auto failCreateShaderMsg = "[D3D9] failed to create a critical resource (shader)";
+  auto failCreateShaderMsg = "[D3D9] failed to create a critical resource (shader) code: ";
 
   hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS,
                                    getter_AddRefs(mLayerVS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -345,7 +345,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mRGBPS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -353,7 +353,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mRGBAPS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -361,7 +361,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mComponentPass1PS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -369,7 +369,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mComponentPass2PS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -377,7 +377,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mYCbCrPS));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -393,14 +393,14 @@ DeviceManagerD3D9::Init()
                                    getter_AddRefs(mLayerVSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
   hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask3D,
                                    getter_AddRefs(mLayerVSMask3D));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -408,7 +408,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mRGBPSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -416,7 +416,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mRGBAPSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -424,7 +424,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mRGBAPSMask3D));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -432,7 +432,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mComponentPass1PSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -448,7 +448,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mYCbCrPSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -456,7 +456,7 @@ DeviceManagerD3D9::Init()
                                   getter_AddRefs(mSolidColorPSMask));
 
   if (FAILED(hr)) {
-    gfxCriticalError() << failCreateShaderMsg;
+    gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
     return false;
   }
 
@@ -467,7 +467,7 @@ DeviceManagerD3D9::Init()
 
   hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
   if (FAILED(hr)) {
-    gfxCriticalError() << "[D3D9] Failed to set the stream source";
+    gfxCriticalError() << "[D3D9] Failed to set the stream source code: " << gfx::hexa(hr);
     return false;
   }
 
diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp
index 1eec55b1caf..65a1b5718ac 100644
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -447,7 +447,7 @@ DataTextureSourceD3D9::Update(gfxWindowsSurface* aSurface)
     NS_WARNING("No D3D device to update the texture.");
     return false;
   }
-  mSize = ToIntSize(aSurface->GetSize());
+  mSize = aSurface->GetSize();
 
   uint32_t bpp = 0;
 
diff --git a/gfx/layers/ipc/SharedRGBImage.cpp b/gfx/layers/ipc/SharedRGBImage.cpp
index 1ff20eac8e5..d601748c353 100644
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -49,8 +49,7 @@ CreateSharedRGBImage(ImageContainer *aImageContainer,
   }
 
   nsRefPtr rgbImage = static_cast(image.get());
-  if (!rgbImage->Allocate(gfx::ToIntSize(aSize),
-                          gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
+  if (!rgbImage->Allocate(aSize, gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
     NS_WARNING("Failed to allocate a shared image");
     return nullptr;
   }
diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h
index 04c71d9f7f1..ff82fa5956c 100644
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -307,7 +307,7 @@ public:
 private:
   virtual gfx::IntSize GetWidgetSize() const override
   {
-    return gfx::ToIntSize(mWidgetSize);
+    return mWidgetSize;
   }
 
   bool InitializeVR();
@@ -321,7 +321,7 @@ private:
 
   /** Widget associated with this compositor */
   nsIWidget *mWidget;
-  nsIntSize mWidgetSize;
+  gfx::IntSize mWidgetSize;
   nsRefPtr mGLContext;
   UniquePtr mBlitTextureImageHelper;
   gfx::Matrix4x4 mProjMatrix;
diff --git a/gfx/layers/opengl/X11TextureSourceOGL.cpp b/gfx/layers/opengl/X11TextureSourceOGL.cpp
index b744e92b376..42caad2f2e4 100644
--- a/gfx/layers/opengl/X11TextureSourceOGL.cpp
+++ b/gfx/layers/opengl/X11TextureSourceOGL.cpp
@@ -60,7 +60,7 @@ X11TextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
 IntSize
 X11TextureSourceOGL::GetSize() const
 {
-  return ToIntSize(mSurface->GetSize());
+  return mSurface->GetSize();
 }
 
 SurfaceFormat
diff --git a/gfx/tests/gtest/TestSkipChars.cpp b/gfx/tests/gtest/TestSkipChars.cpp
index 8446b130f0e..de9f5ead467 100644
--- a/gfx/tests/gtest/TestSkipChars.cpp
+++ b/gfx/tests/gtest/TestSkipChars.cpp
@@ -69,6 +69,9 @@ TestIterator()
   EXPECT_TRUE(iter1.GetSkippedOffset() == 0) <<
     "[3] Check initial skipped offset";
 
+  EXPECT_TRUE(iter1.IsOriginalCharSkipped() == false) <<
+    "[3a] Check IsOriginalCharSkipped for initial position";
+
   uint32_t expectSkipped1[] =
   {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
      9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
@@ -89,6 +92,18 @@ TestIterator()
       "[5] Check mapping of skipped to original for " << i;
   }
 
+  bool expectIsOriginalSkipped1[] =
+  {  false, false, false, false, false, false, false, false, false, true,
+     false, false, false, false, false, false, false, false, false, true,
+     false, false, false, false, false, false, false, false, false
+  };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectIsOriginalSkipped1); i++) {
+    iter1.SetOriginalOffset(i);
+    EXPECT_TRUE(iter1.IsOriginalCharSkipped() == expectIsOriginalSkipped1[i]) <<
+      "[5.a] Check IsOriginalCharSkipped for " << i;
+  }
+
   // Test a gfxSkipChars that starts with skipped chars
   gfxSkipChars skipChars2;
 
@@ -108,6 +123,9 @@ TestIterator()
   EXPECT_TRUE(iter2.GetSkippedOffset() == 0) <<
     "[8] Check initial skipped offset";
 
+  EXPECT_TRUE(iter2.IsOriginalCharSkipped() == true) <<
+    "[8a] Check IsOriginalCharSkipped for initial position";
+
   uint32_t expectSkipped2[] =
   {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
@@ -125,6 +143,18 @@ TestIterator()
       "[10] Check mapping of skipped to original for " << i;
   }
 
+  bool expectIsOriginalSkipped2[] =
+  {  true, true, true, true, true, true, true, true, true, false,
+     true, true, true, true, true, true, true, true, true, false,
+     true, true, true, true, true, true, true, true, true
+  };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectIsOriginalSkipped2); i++) {
+    iter2.SetOriginalOffset(i);
+    EXPECT_TRUE(iter2.IsOriginalCharSkipped() == expectIsOriginalSkipped2[i]) <<
+      "[10.a] Check IsOriginalCharSkipped for " << i;
+  }
+
   return true;
 }
 
diff --git a/gfx/tests/gtest/TestTextures.cpp b/gfx/tests/gtest/TestTextures.cpp
index c49aafb816f..3177aa6297b 100644
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -148,7 +148,7 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
 
   // client allocation
   ASSERT_TRUE(texture->CanExposeDrawTarget());
-  texture->AllocateForSurface(ToIntSize(surface->GetSize()));
+  texture->AllocateForSurface(surface->GetSize());
   ASSERT_TRUE(texture->IsAllocated());
 
   ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
diff --git a/gfx/thebes/gfx2DGlue.h b/gfx/thebes/gfx2DGlue.h
index a276de12712..8ed44c25d5e 100644
--- a/gfx/thebes/gfx2DGlue.h
+++ b/gfx/thebes/gfx2DGlue.h
@@ -81,11 +81,6 @@ inline Size ToSize(const gfxSize &aSize)
   return Size(Float(aSize.width), Float(aSize.height));
 }
 
-inline IntSize ToIntSize(const gfxIntSize &aSize)
-{
-  return IntSize(aSize.width, aSize.height);
-}
-
 inline Filter ToFilter(GraphicsFilter aFilter)
 {
   switch (aFilter) {
diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
index 229cd931fa8..deedd9ae0ff 100644
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -837,7 +837,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
     surf.mFormat = format;
     surf.mType = NativeSurfaceType::CAIRO_SURFACE;
     surf.mSurface = aSurface->CairoSurface();
-    surf.mSize = ToIntSize(aSurface->GetSize());
+    surf.mSize = aSurface->GetSize();
     // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
     // succeeds or not since we don't expect to be able to do any better below
     // if it fails.
@@ -862,7 +862,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
     surf.mFormat = format;
     surf.mType = NativeSurfaceType::D3D10_TEXTURE;
     surf.mSurface = static_cast(aSurface)->GetTexture();
-    surf.mSize = ToIntSize(aSurface->GetSize());
+    surf.mSize = aSurface->GetSize();
     mozilla::gfx::DrawTarget *dt = static_cast(aSurface->GetData(&kDrawTarget));
     if (dt) {
       dt->Flush();
@@ -910,7 +910,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
     surf.mFormat = format;
     surf.mType = NativeSurfaceType::CAIRO_SURFACE;
     surf.mSurface = aSurface->CairoSurface();
-    surf.mSize = ToIntSize(aSurface->GetSize());
+    surf.mSize = aSurface->GetSize();
     RefPtr drawTarget =
       Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format);
     if (!drawTarget) {
@@ -956,7 +956,7 @@ gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
   RefPtr result =
     Factory::CreateWrappingDataSourceSurface(image->Data(),
                                              image->Stride(),
-                                             ToIntSize(image->GetSize()),
+                                             image->GetSize(),
                                              ImageFormatToSurfaceFormat(image->Format()));
 
   if (!result) {
diff --git a/gfx/thebes/gfxSkipChars.h b/gfx/thebes/gfxSkipChars.h
index 6d7c1c0eda8..5663dd32858 100644
--- a/gfx/thebes/gfxSkipChars.h
+++ b/gfx/thebes/gfxSkipChars.h
@@ -177,7 +177,7 @@ public:
           mCurrentRangeIndex(-1),
           mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
     {
-          SetOriginalOffset(aOriginalStringOffset);
+        SetOriginalOffset(aOriginalStringOffset);
     }
 
     explicit gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
@@ -185,9 +185,12 @@ public:
         : mSkipChars(&aSkipChars),
           mOriginalStringOffset(0),
           mSkippedStringOffset(0),
-          mCurrentRangeIndex(-1),
           mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
-    { }
+    {
+        mCurrentRangeIndex =
+            mSkipChars->mRanges.IsEmpty() ||
+            mSkipChars->mRanges[0].Start() > 0 ? -1 : 0;
+    }
 
     gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator)
         : mSkipChars(aIterator.mSkipChars),
diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp
index f7650c761ff..79413108e43 100644
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -441,8 +441,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
     gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height()));
 
     RefPtr target =
-      gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(ToIntSize(size),
-                                                                   aFormat);
+      gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(size, aFormat);
     if (!target) {
       return nullptr;
     }
@@ -869,7 +868,7 @@ gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrData& aData,
   // 'prescale' is true if the scaling is to be done as part of the
   // YCbCr to RGB conversion rather than on the RGB data when rendered.
   bool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 &&
-                    ToIntSize(aSuggestedSize) != aData.mPicSize;
+                    aSuggestedSize != aData.mPicSize;
 
   if (aSuggestedFormat == gfxImageFormat::RGB16_565) {
 #if defined(HAVE_YCBCR_TO_RGB565)
@@ -905,7 +904,7 @@ gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrData& aData,
       prescale = false;
   }
   if (!prescale) {
-    ToIntSize(aSuggestedSize) = aData.mPicSize;
+    aSuggestedSize = aData.mPicSize;
   }
 }
 
@@ -929,7 +928,7 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
                       aData.mCbCrSize.height);
 
   // Convert from YCbCr to RGB now, scaling the image if needed.
-  if (ToIntSize(aDestSize) != aData.mPicSize) {
+  if (aDestSize != aData.mPicSize) {
 #if defined(HAVE_YCBCR_TO_RGB565)
     if (aDestFormat == gfxImageFormat::RGB16_565) {
       ScaleYCbCrToRGB565(aData.mYChannel,
diff --git a/gfx/thebes/gfxWindowsNativeDrawing.cpp b/gfx/thebes/gfxWindowsNativeDrawing.cpp
index b2c97dbee10..ec1575b42bc 100644
--- a/gfx/thebes/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp
@@ -272,7 +272,7 @@ gfxWindowsNativeDrawing::PaintToContext()
         RefPtr source =
             Factory::CreateWrappingDataSourceSurface(black->Data(),
                                                      black->Stride(),
-                                                     ToIntSize(black->GetSize()),
+                                                     black->GetSize(),
                                                      SurfaceFormat::B8G8R8A8);
 
         mContext->Save();
diff --git a/gfx/thebes/gfxXlibNativeRenderer.cpp b/gfx/thebes/gfxXlibNativeRenderer.cpp
index 75883f1ba9f..5dc8a723ae0 100644
--- a/gfx/thebes/gfxXlibNativeRenderer.cpp
+++ b/gfx/thebes/gfxXlibNativeRenderer.cpp
@@ -573,7 +573,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
             native.mFormat = moz2DFormat;
             native.mType = NativeSurfaceType::CAIRO_SURFACE;
             native.mSurface = tempXlibSurface;
-            native.mSize = ToIntSize(size);
+            native.mSize = size;
             RefPtr sourceSurface =
                 drawTarget->CreateSourceSurfaceFromNativeSurface(native);
             if (sourceSurface) {
@@ -615,7 +615,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
             native.mFormat = moz2DFormat;
             native.mType = NativeSurfaceType::CAIRO_SURFACE;
             native.mSurface = paintSurface->CairoSurface();
-            native.mSize = ToIntSize(size);
+            native.mSize = size;
             RefPtr sourceSurface =
                 drawTarget->CreateSourceSurfaceFromNativeSurface(native);
             if (sourceSurface) {
diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp
index cc7f4a4204d..25dc8edc6ce 100644
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -281,7 +281,7 @@ nsPNGDecoder::InitInternal()
                               (int)sizeof(unused_chunks)/5);
 #endif
 
-#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
   if (mCMSMode != eCMSMode_Off) {
     png_set_chunk_malloc_max(mPNG, 4000000L);
   }
diff --git a/image/src/OrientedImage.cpp b/image/src/OrientedImage.cpp
index a53e89c7131..4fa25ec61ab 100644
--- a/image/src/OrientedImage.cpp
+++ b/image/src/OrientedImage.cpp
@@ -98,7 +98,7 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
   // Create a surface to draw into.
   RefPtr target =
     gfxPlatform::GetPlatform()->
-      CreateOffscreenContentDrawTarget(ToIntSize(size), surfaceFormat);
+      CreateOffscreenContentDrawTarget(size, surfaceFormat);
   if (!target) {
     NS_ERROR("Could not create a DrawTarget");
     return nullptr;
diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
index c91a5f8be65..15688c06c8a 100644
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -2622,6 +2622,9 @@ void imgCacheValidator::AddProxy(imgRequestProxy *aProxy)
 /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
 NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
 {
+  // We may be holding on to a document, so ensure that it's released.
+  nsCOMPtr context = mContext.forget();
+
   // If for some reason we don't still have an existing request (probably
   // because OnStartRequest got delivered more than once), just bail.
   if (!mRequest) {
@@ -2670,7 +2673,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
       // We don't need to load this any more.
       aRequest->Cancel(NS_BINDING_ABORTED);
 
-      mRequest->SetLoadId(mContext);
+      mRequest->SetLoadId(context);
       mRequest->SetValidator(nullptr);
 
       mRequest = nullptr;
@@ -2711,7 +2714,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
   nsCOMPtr originalURI;
   channel->GetOriginalURI(getter_AddRefs(originalURI));
   mNewRequest->Init(originalURI, uri, mHadInsecureRedirect, aRequest, channel,
-                    mNewEntry, mContext, loadingPrincipal, corsmode, refpol);
+                    mNewEntry, context, loadingPrincipal, corsmode, refpol);
 
   mDestListener = new ProxyListener(mNewRequest);
 
@@ -2740,6 +2743,9 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
 /* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */
 NS_IMETHODIMP imgCacheValidator::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, nsresult status)
 {
+  // Be sure we've released the document that we may have been holding on to.
+  mContext = nullptr;
+
   if (!mDestListener)
     return NS_OK;
 
diff --git a/intl/unicharutil/util/moz.build b/intl/unicharutil/util/moz.build
index 1c07ef047a2..7f066d12717 100644
--- a/intl/unicharutil/util/moz.build
+++ b/intl/unicharutil/util/moz.build
@@ -4,7 +4,7 @@
 # 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/.
 
-DIRS += ['internal']
+DIRS += ['internal', 'standalone']
 
 EXPORTS += [
     'GreekCasing.h',
diff --git a/intl/unicharutil/util/standalone/moz.build b/intl/unicharutil/util/standalone/moz.build
new file mode 100644
index 00000000000..3f6ba2ba039
--- /dev/null
+++ b/intl/unicharutil/util/standalone/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
+    Library('unicharutil_standalone')
+
+intl_unicharutil_util_lcppsrcs = [
+    'nsUnicodeProperties.cpp',
+]
+
+intl_unicharutil_util_cppsrcs = [
+    '%s/intl/unicharutil/util/%s' % (TOPSRCDIR, s) \
+        for s in intl_unicharutil_util_lcppsrcs
+]
+
+UNIFIED_SOURCES += intl_unicharutil_util_cppsrcs
+
+for var in ('MOZILLA_INTERNAL_API', 'MOZILLA_XPCOMRT_API', 'MOZILLA_EXTERNAL_LINKAGE',
+            'NR_SOCKET_IS_VOID_PTR', 'HAVE_STRDUP'):
+    DEFINES[var] = True
diff --git a/js/src/asmjs/AsmJSFrameIterator.cpp b/js/src/asmjs/AsmJSFrameIterator.cpp
index d829aa725af..332ea3dbad9 100644
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -682,6 +682,12 @@ BuiltinToName(AsmJSExit::BuiltinKind builtin)
 #if defined(JS_CODEGEN_ARM)
       case AsmJSExit::Builtin_IDivMod:   return "software idivmod (in asm.js)";
       case AsmJSExit::Builtin_UDivMod:   return "software uidivmod (in asm.js)";
+      case AsmJSExit::Builtin_AtomicCmpXchg:  return "Atomics.compareExchange (in asm.js)";
+      case AsmJSExit::Builtin_AtomicFetchAdd: return "Atomics.add (in asm.js)";
+      case AsmJSExit::Builtin_AtomicFetchSub: return "Atomics.sub (in asm.js)";
+      case AsmJSExit::Builtin_AtomicFetchAnd: return "Atomics.and (in asm.js)";
+      case AsmJSExit::Builtin_AtomicFetchOr:  return "Atomics.or (in asm.js)";
+      case AsmJSExit::Builtin_AtomicFetchXor: return "Atomics.xor (in asm.js)";
 #endif
       case AsmJSExit::Builtin_ModD:      return "fmod (in asm.js)";
       case AsmJSExit::Builtin_SinD:      return "Math.sin (in asm.js)";
diff --git a/js/src/asmjs/AsmJSFrameIterator.h b/js/src/asmjs/AsmJSFrameIterator.h
index 4175c80478a..3c493d2311e 100644
--- a/js/src/asmjs/AsmJSFrameIterator.h
+++ b/js/src/asmjs/AsmJSFrameIterator.h
@@ -80,6 +80,12 @@ namespace AsmJSExit
 #if defined(JS_CODEGEN_ARM)
         Builtin_IDivMod,
         Builtin_UDivMod,
+        Builtin_AtomicCmpXchg,
+        Builtin_AtomicFetchAdd,
+        Builtin_AtomicFetchSub,
+        Builtin_AtomicFetchAnd,
+        Builtin_AtomicFetchOr,
+        Builtin_AtomicFetchXor,
 #endif
         Builtin_ModD,
         Builtin_SinD,
diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp
index e41de5b6ddf..523e5b9c3db 100644
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -817,6 +817,16 @@ HandleDynamicLinkFailure(JSContext* cx, CallArgs args, AsmJSModule& module, Hand
     if (cx->isExceptionPending())
         return false;
 
+    // Source discarding is allowed to affect JS semantics because it is never
+    // enabled for normal JS content.
+    bool haveSource = module.scriptSource()->hasSourceData();
+    if (!haveSource && !JSScript::loadSource(cx, module.scriptSource(), &haveSource))
+        return false;
+    if (!haveSource) {
+        JS_ReportError(cx, "asm.js link failure with source discarding enabled");
+        return false;
+    }
+
     uint32_t begin = module.srcBodyStart();  // starts right after 'use asm'
     uint32_t end = module.srcEndBeforeCurly();
     Rooted src(cx, module.scriptSource()->substringDontDeflate(cx, begin, end));
diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp
index 860653cdc82..9a8975763ea 100644
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -35,6 +35,7 @@
 #endif
 #include "prmjtime.h"
 
+#include "builtin/AtomicsObject.h"
 #include "frontend/Parser.h"
 #include "jit/IonCode.h"
 #include "js/Class.h"
@@ -690,6 +691,18 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext* cx)
         return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
       case AsmJSImm_aeabi_uidivmod:
         return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
+      case AsmJSImm_AtomicCmpXchg:
+        return RedirectCall(FuncCast(js::atomics_cmpxchg_asm_callout), Args_General4);
+      case AsmJSImm_AtomicFetchAdd:
+        return RedirectCall(FuncCast(js::atomics_add_asm_callout), Args_General3);
+      case AsmJSImm_AtomicFetchSub:
+        return RedirectCall(FuncCast(js::atomics_sub_asm_callout), Args_General3);
+      case AsmJSImm_AtomicFetchAnd:
+        return RedirectCall(FuncCast(js::atomics_and_asm_callout), Args_General3);
+      case AsmJSImm_AtomicFetchOr:
+        return RedirectCall(FuncCast(js::atomics_or_asm_callout), Args_General3);
+      case AsmJSImm_AtomicFetchXor:
+        return RedirectCall(FuncCast(js::atomics_xor_asm_callout), Args_General3);
 #endif
       case AsmJSImm_ModD:
         return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp
index 0e6455c1742..15734081b28 100644
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -8921,7 +8921,7 @@ GenerateBuiltinThunk(ModuleCompiler& m, AsmJSExit::BuiltinKind builtin)
     MOZ_ASSERT(masm.framePushed() == 0);
 
     MIRTypeVector argTypes(m.cx());
-    if (!argTypes.reserve(2))
+    if (!argTypes.reserve(5))
         return false;
 
     switch (builtin) {
@@ -8934,6 +8934,21 @@ GenerateBuiltinThunk(ModuleCompiler& m, AsmJSExit::BuiltinKind builtin)
         argTypes.infallibleAppend(MIRType_Int32);
         argTypes.infallibleAppend(MIRType_Int32);
         break;
+      case AsmJSExit::Builtin_AtomicCmpXchg:
+        argTypes.infallibleAppend(MIRType_Int32);
+        argTypes.infallibleAppend(MIRType_Int32);
+        argTypes.infallibleAppend(MIRType_Int32);
+        argTypes.infallibleAppend(MIRType_Int32);
+        break;
+      case AsmJSExit::Builtin_AtomicFetchAdd:
+      case AsmJSExit::Builtin_AtomicFetchSub:
+      case AsmJSExit::Builtin_AtomicFetchAnd:
+      case AsmJSExit::Builtin_AtomicFetchOr:
+      case AsmJSExit::Builtin_AtomicFetchXor:
+        argTypes.infallibleAppend(MIRType_Int32);
+        argTypes.infallibleAppend(MIRType_Int32);
+        argTypes.infallibleAppend(MIRType_Int32);
+        break;
 #endif
       case AsmJSExit::Builtin_SinD:
       case AsmJSExit::Builtin_CosD:
diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp
index d5288dc3bc0..520aa0ca9fd 100644
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -215,6 +215,78 @@ js::atomics_fence(JSContext* cx, unsigned argc, Value* vp)
     return atomics_fence_impl(cx, args.rval());
 }
 
+static int32_t
+do_cmpxchg(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate, void* viewData,
+           uint32_t offset, bool* badArrayType)
+{
+    // CAS always sets oldval to the old value of the cell.
+    // addr must be a T*, and oldval and newval should be variables of type T
+
+#if defined(CXX11_ATOMICS)
+# define CAS(T, addr, oldval, newval)                                    \
+    do {                                                                \
+        std::atomic_compare_exchange_strong(reinterpret_cast*>(addr), &oldval, newval); \
+    } while(0)
+#elif defined(GNU_ATOMICS)
+# define CAS(T, addr, oldval, newval)                                    \
+    do {                                                                \
+        oldval = __sync_val_compare_and_swap(addr, (oldval), (newval)); \
+    } while(0)
+#else
+# define CAS(a, b, c, newval)  (void)newval
+#endif
+
+    switch (viewType) {
+      case Scalar::Int8: {
+          int8_t oldval = (int8_t)oldCandidate;
+          int8_t newval = (int8_t)newCandidate;
+          CAS(int8_t, (int8_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Uint8: {
+          uint8_t oldval = (uint8_t)oldCandidate;
+          uint8_t newval = (uint8_t)newCandidate;
+          CAS(uint8_t, (uint8_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Uint8Clamped: {
+          uint8_t oldval = ClampIntForUint8Array(oldCandidate);
+          uint8_t newval = ClampIntForUint8Array(newCandidate);
+          CAS(uint8_t, (uint8_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Int16: {
+          int16_t oldval = (int16_t)oldCandidate;
+          int16_t newval = (int16_t)newCandidate;
+          CAS(int16_t, (int16_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Uint16: {
+          uint16_t oldval = (uint16_t)oldCandidate;
+          uint16_t newval = (uint16_t)newCandidate;
+          CAS(uint16_t, (uint16_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Int32: {
+          int32_t oldval = oldCandidate;
+          int32_t newval = newCandidate;
+          CAS(int32_t, (int32_t*)viewData + offset, oldval, newval);
+          return oldval;
+      }
+      case Scalar::Uint32: {
+          uint32_t oldval = (uint32_t)oldCandidate;
+          uint32_t newval = (uint32_t)newCandidate;
+          CAS(uint32_t, (uint32_t*)viewData + offset, oldval, newval);
+          return (int32_t)oldval;
+      }
+      default:
+        *badArrayType = true;
+        return 0;
+    }
+
+    // Do not undef CAS, it is used later
+}
+
 bool
 js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -242,78 +314,17 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
     if (!inRange)
         return atomics_fence_impl(cx, r);
 
-    // CAS always sets oldval to the old value of the cell.
-    // addr must be a T*, and oldval and newval should be variables of type T
+    bool badType = false;
+    int32_t result = do_cmpxchg(view->type(), oldCandidate, newCandidate, view->viewData(), offset, &badType);
 
-#if defined(CXX11_ATOMICS)
-# define CAS(T, addr, oldval, newval)                                    \
-    do {                                                                \
-        std::atomic_compare_exchange_strong(reinterpret_cast*>(addr), &oldval, newval); \
-    } while(0)
-#elif defined(GNU_ATOMICS)
-# define CAS(T, addr, oldval, newval)                                    \
-    do {                                                                \
-        oldval = __sync_val_compare_and_swap(addr, (oldval), (newval)); \
-    } while(0)
-#else
-# define CAS(a, b, c, newval)  (void)newval
-#endif
-
-    switch (view->type()) {
-      case Scalar::Int8: {
-          int8_t oldval = (int8_t)oldCandidate;
-          int8_t newval = (int8_t)newCandidate;
-          CAS(int8_t, (int8_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Uint8: {
-          uint8_t oldval = (uint8_t)oldCandidate;
-          uint8_t newval = (uint8_t)newCandidate;
-          CAS(uint8_t, (uint8_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Uint8Clamped: {
-          uint8_t oldval = ClampIntForUint8Array(oldCandidate);
-          uint8_t newval = ClampIntForUint8Array(newCandidate);
-          CAS(uint8_t, (uint8_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Int16: {
-          int16_t oldval = (int16_t)oldCandidate;
-          int16_t newval = (int16_t)newCandidate;
-          CAS(int16_t, (int16_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Uint16: {
-          uint16_t oldval = (uint16_t)oldCandidate;
-          uint16_t newval = (uint16_t)newCandidate;
-          CAS(uint16_t, (uint16_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Int32: {
-          int32_t oldval = oldCandidate;
-          int32_t newval = newCandidate;
-          CAS(int32_t, (int32_t*)view->viewData() + offset, oldval, newval);
-          r.setInt32(oldval);
-          return true;
-      }
-      case Scalar::Uint32: {
-          uint32_t oldval = (uint32_t)oldCandidate;
-          uint32_t newval = (uint32_t)newCandidate;
-          CAS(uint32_t, (uint32_t*)view->viewData() + offset, oldval, newval);
-          r.setNumber((double)oldval);
-          return true;
-      }
-      default:
+    if (badType)
         return ReportBadArrayType(cx);
-    }
 
-    // Do not undef CAS, it is used later
+    if (view->type() == Scalar::Uint32)
+        r.setNumber((double)(uint32_t)result);
+    else
+        r.setInt32(result);
+    return true;
 }
 
 bool
@@ -688,6 +699,152 @@ js::atomics_xor(JSContext* cx, unsigned argc, Value* vp)
 #undef DO_NOTHING
 #undef ZERO
 
+// asm.js callouts for platforms that do not have non-word-sized
+// atomics where we don't want to inline the logic for the atomics.
+//
+// size is currently -1 (signed byte), 1 (unsigned byte), -2 (signed halfword),
+// or 2 (halfword).
+// ptr is the byte offset within the heap array.  This will have low bit zero
+// for halfword accesses.
+// value (for binops) and oldval/newval (for cmpxchg) are the values
+// to be operated upon.
+
+static void
+GetCurrentAsmJSHeap(void** heap, size_t* length)
+{
+    JSRuntime* rt = js::TlsPerThreadData.get()->runtimeFromMainThread();
+    AsmJSModule& mod = rt->asmJSActivationStack()->module();
+    *heap = mod.heapDatum();
+    *length = mod.heapLength();
+}
+
+int32_t
+js::atomics_add_asm_callout(int32_t vt, int32_t offset, int32_t value)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_add::operate((int8_t*)heap + offset, value);
+      case Scalar::Uint8:
+        return do_add::operate((uint8_t*)heap + offset, value);
+      case Scalar::Int16:
+        return do_add::operate((int16_t*)heap + (offset >> 1), value);
+      case Scalar::Uint16:
+        return do_add::operate((uint16_t*)heap + (offset >> 1), value);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
+int32_t
+js::atomics_sub_asm_callout(int32_t vt, int32_t offset, int32_t value)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_sub::operate((int8_t*)heap + offset, value);
+      case Scalar::Uint8:
+        return do_sub::operate((uint8_t*)heap + offset, value);
+      case Scalar::Int16:
+        return do_sub::operate((int16_t*)heap + (offset >> 1), value);
+      case Scalar::Uint16:
+        return do_sub::operate((uint16_t*)heap + (offset >> 1), value);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
+int32_t
+js::atomics_and_asm_callout(int32_t vt, int32_t offset, int32_t value)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_and::operate((int8_t*)heap + offset, value);
+      case Scalar::Uint8:
+        return do_and::operate((uint8_t*)heap + offset, value);
+      case Scalar::Int16:
+        return do_and::operate((int16_t*)heap + (offset >> 1), value);
+      case Scalar::Uint16:
+        return do_and::operate((uint16_t*)heap + (offset >> 1), value);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
+int32_t
+js::atomics_or_asm_callout(int32_t vt, int32_t offset, int32_t value)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_or::operate((int8_t*)heap + offset, value);
+      case Scalar::Uint8:
+        return do_or::operate((uint8_t*)heap + offset, value);
+      case Scalar::Int16:
+        return do_or::operate((int16_t*)heap + (offset >> 1), value);
+      case Scalar::Uint16:
+        return do_or::operate((uint16_t*)heap + (offset >> 1), value);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
+int32_t
+js::atomics_xor_asm_callout(int32_t vt, int32_t offset, int32_t value)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_xor::operate((int8_t*)heap + offset, value);
+      case Scalar::Uint8:
+        return do_xor::operate((uint8_t*)heap + offset, value);
+      case Scalar::Int16:
+        return do_xor::operate((int16_t*)heap + (offset >> 1), value);
+      case Scalar::Uint16:
+        return do_xor::operate((uint16_t*)heap + (offset >> 1), value);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
+int32_t
+js::atomics_cmpxchg_asm_callout(int32_t vt, int32_t offset, int32_t oldval, int32_t newval)
+{
+    void* heap;
+    size_t heapLength;
+    GetCurrentAsmJSHeap(&heap, &heapLength);
+    if ((size_t)offset >= heapLength) return 0;
+    bool badType = false;
+    switch (Scalar::Type(vt)) {
+      case Scalar::Int8:
+        return do_cmpxchg(Scalar::Int8, oldval, newval, heap, offset, &badType);
+      case Scalar::Uint8:
+        return do_cmpxchg(Scalar::Uint8, oldval, newval, heap, offset, &badType);
+      case Scalar::Int16:
+        return do_cmpxchg(Scalar::Int16, oldval, newval, heap, offset>>1, &badType);
+      case Scalar::Uint16:
+        return do_cmpxchg(Scalar::Uint16, oldval, newval, heap, offset>>1, &badType);
+      default:
+        MOZ_CRASH("Invalid size");
+    }
+}
+
 namespace js {
 
 // Represents one waiting worker.
diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h
index 768225459ff..a3f9ef378da 100644
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -44,6 +44,14 @@ bool atomics_futexWait(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_futexWake(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_futexWakeOrRequeue(JSContext* cx, unsigned argc, Value* vp);
 
+/* asm.js callouts */
+int32_t atomics_add_asm_callout(int32_t vt, int32_t offset, int32_t value);
+int32_t atomics_sub_asm_callout(int32_t vt, int32_t offset, int32_t value);
+int32_t atomics_and_asm_callout(int32_t vt, int32_t offset, int32_t value);
+int32_t atomics_or_asm_callout(int32_t vt, int32_t offset, int32_t value);
+int32_t atomics_xor_asm_callout(int32_t vt, int32_t offset, int32_t value);
+int32_t atomics_cmpxchg_asm_callout(int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
+
 class FutexRuntime
 {
 public:
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index aa317beb2b3..e7343ca3280 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2494,17 +2494,24 @@ DumpStringRepresentation(JSContext* cx, unsigned argc, Value* vp)
 #endif
 
 static bool
-SetLazyParsingEnabled(JSContext* cx, unsigned argc, Value* vp)
+SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (argc < 1) {
-        JS_ReportError(cx, "setLazyParsingEnabled: need an argument");
-        return false;
-    }
+    bool disable = !args.hasDefined(0) || ToBoolean(args[0]);
+    JS::CompartmentOptionsRef(cx->compartment()).setDisableLazyParsing(disable);
 
-    bool arg = ToBoolean(args.get(0));
-    JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(!arg);
+    args.rval().setUndefined();
+    return true;
+}
+
+static bool
+SetDiscardSource(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool discard = !args.hasDefined(0) || ToBoolean(args[0]);
+    JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(discard);
 
     args.rval().setUndefined();
     return true;
@@ -2902,9 +2909,15 @@ gc::ZealModeHelpText),
 "  Print a human-readable description of how the string |str| is represented.\n"),
 #endif
 
-    JS_FN_HELP("setLazyParsingEnabled", SetLazyParsingEnabled, 1, 0,
-"setLazyParsingEnabled(bool)",
-"  Enable or disable lazy parsing in the current compartment.  The default is enabled."),
+    JS_FN_HELP("setLazyParsingDisabled", SetLazyParsingDisabled, 1, 0,
+"setLazyParsingDisabled(bool)",
+"  Explicitly disable lazy parsing in the current compartment.  The default is that lazy "
+"  parsing is not explicitly disabled."),
+
+    JS_FN_HELP("setDiscardSource", SetDiscardSource, 1, 0,
+"setDiscardSource(bool)",
+"  Explicitly enable source discarding in the current compartment.  The default is that "
+"  source discarding is not explicitly enabled."),
 
     JS_FS_HELP_END
 };
diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
index 0e8501657ed..8e1b9f21ab1 100644
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1485,7 +1485,7 @@ OutlineTypedObject::createUnattachedWithClass(JSContext* cx,
     if (!group)
         return nullptr;
 
-    NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
+    NewObjectKind newKind = (heap == gc::TenuredHeap) ? TenuredObject : GenericObject;
     OutlineTypedObject* obj = NewObjectWithGroup(cx, group,
                                                                      gc::AllocKind::OBJECT0,
                                                                      newKind);
@@ -2119,7 +2119,7 @@ InlineTypedObject::create(JSContext* cx, HandleTypeDescr descr, gc::InitialHeap
     if (!group)
         return nullptr;
 
-    NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
+    NewObjectKind newKind = (heap == gc::TenuredHeap) ? TenuredObject : GenericObject;
     return NewObjectWithGroup(cx, group, allocKind, newKind);
 }
 
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index d1a4f054e90..875650ffaa4 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -147,6 +147,7 @@ CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
 {
     return options.canLazilyParse &&
            !options.hasPollutedGlobalScope &&
+           !cx->compartment()->options().disableLazyParsing() &&
            !cx->compartment()->options().discardSource() &&
            !options.sourceIsLazy;
 }
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 704ab9dde91..a52b5a334d7 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1232,7 +1232,7 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, Hand
     if (kind == Arrow)
         allocKind = JSFunction::ExtendedFinalizeKind;
     fun = NewFunctionWithProto(context, nullptr, 0, flags, NullPtr(), atom, proto,
-                               allocKind, MaybeSingletonObject);
+                               allocKind, TenuredObject);
     if (!fun)
         return nullptr;
     if (options().selfHostingMode)
diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
index 8e43fc48f7b..13ac99257a0 100644
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -853,13 +853,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
     sb.markGenericEntries(&trc);
     TIME_END(markGenericEntries);
 
-    TIME_START(checkHashTables);
-#ifdef JS_GC_ZEAL
-    if (rt->gcZeal() == ZealCheckHashTablesOnMinorGC)
-        CheckHashTablesAfterMovingGC(rt);
-#endif
-    TIME_END(checkHashTables);
-
     TIME_START(markRuntime);
     rt->gc.markRuntime(&trc);
     TIME_END(markRuntime);
@@ -915,6 +908,14 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
     rt->gc.storeBuffer.clear();
     TIME_END(clearStoreBuffer);
 
+    // Make sure hashtables have been updated after the collection.
+    TIME_START(checkHashTables);
+#ifdef JS_GC_ZEAL
+    if (rt->gcZeal() == ZealCheckHashTablesOnMinorGC)
+        CheckHashTablesAfterMovingGC(rt);
+#endif
+    TIME_END(checkHashTables);
+
     // Resize the nursery.
     TIME_START(resize);
     double promotionRate = trc.tenuredSize / double(allocationEnd() - start());
diff --git a/js/src/jit-test/tests/SIMD/swizzle.js b/js/src/jit-test/tests/SIMD/swizzle.js
index 8eb365e829c..8ab1c17047d 100644
--- a/js/src/jit-test/tests/SIMD/swizzle.js
+++ b/js/src/jit-test/tests/SIMD/swizzle.js
@@ -60,6 +60,14 @@ function testBailouts(uglyDuckling) {
     }
 }
 
+function testInt32x4SwizzleBailout() {
+    // Test out-of-bounds non-constant indices. This is expected to throw.
+    var i4 = SIMD.int32x4(1, 2, 3, 4);
+    for (var i = 0; i < 150; i++) {
+        assertEqX4(SIMD.int32x4.swizzle(i4, i, 3, 2, 0), [i + 1, 4, 3, 1]);
+    }
+}
+
 f();
 testBailouts(-1);
 testBailouts(4);
@@ -69,3 +77,10 @@ testBailouts(null);
 testBailouts({});
 testBailouts('one');
 testBailouts(true);
+
+try {
+    testInt32x4SwizzleBailout();
+    throw 'not caught';
+} catch(e) {
+    assertEq(e instanceof TypeError, true);
+}
diff --git a/js/src/jit-test/tests/asm.js/testBug1147144.js b/js/src/jit-test/tests/asm.js/testBug1147144.js
index ac185be3a29..fbdf3a3961e 100644
--- a/js/src/jit-test/tests/asm.js/testBug1147144.js
+++ b/js/src/jit-test/tests/asm.js/testBug1147144.js
@@ -1,5 +1,10 @@
 load(libdir + 'asm.js');
-setLazyParsingEnabled(false)
+load(libdir + 'asserts.js');
+
+if (!isAsmJSCompilationAvailable())
+    quit();
+
+setDiscardSource(true)
 assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`).toString(), "function asmModule() {\n    [sourceless code]\n}");
 assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`).toSource(), "(function asmModule() {\n    [sourceless code]\n})");
 assertEq(eval(`(function asmModule() { "use asm"; function asmFun() {} return asmFun })`)().toString(), "function asmFun() {\n    [sourceless code]\n}");
@@ -12,3 +17,4 @@ assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`).toString(),
 assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`).toSource(), "(function anonymous() {\n    [sourceless code]\n})");
 assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`)().toString(), "function asmFun() {\n    [sourceless code]\n}");
 assertEq(asmCompile(USE_ASM + `function asmFun() {} return asmFun`)().toSource(), "function asmFun() {\n    [sourceless code]\n}");
+assertThrowsInstanceOf(()=>asmCompile('stdlib',USE_ASM + "var sin=stdlib.Math.sin;return {}")({Math:{}}), Error);
diff --git a/js/src/jit-test/tests/basic/eval-scopes.js b/js/src/jit-test/tests/basic/eval-scopes.js
index 35c519b32ae..b1911881cfb 100644
--- a/js/src/jit-test/tests/basic/eval-scopes.js
+++ b/js/src/jit-test/tests/basic/eval-scopes.js
@@ -22,7 +22,7 @@ function hasGname(f, v, hasIt = true) {
 
 var x = "outer";
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 {
     let x = "inner";
     eval("function g() { assertEq(x, 'inner');} g()");
@@ -43,7 +43,7 @@ eval(`
      }
      hasGname(g4(), 'x');
      `);
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
 
 {
     let x = "inner";
@@ -70,13 +70,13 @@ eval(`
      hasGname(h4(), 'x', false);
      `);
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 with ({}) {
     let x = "inner";
     eval("function i() { assertEq(x, 'inner');} i()");
     eval("function i2() { (function nest() { assertEq(x, 'inner'); })(); } i2()");
 }
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
 
 with ({}) {
     let x = "inner";
@@ -84,13 +84,13 @@ with ({}) {
     eval("function j2() { (function nest() { assertEq(x, 'inner'); })(); } j2()");
 }
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 (function () {
     var x = "inner";
     eval("function k() { assertEq(x, 'inner');} k()");
     eval("function k2() { (function nest() { assertEq(x, 'inner'); })(); } k2()");
 })();
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
 
 (function () {
     let x = "inner";
@@ -114,7 +114,7 @@ eval(`
      (function() { assertEq(y2, 6); })()
      `);
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 
 var y3 = 5;
 eval(`
@@ -132,4 +132,4 @@ eval(`
      (function() { assertEq(y4, 6); })()
      `);
 
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
diff --git a/js/src/jit-test/tests/basic/function-gname.js b/js/src/jit-test/tests/basic/function-gname.js
index 34a0d848717..fa9685b621d 100644
--- a/js/src/jit-test/tests/basic/function-gname.js
+++ b/js/src/jit-test/tests/basic/function-gname.js
@@ -26,11 +26,11 @@ var f1 = new Function("assertEq(x, 'outer')");
 f1();
 hasGname(f1, 'x');
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 var f2 = new Function("assertEq(x, 'outer')");
 f2();
 hasGname(f2, 'x');
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
 
 {
     let x = "inner";
@@ -39,11 +39,11 @@ setLazyParsingEnabled(true);
     hasGname(f3, 'x');
 }
 
-setLazyParsingEnabled(false);
+setLazyParsingDisabled(true);
 {
     let x = "inner";
     var f4 = new Function("assertEq(x, 'outer')");
     f4();
     hasGname(f4, 'x');
 }
-setLazyParsingEnabled(true);
+setLazyParsingDisabled(false);
diff --git a/js/src/jit-test/tests/gc/bug-1148383.js b/js/src/jit-test/tests/gc/bug-1148383.js
new file mode 100644
index 00000000000..eea1d6c1ddc
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1148383.js
@@ -0,0 +1,19 @@
+// This testcase tests setting object metadata for objects created from JIT
+// code.
+if (!("getJitCompilerOptions" in this))
+  quit();
+opts = getJitCompilerOptions();
+if (!opts['ion.enable'] || !opts['baseline.enable'])
+  quit();
+
+function TestCase() {}
+function reportCompare () {
+  var output = "";
+  var testcase = new TestCase();
+  testcase.reason = output;
+}
+reportCompare();
+gczeal(4, 1000);
+setObjectMetadataCallback(true);
+for (var i = 0; i < 10000; ++i)
+  reportCompare();
diff --git a/js/src/jit-test/tests/saved-stacks/bug-1149495.js b/js/src/jit-test/tests/saved-stacks/bug-1149495.js
new file mode 100644
index 00000000000..aedd7726d6e
--- /dev/null
+++ b/js/src/jit-test/tests/saved-stacks/bug-1149495.js
@@ -0,0 +1,6 @@
+try {
+  offThreadCompileScript('Error()', { lineNumber: (4294967295)});
+  runOffThreadScript().stack;
+} catch (e) {
+  // Ignore "Error: Can't use offThreadCompileScript with --no-threads"
+}
diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp
index 13baa43c20c..59a251bd34d 100644
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1377,7 +1377,7 @@ BaselineCompiler::emit_JSOP_OBJECT()
 
         prepareVMCall();
 
-        pushArg(ImmWord(js::MaybeSingletonObject));
+        pushArg(ImmWord(TenuredObject));
         pushArg(ImmGCPtr(obj));
 
         if (!callVM(DeepCloneObjectLiteralInfo))
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index e831ab649ba..d8eead35783 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -174,6 +174,48 @@ ReceiverGuard::trace(JSTracer* trc)
         TraceEdge(trc, &group_, "receiver_guard_group");
 }
 
+ReceiverGuard::StackGuard::StackGuard(JSObject* obj)
+  : group(nullptr), shape(nullptr)
+{
+    if (obj) {
+        if (obj->is()) {
+            group = obj->group();
+            if (UnboxedExpandoObject* expando = obj->as().maybeExpando())
+                shape = expando->lastProperty();
+        } else if (obj->is()) {
+            group = obj->group();
+        } else {
+            shape = obj->maybeShape();
+        }
+    }
+}
+
+ReceiverGuard::StackGuard::StackGuard(ObjectGroup* group, Shape* shape)
+  : group(group), shape(shape)
+{
+    if (group) {
+        if (IsTypedObjectClass(group->clasp()))
+            this->shape = nullptr;
+        else if (group->clasp() != &UnboxedPlainObject::class_)
+            this->group = nullptr;
+    }
+}
+
+/* static */ int32_t
+ReceiverGuard::keyBits(JSObject* obj)
+{
+    if (obj->is()) {
+        // Both the group and shape need to be guarded for unboxed plain objects.
+        return obj->as().maybeExpando() ? 0 : 1;
+    }
+    if (obj->is()) {
+        // Only the group needs to be guarded for typed objects.
+        return 2;
+    }
+    // Other objects only need the shape to be guarded.
+    return 3;
+}
+
 /* static */ void
 ICStub::trace(JSTracer* trc)
 {
@@ -3166,14 +3208,13 @@ ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
 // GetElem_Fallback
 //
 
-static void GetFixedOrDynamicSlotOffset(NativeObject* obj, uint32_t slot,
-                                        bool* isFixed, uint32_t* offset)
+static void GetFixedOrDynamicSlotOffset(Shape* shape, bool* isFixed, uint32_t* offset)
 {
     MOZ_ASSERT(isFixed);
     MOZ_ASSERT(offset);
-    *isFixed = obj->isFixedSlot(slot);
-    *offset = *isFixed ? NativeObject::getFixedSlotOffset(slot)
-                       : obj->dynamicSlotIndex(slot) * sizeof(Value);
+    *isFixed = shape->slot() < shape->numFixedSlots();
+    *offset = *isFixed ? NativeObject::getFixedSlotOffset(shape->slot())
+                       : (shape->slot() - shape->numFixedSlots()) * sizeof(Value);
 }
 
 static JSObject*
@@ -3352,7 +3393,9 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy=false)
     MOZ_ASSERT_IF(isDOMProxy, IsCacheableDOMProxy(obj));
 
     if (!isDOMProxy && !obj->isNative()) {
-        if (obj == holder || !obj->is() || !obj->is())
+        if (obj == holder)
+            return false;
+        if (!obj->is() && !obj->is())
             return false;
     }
 
@@ -3428,45 +3471,54 @@ IsCacheableGetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh
     return true;
 }
 
-static bool
-IsCacheableSetPropWriteSlot(JSObject* obj, Shape* oldShape, JSObject* holder, Shape* shape)
+static Shape*
+LastPropertyForSetProp(JSObject* obj)
 {
-    if (!shape)
-        return false;
+    if (obj->isNative())
+        return obj->as().lastProperty();
 
+    if (obj->is()) {
+        UnboxedExpandoObject* expando = obj->as().maybeExpando();
+        return expando ? expando->lastProperty() : nullptr;
+    }
+
+    return nullptr;
+}
+
+static bool
+IsCacheableSetPropWriteSlot(JSObject* obj, Shape* oldShape, Shape* propertyShape)
+{
     // Object shape must not have changed during the property set.
-    if (!obj->isNative() || obj->as().lastProperty() != oldShape)
+    if (LastPropertyForSetProp(obj) != oldShape)
         return false;
 
-    // Currently we only optimize direct writes.
-    if (obj != holder)
-        return false;
-
-    if (!shape->hasSlot() || !shape->hasDefaultSetter() || !shape->writable())
+    if (!propertyShape->hasSlot() ||
+        !propertyShape->hasDefaultSetter() ||
+        !propertyShape->writable())
+    {
         return false;
+    }
 
     return true;
 }
 
 static bool
 IsCacheableSetPropAddSlot(JSContext* cx, JSObject* obj, Shape* oldShape,
-                          jsid id, JSObject* holder, Shape* shape,
-                          size_t* protoChainDepth)
+                          jsid id, Shape* propertyShape, size_t* protoChainDepth)
 {
-    if (!shape)
+    // The property must be the last added property of the object.
+    if (LastPropertyForSetProp(obj) != propertyShape)
         return false;
 
-    // Property must be set directly on object, and be last added property of object.
-    if (!obj->isNative() || obj != holder || shape != obj->as().lastProperty())
-        return false;
-
-    // Object must be extensible, oldShape must be immediate parent of curShape.
-    if (!obj->nonProxyIsExtensible() || shape->previous() != oldShape)
+    // Object must be extensible, oldShape must be immediate parent of current shape.
+    if (!obj->nonProxyIsExtensible() || propertyShape->previous() != oldShape)
         return false;
 
     // Basic shape checks.
-    if (shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter() ||
-        !shape->writable())
+    if (propertyShape->inDictionary() ||
+        !propertyShape->hasSlot() ||
+        !propertyShape->hasDefaultSetter() ||
+        !propertyShape->writable())
     {
         return false;
     }
@@ -3476,8 +3528,8 @@ IsCacheableSetPropAddSlot(JSContext* cx, JSObject* obj, Shape* oldShape,
         return false;
 
     size_t chainDepth = 0;
-    // walk up the object prototype chain and ensure that all prototypes
-    // are native, and that all prototypes have setter defined on the property
+    // Walk up the object prototype chain and ensure that all prototypes are
+    // native, and that all prototypes have no setter defined on the property.
     for (JSObject* proto = obj->getProto(); proto; proto = proto->getProto()) {
         chainDepth++;
         // if prototype is non-native, don't optimize
@@ -3498,7 +3550,7 @@ IsCacheableSetPropAddSlot(JSContext* cx, JSObject* obj, Shape* oldShape,
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
-    if (NativeObject::dynamicSlotsCount(shape) != NativeObject::dynamicSlotsCount(oldShape))
+    if (NativeObject::dynamicSlotsCount(propertyShape) != NativeObject::dynamicSlotsCount(oldShape))
         return false;
 
     *protoChainDepth = chainDepth;
@@ -3758,8 +3810,7 @@ TryAttachNativeGetValueElemStub(JSContext* cx, HandleScript script, jsbytecode*
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(&holder->as(),
-                                    shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
         ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
         ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot
@@ -5940,7 +5991,7 @@ TryAttachGlobalNameValueStub(JSContext* cx, HandleScript script, jsbytecode* pc,
         } else {
             bool isFixedSlot;
             uint32_t offset;
-            GetFixedOrDynamicSlotOffset(current, shape->slot(), &isFixedSlot, &offset);
+            GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
             if (!IsCacheableGetPropReadSlot(global, current, shape))
                 return true;
 
@@ -6063,8 +6114,7 @@ TryAttachScopeNameStub(JSContext* cx, HandleScript script, ICGetName_Fallback* s
 
     bool isFixedSlot;
     uint32_t offset;
-    GetFixedOrDynamicSlotOffset(&scopeChain->as(),
-                                shape->slot(), &isFixedSlot, &offset);
+    GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
     ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     ICStub* newStub;
@@ -6521,8 +6571,10 @@ UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback* stub,
     return false;
 }
 
+// Return whether obj is in some PreliminaryObjectArray and has a structure
+// that might change in the future.
 static bool
-HasUnanalyzedNewScript(JSObject* obj)
+IsPreliminaryObject(JSObject* obj)
 {
     if (obj->isSingleton())
         return false;
@@ -6531,6 +6583,9 @@ HasUnanalyzedNewScript(JSObject* obj)
     if (newScript && !newScript->analyzed())
         return true;
 
+    if (obj->group()->maybePreliminaryObjects())
+        return true;
+
     return false;
 }
 
@@ -6583,7 +6638,7 @@ TryAttachNativeGetValuePropStub(JSContext* cx, HandleScript script, jsbytecode*
     if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(&holder->as(), shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
         // Instantiate this property for singleton holders, for use during Ion compilation.
         if (IsIonEnabled(cx))
@@ -6600,7 +6655,7 @@ TryAttachNativeGetValuePropStub(JSContext* cx, HandleScript script, jsbytecode*
         if (!newStub)
             return false;
 
-        if (HasUnanalyzedNewScript(obj))
+        if (IsPreliminaryObject(obj))
             newStub->notePreliminaryObject();
         else
             StripPreliminaryObjectStubs(cx, stub);
@@ -6838,7 +6893,7 @@ TryAttachUnboxedExpandoGetPropStub(JSContext* cx, HandleScript script, jsbytecod
 
     bool isFixedSlot;
     uint32_t offset;
-    GetFixedOrDynamicSlotOffset(expando, shape->slot(), &isFixedSlot, &offset);
+    GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
     ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
 
@@ -6935,7 +6990,7 @@ TryAttachPrimitiveGetPropStub(JSContext* cx, HandleScript script, jsbytecode* pc
 
     bool isFixedSlot;
     uint32_t offset;
-    GetFixedOrDynamicSlotOffset(proto, shape->slot(), &isFixedSlot, &offset);
+    GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
     ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
 
@@ -8171,16 +8226,33 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
 {
     MOZ_ASSERT(!*attached);
 
-    if (!obj->isNative() || obj->watched())
+    if (obj->watched())
         return true;
 
     RootedShape shape(cx);
     RootedObject holder(cx);
     if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape))
         return false;
+    if (obj != holder)
+        return true;
+
+    if (!obj->isNative()) {
+        if (obj->is()) {
+            UnboxedExpandoObject* expando = obj->as().maybeExpando();
+            if (expando) {
+                shape = expando->lookup(cx, name);
+                if (!shape)
+                    return true;
+            } else {
+                return true;
+            }
+        } else {
+            return true;
+        }
+    }
 
     size_t chainDepth;
-    if (IsCacheableSetPropAddSlot(cx, obj, oldShape, id, holder, shape, &chainDepth)) {
+    if (IsCacheableSetPropAddSlot(cx, obj, oldShape, id, shape, &chainDepth)) {
         // Don't attach if proto chain depth is too high.
         if (chainDepth > ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH)
             return true;
@@ -8196,7 +8268,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(&obj->as(), shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
         JitSpew(JitSpew_BaselineIC, "  Generating SetProp(NativeObject.ADD) stub");
         ICSetPropNativeAddCompiler compiler(cx, obj, oldShape, oldGroup,
@@ -8212,7 +8284,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
         return true;
     }
 
-    if (IsCacheableSetPropWriteSlot(obj, oldShape, holder, shape)) {
+    if (IsCacheableSetPropWriteSlot(obj, oldShape, shape)) {
         // For some property writes, such as the initial overwrite of global
         // properties, TI will not mark the property as having been
         // overwritten. Don't attach a stub in this case, so that we don't
@@ -8225,10 +8297,10 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
 
         bool isFixedSlot;
         uint32_t offset;
-        GetFixedOrDynamicSlotOffset(&obj->as(), shape->slot(), &isFixedSlot, &offset);
+        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
 
         JitSpew(JitSpew_BaselineIC, "  Generating SetProp(NativeObject.PROP) stub");
-        MOZ_ASSERT(obj->as().lastProperty() == oldShape,
+        MOZ_ASSERT(LastPropertyForSetProp(obj) == oldShape,
                    "Should this really be a SetPropWriteSlot?");
         ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
         ICSetProp_Native* newStub = compiler.getStub(compiler.getStubSpace(script));
@@ -8237,7 +8309,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
 
-        if (HasUnanalyzedNewScript(obj))
+        if (IsPreliminaryObject(obj))
             newStub->notePreliminaryObject();
         else
             StripPreliminaryObjectStubs(cx, stub);
@@ -8444,6 +8516,11 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
         return false;
     ReceiverGuard::RootedStackGuard oldGuard(cx, ReceiverGuard::StackGuard(obj));
 
+    if (obj->is()) {
+        if (UnboxedExpandoObject* expando = obj->as().maybeExpando())
+            oldShape = expando->lastProperty();
+    }
+
     bool attached = false;
     // There are some reasons we can fail to attach a stub that are temporary.
     // We want to avoid calling noteUnoptimizableAccess() if the reason we
@@ -8581,6 +8658,34 @@ ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<
     return true;
 }
 
+static void
+GuardGroupAndShapeMaybeUnboxedExpando(MacroAssembler& masm, JSObject* obj,
+                                      Register object, Register scratch,
+                                      size_t offsetOfGroup, size_t offsetOfShape, Label* failure)
+{
+    // Guard against object group.
+    masm.loadPtr(Address(BaselineStubReg, offsetOfGroup), scratch);
+    masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), scratch,
+                   failure);
+
+    // Guard against shape or expando shape.
+    masm.loadPtr(Address(BaselineStubReg, offsetOfShape), scratch);
+    if (obj->is()) {
+        Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
+        masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure);
+        Label done;
+        masm.push(object);
+        masm.loadPtr(expandoAddress, object);
+        masm.branchTestObjShape(Assembler::Equal, object, scratch, &done);
+        masm.pop(object);
+        masm.jump(failure);
+        masm.bind(&done);
+        masm.pop(object);
+    } else {
+        masm.branchTestObjShape(Assembler::NotEqual, object, scratch, failure);
+    }
+}
+
 bool
 ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm)
 {
@@ -8588,19 +8693,15 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm)
 
     // Guard input is an object.
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+    Register objReg = masm.extractObject(R0, ExtractTemp0);
 
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
     Register scratch = regs.takeAny();
 
-    // Unbox and shape guard.
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_Native::offsetOfShape()), scratch);
-    masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
-
-    // Guard that the object group matches.
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_Native::offsetOfGroup()), scratch);
-    masm.branchPtr(Assembler::NotEqual, Address(objReg, JSObject::offsetOfGroup()), scratch,
-                   &failure);
+    GuardGroupAndShapeMaybeUnboxedExpando(masm, obj_, objReg, scratch,
+                                          ICSetProp_Native::offsetOfGroup(),
+                                          ICSetProp_Native::offsetOfShape(),
+                                          &failure);
 
     // Stow both R0 and R1 (object and value).
     EmitStowICValues(masm, 2);
@@ -8619,7 +8720,13 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm)
     regs.takeUnchecked(objReg);
 
     Register holderReg;
-    if (isFixedSlot_) {
+    if (obj_->is()) {
+        // We are loading off the expando object, so use that for the holder.
+        holderReg = regs.takeAny();
+        masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
+        if (!isFixedSlot_)
+            masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
+    } else if (isFixedSlot_) {
         holderReg = objReg;
     } else {
         holderReg = regs.takeAny();
@@ -8684,19 +8791,15 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
 
     // Guard input is an object.
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+    Register objReg = masm.extractObject(R0, ExtractTemp0);
 
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
     Register scratch = regs.takeAny();
 
-    // Unbox and guard against old shape.
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfShape(0)), scratch);
-    masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
-
-    // Guard that the object group matches.
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfGroup()), scratch);
-    masm.branchPtr(Assembler::NotEqual, Address(objReg, JSObject::offsetOfGroup()), scratch,
-                   &failure);
+    GuardGroupAndShapeMaybeUnboxedExpando(masm, obj_, objReg, scratch,
+                                          ICSetProp_NativeAdd::offsetOfGroup(),
+                                          ICSetProp_NativeAddImpl<0>::offsetOfShape(0),
+                                          &failure);
 
     // Stow both R0 and R1 (object and value).
     EmitStowICValues(masm, 2);
@@ -8728,44 +8831,61 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
     regs = availableGeneralRegs(2);
     scratch = regs.takeAny();
 
-    // Changing object shape.  Write the object's new shape.
-    Address shapeAddr(objReg, JSObject::offsetOfShape());
-    EmitPreBarrier(masm, shapeAddr, MIRType_Shape);
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
-    masm.storePtr(scratch, shapeAddr);
+    if (obj_->is()) {
+        // Try to change the object's group.
+        Label noGroupChange;
 
-    // Try to change the object's group.
-    Label noGroupChange;
+        // Check if the cache has a new group to change to.
+        masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewGroup()), scratch);
+        masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noGroupChange);
 
-    // Check if the cache has a new group to change to.
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewGroup()), scratch);
-    masm.branchTestPtr(Assembler::Zero, scratch, scratch, &noGroupChange);
+        // Check if the old group still has a newScript.
+        masm.loadPtr(Address(objReg, JSObject::offsetOfGroup()), scratch);
+        masm.branchPtr(Assembler::Equal,
+                       Address(scratch, ObjectGroup::offsetOfAddendum()),
+                       ImmWord(0),
+                       &noGroupChange);
 
-    // Check if the old group still has a newScript.
-    masm.loadPtr(Address(objReg, JSObject::offsetOfGroup()), scratch);
-    masm.branchPtr(Assembler::Equal,
-                   Address(scratch, ObjectGroup::offsetOfAddendum()),
-                   ImmWord(0),
-                   &noGroupChange);
+        // Reload the new group from the cache.
+        masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewGroup()), scratch);
 
-    // Reload the new group from the cache.
-    masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewGroup()), scratch);
+        // Change the object's group.
+        Address groupAddr(objReg, JSObject::offsetOfGroup());
+        EmitPreBarrier(masm, groupAddr, MIRType_ObjectGroup);
+        masm.storePtr(scratch, groupAddr);
 
-    // Change the object's group.
-    Address groupAddr(objReg, JSObject::offsetOfGroup());
-    EmitPreBarrier(masm, groupAddr, MIRType_ObjectGroup);
-    masm.storePtr(scratch, groupAddr);
-
-    masm.bind(&noGroupChange);
+        masm.bind(&noGroupChange);
+    }
 
     Register holderReg;
     regs.add(R0);
     regs.takeUnchecked(objReg);
-    if (isFixedSlot_) {
-        holderReg = objReg;
-    } else {
+
+    if (obj_->is()) {
         holderReg = regs.takeAny();
-        masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
+        masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
+
+        // Write the expando object's new shape.
+        Address shapeAddr(holderReg, JSObject::offsetOfShape());
+        EmitPreBarrier(masm, shapeAddr, MIRType_Shape);
+        masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
+        masm.storePtr(scratch, shapeAddr);
+
+        if (!isFixedSlot_)
+            masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
+    } else {
+        // Write the object's new shape.
+        Address shapeAddr(objReg, JSObject::offsetOfShape());
+        EmitPreBarrier(masm, shapeAddr, MIRType_Shape);
+        masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
+        masm.storePtr(scratch, shapeAddr);
+
+        if (isFixedSlot_) {
+            holderReg = objReg;
+        } else {
+            holderReg = regs.takeAny();
+            masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), holderReg);
+        }
     }
 
     // Perform the store.  No write barrier required since this is a new
@@ -9541,7 +9661,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
                 }
             }
 
-            JSObject* thisObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
+            JSObject* thisObject = CreateThisForFunction(cx, fun, TenuredObject);
             if (!thisObject)
                 return false;
 
@@ -12082,7 +12202,7 @@ ICSetProp_Native::Compiler::getStub(ICStubSpace* space)
     if (!group)
         return nullptr;
 
-    RootedShape shape(cx, obj_->as().lastProperty());
+    RootedShape shape(cx, LastPropertyForSetProp(obj_));
     ICSetProp_Native* stub = ICStub::New(space, getStubCode(), group, shape, offset_);
     if (!stub || !stub->initUpdatingChain(cx, space))
         return nullptr;
@@ -12268,7 +12388,7 @@ ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitC
                                                                  Shape* holderShape,
                                                                  JSFunction* getter,
                                                                  uint32_t pcOffset)
-  : ICGetPropCallGetter(kind, stubCode, firstMonitorStub, ReceiverGuard::StackGuard(shape),
+  : ICGetPropCallGetter(kind, stubCode, firstMonitorStub, ReceiverGuard::StackGuard(nullptr, shape),
                         holder, holderShape, getter, pcOffset),
     expandoShape_(expandoShape)
 { }
diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h
index 7b25391a39b..13ed43c4128 100644
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -3873,6 +3873,10 @@ class ReceiverGuard
         ObjectGroup* group;
         Shape* shape;
 
+        StackGuard()
+          : group(nullptr), shape(nullptr)
+        {}
+
         MOZ_IMPLICIT StackGuard(const ReceiverGuard& guard)
           : group(guard.group_), shape(guard.shape_)
         {}
@@ -3881,31 +3885,15 @@ class ReceiverGuard
           : group(guard.group), shape(guard.shape)
         {}
 
-        explicit StackGuard(JSObject* obj)
-          : group(nullptr), shape(nullptr)
-        {
-            if (obj) {
-                if (obj->is()) {
-                    group = obj->group();
-                    if (UnboxedExpandoObject* expando = obj->as().maybeExpando())
-                        shape = expando->lastProperty();
-                } else if (obj->is()) {
-                    group = obj->group();
-                } else {
-                    shape = obj->maybeShape();
-                }
-            }
+        explicit StackGuard(JSObject* obj);
+        StackGuard(ObjectGroup* group, Shape* shape);
+
+        bool operator ==(const StackGuard& other) const {
+            return group == other.group && shape == other.shape;
         }
 
-        explicit StackGuard(Shape* shape)
-          : group(nullptr), shape(shape)
-        {}
-
-        Shape* ownShape() const {
-            // Get a shape belonging to the object itself, rather than an unboxed expando.
-            if (!group || !group->maybeUnboxedLayout())
-                return shape;
-            return nullptr;
+        bool operator !=(const StackGuard& other) const {
+            return !(*this == other);
         }
     };
 
@@ -3931,10 +3919,6 @@ class ReceiverGuard
         return group_;
     }
 
-    Shape* ownShape() const {
-        return StackGuard(*this).ownShape();
-    }
-
     static size_t offsetOfShape() {
         return offsetof(ReceiverGuard, shape_);
     }
@@ -3943,20 +3927,8 @@ class ReceiverGuard
     }
 
     // Bits to munge into IC compiler keys when that IC has a ReceiverGuard.
-    // This uses at two bits for data.
-    static int32_t keyBits(JSObject* obj) {
-        if (obj->is()) {
-            // Both the group and shape need to be guarded for unboxed objects.
-            return obj->as().maybeExpando() ? 0 : 1;
-        }
-        if (obj->is()) {
-            // Only the group needs to be guarded for typed objects.
-            return 2;
-        }
-        // Other objects only need the shape to be guarded, except for ICs
-        // which always guard the group.
-        return 3;
-    }
+    // This uses at most two bits for data.
+    static int32_t keyBits(JSObject* obj);
 };
 
 // Base class for native GetProp stubs.
@@ -4807,7 +4779,9 @@ class ICSetProp_Native : public ICUpdatedStub
 
       protected:
         virtual int32_t getKey() const {
-            return static_cast(kind) | (static_cast(isFixedSlot_) << 16);
+            return static_cast(kind) |
+                   (static_cast(isFixedSlot_) << 16) |
+                   (static_cast(obj_->is()) << 17);
         }
 
         bool generateStubCode(MacroAssembler& masm);
@@ -4909,8 +4883,10 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
 
   protected:
     virtual int32_t getKey() const {
-        return static_cast(kind) | (static_cast(isFixedSlot_) << 16) |
-               (static_cast(protoChainDepth_) << 20);
+        return static_cast(kind) |
+               (static_cast(isFixedSlot_) << 16) |
+               (static_cast(obj_->is()) << 17) |
+               (static_cast(protoChainDepth_) << 18);
     }
 
     bool generateStubCode(MacroAssembler& masm);
@@ -4933,7 +4909,11 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
         if (newGroup == oldGroup_)
             newGroup = nullptr;
 
-        RootedShape newShape(cx, obj_->as().lastProperty());
+        RootedShape newShape(cx);
+        if (obj_->isNative())
+            newShape = obj_->as().lastProperty();
+        else
+            newShape = obj_->as().maybeExpando()->lastProperty();
 
         return ICStub::New>(
                     space, getStubCode(), oldGroup_, shapes, newShape, newGroup, offset_);
diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp
index c3209cebdab..f52bc92d269 100644
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -90,19 +90,28 @@ VectorAppendNoDuplicate(S& list, T value)
     return list.append(value);
 }
 
+static bool
+AddReceiver(const ReceiverGuard::StackGuard& receiver,
+            BaselineInspector::ReceiverVector& receivers,
+            BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
+{
+    if (receiver.group && receiver.group->maybeUnboxedLayout()) {
+        if (receiver.group->unboxedLayout().nativeGroup())
+            return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
+    }
+    return VectorAppendNoDuplicate(receivers, receiver);
+}
+
 bool
-BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc,
-                                          ShapeVector& nativeShapes,
-                                          ObjectGroupVector& unboxedGroups,
+BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
                                           ObjectGroupVector& convertUnboxedGroups)
 {
-    // Return lists of native shapes and unboxed objects seen by the baseline
-    // IC for the current op. Empty lists indicate no shapes/types are known,
-    // or there was an uncacheable access. convertUnboxedGroups is used for
-    // unboxed object groups which have been seen, but have had instances
-    // converted to native objects and should be eagerly converted by Ion.
-    MOZ_ASSERT(nativeShapes.empty());
-    MOZ_ASSERT(unboxedGroups.empty());
+    // Return a list of the receivers seen by the baseline IC for the current
+    // op. Empty lists indicate no receivers are known, or there was an
+    // uncacheable access. convertUnboxedGroups is used for unboxed object
+    // groups which have been seen, but have had instances converted to native
+    // objects and should be eagerly converted by Ion.
+    MOZ_ASSERT(receivers.empty());
     MOZ_ASSERT(convertUnboxedGroups.empty());
 
     if (!hasBaselineScript())
@@ -113,59 +122,38 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc,
 
     ICStub* stub = entry.firstStub();
     while (stub->next()) {
-        Shape* shape = nullptr;
-        ObjectGroup* group = nullptr;
+        ReceiverGuard::StackGuard receiver;
         if (stub->isGetProp_Native()) {
-            shape = stub->toGetProp_Native()->receiverGuard().ownShape();
+            receiver = stub->toGetProp_Native()->receiverGuard();
         } else if (stub->isSetProp_Native()) {
-            shape = stub->toSetProp_Native()->shape();
+            receiver = ReceiverGuard::StackGuard(stub->toSetProp_Native()->group(),
+                                                 stub->toSetProp_Native()->shape());
         } else if (stub->isGetProp_Unboxed()) {
-            group = stub->toGetProp_Unboxed()->group();
+            receiver = ReceiverGuard::StackGuard(stub->toGetProp_Unboxed()->group(), nullptr);
         } else if (stub->isSetProp_Unboxed()) {
-            group = stub->toSetProp_Unboxed()->group();
-        }
-
-        if (!shape && !group) {
-            nativeShapes.clear();
-            unboxedGroups.clear();
+            receiver = ReceiverGuard::StackGuard(stub->toSetProp_Unboxed()->group(), nullptr);
+        } else {
+            receivers.clear();
             return true;
         }
 
-        if (group && group->unboxedLayout().nativeGroup()) {
-            if (!VectorAppendNoDuplicate(convertUnboxedGroups, group))
-                return false;
-            shape = group->unboxedLayout().nativeShape();
-            group = nullptr;
-        }
-
-        if (shape) {
-            if (!VectorAppendNoDuplicate(nativeShapes, shape))
-                return false;
-        } else {
-            if (!VectorAppendNoDuplicate(unboxedGroups, group))
-                return false;
-        }
+        if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
+            return false;
 
         stub = stub->next();
     }
 
     if (stub->isGetProp_Fallback()) {
-        if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) {
-            nativeShapes.clear();
-            unboxedGroups.clear();
-        }
+        if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
+            receivers.clear();
     } else {
-        if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) {
-            nativeShapes.clear();
-            unboxedGroups.clear();
-        }
+        if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
+            receivers.clear();
     }
 
-    // Don't inline if there are more than 5 shapes/groups.
-    if (nativeShapes.length() + unboxedGroups.length() > 5) {
-        nativeShapes.clear();
-        unboxedGroups.clear();
-    }
+    // Don't inline if there are more than 5 receivers.
+    if (receivers.length() > 5)
+        receivers.clear();
 
     return true;
 }
@@ -589,45 +577,18 @@ GlobalShapeForGetPropFunction(ICStub* stub)
     return nullptr;
 }
 
-static bool
-AddReceiver(BaselineInspector::ShapeVector& nativeShapes,
-            BaselineInspector::ObjectGroupVector& unboxedGroups,
-            ReceiverGuard::StackGuard receiver)
-{
-    if (Shape* shape = receiver.ownShape())
-        return VectorAppendNoDuplicate(nativeShapes, shape);
-
-    // Only unboxed objects with no expandos are handled by the common
-    // getprop/setprop optimizations.
-    if (!receiver.shape)
-        return VectorAppendNoDuplicate(unboxedGroups, receiver.group);
-
-    return false;
-}
-
-static bool
-AddReceiverForGetPropFunction(BaselineInspector::ShapeVector& nativeShapes,
-                              BaselineInspector::ObjectGroupVector& unboxedGroups,
-                              ICGetPropCallGetter* stub)
-{
-    if (stub->isOwnGetter())
-        return true;
-
-    return AddReceiver(nativeShapes, unboxedGroups, stub->receiverGuard());
-}
-
 bool
 BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
                                          JSFunction** commonGetter, Shape** globalShape,
                                          bool* isOwnProperty,
-                                         ShapeVector& nativeShapes,
-                                         ObjectGroupVector& unboxedGroups)
+                                         ReceiverVector& receivers,
+                                         ObjectGroupVector& convertUnboxedGroups)
 {
     if (!hasBaselineScript())
         return false;
 
-    MOZ_ASSERT(nativeShapes.empty());
-    MOZ_ASSERT(unboxedGroups.empty());
+    MOZ_ASSERT(receivers.empty());
+    MOZ_ASSERT(convertUnboxedGroups.empty());
 
     *holder = nullptr;
     const ICEntry& entry = icEntryFromPC(pc);
@@ -638,7 +599,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
         {
             ICGetPropCallGetter* nstub = static_cast(stub);
             bool isOwn = nstub->isOwnGetter();
-            if (!AddReceiverForGetPropFunction(nativeShapes, unboxedGroups, nstub))
+            if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
                 return false;
 
             if (!*holder) {
@@ -670,21 +631,21 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
     if (!*holder)
         return false;
 
-    MOZ_ASSERT(*isOwnProperty == (nativeShapes.empty() && unboxedGroups.empty()));
+    MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty()));
     return true;
 }
 
 bool
 BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
                                          JSFunction** commonSetter, bool* isOwnProperty,
-                                         ShapeVector& nativeShapes,
-                                         ObjectGroupVector& unboxedGroups)
+                                         ReceiverVector& receivers,
+                                         ObjectGroupVector& convertUnboxedGroups)
 {
     if (!hasBaselineScript())
         return false;
 
-    MOZ_ASSERT(nativeShapes.empty());
-    MOZ_ASSERT(unboxedGroups.empty());
+    MOZ_ASSERT(receivers.empty());
+    MOZ_ASSERT(convertUnboxedGroups.empty());
 
     *holder = nullptr;
     const ICEntry& entry = icEntryFromPC(pc);
@@ -692,7 +653,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
             ICSetPropCallSetter* nstub = static_cast(stub);
-            if (!AddReceiver(nativeShapes, unboxedGroups, nstub->guard()))
+            if (!AddReceiver(nstub->guard(), receivers, convertUnboxedGroups))
                 return false;
 
             if (!*holder) {
diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h
index 463b5416a33..7146a43a1eb 100644
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -92,11 +92,9 @@ class BaselineInspector
     bool dimorphicStub(jsbytecode* pc, ICStub** pfirst, ICStub** psecond);
 
   public:
-    typedef Vector ShapeVector;
+    typedef Vector ReceiverVector;
     typedef Vector ObjectGroupVector;
-    bool maybeInfoForPropertyOp(jsbytecode* pc,
-                                ShapeVector& nativeShapes,
-                                ObjectGroupVector& unboxedGroups,
+    bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
                                 ObjectGroupVector& convertUnboxedGroups);
 
     SetElemICInspector setElemICInspector(jsbytecode* pc) {
@@ -126,10 +124,10 @@ class BaselineInspector
 
     bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
                                JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty,
-                               ShapeVector& nativeShapes, ObjectGroupVector& unboxedGroups);
+                               ReceiverVector& receivers, ObjectGroupVector& convertUnboxedGroups);
     bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
                                JSFunction** commonSetter, bool* isOwnProperty,
-                               ShapeVector& nativeShapes, ObjectGroupVector& unboxedGroups);
+                               ReceiverVector& receivers, ObjectGroupVector& convertUnboxedGroups);
 
     bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot, JSObject** prototypeObject);
 };
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 3784e775437..a9c8720a99b 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1950,7 +1950,7 @@ static const VMFunction DeepCloneObjectLiteralInfo =
 void
 CodeGenerator::visitCloneLiteral(LCloneLiteral* lir)
 {
-    pushArg(ImmWord(js::MaybeSingletonObject));
+    pushArg(ImmWord(TenuredObject));
     pushArg(ToRegister(lir->getObjectLiteral()));
     callVM(DeepCloneObjectLiteralInfo, lir);
 }
@@ -2261,69 +2261,70 @@ CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
     masm.storeValue(value, Address(base, offset));
 }
 
+static void
+GuardReceiver(MacroAssembler& masm, const ReceiverGuard::StackGuard& guard,
+              Register obj, Register scratch, Label* miss, bool checkNullExpando)
+{
+    if (guard.group) {
+        masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss);
+
+        Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando());
+        if (guard.shape) {
+            masm.loadPtr(expandoAddress, scratch);
+            masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss);
+            masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss);
+        } else if (checkNullExpando) {
+            masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss);
+        }
+    } else {
+        masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss);
+    }
+}
+
 void
 CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
                                           const TypedOrValueRegister& output)
 {
     MGetPropertyPolymorphic* mir = ins->mirRaw()->toGetPropertyPolymorphic();
 
-    size_t total = mir->numUnboxedGroups() + mir->numShapes();
-    MOZ_ASSERT(total > 1);
-
-    bool groupInScratch = mir->numUnboxedGroups() > 1;
-    bool shapeInScratch = mir->numShapes() > 1;
-
     Label done;
 
-    for (size_t i = 0; i < total; i++) {
-        bool unboxedGroup = i < mir->numUnboxedGroups();
-
-        ImmGCPtr comparePtr = unboxedGroup
-                              ? ImmGCPtr(mir->unboxedGroup(i))
-                              : ImmGCPtr(mir->objShape(i - mir->numUnboxedGroups()));
-        Address addr(obj, unboxedGroup ? JSObject::offsetOfGroup() : JSObject::offsetOfShape());
-
-        if ((i == 0 && groupInScratch) || (i == mir->numUnboxedGroups() && shapeInScratch))
-            masm.loadPtr(addr, scratch);
-
-        bool inScratch = unboxedGroup ? groupInScratch : shapeInScratch;
+    for (size_t i = 0; i < mir->numReceivers(); i++) {
+        ReceiverGuard::StackGuard receiver = mir->receiver(i);
 
         Label next;
-        if (i == total - 1) {
-            if (inScratch)
-                bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
-            else
-                bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
-        } else {
-            if (inScratch)
-                masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
-            else
-                masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
-        }
+        GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
 
-        if (unboxedGroup) {
-            const UnboxedLayout::Property* property =
-                mir->unboxedGroup(i)->unboxedLayout().lookup(mir->name());
-            Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
+        if (receiver.shape) {
+            // If this is an unboxed expando access, GuardReceiver loaded the
+            // expando object into scratch.
+            Register target = receiver.group ? scratch : obj;
 
-            masm.loadUnboxedProperty(propertyAddr, property->type, output);
-        } else {
-            Shape* shape = mir->shape(i - mir->numUnboxedGroups());
+            Shape* shape = mir->shape(i);
             if (shape->slot() < shape->numFixedSlots()) {
                 // Fixed slot.
-                masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
+                masm.loadTypedOrValue(Address(target, NativeObject::getFixedSlotOffset(shape->slot())),
                                       output);
             } else {
                 // Dynamic slot.
                 uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
-                masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
+                masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
                 masm.loadTypedOrValue(Address(scratch, offset), output);
             }
+        } else {
+            const UnboxedLayout::Property* property =
+                receiver.group->unboxedLayout().lookup(mir->name());
+            Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
+
+            masm.loadUnboxedProperty(propertyAddr, property->type, output);
         }
 
-        if (i != total - 1)
+        if (i == mir->numReceivers() - 1) {
+            bailoutFrom(&next, ins->snapshot());
+        } else {
             masm.jump(&done);
-        masm.bind(&next);
+            masm.bind(&next);
+        }
     }
 
     masm.bind(&done);
@@ -2354,42 +2355,36 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
 {
     MSetPropertyPolymorphic* mir = ins->mirRaw()->toSetPropertyPolymorphic();
 
-    size_t total = mir->numUnboxedGroups() + mir->numShapes();
-    MOZ_ASSERT(total > 1);
-
-    bool groupInScratch = mir->numUnboxedGroups() > 1;
-    bool shapeInScratch = mir->numShapes() > 1;
-
     Label done;
-    for (size_t i = 0; i < total; i++) {
-        bool unboxedGroup = i < mir->numUnboxedGroups();
-
-        ImmGCPtr comparePtr = unboxedGroup
-                              ? ImmGCPtr(mir->unboxedGroup(i))
-                              : ImmGCPtr(mir->objShape(i - mir->numUnboxedGroups()));
-        Address addr(obj, unboxedGroup ? JSObject::offsetOfGroup() : JSObject::offsetOfShape());
-
-        if ((i == 0 && groupInScratch) || (i == mir->numUnboxedGroups() && shapeInScratch))
-            masm.loadPtr(addr, scratch);
-
-        bool inScratch = unboxedGroup ? groupInScratch : shapeInScratch;
+    for (size_t i = 0; i < mir->numReceivers(); i++) {
+        ReceiverGuard::StackGuard receiver = mir->receiver(i);
 
         Label next;
-        if (i == total - 1) {
-            if (inScratch)
-                bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
-            else
-                bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
-        } else {
-            if (inScratch)
-                masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
-            else
-                masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
-        }
+        GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
 
-        if (unboxedGroup) {
+        if (receiver.shape) {
+            // If this is an unboxed expando access, GuardReceiver loaded the
+            // expando object into scratch.
+            Register target = receiver.group ? scratch : obj;
+
+            Shape* shape = mir->shape(i);
+            if (shape->slot() < shape->numFixedSlots()) {
+                // Fixed slot.
+                Address addr(target, NativeObject::getFixedSlotOffset(shape->slot()));
+                if (mir->needsBarrier())
+                    emitPreBarrier(addr);
+                masm.storeConstantOrRegister(value, addr);
+            } else {
+                // Dynamic slot.
+                masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
+                Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
+                if (mir->needsBarrier())
+                    emitPreBarrier(addr);
+                masm.storeConstantOrRegister(value, addr);
+            }
+        } else {
             const UnboxedLayout::Property* property =
-                mir->unboxedGroup(i)->unboxedLayout().lookup(mir->name());
+                receiver.group->unboxedLayout().lookup(mir->name());
             Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
 
             if (property->type == JSVAL_TYPE_OBJECT)
@@ -2400,27 +2395,14 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
                 MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(property->type));
 
             masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
-        } else {
-            Shape* shape = mir->shape(i - mir->numUnboxedGroups());
-            if (shape->slot() < shape->numFixedSlots()) {
-                // Fixed slot.
-                Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
-                if (mir->needsBarrier())
-                    emitPreBarrier(addr);
-                masm.storeConstantOrRegister(value, addr);
-            } else {
-                // Dynamic slot.
-                masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
-                Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
-                if (mir->needsBarrier())
-                    emitPreBarrier(addr);
-                masm.storeConstantOrRegister(value, addr);
-            }
         }
 
-        if (i != total - 1)
+        if (i == mir->numReceivers() - 1) {
+            bailoutFrom(&next, ins->snapshot());
+        } else {
             masm.jump(&done);
-        masm.bind(&next);
+            masm.bind(&next);
+        }
     }
 
     masm.bind(&done);
@@ -2548,41 +2530,46 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
     Register obj = ToRegister(lir->object());
     Register temp = ToRegister(lir->temp());
 
-    MOZ_ASSERT(mir->numShapes() + mir->numUnboxedGroups() > 1);
-
     Label done;
 
-    if (mir->numShapes()) {
-        masm.loadObjShape(obj, temp);
+    for (size_t i = 0; i < mir->numReceivers(); i++) {
+        const ReceiverGuard::StackGuard& receiver = mir->receiver(i);
 
-        for (size_t i = 0; i < mir->numShapes(); i++) {
-            Shape* shape = mir->getShape(i);
-            if (i == mir->numShapes() - 1 && !mir->numUnboxedGroups())
-                bailoutCmpPtr(Assembler::NotEqual, temp, ImmGCPtr(shape), lir->snapshot());
-            else
-                masm.branchPtr(Assembler::Equal, temp, ImmGCPtr(shape), &done);
-        }
-    }
+        Label next;
+        GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true);
 
-    if (mir->numUnboxedGroups()) {
-        // The guard requires that unboxed objects not have expandos.
-        bailoutCmpPtr(Assembler::NotEqual, Address(obj, JSObject::offsetOfShape()),
-                      ImmWord(0), lir->snapshot());
-
-        masm.loadObjGroup(obj, temp);
-
-        for (size_t i = 0; i < mir->numUnboxedGroups(); i++) {
-            ObjectGroup* group = mir->getUnboxedGroup(i);
-            if (i == mir->numUnboxedGroups() - 1)
-                bailoutCmpPtr(Assembler::NotEqual, temp, ImmGCPtr(group), lir->snapshot());
-            else
-                masm.branchPtr(Assembler::Equal, temp, ImmGCPtr(group), &done);
+        if (i == mir->numReceivers() - 1) {
+            bailoutFrom(&next, lir->snapshot());
+        } else {
+            masm.jump(&done);
+            masm.bind(&next);
         }
     }
 
     masm.bind(&done);
 }
 
+void
+CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir)
+{
+    Label miss;
+
+    Register obj = ToRegister(lir->object());
+    masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual,
+                   Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss);
+
+    bailoutFrom(&miss, lir->snapshot());
+}
+
+void
+CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
+{
+    Register obj = ToRegister(lir->object());
+    Register result = ToRegister(lir->getDef(0));
+
+    masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
+}
+
 void
 CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
 {
diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
index 78621fa088d..20bbcc8f88e 100644
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -123,6 +123,8 @@ class CodeGenerator : public CodeGeneratorSpecific
     void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir);
     void visitGuardObjectIdentity(LGuardObjectIdentity* guard);
     void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
+    void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
+    void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
     void visitTypeBarrierV(LTypeBarrierV* lir);
     void visitTypeBarrierO(LTypeBarrierO* lir);
     void visitMonitorTypes(LMonitorTypes* lir);
diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
index 30833206e80..3f8a9a9f088 100644
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10593,22 +10593,24 @@ IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* nam
 
 MDefinition*
 IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
-                const BaselineInspector::ShapeVector& receiverShapes,
-                const BaselineInspector::ObjectGroupVector& receiverUnboxedGroups,
+                const BaselineInspector::ReceiverVector& receivers,
+                const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
                 bool isOwnProperty)
 {
     MOZ_ASSERT(holder);
     MOZ_ASSERT(holderShape);
 
+    obj = convertUnboxedObjects(obj, convertUnboxedGroups);
+
     if (isOwnProperty) {
-        MOZ_ASSERT(receiverShapes.empty());
+        MOZ_ASSERT(receivers.empty());
         return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
     }
 
     MDefinition* holderDef = constantMaybeNursery(holder);
     addShapeGuard(holderDef, holderShape, Bailout_ShapeGuard);
 
-    return addGuardReceiverPolymorphic(obj, receiverShapes, receiverUnboxedGroups);
+    return addGuardReceiverPolymorphic(obj, receivers);
 }
 
 bool
@@ -10622,11 +10624,11 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
     Shape* globalShape = nullptr;
     JSObject* foundProto = nullptr;
     bool isOwnProperty = false;
-    BaselineInspector::ShapeVector receiverShapes(alloc());
-    BaselineInspector::ObjectGroupVector receiverUnboxedGroups(alloc());
+    BaselineInspector::ReceiverVector receivers(alloc());
+    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
     if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter,
                                           &globalShape, &isOwnProperty,
-                                          receiverShapes, receiverUnboxedGroups))
+                                          receivers, convertUnboxedGroups))
     {
         return true;
     }
@@ -10642,7 +10644,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
         // If type information is bad, we can still optimize the getter if we
         // shape guard.
         obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
-                                            receiverShapes, receiverUnboxedGroups,
+                                            receivers, convertUnboxedGroups,
                                             isOwnProperty);
         if (!obj)
             return false;
@@ -10754,20 +10756,19 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
 }
 
 bool
-IonBuilder::canInlinePropertyOpShapes(const BaselineInspector::ShapeVector& nativeShapes,
-                                      const BaselineInspector::ObjectGroupVector& unboxedGroups)
+IonBuilder::canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers)
 {
-    if (nativeShapes.empty() && unboxedGroups.empty()) {
+    if (receivers.empty()) {
         trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
         return false;
     }
 
-    for (size_t i = 0; i < nativeShapes.length(); i++) {
+    for (size_t i = 0; i < receivers.length(); i++) {
         // We inline the property access as long as the shape is not in
         // dictionary mode. We cannot be sure that the shape is still a
         // lastProperty, and calling Shape::search() on dictionary mode
         // shapes that aren't lastProperty is invalid.
-        if (nativeShapes[i]->inDictionary()) {
+        if (receivers[i].shape && receivers[i].shape->inDictionary()) {
             trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
             return false;
         }
@@ -10776,32 +10777,27 @@ IonBuilder::canInlinePropertyOpShapes(const BaselineInspector::ShapeVector& nati
     return true;
 }
 
-static bool
-GetPropertyShapes(jsid id, const BaselineInspector::ShapeVector& shapes,
-                  BaselineInspector::ShapeVector& propShapes, bool* sameSlot)
+static Shape*
+PropertyShapesHaveSameSlot(const BaselineInspector::ReceiverVector& receivers, jsid id)
 {
-    MOZ_ASSERT(propShapes.empty());
+    Shape* firstShape = nullptr;
+    for (size_t i = 0; i < receivers.length(); i++) {
+        if (receivers[i].group)
+            return nullptr;
 
-    if (!propShapes.reserve(shapes.length()))
-        return false;
-
-    *sameSlot = true;
-    for (size_t i = 0; i < shapes.length(); i++) {
-        Shape* objShape = shapes[i];
-        Shape* shape = objShape->searchLinear(id);
+        Shape* shape = receivers[i].shape->searchLinear(id);
         MOZ_ASSERT(shape);
-        propShapes.infallibleAppend(shape);
 
-        if (i > 0) {
-            if (shape->slot() != propShapes[0]->slot() ||
-                shape->numFixedSlots() != propShapes[0]->numFixedSlots())
-            {
-                *sameSlot = false;
-            }
+        if (i == 0) {
+            firstShape = shape;
+        } else if (shape->slot() != firstShape->slot() ||
+                   shape->numFixedSlots() != firstShape->numFixedSlots())
+        {
+            return nullptr;
         }
     }
 
-    return true;
+    return firstShape;
 }
 
 bool
@@ -10815,12 +10811,12 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
         return true;
     }
 
-    BaselineInspector::ShapeVector nativeShapes(alloc());
-    BaselineInspector::ObjectGroupVector unboxedGroups(alloc()), convertUnboxedGroups(alloc());
-    if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedGroups, convertUnboxedGroups))
+    BaselineInspector::ReceiverVector receivers(alloc());
+    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
+    if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
         return false;
 
-    if (!canInlinePropertyOpShapes(nativeShapes, unboxedGroups))
+    if (!canInlinePropertyOpShapes(receivers))
         return true;
 
     obj = convertUnboxedObjects(obj, convertUnboxedGroups);
@@ -10829,18 +10825,55 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
     if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
         rvalType = MIRType_Value;
 
-    if (nativeShapes.length() == 1 && unboxedGroups.empty()) {
-        // In the monomorphic case, use separate ShapeGuard and LoadSlot
-        // instructions.
-        spew("Inlining monomorphic GETPROP");
+    if (receivers.length() == 1) {
+        if (!receivers[0].group) {
+            // Monomorphic load from a native object.
+            spew("Inlining monomorphic native GETPROP");
 
-        Shape* objShape = nativeShapes[0];
-        obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
+            obj = addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard);
 
-        Shape* shape = objShape->searchLinear(NameToId(name));
-        MOZ_ASSERT(shape);
+            Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(shape);
 
-        if (!loadSlot(obj, shape, rvalType, barrier, types))
+            if (!loadSlot(obj, shape, rvalType, barrier, types))
+                return false;
+
+            trackOptimizationOutcome(TrackedOutcome::Monomorphic);
+            *emitted = true;
+            return true;
+        }
+
+        if (receivers[0].shape) {
+            // Monomorphic load from an unboxed object expando.
+            spew("Inlining monomorphic unboxed expando GETPROP");
+
+            obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
+            obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard);
+
+            MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj);
+            current->add(expando);
+
+            expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard);
+
+            Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(shape);
+
+            if (!loadSlot(expando, shape, rvalType, barrier, types))
+                return false;
+
+            trackOptimizationOutcome(TrackedOutcome::Monomorphic);
+            *emitted = true;
+            return true;
+        }
+
+        // Monomorphic load from an unboxed object.
+        obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
+
+        const UnboxedLayout::Property* property = receivers[0].group->unboxedLayout().lookup(name);
+        MInstruction* load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types);
+        current->push(load);
+
+        if (!pushTypeBarrier(load, types, barrier))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Monomorphic);
@@ -10848,37 +10881,15 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
         return true;
     }
 
-    if (nativeShapes.empty() && unboxedGroups.length() == 1) {
-        spew("Inlining monomorphic unboxed GETPROP");
-
-        ObjectGroup* group = unboxedGroups[0];
-        obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
-
-        const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
-        MInstruction* load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types);
-        current->push(load);
-
-        if (!pushTypeBarrier(load, types, barrier))
-            return false;
-
-        *emitted = true;
-        return true;
-    }
-
-    MOZ_ASSERT(nativeShapes.length() + unboxedGroups.length() > 1);
+    MOZ_ASSERT(receivers.length() > 1);
     spew("Inlining polymorphic GETPROP");
 
-    BaselineInspector::ShapeVector propShapes(alloc());
-    bool sameSlot;
-    if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
-        return false;
-
-    if (sameSlot && unboxedGroups.empty()) {
-        obj = addGuardReceiverPolymorphic(obj, nativeShapes, unboxedGroups);
+    if (Shape* propShape = PropertyShapesHaveSameSlot(receivers, NameToId(name))) {
+        obj = addGuardReceiverPolymorphic(obj, receivers);
         if (!obj)
             return false;
 
-        if (!loadSlot(obj, propShapes[0], rvalType, barrier, types))
+        if (!loadSlot(obj, propShape, rvalType, barrier, types))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Polymorphic);
@@ -10890,13 +10901,13 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
     current->add(load);
     current->push(load);
 
-    for (size_t i = 0; i < nativeShapes.length(); i++) {
-        if (!load->addShape(nativeShapes[i], propShapes[i]))
-            return false;
-    }
-
-    for (size_t i = 0; i < unboxedGroups.length(); i++) {
-        if (!load->addUnboxedGroup(unboxedGroups[i]))
+    for (size_t i = 0; i < receivers.length(); i++) {
+        Shape* propShape = nullptr;
+        if (receivers[i].shape) {
+            propShape = receivers[i].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(propShape);
+        }
+        if (!load->addReceiver(receivers[i], propShape))
             return false;
     }
 
@@ -11130,11 +11141,11 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
     JSFunction* commonSetter = nullptr;
     JSObject* foundProto = nullptr;
     bool isOwnProperty;
-    BaselineInspector::ShapeVector receiverShapes(alloc());
-    BaselineInspector::ObjectGroupVector receiverUnboxedGroups(alloc());
+    BaselineInspector::ReceiverVector receivers(alloc());
+    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
     if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter,
                                           &isOwnProperty,
-                                          receiverShapes, receiverUnboxedGroups))
+                                          receivers, convertUnboxedGroups))
     {
         trackOptimizationOutcome(TrackedOutcome::NoProtoFound);
         return true;
@@ -11149,7 +11160,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
         // If type information is bad, we can still optimize the setter if we
         // shape guard.
         obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
-                                            receiverShapes, receiverUnboxedGroups,
+                                            receivers, convertUnboxedGroups,
                                             isOwnProperty);
         if (!obj)
             return false;
@@ -11498,42 +11509,63 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
         return true;
     }
 
-    BaselineInspector::ShapeVector nativeShapes(alloc());
-    BaselineInspector::ObjectGroupVector unboxedGroups(alloc()), convertUnboxedGroups(alloc());
-    if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedGroups, convertUnboxedGroups))
+    BaselineInspector::ReceiverVector receivers(alloc());
+    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
+    if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
         return false;
 
-    if (!canInlinePropertyOpShapes(nativeShapes, unboxedGroups))
+    if (!canInlinePropertyOpShapes(receivers))
         return true;
 
     obj = convertUnboxedObjects(obj, convertUnboxedGroups);
 
-    if (nativeShapes.length() == 1 && unboxedGroups.empty()) {
-        spew("Inlining monomorphic SETPROP");
+    if (receivers.length() == 1) {
+        if (!receivers[0].group) {
+            // Monomorphic store to a native object.
+            spew("Inlining monomorphic native SETPROP");
 
-        // The Baseline IC was monomorphic, so we inline the property access as
-        // long as the shape is not in dictionary mode. We cannot be sure
-        // that the shape is still a lastProperty, and calling Shape::search
-        // on dictionary mode shapes that aren't lastProperty is invalid.
-        Shape* objShape = nativeShapes[0];
-        obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
+            obj = addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard);
 
-        Shape* shape = objShape->searchLinear(NameToId(name));
-        MOZ_ASSERT(shape);
+            Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(shape);
 
-        bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
-        if (!storeSlot(obj, shape, value, needsBarrier))
-            return false;
+            bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
+            if (!storeSlot(obj, shape, value, needsBarrier))
+                return false;
 
-        trackOptimizationOutcome(TrackedOutcome::Monomorphic);
-        *emitted = true;
-        return true;
-    }
+            trackOptimizationOutcome(TrackedOutcome::Monomorphic);
+            *emitted = true;
+            return true;
+        }
 
-    if (nativeShapes.empty() && unboxedGroups.length() == 1) {
+        if (receivers[0].shape) {
+            // Monomorphic store to an unboxed object expando.
+            spew("Inlining monomorphic unboxed expando SETPROP");
+
+            obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
+            obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard);
+
+            MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj);
+            current->add(expando);
+
+            expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard);
+
+            Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(shape);
+
+            bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
+            if (!storeSlot(expando, shape, value, needsBarrier))
+                return false;
+
+            trackOptimizationOutcome(TrackedOutcome::Monomorphic);
+            *emitted = true;
+            return true;
+        }
+
+        // Monomorphic store to an unboxed object.
         spew("Inlining monomorphic unboxed SETPROP");
 
-        ObjectGroup* group = unboxedGroups[0];
+        ObjectGroup* group = receivers[0].group;
         obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
 
         const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
@@ -11541,25 +11573,21 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
 
         current->push(value);
 
+        trackOptimizationOutcome(TrackedOutcome::Monomorphic);
         *emitted = true;
         return true;
     }
 
-    MOZ_ASSERT(nativeShapes.length() + unboxedGroups.length() > 1);
+    MOZ_ASSERT(receivers.length() > 1);
     spew("Inlining polymorphic SETPROP");
 
-    BaselineInspector::ShapeVector propShapes(alloc());
-    bool sameSlot;
-    if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
-        return false;
-
-    if (sameSlot && unboxedGroups.empty()) {
-        obj = addGuardReceiverPolymorphic(obj, nativeShapes, unboxedGroups);
+    if (Shape* propShape = PropertyShapesHaveSameSlot(receivers, NameToId(name))) {
+        obj = addGuardReceiverPolymorphic(obj, receivers);
         if (!obj)
             return false;
 
         bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
-        if (!storeSlot(obj, propShapes[0], value, needsBarrier))
+        if (!storeSlot(obj, propShape, value, needsBarrier))
             return false;
 
         trackOptimizationOutcome(TrackedOutcome::Polymorphic);
@@ -11571,16 +11599,13 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
     current->add(ins);
     current->push(value);
 
-    for (size_t i = 0; i < nativeShapes.length(); i++) {
-        Shape* objShape = nativeShapes[i];
-        Shape* shape =  objShape->searchLinear(NameToId(name));
-        MOZ_ASSERT(shape);
-        if (!ins->addShape(objShape, shape))
-            return false;
-    }
-
-    for (size_t i = 0; i < unboxedGroups.length(); i++) {
-        if (!ins->addUnboxedGroup(unboxedGroups[i]))
+    for (size_t i = 0; i < receivers.length(); i++) {
+        Shape* propShape = nullptr;
+        if (receivers[i].shape) {
+            propShape = receivers[i].shape->searchLinear(NameToId(name));
+            MOZ_ASSERT(propShape);
+        }
+        if (!ins->addReceiver(receivers[i], propShape))
             return false;
     }
 
@@ -12466,12 +12491,10 @@ IonBuilder::addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bail
 }
 
 MInstruction*
-IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind,
-                          bool checkUnboxedExpando)
+IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind)
 {
     MGuardObjectGroup* guard = MGuardObjectGroup::New(alloc(), obj, group,
-                                                      /* bailOnEquality = */ false,
-                                                      bailoutKind, checkUnboxedExpando);
+                                                      /* bailOnEquality = */ false, bailoutKind);
     current->add(guard);
 
     // If a shape guard failed in the past, don't optimize group guards.
@@ -12486,35 +12509,46 @@ IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bail
 }
 
 MInstruction*
-IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj,
-                                        const BaselineInspector::ShapeVector& shapes,
-                                        const BaselineInspector::ObjectGroupVector& unboxedGroups)
+IonBuilder::addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind)
 {
-    if (shapes.length() == 1 && unboxedGroups.empty())
-        return addShapeGuard(obj, shapes[0], Bailout_ShapeGuard);
+    MGuardUnboxedExpando* guard = MGuardUnboxedExpando::New(alloc(), obj, hasExpando, bailoutKind);
+    current->add(guard);
 
-    if (shapes.empty() && unboxedGroups.length() == 1) {
-        // The guard requires that unboxed objects not have expando objects.
-        // An inline cache will be used in these cases.
-        return addGroupGuard(obj, unboxedGroups[0], Bailout_ShapeGuard,
-                             /* checkUnboxedExpando = */ true);
+    // If a shape guard failed in the past, don't optimize group guards.
+    if (failedShapeGuard_)
+        guard->setNotMovable();
+
+    return guard;
+}
+
+MInstruction*
+IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj,
+                                        const BaselineInspector::ReceiverVector& receivers)
+{
+    if (receivers.length() == 1) {
+        if (!receivers[0].group) {
+            // Monomorphic guard on a native object.
+            return addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard);
+        }
+
+        if (!receivers[0].shape) {
+            // Guard on an unboxed object that does not have an expando.
+            obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
+            return addUnboxedExpandoGuard(obj, /* hasExpando = */ false, Bailout_ShapeGuard);
+        }
+
+        // Monomorphic receiver guards are not yet supported when the receiver
+        // is an unboxed object with an expando.
     }
 
-    MOZ_ASSERT(shapes.length() + unboxedGroups.length() > 1);
-
     MGuardReceiverPolymorphic* guard = MGuardReceiverPolymorphic::New(alloc(), obj);
     current->add(guard);
 
     if (failedShapeGuard_)
         guard->setNotMovable();
 
-    for (size_t i = 0; i < shapes.length(); i++) {
-        if (!guard->addShape(shapes[i]))
-            return nullptr;
-    }
-
-    for (size_t i = 0; i < unboxedGroups.length(); i++) {
-        if (!guard->addUnboxedGroup(unboxedGroups[i]))
+    for (size_t i = 0; i < receivers.length(); i++) {
+        if (!guard->addReceiver(receivers[i]))
             return nullptr;
     }
 
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
index 69e59a2490a..380bcbc6d7a 100644
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -401,13 +401,11 @@ class IonBuilder
     MDefinition* addMaybeCopyElementsForWrite(MDefinition* object);
     MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
     MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
-    MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind,
-                                bool checkUnboxedExpando = false);
+    MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
+    MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
 
     MInstruction*
-    addGuardReceiverPolymorphic(MDefinition* obj,
-                                const BaselineInspector::ShapeVector& shapes,
-                                const BaselineInspector::ObjectGroupVector& unboxedGroups);
+    addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
 
     MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id,
                                                        Scalar::Type viewType);
@@ -921,8 +919,8 @@ class IonBuilder
 
     MDefinition*
     addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
-                                  const BaselineInspector::ShapeVector& receiverShapes,
-                                  const BaselineInspector::ObjectGroupVector& receiverGroups,
+                                  const BaselineInspector::ReceiverVector& receivers,
+                                  const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
                                   bool isOwnProperty);
 
     bool annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPropCache,
@@ -946,8 +944,7 @@ class IonBuilder
                                        MDefinition* value);
     bool freezePropTypeSets(TemporaryTypeSet* types,
                             JSObject* foundProto, PropertyName* name);
-    bool canInlinePropertyOpShapes(const BaselineInspector::ShapeVector& nativeShapes,
-                                   const BaselineInspector::ObjectGroupVector& unboxedGroups);
+    bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers);
 
     TemporaryTypeSet* bytecodeTypes(jsbytecode* pc);
 
diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp
index 363c002c7cb..d37c41fe2cb 100644
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -794,7 +794,7 @@ JitcodeGlobalTable::sweep(JSRuntime* rt)
         if (entry->baseEntry().isJitcodeAboutToBeFinalized())
             e.removeFront();
         else
-            entry->sweep();
+            entry->sweep(rt);
     }
 }
 
@@ -930,6 +930,22 @@ JitcodeGlobalEntry::IonEntry::isMarkedFromAnyThread()
     return true;
 }
 
+bool
+JitcodeGlobalEntry::IonCacheEntry::markIfUnmarked(JSTracer* trc)
+{
+    JitcodeGlobalEntry entry;
+    RejoinEntry(trc->runtime(), *this, nativeStartAddr(), &entry);
+    return entry.markIfUnmarked(trc);
+}
+
+void
+JitcodeGlobalEntry::IonCacheEntry::sweep(JSRuntime* rt)
+{
+    JitcodeGlobalEntry entry;
+    RejoinEntry(rt, *this, nativeStartAddr(), &entry);
+    entry.sweep(rt);
+}
+
 bool
 JitcodeGlobalEntry::IonCacheEntry::isMarkedFromAnyThread(JSRuntime* rt)
 {
diff --git a/js/src/jit/JitcodeMap.h b/js/src/jit/JitcodeMap.h
index d96fa9b7378..fe1872b276c 100644
--- a/js/src/jit/JitcodeMap.h
+++ b/js/src/jit/JitcodeMap.h
@@ -446,6 +446,8 @@ class JitcodeGlobalEntry
         void youngestFrameLocationAtAddr(JSRuntime* rt, void* ptr,
                                          JSScript** script, jsbytecode** pc) const;
 
+        bool markIfUnmarked(JSTracer* trc);
+        void sweep(JSRuntime* rt);
         bool isMarkedFromAnyThread(JSRuntime* rt);
     };
 
@@ -828,6 +830,7 @@ class JitcodeGlobalEntry
             markedAny |= baselineEntry().markIfUnmarked(trc);
             break;
           case IonCache:
+            markedAny |= ionCacheEntry().markIfUnmarked(trc);
           case Dummy:
             break;
           default:
@@ -836,7 +839,7 @@ class JitcodeGlobalEntry
         return markedAny;
     }
 
-    void sweep() {
+    void sweep(JSRuntime* rt) {
         switch (kind()) {
           case Ion:
             ionEntry().sweep();
@@ -845,6 +848,7 @@ class JitcodeGlobalEntry
             baselineEntry().sweep();
             break;
           case IonCache:
+            ionCacheEntry().sweep(rt);
           case Dummy:
             break;
           default:
diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h
index 637f76d7f90..8be42a7a1f3 100644
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -6128,6 +6128,38 @@ class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1>
     }
 };
 
+class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(GuardUnboxedExpando)
+
+    explicit LGuardUnboxedExpando(const LAllocation& in) {
+        setOperand(0, in);
+    }
+    const LAllocation* object() {
+        return getOperand(0);
+    }
+    const MGuardUnboxedExpando* mir() const {
+        return mir_->toGuardUnboxedExpando();
+    }
+};
+
+class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(LoadUnboxedExpando)
+
+    explicit LLoadUnboxedExpando(const LAllocation& in) {
+        setOperand(0, in);
+    }
+    const LAllocation* object() {
+        return getOperand(0);
+    }
+    const MLoadUnboxedExpando* mir() const {
+        return mir_->toLoadUnboxedExpando();
+    }
+};
+
 // Guard that a value is in a TypeSet.
 class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
 {
diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h
index 5b37a29f2d4..82f179c254c 100644
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -208,6 +208,8 @@
     _(GuardObjectGroup)             \
     _(GuardObjectIdentity)          \
     _(GuardClass)                   \
+    _(GuardUnboxedExpando)          \
+    _(LoadUnboxedExpando)           \
     _(TypeBarrierV)                 \
     _(TypeBarrierO)                 \
     _(MonitorTypes)                 \
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index 0c8b0d3a33e..e50bb785234 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3269,6 +3269,24 @@ LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins)
     redefine(ins, ins->obj());
 }
 
+void
+LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins)
+{
+    LGuardUnboxedExpando* guard =
+        new(alloc()) LGuardUnboxedExpando(useRegister(ins->obj()));
+    assignSnapshot(guard, ins->bailoutKind());
+    add(guard, ins);
+    redefine(ins, ins->obj());
+}
+
+void
+LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins)
+{
+    LLoadUnboxedExpando* lir =
+        new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object()));
+    define(lir, ins);
+}
+
 void
 LIRGenerator::visitAssertRange(MAssertRange* ins)
 {
diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
index b7ab871fb5a..a8e6243729a 100644
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -221,6 +221,8 @@ class LIRGenerator : public LIRGeneratorSpecific
     void visitGuardObject(MGuardObject* ins);
     void visitGuardString(MGuardString* ins);
     void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
+    void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
+    void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
     void visitPolyInlineGuard(MPolyInlineGuard* ins);
     void visitAssertRange(MAssertRange* ins);
     void visitCallGetProperty(MCallGetProperty* ins);
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
index 556730f4ac8..ae3ee1e48d5 100644
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4342,17 +4342,10 @@ MGuardReceiverPolymorphic::congruentTo(const MDefinition* ins) const
 
     const MGuardReceiverPolymorphic* other = ins->toGuardReceiverPolymorphic();
 
-    if (numShapes() != other->numShapes())
+    if (numReceivers() != other->numReceivers())
         return false;
-    for (size_t i = 0; i < numShapes(); i++) {
-        if (getShape(i) != other->getShape(i))
-            return false;
-    }
-
-    if (numUnboxedGroups() != other->numUnboxedGroups())
-        return false;
-    for (size_t i = 0; i < numUnboxedGroups(); i++) {
-        if (getUnboxedGroup(i) != other->getUnboxedGroup(i))
+    for (size_t i = 0; i < numReceivers(); i++) {
+        if (receiver(i) != other->receiver(i))
             return false;
     }
 
@@ -4498,8 +4491,10 @@ MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const
     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
         return true;
 
-    for (size_t i = 0; i < numShapes(); i++) {
+    for (size_t i = 0; i < numReceivers(); i++) {
         const Shape* shape = this->shape(i);
+        if (!shape)
+            continue;
         if (shape->slot() < shape->numFixedSlots()) {
             // Fixed slot.
             uint32_t slot = shape->slot();
@@ -5119,8 +5114,7 @@ AddGroupGuard(TempAllocator& alloc, MBasicBlock* current, MDefinition* obj,
 
     if (key->isGroup()) {
         guard = MGuardObjectGroup::New(alloc, obj, key->group(), bailOnEquality,
-                                       Bailout_ObjectIdentityOrTypeGuard,
-                                       /* checkUnboxedExpando = */ false);
+                                       Bailout_ObjectIdentityOrTypeGuard);
     } else {
         MConstant* singletonConst = MConstant::NewConstraintlessObject(alloc, key->singleton());
         current->add(singletonConst);
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 4a170415855..e5438f4a416 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -17,6 +17,7 @@
 
 #include "builtin/SIMD.h"
 #include "jit/AtomicOp.h"
+#include "jit/BaselineIC.h"
 #include "jit/FixedList.h"
 #include "jit/InlineList.h"
 #include "jit/JitAllocPolicy.h"
@@ -9755,28 +9756,26 @@ class MGetPropertyCache
     bool updateForReplacement(MDefinition* ins) override;
 };
 
-// Emit code to load a value from an object if its shape/group matches one of
-// the shapes/groups observed by the baseline IC, else bails out.
+// Emit code to load a value from an object if it matches one of the receivers
+// observed by the baseline IC, else bails out.
 class MGetPropertyPolymorphic
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
     struct Entry {
-        // The shape to guard against.
-        Shape* objShape;
+        // The group and/or shape to guard against.
+        ReceiverGuard::StackGuard receiver;
 
-        // The property to laod.
+        // The property to load, null for loads from unboxed properties.
         Shape* shape;
     };
 
-    Vector nativeShapes_;
-    Vector unboxedGroups_;
+    Vector receivers_;
     AlwaysTenuredPropertyName name_;
 
     MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
       : MUnaryInstruction(obj),
-        nativeShapes_(alloc),
-        unboxedGroups_(alloc),
+        receivers_(alloc),
         name_(name)
     {
         setGuard();
@@ -9799,29 +9798,20 @@ class MGetPropertyPolymorphic
         return congruentIfOperandsEqual(ins);
     }
 
-    bool addShape(Shape* objShape, Shape* shape) {
+    bool addReceiver(const ReceiverGuard::StackGuard receiver, Shape* shape) {
         Entry entry;
-        entry.objShape = objShape;
+        entry.receiver = receiver;
         entry.shape = shape;
-        return nativeShapes_.append(entry);
+        return receivers_.append(entry);
     }
-    bool addUnboxedGroup(ObjectGroup* group) {
-        return unboxedGroups_.append(group);
+    size_t numReceivers() const {
+        return receivers_.length();
     }
-    size_t numShapes() const {
-        return nativeShapes_.length();
-    }
-    Shape* objShape(size_t i) const {
-        return nativeShapes_[i].objShape;
+    const ReceiverGuard::StackGuard receiver(size_t i) const {
+        return receivers_[i].receiver;
     }
     Shape* shape(size_t i) const {
-        return nativeShapes_[i].shape;
-    }
-    size_t numUnboxedGroups() const {
-        return unboxedGroups_.length();
-    }
-    ObjectGroup* unboxedGroup(size_t i) const {
-        return unboxedGroups_[i];
+        return receivers_[i].shape;
     }
     PropertyName* name() const {
         return name_;
@@ -9830,10 +9820,17 @@ class MGetPropertyPolymorphic
         return getOperand(0);
     }
     AliasSet getAliasSet() const override {
+        bool hasUnboxedLoad = false;
+        for (size_t i = 0; i < numReceivers(); i++) {
+            if (!shape(i)) {
+                hasUnboxedLoad = true;
+                break;
+            }
+        }
         return AliasSet::Load(AliasSet::ObjectFields |
                               AliasSet::FixedSlot |
                               AliasSet::DynamicSlot |
-                              (!unboxedGroups_.empty() ? AliasSet::UnboxedElement : 0));
+                              (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
     }
 
     bool mightAlias(const MDefinition* store) const override;
@@ -9846,23 +9843,21 @@ class MSetPropertyPolymorphic
     public MixPolicy >::Data
 {
     struct Entry {
-        // The shape to guard against.
-        Shape* objShape;
+        // The group and/or shape to guard against.
+        ReceiverGuard::StackGuard receiver;
 
-        // The property to load.
+        // The property to store, null for stores to unboxed properties.
         Shape* shape;
     };
 
-    Vector nativeShapes_;
-    Vector unboxedGroups_;
+    Vector receivers_;
     AlwaysTenuredPropertyName name_;
     bool needsBarrier_;
 
     MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
                             PropertyName* name)
       : MBinaryInstruction(obj, value),
-        nativeShapes_(alloc),
-        unboxedGroups_(alloc),
+        receivers_(alloc),
         name_(name),
         needsBarrier_(false)
     {
@@ -9876,29 +9871,20 @@ class MSetPropertyPolymorphic
         return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
     }
 
-    bool addShape(Shape* objShape, Shape* shape) {
+    bool addReceiver(const ReceiverGuard::StackGuard& receiver, Shape* shape) {
         Entry entry;
-        entry.objShape = objShape;
+        entry.receiver = receiver;
         entry.shape = shape;
-        return nativeShapes_.append(entry);
+        return receivers_.append(entry);
     }
-    bool addUnboxedGroup(ObjectGroup* group) {
-        return unboxedGroups_.append(group);
+    size_t numReceivers() const {
+        return receivers_.length();
     }
-    size_t numShapes() const {
-        return nativeShapes_.length();
-    }
-    Shape* objShape(size_t i) const {
-        return nativeShapes_[i].objShape;
+    const ReceiverGuard::StackGuard& receiver(size_t i) const {
+        return receivers_[i].receiver;
     }
     Shape* shape(size_t i) const {
-        return nativeShapes_[i].shape;
-    }
-    size_t numUnboxedGroups() const {
-        return unboxedGroups_.length();
-    }
-    ObjectGroup* unboxedGroup(size_t i) const {
-        return unboxedGroups_[i];
+        return receivers_[i].shape;
     }
     PropertyName* name() const {
         return name_;
@@ -9916,10 +9902,17 @@ class MSetPropertyPolymorphic
         needsBarrier_ = true;
     }
     AliasSet getAliasSet() const override {
+        bool hasUnboxedStore = false;
+        for (size_t i = 0; i < numReceivers(); i++) {
+            if (!shape(i)) {
+                hasUnboxedStore = true;
+                break;
+            }
+        }
         return AliasSet::Store(AliasSet::ObjectFields |
                                AliasSet::FixedSlot |
                                AliasSet::DynamicSlot |
-                               (!unboxedGroups_.empty() ? AliasSet::UnboxedElement : 0));
+                               (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
     }
 };
 
@@ -10214,13 +10207,11 @@ class MGuardReceiverPolymorphic
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
-    Vector shapes_;
-    Vector unboxedGroups_;
+    Vector receivers_;
 
     MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
       : MUnaryInstruction(obj),
-        shapes_(alloc),
-        unboxedGroups_(alloc)
+        receivers_(alloc)
     {
         setGuard();
         setMovable();
@@ -10238,24 +10229,14 @@ class MGuardReceiverPolymorphic
         return getOperand(0);
     }
 
-    bool addShape(Shape* shape) {
-        return shapes_.append(shape);
+    bool addReceiver(const ReceiverGuard::StackGuard& receiver) {
+        return receivers_.append(receiver);
     }
-    size_t numShapes() const {
-        return shapes_.length();
+    size_t numReceivers() const {
+        return receivers_.length();
     }
-    Shape* getShape(size_t i) const {
-        return shapes_[i];
-    }
-
-    bool addUnboxedGroup(ObjectGroup* group) {
-        return unboxedGroups_.append(group);
-    }
-    size_t numUnboxedGroups() const {
-        return unboxedGroups_.length();
-    }
-    ObjectGroup* getUnboxedGroup(size_t i) const {
-        return unboxedGroups_[i];
+    const ReceiverGuard::StackGuard& receiver(size_t i) const {
+        return receivers_[i];
     }
 
     bool congruentTo(const MDefinition* ins) const override;
@@ -10273,15 +10254,13 @@ class MGuardObjectGroup
     AlwaysTenured group_;
     bool bailOnEquality_;
     BailoutKind bailoutKind_;
-    bool checkUnboxedExpando_;
 
     MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
-                      BailoutKind bailoutKind, bool checkUnboxedExpando)
+                      BailoutKind bailoutKind)
       : MUnaryInstruction(obj),
         group_(group),
         bailOnEquality_(bailOnEquality),
-        bailoutKind_(bailoutKind),
-        checkUnboxedExpando_(checkUnboxedExpando)
+        bailoutKind_(bailoutKind)
     {
         setGuard();
         setMovable();
@@ -10296,10 +10275,8 @@ class MGuardObjectGroup
     INSTRUCTION_HEADER(GuardObjectGroup)
 
     static MGuardObjectGroup* New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group,
-                                  bool bailOnEquality, BailoutKind bailoutKind,
-                                  bool checkUnboxedExpando) {
-        return new(alloc) MGuardObjectGroup(obj, group, bailOnEquality, bailoutKind,
-                                            checkUnboxedExpando);
+                                  bool bailOnEquality, BailoutKind bailoutKind) {
+        return new(alloc) MGuardObjectGroup(obj, group, bailOnEquality, bailoutKind);
     }
 
     MDefinition* obj() const {
@@ -10314,9 +10291,6 @@ class MGuardObjectGroup
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
-    bool checkUnboxedExpando() const {
-        return checkUnboxedExpando_;
-    }
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isGuardObjectGroup())
             return false;
@@ -10420,6 +10394,84 @@ class MGuardClass
     ALLOW_CLONE(MGuardClass)
 };
 
+// Guard on the presence or absence of an unboxed object's expando.
+class MGuardUnboxedExpando
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool requireExpando_;
+    BailoutKind bailoutKind_;
+
+    MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
+      : MUnaryInstruction(obj),
+        requireExpando_(requireExpando),
+        bailoutKind_(bailoutKind)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType_Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardUnboxedExpando)
+
+    static MGuardUnboxedExpando* New(TempAllocator& alloc, MDefinition* obj,
+                                     bool requireExpando, BailoutKind bailoutKind) {
+        return new(alloc) MGuardUnboxedExpando(obj, requireExpando, bailoutKind);
+    }
+
+    MDefinition* obj() const {
+        return getOperand(0);
+    }
+    bool requireExpando() const {
+        return requireExpando_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
+            return false;
+        return true;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Load an unboxed plain object's expando.
+class MLoadUnboxedExpando
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  private:
+    explicit MLoadUnboxedExpando(MDefinition* object)
+      : MUnaryInstruction(object)
+    {
+        setResultType(MIRType_Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadUnboxedExpando)
+
+    static MLoadUnboxedExpando* New(TempAllocator& alloc, MDefinition* object) {
+        return new(alloc) MLoadUnboxedExpando(object);
+    }
+
+    MDefinition* object() const {
+        return getOperand(0);
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
 // Load from vp[slot] (slots that are not inline in an object).
 class MLoadSlot
   : public MUnaryInstruction,
diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
index 5387dfefdc0..0156544142e 100644
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -166,6 +166,8 @@ namespace jit {
     _(GuardObjectGroup)                                                     \
     _(GuardObjectIdentity)                                                  \
     _(GuardClass)                                                           \
+    _(GuardUnboxedExpando)                                                  \
+    _(LoadUnboxedExpando)                                                   \
     _(ArrayLength)                                                          \
     _(SetArrayLength)                                                       \
     _(TypedArrayLength)                                                     \
diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp
index 719f83c18ce..a7d1a19b84d 100644
--- a/js/src/jit/OptimizationTracking.cpp
+++ b/js/src/jit/OptimizationTracking.cpp
@@ -1213,11 +1213,14 @@ IonTrackedOptimizationsTypeInfo::ForEachOpAdapter::readType(const IonTrackedType
             return;
         }
 
-        PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
+        if (fun->displayAtom())
+            PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
         const char* filename;
         unsigned lineno;
         InterpretedFunctionFilenameAndLineNumber(fun, &filename, &lineno);
-        op_.readType(tracked.constructor ? "constructor" : "function", buf, filename, lineno);
+        op_.readType(tracked.constructor ? "constructor" : "function",
+                     fun->displayAtom() ? buf : nullptr,
+                     filename, lineno);
         return;
     }
 
diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp
index 1106e07a4b5..b15cb76f878 100644
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1664,12 +1664,6 @@ CodeGeneratorARM::visitGuardObjectGroup(LGuardObjectGroup* guard)
     Register tmp = ToRegister(guard->tempInt());
     MOZ_ASSERT(obj != tmp);
 
-    if (guard->mir()->checkUnboxedExpando()) {
-        masm.ma_ldr(DTRAddr(obj, DtrOffImm(UnboxedPlainObject::offsetOfExpando())), tmp);
-        masm.ma_cmp(tmp, ImmWord(0));
-        bailoutIf(Assembler::NotEqual, guard->snapshot());
-    }
-
     masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfGroup())), tmp);
     masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->group()));
 
@@ -1962,6 +1956,27 @@ CodeGeneratorARM::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
     }
 }
 
+void
+CodeGeneratorARM::visitAsmJSCompareExchangeCallout(LAsmJSCompareExchangeCallout* ins)
+{
+    const MAsmJSCompareExchangeHeap* mir = ins->mir();
+    Scalar::Type viewType = mir->accessType();
+    Register ptr = ToRegister(ins->ptr());
+    Register oldval = ToRegister(ins->oldval());
+    Register newval = ToRegister(ins->newval());
+
+    MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
+
+    masm.setupAlignedABICall(4);
+    masm.ma_mov(Imm32(viewType), ScratchRegister);
+    masm.passABIArg(ScratchRegister);
+    masm.passABIArg(ptr);
+    masm.passABIArg(oldval);
+    masm.passABIArg(newval);
+
+    masm.callWithABI(AsmJSImm_AtomicCmpXchg);
+}
+
 void
 CodeGeneratorARM::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
 {
@@ -2042,6 +2057,41 @@ CodeGeneratorARM::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEff
     }
 }
 
+void
+CodeGeneratorARM::visitAsmJSAtomicBinopCallout(LAsmJSAtomicBinopCallout* ins)
+{
+    const MAsmJSAtomicBinopHeap* mir = ins->mir();
+    Scalar::Type viewType = mir->accessType();
+    Register ptr = ToRegister(ins->ptr());
+    Register value = ToRegister(ins->value());
+
+    masm.setupAlignedABICall(3);
+    masm.ma_mov(Imm32(viewType), ScratchRegister);
+    masm.passABIArg(ScratchRegister);
+    masm.passABIArg(ptr);
+    masm.passABIArg(value);
+
+    switch (mir->operation()) {
+      case AtomicFetchAddOp:
+        masm.callWithABI(AsmJSImm_AtomicFetchAdd);
+        break;
+      case AtomicFetchSubOp:
+        masm.callWithABI(AsmJSImm_AtomicFetchSub);
+        break;
+      case AtomicFetchAndOp:
+        masm.callWithABI(AsmJSImm_AtomicFetchAnd);
+        break;
+      case AtomicFetchOrOp:
+        masm.callWithABI(AsmJSImm_AtomicFetchOr);
+        break;
+      case AtomicFetchXorOp:
+        masm.callWithABI(AsmJSImm_AtomicFetchXor);
+        break;
+      default:
+        MOZ_CRASH("Unknown op");
+    }
+}
+
 void
 CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
 {
diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h
index ef89a3d81d8..1d6cd42bebc 100644
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -218,8 +218,10 @@ class CodeGeneratorARM : public CodeGeneratorShared
     void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
     void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
     void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
+    void visitAsmJSCompareExchangeCallout(LAsmJSCompareExchangeCallout* ins);
     void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
     void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins);
+    void visitAsmJSAtomicBinopCallout(LAsmJSAtomicBinopCallout* ins);
     void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
diff --git a/js/src/jit/arm/LIR-arm.h b/js/src/jit/arm/LIR-arm.h
index f2f83b16471..b47b29ba38c 100644
--- a/js/src/jit/arm/LIR-arm.h
+++ b/js/src/jit/arm/LIR-arm.h
@@ -465,6 +465,53 @@ class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 1>
     }
 };
 
+class LAsmJSCompareExchangeCallout : public LInstructionHelper<1, 3, 0>
+{
+  public:
+    LIR_HEADER(AsmJSCompareExchangeCallout)
+    LAsmJSCompareExchangeCallout(const LAllocation& ptr, const LAllocation& oldval,
+                                 const LAllocation& newval)
+    {
+        setOperand(0, ptr);
+        setOperand(1, oldval);
+        setOperand(2, newval);
+    }
+    const LAllocation* ptr() {
+        return getOperand(0);
+    }
+    const LAllocation* oldval() {
+        return getOperand(1);
+    }
+    const LAllocation* newval() {
+        return getOperand(2);
+    }
+
+    const MAsmJSCompareExchangeHeap* mir() const {
+        return mir_->toAsmJSCompareExchangeHeap();
+    }
+};
+
+class LAsmJSAtomicBinopCallout : public LInstructionHelper<1, 2, 0>
+{
+  public:
+    LIR_HEADER(AsmJSAtomicBinopCallout)
+    LAsmJSAtomicBinopCallout(const LAllocation& ptr, const LAllocation& value)
+    {
+        setOperand(0, ptr);
+        setOperand(1, value);
+    }
+    const LAllocation* ptr() {
+        return getOperand(0);
+    }
+    const LAllocation* value() {
+        return getOperand(1);
+    }
+
+    const MAsmJSAtomicBinopHeap* mir() const {
+        return mir_->toAsmJSAtomicBinopHeap();
+    }
+};
+
 } // namespace jit
 } // namespace js
 
diff --git a/js/src/jit/arm/LOpcodes-arm.h b/js/src/jit/arm/LOpcodes-arm.h
index d412640393e..5a2e3c13332 100644
--- a/js/src/jit/arm/LOpcodes-arm.h
+++ b/js/src/jit/arm/LOpcodes-arm.h
@@ -25,6 +25,8 @@
     _(UDiv)                     \
     _(UMod)                     \
     _(SoftUDivOrMod)            \
-    _(AsmJSLoadFuncPtr)
+    _(AsmJSLoadFuncPtr)         \
+    _(AsmJSCompareExchangeCallout) \
+    _(AsmJSAtomicBinopCallout)
 
 #endif /* jit_arm_LOpcodes_arm_h */
diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp
index 18b8824cf7c..8c799ed1771 100644
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -655,6 +655,15 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
 
+    if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) {
+        LAsmJSCompareExchangeCallout* lir =
+            new(alloc()) LAsmJSCompareExchangeCallout(useRegister(ptr),
+                                                      useRegister(ins->oldValue()),
+                                                      useRegister(ins->newValue()));
+        defineFixed(lir, ins, LAllocation(AnyRegister(ReturnReg)));
+        return;
+    }
+
     LAsmJSCompareExchangeHeap* lir =
         new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr),
                                                useRegister(ins->oldValue()),
@@ -671,6 +680,13 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
 
+    if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) {
+        LAsmJSAtomicBinopCallout* lir =
+            new(alloc()) LAsmJSAtomicBinopCallout(useRegister(ptr), useRegister(ins->value()));
+        defineFixed(lir, ins, LAllocation(AnyRegister(ReturnReg)));
+        return;
+    }
+
     if (!ins->hasUses()) {
         LAsmJSAtomicBinopHeapForEffect* lir =
             new(alloc()) LAsmJSAtomicBinopHeapForEffect(useRegister(ptr),
diff --git a/js/src/jit/mips/CodeGenerator-mips.cpp b/js/src/jit/mips/CodeGenerator-mips.cpp
index 3354885f764..d722ed528ed 100644
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -1753,11 +1753,6 @@ CodeGeneratorMIPS::visitGuardObjectGroup(LGuardObjectGroup* guard)
     Register tmp = ToRegister(guard->tempInt());
     MOZ_ASSERT(obj != tmp);
 
-    if (guard->mir()->checkUnboxedExpando()) {
-        masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), tmp);
-        bailoutCmpPtr(Assembler::NotEqual, tmp, ImmWord(0), guard->snapshot());
-    }
-
     masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp);
     Assembler::Condition cond = guard->mir()->bailOnEquality()
                                 ? Assembler::Equal
diff --git a/js/src/jit/none/Architecture-none.h b/js/src/jit/none/Architecture-none.h
index 591d83754b3..dbf9842e6bf 100644
--- a/js/src/jit/none/Architecture-none.h
+++ b/js/src/jit/none/Architecture-none.h
@@ -16,7 +16,7 @@ namespace jit {
 
 static const bool SupportsSimd = false;
 static const uint32_t SimdMemoryAlignment = 4; // Make it 4 to avoid a bunch of div-by-zero warnings
-static const uint32_t AsmJSStackAlignment = 4;
+static const uint32_t AsmJSStackAlignment = 8;
 
 class Registers
 {
diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h
index 6dae2ad3144..bd19b837b0c 100644
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -856,6 +856,12 @@ enum AsmJSImmKind
 #if defined(JS_CODEGEN_ARM)
     AsmJSImm_aeabi_idivmod   = AsmJSExit::Builtin_IDivMod,
     AsmJSImm_aeabi_uidivmod  = AsmJSExit::Builtin_UDivMod,
+    AsmJSImm_AtomicCmpXchg   = AsmJSExit::Builtin_AtomicCmpXchg,
+    AsmJSImm_AtomicFetchAdd  = AsmJSExit::Builtin_AtomicFetchAdd,
+    AsmJSImm_AtomicFetchSub  = AsmJSExit::Builtin_AtomicFetchSub,
+    AsmJSImm_AtomicFetchAnd  = AsmJSExit::Builtin_AtomicFetchAnd,
+    AsmJSImm_AtomicFetchOr   = AsmJSExit::Builtin_AtomicFetchOr,
+    AsmJSImm_AtomicFetchXor  = AsmJSExit::Builtin_AtomicFetchXor,
 #endif
     AsmJSImm_ModD            = AsmJSExit::Builtin_ModD,
     AsmJSImm_SinD            = AsmJSExit::Builtin_SinD,
diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.h b/js/src/jit/x86-shared/Assembler-x86-shared.h
index 1b21b381f9f..23fa553951e 100644
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -1101,6 +1101,9 @@ class AssemblerX86Shared : public AssemblerShared
           case Operand::MEM_ADDRESS32:
             masm.addl_im(imm.value, op.address());
             break;
+          case Operand::MEM_SCALE:
+            masm.addl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
@@ -1116,6 +1119,9 @@ class AssemblerX86Shared : public AssemblerShared
           case Operand::MEM_REG_DISP:
             masm.subl_im(imm.value, op.disp(), op.base());
             break;
+          case Operand::MEM_SCALE:
+            masm.subl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
@@ -1197,6 +1203,9 @@ class AssemblerX86Shared : public AssemblerShared
           case Operand::MEM_REG_DISP:
             masm.orl_im(imm.value, op.disp(), op.base());
             break;
+          case Operand::MEM_SCALE:
+            masm.orl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
@@ -1230,6 +1239,9 @@ class AssemblerX86Shared : public AssemblerShared
           case Operand::MEM_REG_DISP:
             masm.xorl_im(imm.value, op.disp(), op.base());
             break;
+          case Operand::MEM_SCALE:
+            masm.xorl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
@@ -1263,6 +1275,9 @@ class AssemblerX86Shared : public AssemblerShared
           case Operand::MEM_REG_DISP:
             masm.andl_im(imm.value, op.disp(), op.base());
             break;
+          case Operand::MEM_SCALE:
+            masm.andl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
index c2a338d1ed9..93bcb01e945 100644
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -331,6 +331,18 @@ public:
         }
     }
 
+    void addl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("addl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_ADD);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_ADD);
+            m_formatter.immediate32(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void addq_rr(RegisterID src, RegisterID dst)
     {
@@ -726,6 +738,18 @@ public:
         }
     }
 
+    void andl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("andl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_AND);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_AND);
+            m_formatter.immediate32(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void andq_rr(RegisterID src, RegisterID dst)
     {
@@ -892,6 +916,18 @@ public:
         }
     }
 
+    void orl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("orl        $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_OR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_OR);
+            m_formatter.immediate32(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void negq_r(RegisterID dst)
     {
@@ -990,6 +1026,18 @@ public:
         }
     }
 
+    void subl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("subl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_SUB);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_SUB);
+            m_formatter.immediate32(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void subq_rr(RegisterID src, RegisterID dst)
     {
@@ -1079,6 +1127,18 @@ public:
         }
     }
 
+    void xorl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("xorl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_XOR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_XOR);
+            m_formatter.immediate32(imm);
+        }
+    }
+
     void xorl_ir(int32_t imm, RegisterID dst)
     {
         spew("xorl       $%d, %s", imm, GPReg32Name(dst));
diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
index 234df3aeb6b..fe7c9c9180f 100644
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -2071,11 +2071,6 @@ CodeGeneratorX86Shared::visitGuardObjectGroup(LGuardObjectGroup* guard)
 {
     Register obj = ToRegister(guard->input());
 
-    if (guard->mir()->checkUnboxedExpando()) {
-        masm.cmpPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0));
-        bailoutIf(Assembler::NotEqual, guard->snapshot());
-    }
-
     masm.cmpPtr(Operand(obj, JSObject::offsetOfGroup()), ImmGCPtr(guard->mir()->group()));
 
     Assembler::Condition cond =
@@ -2396,7 +2391,10 @@ CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Re
     // This won't generate fast code, but it's fine because we expect users
     // to have used constant indices (and thus MSimdGeneralShuffle to be fold
     // into MSimdSwizzle/MSimdShuffle, which are fast).
-    masm.reserveStack(Simd128DataSize * numVectors);
+
+    // We need stack space for the numVectors inputs and for the output vector.
+    unsigned stackSpace = Simd128DataSize * (numVectors + 1);
+    masm.reserveStack(stackSpace);
 
     for (unsigned i = 0; i < numVectors; i++) {
         masm.storeAlignedVector(ToFloatRegister(ins->vector(i)),
@@ -2408,7 +2406,7 @@ CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Re
     for (size_t i = 0; i < mir->numLanes(); i++) {
         Operand lane = ToOperand(ins->lane(i));
 
-        masm.cmp32(lane, Imm32(mir->numVectors() * mir->numLanes() - 1));
+        masm.cmp32(lane, Imm32(numVectors * mir->numLanes() - 1));
         masm.j(Assembler::Above, &bail);
 
         if (lane.kind() == Operand::REG) {
@@ -2430,13 +2428,13 @@ CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Re
 
     {
         masm.bind(&bail);
-        masm.freeStack(Simd128DataSize * numVectors);
+        masm.freeStack(stackSpace);
         bailout(ins->snapshot());
     }
 
     masm.bind(&join);
-    masm.setFramePushed(masm.framePushed() + Simd128DataSize * numVectors);
-    masm.freeStack(Simd128DataSize * numVectors);
+    masm.setFramePushed(masm.framePushed() + stackSpace);
+    masm.freeStack(stackSpace);
 }
 
 void
diff --git a/js/src/js.msg b/js/src/js.msg
index 79b33981268..30c7d2371b9 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -369,6 +369,7 @@ MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT,  0, JSEXN_TYPEERR, "proxy [[Construct]] mu
 MSG_DEF(JSMSG_PROXY_EXTENSIBILITY,     0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
 MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
 MSG_DEF(JSMSG_PROXY_REVOKED,           0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
+MSG_DEF(JSMSG_PROXY_ARG_REVOKED,       1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy")
 
 // Structured cloning
 MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION,    0, JSEXN_ERR, "unsupported structured clone version")
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index ed00e41fb8f..aac3b6d9116 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2266,6 +2266,7 @@ class JS_PUBLIC_API(CompartmentOptions)
       , invisibleToDebugger_(false)
       , mergeable_(false)
       , discardSource_(false)
+      , disableLazyParsing_(false)
       , cloneSingletons_(false)
       , traceGlobal_(nullptr)
       , singletonsAsTemplates_(true)
@@ -2310,6 +2311,12 @@ class JS_PUBLIC_API(CompartmentOptions)
         return *this;
     }
 
+    bool disableLazyParsing() const { return disableLazyParsing_; }
+    CompartmentOptions& setDisableLazyParsing(bool flag) {
+        disableLazyParsing_ = flag;
+        return *this;
+    }
+
     bool cloneSingletons() const { return cloneSingletons_; }
     CompartmentOptions& setCloneSingletons(bool flag) {
         cloneSingletons_ = flag;
@@ -2362,6 +2369,7 @@ class JS_PUBLIC_API(CompartmentOptions)
     bool invisibleToDebugger_;
     bool mergeable_;
     bool discardSource_;
+    bool disableLazyParsing_;
     bool cloneSingletons_;
     Override extraWarningsOverride_;
     union {
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index 7e1641fb327..4c1d2f5473a 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -247,7 +247,7 @@ JSCompartment::checkWrapperMapAfterMovingGC()
         CheckGCThingAfterMovingGC(static_cast(e.front().value().get().toGCThing()));
 
         WrapperMap::Ptr ptr = crossCompartmentWrappers.lookup(key);
-        MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
+        MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
     }
 }
 #endif
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index c4a0250a67c..725077385fe 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1476,6 +1476,27 @@ byteSize(Type atype)
     }
 }
 
+static inline bool
+isSignedIntType(Type atype) {
+    switch (atype) {
+      case Int8:
+      case Int16:
+      case Int32:
+      case Int32x4:
+        return true;
+      case Uint8:
+      case Uint8Clamped:
+      case Uint16:
+      case Uint32:
+      case Float32:
+      case Float64:
+      case Float32x4:
+        return false;
+      default:
+        MOZ_CRASH("invalid scalar type");
+    }
+}
+
 static inline bool
 isSimdType(Type atype) {
     switch (atype) {
diff --git a/js/src/jsgc.h b/js/src/jsgc.h
index a79c338562a..d149c2b19b5 100644
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1259,8 +1259,10 @@ template 
 inline void
 CheckGCThingAfterMovingGC(T* t)
 {
-    MOZ_ASSERT_IF(t, !IsInsideNursery(t));
-    MOZ_ASSERT_IF(t, !RelocationOverlay::isCellForwarded(t));
+    if (t) {
+        MOZ_RELEASE_ASSERT(!IsInsideNursery(t));
+        MOZ_RELEASE_ASSERT(!RelocationOverlay::isCellForwarded(t));
+    }
 }
 
 inline void
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index 9afa7bb24ad..a2e68ef326b 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1347,7 +1347,7 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
         // The initial objects registered with a TypeNewScript can't be in the
         // nursery.
         if (newKind == GenericObject)
-            newKind = MaybeSingletonObject;
+            newKind = TenuredObject;
 
         // Not enough objects with this group have been created yet, so make a
         // plain object and register it with the group. Use the maximum number
@@ -1965,8 +1965,7 @@ js::CloneObjectLiteral(JSContext* cx, HandleObject srcObj)
         if (!group)
             return nullptr;
 
-        RootedPlainObject res(cx, NewObjectWithGroup(cx, group, kind,
-                                                                  MaybeSingletonObject));
+        RootedPlainObject res(cx, NewObjectWithGroup(cx, group, kind, TenuredObject));
         if (!res)
             return nullptr;
 
@@ -1985,8 +1984,7 @@ js::CloneObjectLiteral(JSContext* cx, HandleObject srcObj)
     MOZ_ASSERT(srcArray->getElementsHeader()->ownerObject() == srcObj);
 
     size_t length = srcArray->as().length();
-    RootedArrayObject res(cx, NewDenseFullyAllocatedArray(cx, length, NullPtr(),
-                                                          MaybeSingletonObject));
+    RootedArrayObject res(cx, NewDenseFullyAllocatedArray(cx, length, NullPtr(), TenuredObject));
     if (!res)
         return nullptr;
 
diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h
index f1f9564fa4e..86a2a95196e 100644
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -20,7 +20,7 @@
 
 #include "js/TypeDecls.h"
 
-#if (defined(JS_GC_ZEAL)) || defined(DEBUG)
+#if defined(JS_GC_ZEAL) || defined(DEBUG)
 # define JSGC_HASH_TABLE_CHECKS
 #endif
 
diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp
index dfd415c8445..568aa49df01 100644
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1175,6 +1175,14 @@ ScriptedDirectProxyHandler::isConstructor(JSObject* obj) const
 const char ScriptedDirectProxyHandler::family = 0;
 const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
 
+bool
+IsRevokedScriptedProxy(JSObject* obj)
+{
+    obj = CheckedUnwrap(obj);
+    return obj && IsScriptedProxy(obj) && !obj->as().target();
+}
+
+// ES6 draft rc4 9.5.15.
 static bool
 NewScriptedProxy(JSContext* cx, CallArgs& args, const char* callerName)
 {
@@ -1183,26 +1191,48 @@ NewScriptedProxy(JSContext* cx, CallArgs& args, const char* callerName)
                              callerName, "1", "s");
         return false;
     }
+
+    // Step 1.
     RootedObject target(cx, NonNullObject(cx, args[0]));
     if (!target)
         return false;
+
+    // Step 2.
+    if (IsRevokedScriptedProxy(target)) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "1");
+        return false;
+    }
+
+    // Step 3.
     RootedObject handler(cx, NonNullObject(cx, args[1]));
     if (!handler)
         return false;
+
+    // Step 4.
+    if (IsRevokedScriptedProxy(handler)) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "2");
+        return false;
+    }
+
+    // Steps 5-6, and 8 (reordered).
     RootedValue priv(cx, ObjectValue(*target));
     JSObject* proxy_ =
         NewProxyObject(cx, &ScriptedDirectProxyHandler::singleton,
                        priv, TaggedProto::LazyProto);
     if (!proxy_)
         return false;
+
+    // Step 9 (reordered).
     Rooted proxy(cx, &proxy_->as());
     proxy->setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
 
-    // Assign [[Call]] and [[Construct]]
+    // Step 7, Assign [[Call]] and [[Construct]].
     uint32_t callable = target->isCallable() ? ScriptedDirectProxyHandler::IS_CALLABLE : 0;
     uint32_t constructor = target->isConstructor() ? ScriptedDirectProxyHandler::IS_CONSTRUCTOR : 0;
     proxy->as().setExtra(ScriptedDirectProxyHandler::IS_CALLCONSTRUCT_EXTRA,
                                       PrivateUint32Value(callable | constructor));
+
+    // Step 10.
     args.rval().setObject(*proxy);
     return true;
 }
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 05c57a41cac..dd3804383c7 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -586,7 +586,6 @@ Process(JSContext* cx, const char* filename, bool forceTTY)
         if (!file) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                  JSSMSG_CANT_OPEN, filename, strerror(errno));
-            gExitCode = EXITCODE_FILE_NOT_FOUND;
             return;
         }
     }
@@ -1398,7 +1397,6 @@ FileAsString(JSContext* cx, const char* pathname)
                         JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(buf, len), &len).get();
                     if (!ucbuf) {
                         JS_ReportError(cx, "Invalid UTF-8 in file '%s'", pathname);
-                        gExitCode = EXITCODE_RUNTIME_ERROR;
                         return nullptr;
                     }
                     str = JS_NewUCStringCopyN(cx, ucbuf, len);
diff --git a/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js
new file mode 100644
index 00000000000..e0ae15acf8a
--- /dev/null
+++ b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js
@@ -0,0 +1,53 @@
+var BUGNUMBER = 1151149;
+var summary = "Proxy constructor should throw if either the target or handler is a revoked proxy.";
+
+print(BUGNUMBER + ": " + summary);
+
+var p = new Proxy({}, {});
+
+new Proxy(p, {});
+new Proxy({}, p);
+
+var r = Proxy.revocable({}, {});
+p = r.proxy;
+
+new Proxy(p, {});
+new Proxy({}, p);
+
+r.revoke();
+
+assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError);
+assertThrowsInstanceOf(() => new Proxy({}, p), TypeError);
+
+
+var r2 = Proxy.revocable({}, {});
+r = Proxy.revocable(r2.proxy, {});
+p = r.proxy;
+
+new Proxy(p, {});
+new Proxy({}, p);
+
+r2.revoke();
+
+new Proxy(p, {});
+new Proxy({}, p);
+
+r.revoke();
+
+assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError);
+assertThrowsInstanceOf(() => new Proxy({}, p), TypeError);
+
+
+var g = newGlobal();
+p = g.eval(`var r = Proxy.revocable({}, {}); r.proxy;`);
+
+new Proxy(p, {});
+new Proxy({}, p);
+
+g.eval(`r.revoke();`);
+
+assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError);
+assertThrowsInstanceOf(() => new Proxy({}, p), TypeError);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 386a5398a34..fbf610987ee 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3038,7 +3038,7 @@ CASE(JSOP_OBJECT)
     RootedObject& ref = rootObject0;
     ref = script->getObject(REGS.pc);
     if (JS::CompartmentOptionsRef(cx).cloneSingletons()) {
-        JSObject* obj = DeepCloneObjectLiteral(cx, ref, js::MaybeSingletonObject);
+        JSObject* obj = DeepCloneObjectLiteral(cx, ref, TenuredObject);
         if (!obj)
             goto error;
         PUSH_OBJECT(*obj);
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index dae7ff85353..4f52c489865 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1553,7 +1553,7 @@ ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
 
         NewEntry::Lookup lookup(clasp, proto, entry.associated);
         NewTable::Ptr ptr = table->lookup(lookup);
-        MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
+        MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
     }
 }
 
diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
index 1ff12005e70..2abc275ec10 100644
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -140,17 +140,10 @@ enum NewObjectKind {
     /*
      * Singleton objects are treated specially by the type system. This flag
      * ensures that the new object is automatically set up correctly as a
-     * singleton and is allocated in the correct heap.
+     * singleton and is allocated in the tenured heap.
      */
     SingletonObject,
 
-    /*
-     * Objects which may be marked as a singleton after allocation must still
-     * be allocated on the correct heap, but are not automatically setup as a
-     * singleton after allocation.
-     */
-    MaybeSingletonObject,
-
     /*
      * Objects which will not benefit from being allocated in the nursery
      * (e.g. because they are known to have a long lifetime) may be allocated
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index ab078b940d7..5c5008938bf 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -682,7 +682,7 @@
      * Throws the indicated JSMSG.
      *
      *   Category: Statements
-     *   Type: Exceptions
+     *   Type: Exception Handling
      *   Operands: uint16_t msgNumber
      *   Stack: =>
      */ \
diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
index b86a590ea8f..9860408d2d8 100644
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -251,14 +251,14 @@ uint32_t
 SavedFrame::getLine()
 {
     const Value& v = getReservedSlot(JSSLOT_LINE);
-    return v.toInt32();
+    return v.toPrivateUint32();
 }
 
 uint32_t
 SavedFrame::getColumn()
 {
     const Value& v = getReservedSlot(JSSLOT_COLUMN);
-    return v.toInt32();
+    return v.toPrivateUint32();
 }
 
 JSAtom*
@@ -304,8 +304,8 @@ SavedFrame::initFromLookup(SavedFrame::HandleLookup lookup)
     MOZ_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined());
     setReservedSlot(JSSLOT_SOURCE, StringValue(lookup->source));
 
-    setReservedSlot(JSSLOT_LINE, NumberValue(lookup->line));
-    setReservedSlot(JSSLOT_COLUMN, NumberValue(lookup->column));
+    setReservedSlot(JSSLOT_LINE, PrivateUint32Value(lookup->line));
+    setReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(lookup->column));
     setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME,
                     lookup->functionDisplayName
                         ? StringValue(lookup->functionDisplayName)
diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
index 69743a54dff..ab4eae925ad 100644
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1274,7 +1274,7 @@ JSCompartment::checkBaseShapeTableAfterMovingGC()
         CheckGCThingAfterMovingGC(base);
 
         BaseShapeSet::Ptr ptr = baseShapes.lookup(base);
-        MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
+        MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
     }
 }
 
@@ -1402,7 +1402,7 @@ JSCompartment::checkInitialShapesTableAfterMovingGC()
                                          shape->numFixedSlots(),
                                          shape->getObjectFlags());
         InitialShapeSet::Ptr ptr = initialShapes.lookup(lookup);
-        MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
+        MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
     }
 }
 
diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp
index 8ad11a7f5b2..191b7572542 100644
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -751,6 +751,11 @@ JSFlatString::isIndexSlow(const char16_t* s, size_t length, uint32_t* indexp);
 const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) };
 #undef R
 
+#undef R2
+#undef R4
+#undef R6
+#undef R7
+
 bool
 StaticStrings::init(JSContext* cx)
 {
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 6f3d012f8d8..6c8d828077f 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3647,8 +3647,7 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
     }
 
     RootedObjectGroup groupRoot(cx, group);
-    templateObject_ = NewObjectWithGroup(cx, groupRoot, kind,
-                                                      MaybeSingletonObject);
+    templateObject_ = NewObjectWithGroup(cx, groupRoot, kind, TenuredObject);
     if (!templateObject_)
         return false;
 
diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
index be04f28070c..6914ae8a790 100644
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -437,7 +437,7 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
 
         PlainObject* templateObject = NewObjectWithGroup(cx, replacementNewGroup,
                                                                       layout.getAllocKind(),
-                                                                      MaybeSingletonObject);
+                                                                      TenuredObject);
         if (!templateObject)
             return false;
 
diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h
index c8585dc3c80..3fee94cbe14 100644
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -29,11 +29,11 @@ namespace js {
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 273;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 274;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 391,
+static_assert(JSErr_Limit == 392,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
diff --git a/layout/analysis/pixel-conversion.js b/layout/analysis/pixel-conversion.js
deleted file mode 100644
index 04daa7a693f..00000000000
--- a/layout/analysis/pixel-conversion.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/* 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("simple-match.js");
-
-var patterns = {CSSPixelsToDevPixels: ['AppUnitsToDevPixels', 'CSSPixelsToAppUnits'],
-                DevPixelsToIntCSSPixels: ['AppUnitsToIntCSSPixels', 'DevPixelsToAppUnits'],
-                DevPixelsToFloatCSSPixels: ['AppUnitsToFloatCSSPixels', 'DevPixelsToAppUnits'],
-               };
diff --git a/layout/analysis/simple-match.js b/layout/analysis/simple-match.js
deleted file mode 100644
index fa8e68724be..00000000000
--- a/layout/analysis/simple-match.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/* 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/. */
-
-// This executes a very simple search for all functions that call a
-// given set of functions. It's intended to be the simplest possible
-// way of refactoring a common pattern of function calls. Of course,
-// it's still up to a human to decide if the replacement is truely
-// suitable, but this gets the low-hanging fruit.
-
-// Expects the variable 'patterns' to hold an object with replacement
-// function names as keys and function lists as values. Any function
-// in the tested source that calls all of the functions named in the
-// list will be listed in the output as being likely candidates to
-// instead call the replacement function.
-
-include("unstable/lazy_types.js");
-
-var matches = {};
-
-function identity(x) x;
-
-function process_cp_pre_genericize(fndecl)
-{
-    var c = [];
-    function calls(t, stack)
-    {
-        try {
-            t.tree_check(CALL_EXPR);
-            var fn = callable_arg_function_decl(CALL_EXPR_FN(t));
-            if (fn)
-                c.push(decl_name_string(fn));
-        }
-        catch (e if e.TreeCheckError) { }
-    }
-
-    walk_tree(DECL_SAVED_TREE(fndecl), calls);
-
-    for (let [fnreplace, pattern] in patterns)
-        if (pattern.map(function(e){ return c.some(function(f) { return e == f; }); }).every(identity))
-            if (fnreplace != (n = decl_name_string(fndecl)))
-                print(fnreplace +" could probably be used in "+ n);
-}
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp
index 601ae9e1e19..143cbd7002a 100644
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -502,11 +502,9 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
     return;
   }
   AnimationPlayerCollection* transitions =
-    nsTransitionManager::GetAnimationsForCompositor(content, aProperty,
-      GetCompositorAnimationOptions::NotifyActiveLayerTracker);
+    nsTransitionManager::GetAnimationsForCompositor(content, aProperty);
   AnimationPlayerCollection* animations =
-    nsAnimationManager::GetAnimationsForCompositor(content, aProperty,
-      GetCompositorAnimationOptions::NotifyActiveLayerTracker);
+    nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
 
   if (!animations && !transitions) {
     return;
diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp
index 9d37198f361..b92d7da09bf 100644
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -791,14 +791,11 @@ nsContainerFrame::DoInlineIntrinsicISize(nsRenderingContext *aRenderingContext,
   NS_PRECONDITION(aType == nsLayoutUtils::MIN_ISIZE ||
                   aType == nsLayoutUtils::PREF_ISIZE, "bad type");
 
-  mozilla::css::Side startSide, endSide;
-  if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
-    startSide = NS_SIDE_LEFT;
-    endSide = NS_SIDE_RIGHT;
-  } else {
-    startSide = NS_SIDE_RIGHT;
-    endSide = NS_SIDE_LEFT;
-  }
+  WritingMode wm = GetWritingMode();
+  mozilla::css::Side startSide =
+    wm.PhysicalSideForInlineAxis(eLogicalEdgeStart);
+  mozilla::css::Side endSide =
+    wm.PhysicalSideForInlineAxis(eLogicalEdgeEnd);
 
   const nsStylePadding *stylePadding = StylePadding();
   const nsStyleBorder *styleBorder = StyleBorder();
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 257f4e5adee..de8689273c5 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4090,21 +4090,33 @@ nsFrame::IntrinsicISizeOffsets(nsRenderingContext* aRenderingContext)
 {
   IntrinsicISizeOffsetData result;
 
+  WritingMode wm = GetWritingMode();
+
   const nsStyleMargin *styleMargin = StyleMargin();
-  AddCoord(styleMargin->mMargin.GetLeft(), aRenderingContext, this,
-           &result.hMargin, &result.hPctMargin, false);
-  AddCoord(styleMargin->mMargin.GetRight(), aRenderingContext, this,
-           &result.hMargin, &result.hPctMargin, false);
+  AddCoord(wm.IsVertical() ? styleMargin->mMargin.GetTop()
+                           : styleMargin->mMargin.GetLeft(),
+           aRenderingContext, this, &result.hMargin, &result.hPctMargin,
+           false);
+  AddCoord(wm.IsVertical() ? styleMargin->mMargin.GetBottom()
+                           : styleMargin->mMargin.GetRight(),
+           aRenderingContext, this, &result.hMargin, &result.hPctMargin,
+           false);
 
   const nsStylePadding *stylePadding = StylePadding();
-  AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
-           &result.hPadding, &result.hPctPadding, true);
-  AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
-           &result.hPadding, &result.hPctPadding, true);
+  AddCoord(wm.IsVertical() ? stylePadding->mPadding.GetTop()
+                           : stylePadding->mPadding.GetLeft(),
+           aRenderingContext, this, &result.hPadding, &result.hPctPadding,
+           true);
+  AddCoord(wm.IsVertical() ? stylePadding->mPadding.GetBottom()
+                           : stylePadding->mPadding.GetRight(),
+           aRenderingContext, this, &result.hPadding, &result.hPctPadding,
+           true);
 
   const nsStyleBorder *styleBorder = StyleBorder();
-  result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_LEFT);
-  result.hBorder += styleBorder->GetComputedBorderWidth(NS_SIDE_RIGHT);
+  result.hBorder += styleBorder->GetComputedBorderWidth(
+    wm.PhysicalSideForInlineAxis(eLogicalEdgeStart));
+  result.hBorder += styleBorder->GetComputedBorderWidth(
+    wm.PhysicalSideForInlineAxis(eLogicalEdgeEnd));
 
   const nsStyleDisplay *disp = StyleDisplay();
   if (IsThemed(disp)) {
@@ -4114,13 +4126,17 @@ nsFrame::IntrinsicISizeOffsets(nsRenderingContext* aRenderingContext)
     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
                                              this, disp->mAppearance,
                                              &border);
-    result.hBorder = presContext->DevPixelsToAppUnits(border.LeftRight());
+    result.hBorder =
+      presContext->DevPixelsToAppUnits(wm.IsVertical() ? border.TopBottom()
+                                                       : border.LeftRight());
 
     nsIntMargin padding;
     if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
                                                   this, disp->mAppearance,
                                                   &padding)) {
-      result.hPadding = presContext->DevPixelsToAppUnits(padding.LeftRight());
+      result.hPadding =
+        presContext->DevPixelsToAppUnits(wm.IsVertical() ? padding.TopBottom()
+                                                         : padding.LeftRight());
       result.hPctPadding = 0;
     }
   }
diff --git a/layout/reftests/bugs/1012640-1-ref.html b/layout/reftests/bugs/1012640-1-ref.html
new file mode 100644
index 00000000000..3a197b16084
--- /dev/null
+++ b/layout/reftests/bugs/1012640-1-ref.html
@@ -0,0 +1,21 @@
+
+
+
+
+white-space: nowrap; regressed in Firefox 29
+
+
+
+
    +
  • short string
  • +
  • short string
  • +
  • short string
  • +
  • why doesn't this move to the next line?
  • +
+ + diff --git a/layout/reftests/bugs/1012640-1.html b/layout/reftests/bugs/1012640-1.html new file mode 100644 index 00000000000..adf899bd42d --- /dev/null +++ b/layout/reftests/bugs/1012640-1.html @@ -0,0 +1,21 @@ + + + + +white-space: nowrap; regressed in Firefox 29 + + + +
    +
  • short string
  • +
  • short string
  • +
  • short string
  • +
  • why doesn't this move to the next line?
  • +
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index b5659819df9..c562f00aceb 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1824,6 +1824,7 @@ pref(layout.css.overflow-clip-box.enabled,true) == 992447.html 992447-ref.html == 1003425-1.html 1003425-1-ref.html == 1003425-2.html 1003425-2-ref.html pref(layout.css.sticky.enabled,true) == 1005405-1.html 1005405-1-ref.html +== 1012640-1.html 1012640-1-ref.html fuzzy-if(/^Windows\x20NT\x205\.1/.test(http.oscpu),255,1) == 1013054-1.html 1013054-1-ref.html pref(layout.css.will-change.enabled,true) == 1018522-1.html 1018522-1-ref.html == 1021564-1.html 1021564-ref.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 09c469fc8eb..9bb60e45bba 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -386,6 +386,7 @@ random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == tspan-rotate-06.svg tspa == viewBox-and-pattern-01.svg pass.svg == viewBox-and-pattern-02.svg pass.svg == viewBox-and-pattern-03.svg pass.svg +== viewBox-and-pattern-04.svg pass.svg == viewBox-invalid-01.svg pass.svg == viewBox-valid-01.svg pass.svg == viewBox-valid-02.xhtml pass.svg diff --git a/layout/reftests/svg/viewBox-and-pattern-04.svg b/layout/reftests/svg/viewBox-and-pattern-04.svg new file mode 100644 index 00000000000..8963bb9366f --- /dev/null +++ b/layout/reftests/svg/viewBox-and-pattern-04.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/layout/reftests/writing-mode/1130907-intrinsic-sizing-1-ref.html b/layout/reftests/writing-mode/1130907-intrinsic-sizing-1-ref.html new file mode 100644 index 00000000000..1817d739ee2 --- /dev/null +++ b/layout/reftests/writing-mode/1130907-intrinsic-sizing-1-ref.html @@ -0,0 +1,60 @@ + + + + + Test for intrinsic sizing of float around contents with border + + + +

In each case, the blue border should neatly enclose the text and its yellow border-block.

+
+ x123321 +
+
+ 123321x +
+
+ x
123321
+
+
+ 123321
x
+
+
+
+ x123321 +
+
+ 123321x +
+
+ x
123321
+
+
+ 123321
x
+
+
+
+ x123321 +
+
+ 123321x +
+
+ x
123321
+
+
+ 123321
x
+
+ + diff --git a/layout/reftests/writing-mode/1130907-intrinsic-sizing-1.html b/layout/reftests/writing-mode/1130907-intrinsic-sizing-1.html new file mode 100644 index 00000000000..dd8126d00bb --- /dev/null +++ b/layout/reftests/writing-mode/1130907-intrinsic-sizing-1.html @@ -0,0 +1,61 @@ + + + + + Test for intrinsic sizing of float around contents with border + + + +

In each case, the blue border should neatly enclose the text and its yellow border-block.

+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+ + diff --git a/layout/reftests/writing-mode/1130907-intrinsic-sizing-2-ref.html b/layout/reftests/writing-mode/1130907-intrinsic-sizing-2-ref.html new file mode 100644 index 00000000000..44aca7acf50 --- /dev/null +++ b/layout/reftests/writing-mode/1130907-intrinsic-sizing-2-ref.html @@ -0,0 +1,73 @@ + + + + + Test for intrinsic sizing of float around contents with border + + + +

In each case, the blue border should neatly enclose the text.

+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+ + diff --git a/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html b/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html new file mode 100644 index 00000000000..cef3f3d3775 --- /dev/null +++ b/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html @@ -0,0 +1,74 @@ + + + + + Test for intrinsic sizing of float around contents with border + + + +

In each case, the blue border should neatly enclose the text.

+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+ 123321 +
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+
+
123321
+
+ + diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index 90e1eaa2caf..b2a20a59c86 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -103,6 +103,8 @@ HTTP(..) == 1127488-align-start-vertical-lr-ltr.html 1127488-align-top-left-ref. HTTP(..) == 1127488-align-end-vertical-lr-ltr.html 1127488-align-bottom-left-ref.html HTTP(..) == 1127488-align-left-vertical-lr-ltr.html 1127488-align-top-left-ref.html HTTP(..) == 1127488-align-right-vertical-lr-ltr.html 1127488-align-bottom-left-ref.html +== 1130907-intrinsic-sizing-1.html 1130907-intrinsic-sizing-1-ref.html +== 1130907-intrinsic-sizing-2.html 1130907-intrinsic-sizing-2-ref.html == 1131013-vertical-bidi.html 1131013-vertical-bidi-ref.html == 1133945-1-vertical-align.html 1133945-1-vertical-align-ref.html == 1134744-radio-checkbox-baseline-1.html 1134744-radio-checkbox-baseline-1-ref.html diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index e24ff8c829e..3ef5c5956fc 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -136,9 +136,8 @@ CommonAnimationManager::NeedsRefresh() const AnimationPlayerCollection* CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent, - nsIAtom* aElementProperty, - nsCSSProperty aProperty, - GetCompositorAnimationOptions aFlags) + nsIAtom* aElementProperty, + nsCSSProperty aProperty) { if (!aContent->MayHaveAnimations()) return nullptr; @@ -153,23 +152,7 @@ CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent, return nullptr; } - if (!(aFlags & GetCompositorAnimationOptions::NotifyActiveLayerTracker)) { - return collection; - } - // This animation can be done on the compositor. - // Mark the frame as active, in case we are able to throttle this animation. - nsIFrame* frame = nsLayoutUtils::GetStyleFrame(collection->mElement); - if (frame) { - const auto& info = sLayerAnimationInfo; - for (size_t i = 0; i < ArrayLength(info); i++) { - if (aProperty == info[i].mProperty) { - ActiveLayerTracker::NotifyAnimated(frame, aProperty); - break; - } - } - } - return collection; } diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index fa759e59e61..c25b70c21ee 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -35,14 +35,6 @@ namespace mozilla { class RestyleTracker; struct AnimationPlayerCollection; -// Options to set when fetching animations to run on the compositor. -enum class GetCompositorAnimationOptions { - // When fetching compositor animations, if there are any such animations, - // also let the ActiveLayerTracker know at the same time. - NotifyActiveLayerTracker = 1 << 0 -}; -MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GetCompositorAnimationOptions) - namespace css { bool IsGeometricProperty(nsCSSProperty aProperty); @@ -173,8 +165,7 @@ protected: static AnimationPlayerCollection* GetAnimationsForCompositor(nsIContent* aContent, nsIAtom* aElementProperty, - nsCSSProperty aProperty, - GetCompositorAnimationOptions aFlags); + nsCSSProperty aProperty); PRCList mElementCollections; nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect) diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index 6effed99637..bd62b8e0207 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -166,12 +166,10 @@ public: } static mozilla::AnimationPlayerCollection* - GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty, - mozilla::GetCompositorAnimationOptions aFlags - = mozilla::GetCompositorAnimationOptions(0)) + GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty) { return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor( - aContent, nsGkAtoms::animationsProperty, aProperty, aFlags); + aContent, nsGkAtoms::animationsProperty, aProperty); } void UpdateStyleAndEvents(mozilla::AnimationPlayerCollection* aEA, diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 4b14e41f9b0..76ad20e0046 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -104,12 +104,10 @@ public: typedef mozilla::AnimationPlayerCollection AnimationPlayerCollection; static AnimationPlayerCollection* - GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty, - mozilla::GetCompositorAnimationOptions aFlags - = mozilla::GetCompositorAnimationOptions(0)) + GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty) { return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor( - aContent, nsGkAtoms::transitionsProperty, aProperty, aFlags); + aContent, nsGkAtoms::transitionsProperty, aProperty); } /** diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp index 43f66a5f6d3..60a9dd2d9a0 100644 --- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -353,7 +353,7 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource, RefPtr offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( - ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8); + neededRect.Size(), SurfaceFormat::B8G8R8A8); if (!offscreenDT) { return NS_ERROR_OUT_OF_MEMORY; } @@ -417,7 +417,7 @@ nsFilterInstance::BuildSourceImage(DrawTarget* aTargetDT) RefPtr offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( - ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8); + neededRect.Size(), SurfaceFormat::B8G8R8A8); if (!offscreenDT) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/layout/svg/nsSVGMaskFrame.cpp b/layout/svg/nsSVGMaskFrame.cpp index 91c2e368f49..8ce873495cb 100644 --- a/layout/svg/nsSVGMaskFrame.cpp +++ b/layout/svg/nsSVGMaskFrame.cpp @@ -242,8 +242,7 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gfxContext* aContext, bool resultOverflows; IntSize maskSurfaceSize = - ToIntSize(nsSVGUtils::ConvertToSurfaceSize(maskSurfaceRect.Size(), - &resultOverflows)); + nsSVGUtils::ConvertToSurfaceSize(maskSurfaceRect.Size(), &resultOverflows); if (resultOverflows || maskSurfaceSize.IsEmpty()) { // XXXjwatt we should return an empty surface so we don't paint aMaskedFrame! diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp index 6c835857c85..701945ffd48 100644 --- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -361,9 +361,9 @@ nsSVGPatternFrame::PaintPattern(const DrawTarget* aDrawTarget, patternHeight != surfaceSize.height) { // scale drawing to pattern surface size gfxMatrix tempTM = - gfxMatrix(surfaceSize.width / patternWidth, 0.0f, - 0.0f, surfaceSize.height / patternHeight, - 0.0f, 0.0f); + gfxMatrix(surfaceSize.width / patternWidth, 0.0, + 0.0, surfaceSize.height / patternHeight, + 0.0, 0.0); patternWithChildren->mCTM->PreMultiply(tempTM); // and rescale pattern to compensate @@ -639,23 +639,23 @@ nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox, const Matrix &callerCTM, nsIFrame *aTarget) { - gfxMatrix tCTM; SVGSVGElement *ctx = nullptr; nsIContent* targetContent = aTarget->GetContent(); + gfxFloat scaleX, scaleY; // The objectBoundingBox conversion must be handled in the CTM: if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits)) { - tCTM.Scale(callerBBox.Width(), callerBBox.Height()); + scaleX = callerBBox.Width(); + scaleY = callerBBox.Height(); } else { if (targetContent->IsSVGElement()) { ctx = static_cast(targetContent)->GetCtx(); } - float scale = MaxExpansion(callerCTM); - tCTM.Scale(scale, scale); + scaleX = scaleY = MaxExpansion(callerCTM); } if (!aViewBox.IsExplicitlySet()) { - return tCTM; + return gfxMatrix(scaleX, 0.0, 0.0, scaleY, 0.0, 0.0); } const nsSVGViewBoxRect viewBoxRect = aViewBox.GetAnimValue(); @@ -685,12 +685,12 @@ nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox, } Matrix tm = SVGContentUtils::GetViewBoxTransform( - viewportWidth, viewportHeight, + viewportWidth * scaleX, viewportHeight * scaleY, viewBoxRect.x, viewBoxRect.y, viewBoxRect.width, viewBoxRect.height, GetPreserveAspectRatio()); - return ThebesMatrix(tm) * tCTM; + return ThebesMatrix(tm); } //---------------------------------------------------------------------- diff --git a/media/gmp-clearkey/0.1/AnnexB.cpp b/media/gmp-clearkey/0.1/AnnexB.cpp index a22d62a8e45..8b9b9ae121b 100644 --- a/media/gmp-clearkey/0.1/AnnexB.cpp +++ b/media/gmp-clearkey/0.1/AnnexB.cpp @@ -1,9 +1,21 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "AnnexB.h" -#include "mozilla/Endian.h" +#include "Endian.h" using mozilla::BigEndian; diff --git a/media/gmp-clearkey/0.1/AnnexB.h b/media/gmp-clearkey/0.1/AnnexB.h index 297df06e28b..81ca87e0cf0 100644 --- a/media/gmp-clearkey/0.1/AnnexB.h +++ b/media/gmp-clearkey/0.1/AnnexB.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __AnnexB_h__ #define __AnnexB_h__ diff --git a/media/gmp-clearkey/0.1/ArrayUtils.h b/media/gmp-clearkey/0.1/ArrayUtils.h new file mode 100644 index 00000000000..c5e17689e76 --- /dev/null +++ b/media/gmp-clearkey/0.1/ArrayUtils.h @@ -0,0 +1,23 @@ +/* +* Copyright 2015, Mozilla Foundation and contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __ArrayUtils_h__ +#define __ArrayUtils_h__ + +#define MOZ_ARRAY_LENGTH(array_) \ + (sizeof(array_)/sizeof(array_[0])) + +#endif diff --git a/media/gmp-clearkey/0.1/AudioDecoder.cpp b/media/gmp-clearkey/0.1/AudioDecoder.cpp index 9d6d0865a27..c0d7b11c9cc 100644 --- a/media/gmp-clearkey/0.1/AudioDecoder.cpp +++ b/media/gmp-clearkey/0.1/AudioDecoder.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013, Mozilla Foundation and contributors + * Copyright 2015, Mozilla Foundation and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/media/gmp-clearkey/0.1/AudioDecoder.h b/media/gmp-clearkey/0.1/AudioDecoder.h index 4182d50fd66..d72d652a398 100644 --- a/media/gmp-clearkey/0.1/AudioDecoder.h +++ b/media/gmp-clearkey/0.1/AudioDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, Mozilla Foundation and contributors + * Copyright 2015, Mozilla Foundation and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/media/gmp-clearkey/0.1/ClearKeyBase64.cpp b/media/gmp-clearkey/0.1/ClearKeyBase64.cpp index 1afa4200ff6..f0cbb22f739 100644 --- a/media/gmp-clearkey/0.1/ClearKeyBase64.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyBase64.cpp @@ -1,13 +1,23 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "ClearKeyBase64.h" #include -#include "mozilla/ArrayUtils.h" - using namespace std; /** diff --git a/media/gmp-clearkey/0.1/ClearKeyBase64.h b/media/gmp-clearkey/0.1/ClearKeyBase64.h index 3e86d554275..8c424ad63ae 100644 --- a/media/gmp-clearkey/0.1/ClearKeyBase64.h +++ b/media/gmp-clearkey/0.1/ClearKeyBase64.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyBase64_h__ #define __ClearKeyBase64_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp index a0a6c423e66..ceb10079120 100644 --- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp @@ -1,19 +1,30 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include #include "ClearKeyDecryptionManager.h" #include "gmp-decryption.h" -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" +#include class ClearKeyDecryptor : public RefCounted { public: - MOZ_IMPLICIT ClearKeyDecryptor(); + ClearKeyDecryptor(); void InitKey(const Key& aKey); bool HasKey() const { return !!mKey.size(); } @@ -84,7 +95,7 @@ ClearKeyDecryptionManager::HasKeyForKeyId(const KeyId& aKeyId) const const Key& ClearKeyDecryptionManager::GetDecryptionKey(const KeyId& aKeyId) { - MOZ_ASSERT(HasKeyForKeyId(aKeyId)); + assert(HasKeyForKeyId(aKeyId)); return mDecryptors[aKeyId]->DecryptionKey(); } @@ -111,7 +122,7 @@ void ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId) { CK_LOGD("ClearKeyDecryptionManager::ReleaseKeyId"); - MOZ_ASSERT(HasKeyForKeyId(aKeyId)); + assert(HasKeyForKeyId(aKeyId)); ClearKeyDecryptor* decryptor = mDecryptors[aKeyId]; if (!decryptor->Release()) { @@ -178,7 +189,7 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, memcpy(&tmp[0], aBuffer, aBufferSize); } - MOZ_ASSERT(aMetadata->IVSize() == 8 || aMetadata->IVSize() == 16); + assert(aMetadata->IVSize() == 8 || aMetadata->IVSize() == 16); std::vector iv(aMetadata->IV(), aMetadata->IV() + aMetadata->IVSize()); iv.insert(iv.end(), CLEARKEY_KEY_LEN - aMetadata->IVSize(), 0); diff --git a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h index 3fb2153bb64..ceaa249ccb6 100644 --- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h +++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyDecryptionManager_h__ #define __ClearKeyDecryptionManager_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp index 77741dc0b4d..93df08a0c15 100644 --- a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp @@ -1,20 +1,32 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "ClearKeyPersistence.h" #include "ClearKeyUtils.h" #include "ClearKeyStorage.h" #include "ClearKeySessionManager.h" -#include "mozilla/RefPtr.h" +#include "RefCounted.h" #include #include #include #include #include +#include -using namespace mozilla; using namespace std; // Whether we've loaded the persistent session ids from GMPStorage yet. @@ -36,7 +48,7 @@ ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator, void* aUserArg, GMPErr aStatus) { - MOZ_ASSERT(sPersistentKeyState == LOADING); + assert(sPersistentKeyState == LOADING); if (GMP_SUCCEEDED(aStatus)) { // Extract the record names which are valid uint32_t's; they're // the persistent session ids. @@ -44,7 +56,7 @@ ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator, uint32_t len = 0; while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) { if (ClearKeyUtils::IsValidSessionId(name, len)) { - MOZ_ASSERT(name[len] == 0); + assert(name[len] == 0); sPersistentSessionIds.insert(atoi(name)); } aRecordIterator->NextRecord(); diff --git a/media/gmp-clearkey/0.1/ClearKeyPersistence.h b/media/gmp-clearkey/0.1/ClearKeyPersistence.h index 1bd3800e0b4..5adeed19209 100644 --- a/media/gmp-clearkey/0.1/ClearKeyPersistence.h +++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyPersistence_h__ #define __ClearKeyPersistence_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeySession.cpp b/media/gmp-clearkey/0.1/ClearKeySession.cpp index 05cb29a61db..d6507a65143 100644 --- a/media/gmp-clearkey/0.1/ClearKeySession.cpp +++ b/media/gmp-clearkey/0.1/ClearKeySession.cpp @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "ClearKeyDecryptionManager.h" #include "ClearKeySession.h" @@ -9,7 +21,8 @@ #include "gmp-task-utils.h" #include "gmp-api/gmp-decryption.h" -#include "mozilla/Endian.h" +#include "Endian.h" +#include using namespace mozilla; @@ -29,7 +42,7 @@ ClearKeySession::~ClearKeySession() auto& keyIds = GetKeyIds(); for (auto it = keyIds.begin(); it != keyIds.end(); it++) { - MOZ_ASSERT(ClearKeyDecryptionManager::Get()->HasKeyForKeyId(*it)); + assert(ClearKeyDecryptionManager::Get()->HasKeyForKeyId(*it)); ClearKeyDecryptionManager::Get()->ReleaseKeyId(*it); mCallback->KeyStatusChanged(&mSessionId[0], mSessionId.size(), diff --git a/media/gmp-clearkey/0.1/ClearKeySession.h b/media/gmp-clearkey/0.1/ClearKeySession.h index 68f498aaf01..7756d7aafa8 100644 --- a/media/gmp-clearkey/0.1/ClearKeySession.h +++ b/media/gmp-clearkey/0.1/ClearKeySession.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeySession_h__ #define __ClearKeySession_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp index 254a7eadd5b..4b77ac95a91 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -16,9 +28,8 @@ #include "WMFUtils.h" #endif -#include "mozilla/Assertions.h" +#include -using namespace mozilla; using namespace std; ClearKeySessionManager::ClearKeySessionManager() @@ -36,7 +47,7 @@ ClearKeySessionManager::ClearKeySessionManager() ClearKeySessionManager::~ClearKeySessionManager() { CK_LOGD("ClearKeySessionManager dtor %p", this); - MOZ_ASSERT(!mRefCount); + assert(!mRefCount); } static bool @@ -88,7 +99,7 @@ ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken, } string sessionId = ClearKeyPersistence::GetNewSessionId(aSessionType); - MOZ_ASSERT(mSessions.find(sessionId) == mSessions.end()); + assert(mSessions.find(sessionId) == mSessions.end()); ClearKeySession* session = new ClearKeySession(sessionId, mCallback, aSessionType); session->Init(aCreateSessionToken, aPromiseId, aInitData, aInitDataSize); @@ -172,10 +183,10 @@ ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus, const uint8_t* base = aKeyData + 2 * CLEARKEY_KEY_LEN * i; KeyId keyId(base, base + CLEARKEY_KEY_LEN); - MOZ_ASSERT(keyId.size() == CLEARKEY_KEY_LEN); + assert(keyId.size() == CLEARKEY_KEY_LEN); Key key(base + CLEARKEY_KEY_LEN, base + 2 * CLEARKEY_KEY_LEN); - MOZ_ASSERT(key.size() == CLEARKEY_KEY_LEN); + assert(key.size() == CLEARKEY_KEY_LEN); session->AddKeyId(keyId); @@ -254,10 +265,10 @@ ClearKeySessionManager::Serialize(const ClearKeySession* aSession, if (!mDecryptionManager->HasKeyForKeyId(keyId)) { continue; } - MOZ_ASSERT(keyId.size() == CLEARKEY_KEY_LEN); + assert(keyId.size() == CLEARKEY_KEY_LEN); aOutKeyData.insert(aOutKeyData.end(), keyId.begin(), keyId.end()); const Key& key = mDecryptionManager->GetDecryptionKey(keyId); - MOZ_ASSERT(key.size() == CLEARKEY_KEY_LEN); + assert(key.size() == CLEARKEY_KEY_LEN); aOutKeyData.insert(aOutKeyData.end(), key.begin(), key.end()); } } @@ -278,7 +289,7 @@ ClearKeySessionManager::CloseSession(uint32_t aPromiseId, } ClearKeySession* session = itr->second; - MOZ_ASSERT(session); + assert(session); ClearInMemorySessionData(session); mCallback->ResolvePromise(aPromiseId); @@ -307,7 +318,7 @@ ClearKeySessionManager::RemoveSession(uint32_t aPromiseId, } ClearKeySession* session = itr->second; - MOZ_ASSERT(session); + assert(session); string sid = session->Id(); bool isPersistent = session->Type() == kGMPPersistentSession; ClearInMemorySessionData(session); diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.h b/media/gmp-clearkey/0.1/ClearKeySessionManager.h index 7c11db694b0..034efce3ecf 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyDecryptor_h__ #define __ClearKeyDecryptor_h__ @@ -14,8 +26,6 @@ #include "ClearKeySession.h" #include "ClearKeyUtils.h" #include "gmp-api/gmp-decryption.h" -#include "mozilla/Attributes.h" -#include "mozilla/RefPtr.h" #include "RefCounted.h" class ClearKeySessionManager final : public GMPDecryptor @@ -76,7 +86,7 @@ private: void ClearInMemorySessionData(ClearKeySession* aSession); void Serialize(const ClearKeySession* aSession, std::vector& aOutKeyData); - mozilla::RefPtr mDecryptionManager; + RefPtr mDecryptionManager; GMPDecryptorCallback* mCallback; GMPThread* mThread; diff --git a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp index b76d6e5757b..0db51c9b7ea 100644 --- a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp @@ -1,14 +1,26 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "ClearKeyStorage.h" #include "ClearKeyUtils.h" #include "gmp-task-utils.h" -#include "mozilla/Assertions.h" -#include "mozilla/ArrayUtils.h" +#include +#include "ArrayUtils.h" #include @@ -50,7 +62,7 @@ public: virtual void ReadComplete(GMPErr aStatus, const uint8_t* aData, uint32_t aDataSize) override { - MOZ_ASSERT(false, "Should not reach here."); + assert(false); // Should not reach here. } virtual void WriteComplete(GMPErr aStatus) override { @@ -115,7 +127,7 @@ public: */ static void Read(const std::string& aRecordName, ReadContinuation* aContinuation) { - MOZ_ASSERT(aContinuation); + assert(aContinuation); (new ReadRecordClient(aContinuation))->Do(aRecordName); } @@ -134,7 +146,7 @@ public: } virtual void WriteComplete(GMPErr aStatus) override { - MOZ_ASSERT(false, "Should not reach here."); + assert(false); // Should not reach here. } private: diff --git a/media/gmp-clearkey/0.1/ClearKeyStorage.h b/media/gmp-clearkey/0.1/ClearKeyStorage.h index 41f7c865a46..a1377097bef 100644 --- a/media/gmp-clearkey/0.1/ClearKeyStorage.h +++ b/media/gmp-clearkey/0.1/ClearKeyStorage.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyStorage_h__ #define __ClearKeyStorage_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp index 3d7e58406da..a15f7fed70d 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -10,9 +22,9 @@ #include "ClearKeyUtils.h" #include "ClearKeyBase64.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/Assertions.h" -#include "mozilla/Endian.h" +#include "ArrayUtils.h" +#include +#include "Endian.h" #include "openaes/oaes_lib.h" using namespace std; @@ -43,7 +55,7 @@ static void IncrementIV(vector& aIV) { using mozilla::BigEndian; - MOZ_ASSERT(aIV.size() == 16); + assert(aIV.size() == 16); BigEndian::writeUint64(&aIV[8], BigEndian::readUint64(&aIV[8]) + 1); } @@ -51,8 +63,8 @@ IncrementIV(vector& aIV) { ClearKeyUtils::DecryptAES(const vector& aKey, vector& aData, vector& aIV) { - MOZ_ASSERT(aIV.size() == CLEARKEY_KEY_LEN); - MOZ_ASSERT(aKey.size() == CLEARKEY_KEY_LEN); + assert(aIV.size() == CLEARKEY_KEY_LEN); + assert(aKey.size() == CLEARKEY_KEY_LEN); OAES_CTX* aes = oaes_alloc(); oaes_key_import_data(aes, &aKey[0], aKey.size()); @@ -65,7 +77,7 @@ ClearKeyUtils::DecryptAES(const vector& aKey, vector enc(encLen); oaes_encrypt(aes, &aIV[0], CLEARKEY_KEY_LEN, &enc[0], &encLen); - MOZ_ASSERT(encLen >= 2 * OAES_BLOCK_SIZE + CLEARKEY_KEY_LEN); + assert(encLen >= 2 * OAES_BLOCK_SIZE + CLEARKEY_KEY_LEN); size_t blockLen = min(aData.size() - i, CLEARKEY_KEY_LEN); for (size_t j = 0; j < blockLen; j++) { aData[i + j] ^= enc[2 * OAES_BLOCK_SIZE + j]; @@ -111,8 +123,7 @@ EncodeBase64Web(vector aBinary, string& aEncoded) // Cast idx to size_t before using it as an array-index, // to pacify clang 'Wchar-subscripts' warning: size_t idx = static_cast(out[i]); - MOZ_ASSERT(idx < MOZ_ARRAY_LENGTH(sAlphabet), - "out of bounds index for 'sAlphabet'"); + assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); // out of bounds index for 'sAlphabet' out[i] = sAlphabet[idx]; } @@ -181,7 +192,7 @@ ClearKeyUtils::MakeKeyRequest(const vector& aKeyIDs, string& aOutRequest, GMPSessionType aSessionType) { - MOZ_ASSERT(aKeyIDs.size() && aOutRequest.empty()); + assert(aKeyIDs.size() && aOutRequest.empty()); aOutRequest.append("{ \"kids\":["); for (size_t i = 0; i < aKeyIDs.size(); i++) { @@ -439,7 +450,7 @@ ParseKeys(ParserContext& aCtx, vector& aOutKeys) return false; } - MOZ_ASSERT(!key.mKey.empty() && !key.mKeyId.empty()); + assert(!key.mKey.empty() && !key.mKeyId.empty()); aOutKeys.push_back(key); uint8_t sym = PeekSymbol(aCtx); @@ -507,7 +518,7 @@ ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType) case kGMPTemporySession: return "temporary"; case kGMPPersistentSession: return "persistent"; default: { - MOZ_ASSERT(false, "Should not reach here."); + assert(false); // Should not reach here. return "invalid"; } } diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.h b/media/gmp-clearkey/0.1/ClearKeyUtils.h index 7700e7182e1..4e359e13efd 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.h +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyUtils_h__ #define __ClearKeyUtils_h__ diff --git a/media/gmp-clearkey/0.1/Endian.h b/media/gmp-clearkey/0.1/Endian.h new file mode 100644 index 00000000000..91b7174d498 --- /dev/null +++ b/media/gmp-clearkey/0.1/Endian.h @@ -0,0 +1,68 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __Endian_h__ +#define __Endian_h__ + +#include + +namespace mozilla { + +class BigEndian { +public: + + static uint32_t readUint32(const void* aPtr) { + const uint8_t* p = reinterpret_cast(aPtr); + return uint32_t(p[0]) << 24 | + uint32_t(p[1]) << 16 | + uint32_t(p[2]) << 8 | + uint32_t(p[3]); + } + + static uint16_t readUint16(const void* aPtr) { + const uint8_t* p = reinterpret_cast(aPtr); + return uint32_t(p[0]) << 8 | + uint32_t(p[1]); + } + + static uint64_t readUint64(const void* aPtr) { + const uint8_t* p = reinterpret_cast(aPtr); + return uint64_t(p[0]) << 56 | + uint64_t(p[1]) << 48 | + uint64_t(p[2]) << 40 | + uint64_t(p[3]) << 32 | + uint64_t(p[4]) << 24 | + uint64_t(p[5]) << 16 | + uint64_t(p[6]) << 8 | + uint64_t(p[7]); + } + + static void writeUint64(void* aPtr, uint64_t aValue) { + uint8_t* p = reinterpret_cast(aPtr); + p[0] = uint8_t(aValue >> 56) & 0xff; + p[1] = uint8_t(aValue >> 48) & 0xff; + p[2] = uint8_t(aValue >> 40) & 0xff; + p[3] = uint8_t(aValue >> 32) & 0xff; + p[4] = uint8_t(aValue >> 24) & 0xff; + p[5] = uint8_t(aValue >> 16) & 0xff; + p[6] = uint8_t(aValue >> 8) & 0xff; + p[7] = uint8_t(aValue) & 0xff; + } +}; + +} + +#endif // __Endian_h__ diff --git a/media/gmp-clearkey/0.1/RefCounted.h b/media/gmp-clearkey/0.1/RefCounted.h index f5306759eb3..e7a5c456feb 100644 --- a/media/gmp-clearkey/0.1/RefCounted.h +++ b/media/gmp-clearkey/0.1/RefCounted.h @@ -1,10 +1,24 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __RefCount_h__ #define __RefCount_h__ +#include + // Note: Not thread safe! class RefCounted { public: @@ -31,4 +45,33 @@ protected: uint32_t mRefCount; }; +template +class RefPtr { +public: + explicit RefPtr(T* aPtr) : mPtr(nullptr) { + Assign(aPtr); + } + ~RefPtr() { + Assign(nullptr); + } + T* operator->() const { return mPtr; } + + RefPtr& operator=(T* aVal) { + Assign(aVal); + return *this; + } + +private: + void Assign(T* aPtr) { + if (mPtr) { + mPtr->Release(); + } + mPtr = aPtr; + if (mPtr) { + aPtr->AddRef(); + } + } + T* mPtr; +}; + #endif // __RefCount_h__ diff --git a/media/gmp-clearkey/0.1/VideoDecoder.cpp b/media/gmp-clearkey/0.1/VideoDecoder.cpp index d1393a7aded..4139f2b1444 100644 --- a/media/gmp-clearkey/0.1/VideoDecoder.cpp +++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp @@ -21,9 +21,8 @@ #include "ClearKeyDecryptionManager.h" #include "ClearKeyUtils.h" #include "gmp-task-utils.h" -#include "mozilla/Endian.h" +#include "Endian.h" #include "VideoDecoder.h" -#include "mozilla/Move.h" using namespace wmf; @@ -196,11 +195,10 @@ VideoDecoder::DecodeTask(GMPVideoEncodedFrame* aInput) MaybeRunOnMainThread( WrapTask(this, &VideoDecoder::ReturnOutput, - CComPtr(mozilla::Move(output)), + CComPtr(output), mDecoder->GetFrameWidth(), mDecoder->GetFrameHeight(), mDecoder->GetStride())); - assert(!output.Get()); } if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { AutoLock lock(mMutex); @@ -351,11 +349,10 @@ VideoDecoder::DrainTask() MaybeRunOnMainThread( WrapTask(this, &VideoDecoder::ReturnOutput, - CComPtr(mozilla::Move(output)), + CComPtr(output), mDecoder->GetFrameWidth(), mDecoder->GetFrameHeight(), mDecoder->GetStride())); - assert(!output.Get()); } } MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete)); diff --git a/media/gmp-clearkey/0.1/WMFSymbols.h b/media/gmp-clearkey/0.1/WMFSymbols.h index 5d1729a04d2..6b6a8020b4c 100644 --- a/media/gmp-clearkey/0.1/WMFSymbols.h +++ b/media/gmp-clearkey/0.1/WMFSymbols.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ MFPLAT_FUNC(MFCreateSample); MFPLAT_FUNC(MFCreateAlignedMemoryBuffer); diff --git a/media/gmp-clearkey/0.1/gmp-clearkey.cpp b/media/gmp-clearkey/0.1/gmp-clearkey.cpp index 6dab6f92d91..76cd3177fd0 100644 --- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp +++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -9,7 +21,6 @@ #include "ClearKeySessionManager.h" #include "gmp-api/gmp-decryption.h" #include "gmp-api/gmp-platform.h" -#include "mozilla/Attributes.h" #if defined(ENABLE_WMF) #include "WMFUtils.h" @@ -17,6 +28,12 @@ #include "VideoDecoder.h" #endif +#if defined(WIN32) +#define GMP_EXPORT __declspec(dllexport) +#else +#define GMP_EXPORT __attribute__((visibility("default"))) +#endif + static GMPPlatformAPI* sPlatform = nullptr; GMPPlatformAPI* GetPlatform() @@ -26,14 +43,14 @@ GetPlatform() extern "C" { -MOZ_EXPORT GMPErr +GMP_EXPORT GMPErr GMPInit(GMPPlatformAPI* aPlatformAPI) { sPlatform = aPlatformAPI; return GMPNoErr; } -MOZ_EXPORT GMPErr +GMP_EXPORT GMPErr GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI) { CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName); @@ -58,7 +75,7 @@ GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI) return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr; } -MOZ_EXPORT GMPErr +GMP_EXPORT GMPErr GMPShutdown(void) { CK_LOGD("ClearKey GMPShutdown"); diff --git a/media/gmp-clearkey/0.1/gmp-task-utils-generated.h b/media/gmp-clearkey/0.1/gmp-task-utils-generated.h index 5eec3374a26..efcfa8f2eff 100644 --- a/media/gmp-clearkey/0.1/gmp-task-utils-generated.h +++ b/media/gmp-clearkey/0.1/gmp-task-utils-generated.h @@ -1,6 +1,18 @@ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ // 0 arguments -- diff --git a/media/gmp-clearkey/0.1/gmp-task-utils.h b/media/gmp-clearkey/0.1/gmp-task-utils.h index 78a1393c64e..55cae627d8a 100644 --- a/media/gmp-clearkey/0.1/gmp-task-utils.h +++ b/media/gmp-clearkey/0.1/gmp-task-utils.h @@ -1,8 +1,18 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* 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/. */ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ // Original author: ekr@rtfm.com diff --git a/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp b/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp index 865a225b1f9..b31c50e4200 100644 --- a/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp +++ b/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp @@ -10,10 +10,10 @@ #include #include "../ClearKeyBase64.cpp" +#include "../ArrayUtils.h" using namespace std; -using namespace mozilla; struct B64Test { const char* b64; diff --git a/media/libpng/CHANGES b/media/libpng/CHANGES index 68a80a583f5..4674f7d4c6d 100644 --- a/media/libpng/CHANGES +++ b/media/libpng/CHANGES @@ -2102,7 +2102,7 @@ Version 1.4.0beta24 [July 25, 2008] png_decompress_chunk(), and remove "chunkdata" from parameter list. Put a call to png_check_chunk_name() in png_read_chunk_header(). Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. - Removed two calls to png_check_chunk_name() occuring later in the process. + Removed two calls to png_check_chunk_name() occurring later in the process. Define PNG_NO_ERROR_NUMBERS by default in pngconf.h Version 1.4.0beta25 [July 30, 2008] @@ -5114,17 +5114,97 @@ Version 1.6.16beta03 [December 21, 2014] Version 1.6.16rc01 [December 21, 2014] Restored a test on width that was removed from png.c at libpng-1.6.9 - (Bug report by Alex Eubanks). + (Bug report by Alex Eubanks, CVE-2015-0973). Version 1.6.16rc02 [December 21, 2014] Undid the update to pngrutil.c in 1.6.16rc01. Version 1.6.16rc03 [December 21, 2014] - Fixed an overflow in png_combine_row with very wide interlaced images. + Fixed an overflow in png_combine_row() with very wide interlaced images + (Bug report and fix by John Bowler, CVE-2014-9495). Version 1.6.16 [December 22, 2014] No changes. +Version 1.6.17beta01 [January 29, 2015] + Removed duplicate PNG_SAFE_LIMITS_SUPPORTED handling from pngconf.h + Corrected the width limit calculation in png_check_IHDR(). + Removed user limits from pngfix. Also pass NULL pointers to + png_read_row to skip the unnecessary row de-interlace stuff. + Added testing of png_set_packing() to pngvalid.c + Regenerated configure scripts in the *.tar distributions with libtool-2.4.4 + Implement previously untested cases of libpng transforms in pngvalid.c + Fixed byte order in 2-byte filler, in png_do_read_filler(). + Made the check for out-of-range values in png_set_tRNS() detect + values that are exactly 2^bit_depth, and work on 16-bit platforms. + Merged some parts of libpng-1.6.17beta01 and libpng-1.7.0beta47. + Added #ifndef __COVERITY__ where needed in png.c, pngrutil.c and + pngset.c to avoid warnings about dead code. + Added "& 0xff" to many instances of expressions that are typecast + to (png_byte), to avoid Coverity gripes. + +Version 1.6.17beta02 [February 7, 2015] + Work around one more Coverity-scan dead-code warning. + Do not build png_product2() when it is unused. + +Version 1.6.17beta03 [February 17, 2015] + Display user limits in the output from pngtest. + Eliminated the PNG_SAFE_LIMITS macro and restored the 1-million-column + and 1-million-row default limits in pnglibconf.dfa, that can be reset + by the user at build time or run time. This provides a more robust + defense against DOS and as-yet undiscovered overflows. + +Version 1.6.17beta04 [February 21, 2015] + Added PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED macro, on by default. + Allow user to call png_get_IHDR() with NULL arguments (Reuben Hawkins). + Rebuilt configure scripts with automake-1.15 and libtool-2.4.6 + +Version 1.6.17beta05 [February 25, 2015] + Restored compiling of png_reciprocal2 with PNG_NO_16BIT. + +Version 1.6.17beta06 [February 27, 2015] + Moved png_set_filter() prototype into a PNG_WRITE_SUPPORTED block + of png.h. + Avoid runtime checks when converting integer to png_byte with + Visual Studio (Sergey Kosarevsky) + +Version 1.6.17rc01 [March 4, 2015] + No changes. + +Version 1.6.17rc02 [March 9, 2015] + Removed some comments that the configure script did not handle + properly from scripts/pnglibconf.dfa and pnglibconf.h.prebuilt. + Free the unknown_chunks structure even when it contains no data. + +Version 1.6.17rc03 [March 12, 2015] + Updated CMakeLists.txt to add OSX framework, change YES/NO to ON/OFF + for consistency, and remove some useless tests (Alexey Petruchik). + +Version 1.6.17rc04 [March 16, 2015] + Remove pnglibconf.h, pnglibconf.c, and pnglibconf.out instead of + pnglibconf.* in "make clean" (Cosmin). + Fix bug in calculation of maxbits, in png_write_sBIT, introduced + in libpng-1.6.17beta01 (John Bowler). + +Version 1.6.17rc05 [March 21, 2015] + Define PNG_FILTER_* and PNG_FILTER_VALUE_* in png.h even when WRITE + is not supported (John Bowler). This fixes an error introduced in + libpng-1.6.17beta06. + Reverted "& 0xff" additions of version 1.6.17beta01. Libpng passes + the Coverity scan without them. + +Version 1.6.17rc06 [March 23, 2015] + Remove pnglibconf.dfn and pnglibconf.pre with "make clean". + Reformatted some "&0xff" instances to "& 0xff". + Fixed simplified 8-bit-linear to sRGB alpha. The calculated alpha + value was wrong. It's not clear if this affected the final stored + value; in the obvious code path the upper and lower 8-bits of the + alpha value were identical and the alpha was truncated to 8-bits + rather than dividing by 257 (John Bowler). + +Version 1.6.17 [March 25, 2015] + No changes. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/media/libpng/LICENSE b/media/libpng/LICENSE index f912f6a6d9b..b829de5dce7 100644 --- a/media/libpng/LICENSE +++ b/media/libpng/LICENSE @@ -10,8 +10,8 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.6.16, December 22, 2014, are -Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are +libpng versions 1.2.6, August 15, 2004, through 1.6.17, March 25, 2015, are +Copyright (c) 2004, 2006-2015 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -108,4 +108,4 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -December 22, 2014 +March 25, 2015 diff --git a/media/libpng/MOZCHANGES b/media/libpng/MOZCHANGES index 31a613b6513..36dad98ebfa 100644 --- a/media/libpng/MOZCHANGES +++ b/media/libpng/MOZCHANGES @@ -1,6 +1,8 @@ Changes made to pristine libpng source by mozilla.org developers. +2015/03/27 -- Synced with libpng-1.6.17 (bug #1147909). + 2014/12/22 -- Synced with libpng-1.6.16 (bug #1114360). Added arm.patch file. diff --git a/media/libpng/README b/media/libpng/README index 8c5b0b2f153..0469e2627fd 100644 --- a/media/libpng/README +++ b/media/libpng/README @@ -1,4 +1,4 @@ -README for libpng version 1.6.16 - December 22, 2014 (shared library 16.0) +README for libpng version 1.6.17 - March 25, 2015 (shared library 16.0) See the note about version numbers near the top of png.h See INSTALL for instructions on how to install libpng. diff --git a/media/libpng/apng.patch b/media/libpng/apng.patch index a80f51ff36b..296a8f2ad1f 100644 --- a/media/libpng/apng.patch +++ b/media/libpng/apng.patch @@ -107,7 +107,7 @@ Index: pngget.c =================================================================== --- pngget.c +++ pngget.c -@@ -1210,4 +1210,166 @@ +@@ -1216,4 +1216,166 @@ # endif #endif @@ -278,7 +278,7 @@ Index: png.h =================================================================== --- png.h +++ png.h -@@ -476,6 +476,10 @@ +@@ -480,6 +480,10 @@ # include "pnglibconf.h" #endif @@ -289,7 +289,7 @@ Index: png.h #ifndef PNG_VERSION_INFO_ONLY /* Machine specific configuration. */ # include "pngconf.h" -@@ -566,6 +570,17 @@ +@@ -570,6 +574,17 @@ * See pngconf.h for base types that vary by machine/system */ @@ -307,7 +307,7 @@ Index: png.h /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -@@ -886,6 +901,10 @@ +@@ -890,6 +905,10 @@ #define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ @@ -318,7 +318,7 @@ Index: png.h /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using -@@ -923,6 +942,10 @@ +@@ -927,6 +946,10 @@ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); @@ -329,7 +329,7 @@ Index: png.h /* The following callback receives png_uint_32 row_number, int pass for the * png_bytep data of the row. When transforming an interlaced image the -@@ -3262,6 +3285,75 @@ +@@ -3272,6 +3295,75 @@ * END OF HARDWARE AND SOFTWARE OPTIONS ******************************************************************************/ @@ -405,7 +405,7 @@ Index: png.h /* Maintainer: Put new public prototypes here ^, in libpng.3, in project * defs, and in scripts/symbols.def. */ -@@ -3270,7 +3362,11 @@ +@@ -3280,7 +3372,11 @@ * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL @@ -421,7 +421,7 @@ Index: pngpriv.h =================================================================== --- pngpriv.h +++ pngpriv.h -@@ -555,6 +555,10 @@ +@@ -516,6 +516,10 @@ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ /* 0x4000 (unused) */ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ @@ -432,7 +432,7 @@ Index: pngpriv.h /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001 -@@ -776,6 +780,16 @@ +@@ -737,6 +741,16 @@ #define png_tRNS PNG_U32(116, 82, 78, 83) #define png_zTXt PNG_U32(122, 84, 88, 116) @@ -449,7 +449,7 @@ Index: pngpriv.h /* The following will work on (signed char*) strings, whereas the get_uint_32 * macro will fail on top-bit-set values because of the sign extension. */ -@@ -1456,6 +1470,49 @@ +@@ -1420,6 +1434,49 @@ #endif /* PROGRESSIVE_READ */ @@ -503,7 +503,7 @@ Index: pnginfo.h =================================================================== --- pnginfo.h +++ pnginfo.h -@@ -256,5 +256,18 @@ +@@ -255,5 +255,18 @@ png_bytepp row_pointers; /* the image bits */ #endif @@ -526,7 +526,7 @@ Index: pngstruct.h =================================================================== --- pngstruct.h +++ pngstruct.h -@@ -409,6 +409,27 @@ +@@ -408,6 +408,27 @@ png_byte filter_type; #endif @@ -581,7 +581,7 @@ Index: pngwrite.c #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED if (png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); -@@ -2452,4 +2461,42 @@ +@@ -2456,4 +2465,42 @@ } #endif /* STDIO */ #endif /* SIMPLIFIED_WRITE */ @@ -836,7 +836,7 @@ Index: pngpread.c /* This routine must process all the data it has been given * before returning, calling the row callback as required to * handle the uncompressed results. -@@ -1157,6 +1311,18 @@ +@@ -1163,6 +1317,18 @@ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); } @@ -859,7 +859,7 @@ Index: pngset.c =================================================================== --- pngset.c +++ pngset.c -@@ -240,6 +240,11 @@ +@@ -241,6 +241,11 @@ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); @@ -871,7 +871,7 @@ Index: pngset.c } #ifdef PNG_oFFs_SUPPORTED -@@ -1071,6 +1076,147 @@ +@@ -1090,6 +1095,147 @@ } #endif /* sPLT */ @@ -1035,7 +1035,7 @@ Index: pngrutil.c /* Set internal variables */ png_ptr->width = width; png_ptr->height = height; -@@ -2700,6 +2705,180 @@ +@@ -2702,6 +2707,180 @@ } #endif @@ -1216,7 +1216,7 @@ Index: pngrutil.c #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ static int -@@ -3959,6 +4138,38 @@ +@@ -3961,6 +4140,38 @@ uInt avail_in; png_bytep buffer; @@ -1255,7 +1255,7 @@ Index: pngrutil.c while (png_ptr->idat_size == 0) { png_crc_finish(png_ptr, 0); -@@ -3970,6 +4181,7 @@ +@@ -3972,6 +4183,7 @@ if (png_ptr->chunk_name != png_IDAT) png_error(png_ptr, "Not enough image data"); } @@ -1263,7 +1263,7 @@ Index: pngrutil.c avail_in = png_ptr->IDAT_read_size; -@@ -4033,6 +4245,9 @@ +@@ -4035,6 +4247,9 @@ png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; @@ -1273,7 +1273,7 @@ Index: pngrutil.c if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) png_chunk_benign_error(png_ptr, "Extra compressed data"); -@@ -4471,4 +4686,80 @@ +@@ -4473,4 +4688,80 @@ png_ptr->flags |= PNG_FLAG_ROW_INIT; } @@ -1485,7 +1485,7 @@ Index: pngwutil.c /* Initializes the row writing capability of libpng */ void /* PRIVATE */ png_write_start_row(png_structrp png_ptr) -@@ -3026,4 +3123,39 @@ +@@ -3028,4 +3125,39 @@ } #endif /* WRITE_FLUSH */ } diff --git a/media/libpng/libpng-manual.txt b/media/libpng/libpng-manual.txt index 3aa1f578768..566206e69ec 100644 --- a/media/libpng/libpng-manual.txt +++ b/media/libpng/libpng-manual.txt @@ -1,9 +1,9 @@ libpng-manual.txt - A description on how to use and modify libpng - libpng version 1.6.16 - December 22, 2014 + libpng version 1.6.17 - March 25, 2015 Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2014 Glenn Randers-Pehrson + Copyright (c) 1998-2015 Glenn Randers-Pehrson This document is released under the libpng license. For conditions of distribution and use, see the disclaimer @@ -11,9 +11,9 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng versions 0.97, January 1998, through 1.6.16 - December 22, 2014 + libpng versions 0.97, January 1998, through 1.6.17 - March 25, 2015 Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2014 Glenn Randers-Pehrson + Copyright (c) 1998-2015 Glenn Randers-Pehrson libpng 1.0 beta 6 - version 0.96 - May 28, 1997 Updated and distributed by Andreas Dilger @@ -336,7 +336,7 @@ prediction. If you are intending to keep the file pointer open for use in libpng, you must ensure you don't read more than 8 bytes from the beginning -of the file, and you also have to make a call to png_set_sig_bytes_read() +of the file, and you also have to make a call to png_set_sig_bytes() with the number of bytes you read from the beginning. Libpng will then only check the bytes (if any) that your program didn't read. @@ -344,22 +344,23 @@ then only check the bytes (if any) that your program didn't read. to replace them with custom functions. See the discussion under Customizing libpng. - FILE *fp = fopen(file_name, "rb"); if (!fp) { return (ERROR); } - fread(header, 1, number, fp); - is_png = !png_sig_cmp(header, 0, number); + if (fread(header, 1, number, fp) != number) + { + return (ERROR); + } + is_png = !png_sig_cmp(header, 0, number); if (!is_png) { return (NOT_PNG); } - Next, png_struct and png_info need to be allocated and initialized. In order to ensure that the size of these structures is correct even with a dynamically linked libpng, there are functions to initialize and @@ -649,7 +650,7 @@ User limits The PNG specification allows the width and height of an image to be as large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. Larger images will be rejected immediately with a png_error() call. If -you wish to reduce these limits, you can use +you wish to change these limits, you can use png_set_user_limits(png_ptr, width_max, height_max); @@ -1264,13 +1265,13 @@ in until png_read_end() has read the chunk data following the image. the PNG datastream is embedded in a MNG-1.0 datastream) - Any or all of interlace_type, compression_type, or - filter_method can be NULL if you are - not interested in their values. + Any of width, height, color_type, bit_depth, + interlace_type, compression_type, or filter_method can + be NULL if you are not interested in their values. Note that png_get_IHDR() returns 32-bit data into the application's width and height variables. - This is an unsafe situation if these are 16-bit + This is an unsafe situation if these are not png_uint_32 variables. In such situations, the png_get_image_width() and png_get_image_height() functions described below are safer. @@ -1993,7 +1994,7 @@ value when you call it in this position: png_set_gamma(png_ptr, screen_gamma, 0.45455); If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_quantize() +file has more entries than will fit on your screen, png_set_quantize() will do that. Note that this is a simple match quantization that merely finds the closest color available. This should work fairly well with optimized palettes, but fairly badly with linear color cubes. If you @@ -2546,7 +2547,7 @@ png_infop info_ptr; 64K. The library seems to run fine with sizes of 4K. Although you can give it much less if necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes + 1 byte, I haven't tried less than 256 bytes yet). When this function returns, you may want to display any rows that were generated in the row callback if you don't already do @@ -5031,6 +5032,10 @@ The signatures of many exported functions were changed, such that png_infop became png_inforp or png_const_inforp where "rp" indicates a "restricted pointer". +The support for FAR/far types has been eliminated and the definition of +png_alloc_size_t is now controlled by a flag so that 'small size_t' systems +can select it if necessary. + Error detection in some chunks has improved; in particular the iCCP chunk reader now does pretty complete validation of the basic format. Some bad profiles that were previously accepted are now accepted with a warning or @@ -5045,7 +5050,7 @@ means of PNG_OPTION_ON); #endif -It's not a good idea to do this if you are using the new "simplified API", +It's not a good idea to do this if you are using the "simplified API", which needs to be able to recognize sRGB profiles conveyed via the iCCP chunk. @@ -5274,13 +5279,13 @@ Other rules can be inferred by inspecting the libpng source. XVI. Y2K Compliance in libpng -December 22, 2014 +March 25, 2015 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. This is your unofficial assurance that libpng from version 0.71 and -upward through 1.6.16 are Y2K compliant. It is my belief that earlier +upward through 1.6.17 are Y2K compliant. It is my belief that earlier versions were also Y2K compliant. Libpng only has two year fields. One is a 2-byte unsigned integer diff --git a/media/libpng/png.c b/media/libpng/png.c index 4d93dfa9135..8bee9af9c8d 100644 --- a/media/libpng/png.c +++ b/media/libpng/png.c @@ -1,8 +1,8 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.6.16 [December 22, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -14,7 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_16 Your_png_h_is_not_version_1_6_16; +typedef png_libpng_version_1_6_17 Your_png_h_is_not_version_1_6_17; /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -34,7 +34,7 @@ png_set_sig_bytes(png_structrp png_ptr, int num_bytes) if (num_bytes > 8) png_error(png_ptr, "Too many bytes for PNG signature"); - png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); + png_ptr->sig_bytes = (png_byte)((num_bytes < 0 ? 0 : num_bytes) & 0xff); } /* Checks whether the supplied bytes match the PNG signature. We allow @@ -140,8 +140,10 @@ png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) do { uInt safe_length = (uInt)length; +#ifndef __COVERITY__ if (safe_length == 0) safe_length = (uInt)-1; /* evil, but safe */ +#endif crc = crc32(crc, ptr, safe_length); @@ -476,9 +478,10 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, /* Free any tRNS entry */ if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) { + info_ptr->valid &= ~PNG_INFO_tRNS; png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; + info_ptr->num_trans = 0; } #endif @@ -544,20 +547,17 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, else { - if (info_ptr->splt_palettes_num != 0) + int i; + + for (i = 0; i < info_ptr->splt_palettes_num; i++) { - int i; - - for (i = 0; i < info_ptr->splt_palettes_num; i++) - { - png_free(png_ptr, info_ptr->splt_palettes[i].name); - png_free(png_ptr, info_ptr->splt_palettes[i].entries); - } - - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; + png_free(png_ptr, info_ptr->splt_palettes[i].name); + png_free(png_ptr, info_ptr->splt_palettes[i].entries); } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; info_ptr->valid &= ~PNG_INFO_sPLT; } } @@ -577,15 +577,12 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, { int i; - if (info_ptr->unknown_chunks_num != 0) - { - for (i = 0; i < info_ptr->unknown_chunks_num; i++) - png_free(png_ptr, info_ptr->unknown_chunks[i].data); + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free(png_ptr, info_ptr->unknown_chunks[i].data); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; } } #endif @@ -666,7 +663,7 @@ png_init_io(png_structrp png_ptr, png_FILE_p fp) } # endif -#ifdef PNG_SAVE_INT_32_SUPPORTED +# ifdef PNG_SAVE_INT_32_SUPPORTED /* The png_save_int_32 function assumes integers are stored in two's * complement format. If this isn't the case, then this routine needs to * be modified to write data in two's complement format. Note that, @@ -681,7 +678,7 @@ png_save_int_32(png_bytep buf, png_int_32 i) buf[2] = (png_byte)((i >> 8) & 0xff); buf[3] = (png_byte)(i & 0xff); } -#endif +# endif # ifdef PNG_TIME_RFC1123_SUPPORTED /* Convert the supplied time into an RFC 1123 string suitable for use in @@ -734,7 +731,7 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) return 1; } -# if PNG_LIBPNG_VER < 10700 +# if PNG_LIBPNG_VER < 10700 /* To do: remove the following from libpng-1.7 */ /* Original API that uses a private buffer in png_struct. * Deprecated because it causes png_struct to carry a spurious temporary @@ -755,7 +752,7 @@ png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) return NULL; } -# endif +# endif /* LIBPNG_VER < 10700 */ # endif /* TIME_RFC1123 */ #endif /* READ || WRITE */ @@ -769,14 +766,14 @@ png_get_copyright(png_const_structrp png_ptr) #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.6.16 - December 22, 2014" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2014 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "libpng version 1.6.17 - March 25, 2015" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2015 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else - return "libpng version 1.6.16 - December 22, 2014\ - Copyright (c) 1998-2014 Glenn Randers-Pehrson\ + return "libpng version 1.6.17 - March 25, 2015\ + Copyright (c) 1998-2015 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; # endif @@ -872,9 +869,9 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette) for (i = 0, v = 0; i < num_palette; i++, v += color_inc) { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; + palette[i].red = (png_byte)(v & 0xff); + palette[i].green = (png_byte)(v & 0xff); + palette[i].blue = (png_byte)(v & 0xff); } } #endif @@ -947,8 +944,6 @@ png_access_version_number(void) return((png_uint_32)PNG_LIBPNG_VER); } - - #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Ensure that png_ptr->zstream.msg holds some appropriate error message string. * If it doesn't 'ret' is used to set it to something appropriate, even in cases @@ -1181,7 +1176,7 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) png_colorspace_sync_info(png_ptr, info_ptr); } #endif -#endif +#endif /* GAMMA */ #ifdef PNG_COLORSPACE_SUPPORTED /* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for @@ -2166,7 +2161,8 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, return 1; /* success, maybe with warnings */ } -#if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0 +#ifdef PNG_sRGB_SUPPORTED +#if PNG_sRGB_PROFILE_CHECKS >= 0 /* Information about the known ICC sRGB profiles */ static const struct { @@ -2324,8 +2320,8 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, */ else if (png_sRGB_checks[i].have_md5 == 0) { - png_chunk_report(png_ptr, "out-of-date sRGB profile with" - " no signature", + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", PNG_CHUNK_WARNING); } @@ -2338,8 +2334,8 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, * way. This probably indicates a data error or uninformed hacking. * Fall through to "no match". */ - png_chunk_report(png_ptr, "Not recognizing known sRGB profile that" - " has been edited", + png_chunk_report(png_ptr, + "Not recognizing known sRGB profile that has been edited", PNG_CHUNK_WARNING); break; # endif @@ -2349,9 +2345,8 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, return 0; /* no match */ } -#endif +#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */ -#ifdef PNG_sRGB_SUPPORTED void /* PRIVATE */ png_icc_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_bytep profile, uLong adler) @@ -2365,7 +2360,7 @@ png_icc_set_sRGB(png_const_structrp png_ptr, (void)png_colorspace_set_sRGB(png_ptr, colorspace, (int)/*already checked*/png_get_uint_32(profile+64)); } -#endif /* READ_sRGB */ +#endif /* sRGB */ int /* PRIVATE */ png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, @@ -2457,7 +2452,7 @@ png_colorspace_set_rgb_coefficients(png_structrp png_ptr) png_error(png_ptr, "internal error handling cHRM->XYZ"); } } -#endif +#endif /* READ_RGB_TO_GRAY */ #endif /* COLORSPACE */ @@ -2486,18 +2481,19 @@ png_check_IHDR(png_const_structrp png_ptr, png_warning(png_ptr, "Image width is zero in IHDR"); error = 1; } - else if (width > PNG_UINT_31_MAX) + + if (width > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image width in IHDR"); error = 1; } - else if (png_gt(width, - (PNG_SIZE_MAX >> 3) /* 8-byte RGBA pixels */ - - 48 /* big_row_buf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding width to multiple of 8 pix */ - - 8)) /* extra max_pixel_depth pad */ + if (png_gt(((width + 7) & (~7)), + ((PNG_SIZE_MAX + - 48 /* big_row_buf hack */ + - 1) /* filter byte */ + / 8) /* 8-byte RGBA pixels */ + - 1)) /* extra max_pixel_depth pad */ { /* The size of the row must be within the limits of this architecture. * Because the read code can perform arbitrary transformations the @@ -2513,17 +2509,15 @@ png_check_IHDR(png_const_structrp png_ptr, png_warning(png_ptr, "Image width is too large for this architecture"); error = 1; } - else + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif { -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max) -# else - if (width > PNG_USER_WIDTH_MAX) -# endif - { - png_warning(png_ptr, "Image width exceeds user limit in IHDR"); - error = 1; - } + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; } if (height == 0) @@ -2531,22 +2525,21 @@ png_check_IHDR(png_const_structrp png_ptr, png_warning(png_ptr, "Image height is zero in IHDR"); error = 1; } - else if (height > PNG_UINT_31_MAX) + + if (height > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image height in IHDR"); error = 1; } - else + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif { -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max) -# else - if (height > PNG_USER_HEIGHT_MAX) -# endif - { - png_warning(png_ptr, "Image height exceeds user limit in IHDR"); - error = 1; - } + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; } /* Check other values */ @@ -2585,7 +2578,7 @@ png_check_IHDR(png_const_structrp png_ptr, error = 1; } -# ifdef PNG_MNG_FEATURES_SUPPORTED +#ifdef PNG_MNG_FEATURES_SUPPORTED /* Accept filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not read a PNG signature (this filter_method is only @@ -2618,13 +2611,13 @@ png_check_IHDR(png_const_structrp png_ptr, } } -# else +#else if (filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } -# endif +#endif if (error == 1) png_error(png_ptr, "Invalid IHDR data"); @@ -3041,7 +3034,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, /* Check for an exponent, if we don't need one we are * done and just need to terminate the string. At * this point exp_b10==(-1) is effectively if flag - it got - * to '-1' because of the decrement after outputing + * to '-1' because of the decrement after outputting * the decimal point above (the exponent required is * *not* -1!) */ @@ -3049,7 +3042,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, { /* The following only happens if we didn't output the * leading zeros above for negative exponent, so this - * doest add to the digit requirement. Note that the + * doesn't add to the digit requirement. Note that the * two zeros here can only be output if the two leading * zeros were *not* output, so this doesn't increase * the output count. @@ -3206,7 +3199,7 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, png_error(png_ptr, "ASCII conversion buffer too small"); } # endif /* FIXED_POINT */ -#endif /* READ_SCAL */ +#endif /* SCAL */ #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ @@ -3224,7 +3217,7 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) png_fixed_error(png_ptr, text); # ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(text) + PNG_UNUSED(text) # endif return (png_fixed_point)r; @@ -3405,29 +3398,29 @@ png_gamma_significant(png_fixed_point gamma_val) #endif #ifdef PNG_READ_GAMMA_SUPPORTED -#if defined(PNG_16BIT_SUPPORTED) || !defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) +#ifdef PNG_16BIT_SUPPORTED /* A local convenience routine. */ static png_fixed_point png_product2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED double r = a * 1E-5; r *= b; r = floor(r+.5); if (r <= 2147483647. && r >= -2147483648.) return (png_fixed_point)r; -# else +#else png_fixed_point res; if (png_muldiv(&res, a, b, 100000) != 0) return res; -# endif +#endif return 0; /* overflow */ } -#endif /* 16BIT || !FLOATING_ARITHMETIC */ +#endif /* 16BIT */ /* The inverse of the above. */ png_fixed_point @@ -3435,12 +3428,15 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = 1E15/a; - r /= b; - r = floor(r+.5); + if (a != 0 && b != 0) + { + double r = 1E15/a; + r /= b; + r = floor(r+.5); - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; + } #else /* This may overflow because the range of png_fixed_point isn't symmetric, * but this API is only used for the product of file and screen gamma so it @@ -3731,7 +3727,7 @@ png_exp8bit(png_fixed_point lg2) * step. */ x -= x >> 8; - return (png_byte)((x + 0x7fffffU) >> 24); + return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); } #ifdef PNG_16BIT_SUPPORTED @@ -3792,7 +3788,7 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) # endif } - return (png_byte)value; + return (png_byte)(value & 0xff); } #ifdef PNG_16BIT_SUPPORTED @@ -4014,7 +4010,7 @@ png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, else for (i=0; i<256; ++i) - table[i] = (png_byte)i; + table[i] = (png_byte)(i & 0xff); } /* Used from png_read_destroy and below to release the memory used by the gamma @@ -4154,7 +4150,8 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth) * */ if (sig_bit > 0 && sig_bit < 16U) - shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ + /* shift == insignificant bits */ + shift = (png_byte)((16U - sig_bit) & 0xff); else shift = 0; /* keep all 16 bits */ @@ -4223,7 +4220,7 @@ png_set_option(png_structrp png_ptr, int option, int onoff) int setting = (2 + (onoff != 0)) << option; int current = png_ptr->options; - png_ptr->options = (png_byte)((current & ~mask) | setting); + png_ptr->options = (png_byte)(((current & ~mask) | setting) & 0xff); return (current & mask) >> option; } diff --git a/media/libpng/png.h b/media/libpng/png.h index 0646d2c9b54..f6b7ae7eb15 100644 --- a/media/libpng/png.h +++ b/media/libpng/png.h @@ -1,8 +1,9 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.16, December 22, 2014 - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * libpng version 1.6.17, March 25, 2015 + * + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -11,7 +12,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.6.16, December 22, 2014: Glenn + * libpng versions 0.97, January 1998, through 1.6.17, March 25, 2015: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -212,6 +213,9 @@ * 1.6.16beta01-03 16 10616 16.so.16.16[.0] * 1.6.16rc01-02 16 10616 16.so.16.16[.0] * 1.6.16 16 10616 16.so.16.16[.0] + * 1.6.17beta01-06 16 10617 16.so.16.17[.0] + * 1.6.17rc01-06 16 10617 16.so.16.17[.0] + * 1.6.17 16 10617 16.so.16.17[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -243,8 +247,8 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.6.16, December 22, 2014, are - * Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are + * libpng versions 1.2.6, August 15, 2004, through 1.6.17, March 25, 2015, are + * Copyright (c) 2004, 2006-2015 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: * @@ -355,13 +359,13 @@ * Y2K compliance in libpng: * ========================= * - * December 22, 2014 + * March 25, 2015 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.6.16 are Y2K compliant. It is my belief that + * upward through 1.6.17 are Y2K compliant. It is my belief that * earlier versions were also Y2K compliant. * * Libpng only has two year fields. One is a 2-byte unsigned integer @@ -423,9 +427,9 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.16" +#define PNG_LIBPNG_VER_STRING "1.6.17" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.6.16 - December 22, 2014\n" + " libpng version 1.6.17 - March 25, 2015\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 @@ -433,7 +437,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 16 +#define PNG_LIBPNG_VER_RELEASE 17 /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: @@ -464,7 +468,7 @@ * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10616 /* 1.6.16 */ +#define PNG_LIBPNG_VER 10617 /* 1.6.17 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -584,7 +588,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_16; +typedef char* png_libpng_version_1_6_17; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -1601,6 +1605,7 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ +#ifdef PNG_WRITE_SUPPORTED /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are * mainly useful for testing, as the defaults should work with most users. @@ -1614,6 +1619,7 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, */ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, int filters)); +#endif /* WRITE */ /* Flags for png_set_filter() to say which filters to use. The flags * are chosen so that they don't conflict with real filter types @@ -1639,6 +1645,7 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 +#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ /* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ * defines, either the default (minimum-sum-of-absolute-differences), or @@ -1685,7 +1692,6 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, #define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ #define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ -#ifdef PNG_WRITE_SUPPORTED /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have @@ -1693,6 +1699,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, int level)); @@ -1710,7 +1717,7 @@ PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, int method)); -#endif +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED /* Also set zlib parameters for compressing non-IDAT chunks */ @@ -1732,6 +1739,7 @@ PNG_EXPORT(225, void, png_set_text_compression_window_bits, PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, int method)); #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* WRITE */ /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, @@ -1842,7 +1850,7 @@ PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); * * The integer return from the callback function is interpreted thus: * - * negative: An error occured, png_chunk_error will be called. + * negative: An error occurred; png_chunk_error will be called. * zero: The chunk was not handled, the chunk will be saved. A critical * chunk will cause an error at this point unless it is to be saved. * positive: The chunk was handled, libpng will ignore/discard it. @@ -2687,26 +2695,28 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, * (png_uint_16)(alpha) \ + (png_uint_16)(bg)*(png_uint_16)(255 \ - (png_uint_16)(alpha)) + 128); \ - (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); } # define png_composite_16(composite, fg, alpha, bg) \ { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ * (png_uint_32)(alpha) \ + (png_uint_32)(bg)*(65535 \ - (png_uint_32)(alpha)) + 32768); \ - (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); } #else /* Standard method using integer division */ -# define png_composite(composite, fg, alpha, bg) \ - (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - 127) / 255) +# define png_composite(composite, fg, alpha, bg) \ + (composite) = \ + (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255)) # define png_composite_16(composite, fg, alpha, bg) \ - (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ - 32767) / 65535) + (composite) = \ + (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535)) #endif /* READ_COMPOSITE_NODIV */ #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED diff --git a/media/libpng/pngconf.h b/media/libpng/pngconf.h index 03615f0e775..680dd8aa1f2 100644 --- a/media/libpng/pngconf.h +++ b/media/libpng/pngconf.h @@ -1,9 +1,9 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.6.16,December 22, 2014 + * libpng version 1.6.17, March 25, 2015 * - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -11,9 +11,7 @@ * For conditions of distribution and use, see the disclaimer * and license in png.h * - */ - -/* Any machine specific code is near the front of this file, so if you + * Any machine specific code is near the front of this file, so if you * are configuring libpng for a machine, you may want to read the section * starting here down to where it starts to typedef png_color, png_text, * and png_info. @@ -22,26 +20,6 @@ #ifndef PNGCONF_H #define PNGCONF_H -/* To do: Do all of this in scripts/pnglibconf.dfa */ -#ifdef PNG_SAFE_LIMITS_SUPPORTED -# ifdef PNG_USER_WIDTH_MAX -# undef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000L -# endif -# ifdef PNG_USER_HEIGHT_MAX -# undef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000L -# endif -# ifdef PNG_USER_CHUNK_MALLOC_MAX -# undef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 4000000L -# endif -# ifdef PNG_USER_CHUNK_CACHE_MAX -# undef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 128 -# endif -#endif - #ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ /* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C diff --git a/media/libpng/pngdebug.h b/media/libpng/pngdebug.h index b43c59cde5f..6a01b106ede 100644 --- a/media/libpng/pngdebug.h +++ b/media/libpng/pngdebug.h @@ -1,12 +1,11 @@ /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * + * Last changed in libpng 1.6.8 [December 19, 2013] * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.6.8 [December 19, 2013] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h diff --git a/media/libpng/pngget.c b/media/libpng/pngget.c index 72622838d3b..83013b9c77d 100644 --- a/media/libpng/pngget.c +++ b/media/libpng/pngget.c @@ -1,8 +1,8 @@ /* pngget.c - retrieval of values from info struct * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -799,14 +799,20 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "IHDR"); - if (png_ptr == NULL || info_ptr == NULL || width == NULL || - height == NULL || bit_depth == NULL || color_type == NULL) + if (png_ptr == NULL || info_ptr == NULL) return (0); - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - *color_type = info_ptr->color_type; + if (width != NULL) + *width = info_ptr->width; + + if (height != NULL) + *height = info_ptr->height; + + if (bit_depth != NULL) + *bit_depth = info_ptr->bit_depth; + + if (color_type != NULL) + *color_type = info_ptr->color_type; if (compression_type != NULL) *compression_type = info_ptr->compression_type; @@ -1135,21 +1141,21 @@ png_get_compression_buffer_size(png_const_structrp png_ptr) if (png_ptr == NULL) return 0; -# ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) -# endif +#endif { -# ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED return png_ptr->IDAT_read_size; -# else +#else return PNG_IDAT_READ_SIZE; -# endif +#endif } -# ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_SUPPORTED else return png_ptr->zbuffer_size; -# endif +#endif } #ifdef PNG_SET_USER_LIMITS_SUPPORTED diff --git a/media/libpng/pnginfo.h b/media/libpng/pnginfo.h index b33c38f77a2..bb38ddb6fd8 100644 --- a/media/libpng/pnginfo.h +++ b/media/libpng/pnginfo.h @@ -1,12 +1,11 @@ /* pnginfo.h - header file for PNG reference library * + * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.6.1 [March 28, 2013] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h diff --git a/media/libpng/pnglibconf.h b/media/libpng/pnglibconf.h index 56d4f365adc..4bff8bfb250 100644 --- a/media/libpng/pnglibconf.h +++ b/media/libpng/pnglibconf.h @@ -97,7 +97,6 @@ #define PNG_WRITE_SUPPORTED #define PNG_WRITE_APNG_SUPPORTED #define PNG_WRITE_tRNS_SUPPORTED -#define PNG_WRITE_16BIT_SUPPORTED #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED #define PNG_WRITE_FLUSH_SUPPORTED #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED diff --git a/media/libpng/pngmem.c b/media/libpng/pngmem.c index d6caf273f1f..8b157e54d2a 100644 --- a/media/libpng/pngmem.c +++ b/media/libpng/pngmem.c @@ -41,7 +41,7 @@ png_destroy_png_struct(png_structrp png_ptr) } /* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell + * 64K. However, zlib may allocate more than 64K if you don't tell * it not to. See zconf.h and png.h for more information. zlib does * need to allocate exactly 64K, so whatever you call here must * have the ability to do that. diff --git a/media/libpng/pngpread.c b/media/libpng/pngpread.c index ff847ccf6a3..c4ee5c50f91 100644 --- a/media/libpng/pngpread.c +++ b/media/libpng/pngpread.c @@ -1,8 +1,8 @@ /* pngpread.c - read a png file in push mode * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -880,7 +880,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && - !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { int ret; @@ -1190,6 +1190,7 @@ png_push_process_row(png_structrp png_ptr) } } else +#endif { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); @@ -1199,6 +1200,7 @@ png_push_process_row(png_structrp png_ptr) void /* PRIVATE */ png_read_push_finish_row(png_structrp png_ptr) { +#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ @@ -1223,6 +1225,7 @@ png_read_push_finish_row(png_structrp png_ptr) if (png_ptr->row_number < png_ptr->num_rows) return; +#ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; @@ -1257,6 +1260,7 @@ png_read_push_finish_row(png_structrp png_ptr) } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); } +#endif /* READ_INTERLACING */ } void /* PRIVATE */ @@ -1281,6 +1285,7 @@ png_push_have_row(png_structrp png_ptr, png_bytep row) (int)png_ptr->pass); } +#ifdef PNG_READ_INTERLACING_SUPPORTED void PNGAPI png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row) @@ -1295,6 +1300,7 @@ png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, if (new_row != NULL) png_combine_row(png_ptr, old_row, 1/*blocky display*/); } +#endif /* READ_INTERLACING */ void PNGAPI png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, diff --git a/media/libpng/pngpriv.h b/media/libpng/pngpriv.h index 0a115ab4790..a309ead591b 100644 --- a/media/libpng/pngpriv.h +++ b/media/libpng/pngpriv.h @@ -1,13 +1,11 @@ /* pngpriv.h - private declarations for use inside libpng * - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.6.10 [March 6, 1014]] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -300,46 +298,9 @@ /* SECURITY and SAFETY: * - * By default libpng is built without any internal limits on image size, - * individual heap (png_malloc) allocations or the total amount of memory used. - * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used - * (unless individually overridden). These limits are believed to be fairly - * safe, but builders of secure systems should verify the values against the - * real system capabilities. - */ -#ifdef PNG_SAFE_LIMITS_SUPPORTED - /* 'safe' limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000 -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000 -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 128 -# endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 8000000 -# endif -#else - /* values for no limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 0x7fffffff -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 0x7fffffff -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 0 -# endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 0 -# endif -#endif - -/* Moved to pngpriv.h at libpng-1.5.0 */ -/* NOTE: some of these may have been used in external applications as - * these definitions were exposed in pngconf.h prior to 1.5. + * libpng is built with support for internal limits on image dimensions and + * memory usage. These are documented in scripts/pnglibconf.dfa of the + * source and recorded in the machine generated header file pnglibconf.h. */ /* If you are running on a machine where you cannot allocate more @@ -586,13 +547,13 @@ #define PNG_RGB_TO_GRAY_WARN 0x400000 #define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ #define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ -#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ -#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ - /* 0x8000000 unused */ - /* 0x10000000 unused */ - /* 0x20000000 unused */ - /* 0x40000000 unused */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ /* Flags for png_create_struct */ #define PNG_STRUCT_PNG 0x0001 #define PNG_STRUCT_INFO 0x0002 @@ -794,15 +755,17 @@ * macro will fail on top-bit-set values because of the sign extension. */ #define PNG_CHUNK_FROM_STRING(s)\ - PNG_U32(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) + PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) /* This uses (char), not (png_byte) to avoid warnings on systems where (char) is * signed and the argument is a (char[]) This macro will fail miserably on * systems where (char) is more than 8 bits. */ #define PNG_STRING_FROM_CHUNK(s,c)\ - (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ - ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) + (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ + ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ + ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ + ((char*)(s))[3]=(char)((c & 0xff))) /* Do the same but terminate with a null character. */ #define PNG_CSTRING_FROM_CHUNK(s,c)\ @@ -864,8 +827,9 @@ PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); -#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\ - ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)) +#define PNG_sRGB_FROM_LINEAR(linear) \ + ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB * encoded value with maximum error 0.646365. Note that the input is not a * 16-bit value; it has been multiplied by 255! */ @@ -924,7 +888,7 @@ PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) /* Internal array allocator, outputs no error or warning messages on failure, - * just returns NULL. + * just returns NULL. */ PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, int nelements, size_t element_size),PNG_ALLOCATED); diff --git a/media/libpng/pngread.c b/media/libpng/pngread.c index b61c2a95ae7..e9627691f1a 100644 --- a/media/libpng/pngread.c +++ b/media/libpng/pngread.c @@ -1,8 +1,8 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -894,8 +894,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) /* Zero length IDATs are legal after the last IDAT has been * read, but not after other chunks have been read. */ - if ((length > 0) || - (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); png_crc_finish(png_ptr, length); @@ -1904,6 +1903,7 @@ png_create_colormap_entry(png_image_read_control *display, y = (y + 128) >> 8; y *= 255; y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + alpha = PNG_DIV257(alpha); encoding = P_sRGB; } @@ -2366,8 +2366,14 @@ png_image_read_colormap(png_voidp argument) output_processing = PNG_CMAP_NONE; break; } - +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ + back_alpha = 255; +#else back_alpha = output_encoding == P_LINEAR ? 65535 : 255; +#endif } /* output_processing means that the libpng-processed row will be @@ -2492,7 +2498,14 @@ png_image_read_colormap(png_voidp argument) */ background_index = i; png_create_colormap_entry(display, i++, back_r, back_g, back_b, - output_encoding == P_LINEAR ? 65535U : 255U, output_encoding); +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ 255U, +#else + output_encoding == P_LINEAR ? 65535U : 255U, +#endif + output_encoding); /* For non-opaque input composite on the sRGB background - this * requires inverting the encoding for each component. The input @@ -3326,7 +3339,7 @@ png_image_read_composite(png_voidp argument) png_uint_32 width = image->width; ptrdiff_t step_row = display->row_bytes; unsigned int channels = - (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; int pass; for (pass = 0; pass < passes; ++pass) diff --git a/media/libpng/pngrio.c b/media/libpng/pngrio.c index 1e98395fd7e..79d95ce3f4c 100644 --- a/media/libpng/pngrio.c +++ b/media/libpng/pngrio.c @@ -1,8 +1,8 @@ /* pngrio.c - functions for data input * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -26,7 +26,7 @@ * reads from a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered reads. This should never be asked - * to read more then 64K on a 16 bit machine. + * to read more than 64K on a 16 bit machine. */ void /* PRIVATE */ png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) diff --git a/media/libpng/pngrtran.c b/media/libpng/pngrtran.c index e6fe9fdbfb6..738e553ba9e 100644 --- a/media/libpng/pngrtran.c +++ b/media/libpng/pngrtran.c @@ -1,8 +1,8 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -394,7 +394,7 @@ png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) /* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number - * of colors is greater then the maximum number, the palette will be + * of colors is greater than the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates * whether we need a quantizing cube set up for RGB images, or if we * simply are reducing the number of colors in a paletted image. @@ -2357,7 +2357,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, if (++channel >= channels) channel = 0; *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); + *bp++ = (png_byte)value; } break; } @@ -2662,9 +2662,9 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 row_width = row_info->width; #ifdef PNG_READ_16BIT_SUPPORTED - png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte hi_filler = (png_byte)(filler>>8); #endif - png_byte lo_filler = (png_byte)(filler & 0xff); + png_byte lo_filler = (png_byte)filler; png_debug(1, "in png_do_read_filler"); @@ -2715,13 +2715,13 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; @@ -2736,8 +2736,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } row_info->channels = 2; row_info->pixel_depth = 32; @@ -2796,8 +2796,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); @@ -2805,8 +2805,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; @@ -2825,8 +2825,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } row_info->channels = 4; @@ -3087,10 +3087,11 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, w; + png_byte hi,lo; - red = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red == green && red == blue) { @@ -3104,16 +3105,16 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) else { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) >> png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_16_to_1[(green & 0xff) >> png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + bc*blue_1 + 16384)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } @@ -3138,10 +3139,11 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, gray16; + png_byte hi,lo; - red = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red != green || red != blue) rgb_error |= 1; @@ -3667,7 +3669,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) if (optimize != 0) w = v; else - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + w = gamma_16_from_1[(v & 0xff) >> + gamma_shift][v >> 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); } @@ -3831,7 +3834,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(w, v, a, png_ptr->background_1.red); if (optimize == 0) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); @@ -3839,7 +3842,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; png_composite_16(w, v, a, png_ptr->background_1.green); if (optimize == 0) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *(sp + 2) = (png_byte)((w >> 8) & 0xff); @@ -3848,7 +3851,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; png_composite_16(w, v, a, png_ptr->background_1.blue); if (optimize == 0) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *(sp + 4) = (png_byte)((w >> 8) & 0xff); @@ -4837,7 +4840,7 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) /* Because PNG_COMPOSE does the gamma transform if there is something to * do (if there is an alpha channel or transparency.) */ - !((png_ptr->transformations & PNG_COMPOSE) && + !((png_ptr->transformations & PNG_COMPOSE) != 0 && ((png_ptr->num_trans != 0) || (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && #endif diff --git a/media/libpng/pngrutil.c b/media/libpng/pngrutil.c index af96ce7fa2e..29f22067066 100644 --- a/media/libpng/pngrutil.c +++ b/media/libpng/pngrutil.c @@ -1,8 +1,8 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -1520,8 +1520,10 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) else if (size > 0) errmsg = "truncated"; +#ifndef __COVERITY__ else errmsg = png_ptr->zstream.msg; +#endif } /* else png_icc_check_tag_table output an error */ @@ -2983,7 +2985,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, &png_ptr->unknown_chunk); /* ret is: - * negative: An error occured, png_chunk_error will be called. + * negative: An error occurred; png_chunk_error will be called. * zero: The chunk was not handled, the chunk will be discarded * unless png_set_keep_unknown_chunks has been used to set * a 'keep' behavior for this particular chunk, in which diff --git a/media/libpng/pngset.c b/media/libpng/pngset.c index b5aea0f200a..57bb6a7ef68 100644 --- a/media/libpng/pngset.c +++ b/media/libpng/pngset.c @@ -1,8 +1,8 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -190,6 +190,7 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; } @@ -276,7 +277,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(1, "in %s storage function", "pCAL"); if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL - || (nparams > 0 && params == NULL)) + || (nparams > 0 && params == NULL)) return; length = strlen(purpose) + 1; @@ -306,6 +307,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->pcal_purpose == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + return; } @@ -327,6 +329,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->pcal_units == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; } @@ -338,6 +341,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->pcal_params == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; } @@ -354,6 +358,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->pcal_params[i] == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; } @@ -403,6 +408,7 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->scal_s_width == NULL) { png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } @@ -421,6 +427,7 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, info_ptr->scal_s_width = NULL; png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } @@ -524,6 +531,7 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, else { png_warning(png_ptr, "Invalid palette length"); + return; } } @@ -536,7 +544,6 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, )) { png_error(png_ptr, "Invalid palette"); - return; } /* It may not actually be necessary to set png_ptr->palette here; @@ -660,6 +667,7 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, if (new_iccp_name == NULL) { png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + return; } @@ -673,6 +681,7 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, new_iccp_name = NULL; png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); + return; } @@ -748,6 +757,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, { png_chunk_report(png_ptr, "too many text chunks", PNG_CHUNK_WRITE_ERROR); + return 1; } @@ -803,7 +813,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, else lang_key_len = 0; } -# else /* PNG_iTXt_SUPPORTED */ +# else /* iTXt */ { png_chunk_report(png_ptr, "iTXt chunk not supported", PNG_CHUNK_WRITE_ERROR); @@ -836,6 +846,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, { png_chunk_report(png_ptr, "text chunk: out of memory", PNG_CHUNK_WRITE_ERROR); + return 1; } @@ -909,6 +920,7 @@ png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, mod_time->second > 60) { png_warning(png_ptr, "Ignoring invalid time value"); + return; } @@ -925,6 +937,7 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_debug1(1, "in %s storage function", "tRNS"); if (png_ptr == NULL || info_ptr == NULL) + return; if (trans_alpha != NULL) @@ -950,16 +963,21 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, if (trans_color != NULL) { - int sample_max = (1 << info_ptr->bit_depth); +#ifdef PNG_WARNINGS_SUPPORTED + if (info_ptr->bit_depth < 16) + { + int sample_max = (1 << info_ptr->bit_depth) - 1; - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - trans_color->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - (trans_color->red > sample_max || - trans_color->green > sample_max || - trans_color->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + } +#endif info_ptr->trans_color = *trans_color; @@ -1006,6 +1024,7 @@ png_set_sPLT(png_const_structrp png_ptr, { /* Out of memory or too many chunks */ png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + return; } @@ -1262,7 +1281,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr, png_unknown_chunkp np; if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || - unknowns == NULL) + unknowns == NULL) return; /* Check for the failure cases where support has been disabled at compile @@ -1276,6 +1295,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr, if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) { png_app_error(png_ptr, "no unknown chunk support on read"); + return; } # endif @@ -1284,6 +1304,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr, if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) { png_app_error(png_ptr, "no unknown chunk support on write"); + return; } # endif @@ -1301,6 +1322,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr, { png_chunk_report(png_ptr, "too many unknown chunks", PNG_CHUNK_WRITE_ERROR); + return; } @@ -1378,8 +1400,7 @@ png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, check_location(png_ptr, location); } } -#endif - +#endif /* STORE_UNKNOWN_CHUNKS */ #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI @@ -1410,6 +1431,7 @@ add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) if (memcmp(list, add, 4) == 0) { list[4] = (png_byte)keep; + return count; } } @@ -1437,6 +1459,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + return; } @@ -1486,6 +1509,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, * which can be switched off. */ png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + return; } @@ -1501,6 +1525,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, if (num_chunks + old_num_chunks > UINT_MAX/5) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + return; } @@ -1638,23 +1663,27 @@ png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { png_warning(png_ptr, "Compression buffer size cannot be changed because it is in use"); + return; } +#ifndef __COVERITY__ if (size > ZLIB_IO_MAX) { png_warning(png_ptr, "Compression buffer size limited to system maximum"); size = ZLIB_IO_MAX; /* must fit */ } +#endif - else if (size < 6) + if (size < 6) { /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH * if this is permitted. */ png_warning(png_ptr, "Compression buffer size cannot be reduced below 6"); + return; } @@ -1696,8 +1725,8 @@ png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, void PNGAPI png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { - if (png_ptr != NULL) - png_ptr->user_chunk_cache_max = user_chunk_cache_max; + if (png_ptr != NULL) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ diff --git a/media/libpng/pngstruct.h b/media/libpng/pngstruct.h index b87d1ca8db5..87abe583e26 100644 --- a/media/libpng/pngstruct.h +++ b/media/libpng/pngstruct.h @@ -1,12 +1,11 @@ /* pngstruct.h - header file for PNG reference library * + * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.6.1 [March 28, 2013] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -101,7 +100,7 @@ typedef struct png_XYZ #endif /* COLORSPACE */ #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) -/* A colorspace is all the above plus, potentially, profile information, +/* A colorspace is all the above plus, potentially, profile information; * however at present libpng does not use the profile internally so it is only * stored in the png_info struct (if iCCP is supported.) The rendering intent * is retained here and is checked. diff --git a/media/libpng/pngtrans.c b/media/libpng/pngtrans.c index 56856b48023..64eecf8f29b 100644 --- a/media/libpng/pngtrans.c +++ b/media/libpng/pngtrans.c @@ -1,8 +1,8 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * diff --git a/media/libpng/pngwrite.c b/media/libpng/pngwrite.c index 40f2818325e..fac2c9e803b 100644 --- a/media/libpng/pngwrite.c +++ b/media/libpng/pngwrite.c @@ -1,8 +1,8 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -647,8 +647,8 @@ png_do_write_intrapixel(png_row_infop row_info, png_bytep row) for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { - *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); - *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); + *(rp) = (png_byte)(*rp - *(rp + 1)); + *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); } } @@ -674,10 +674,10 @@ png_do_write_intrapixel(png_row_infop row_info, png_bytep row) png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); + *(rp ) = (png_byte)(red >> 8); + *(rp + 1) = (png_byte)red; + *(rp + 4) = (png_byte)(blue >> 8); + *(rp + 5) = (png_byte)blue; } } #endif /* WRITE_16BIT */ @@ -1059,8 +1059,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters) * it is too late to start using the filters that need it, since we * will be missing the data in the previous row. If an application * wants to start and stop using particular filters during compression, - * it should start out with all of the filters, and then add and - * remove them after the start of compression. + * it should start out with all of the filters, and then remove them + * or add them back after the start of compression. */ if (png_ptr->row_buf != NULL) { @@ -1381,6 +1381,7 @@ png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, #endif /* FIXED_POINT */ #endif /* WRITE_WEIGHTED_FILTER */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED void PNGAPI png_set_compression_level(png_structrp png_ptr, int level) { @@ -1426,8 +1427,8 @@ png_set_compression_window_bits(png_structrp png_ptr, int window_bits) if (png_ptr == NULL) return; - /* Prior to 1.6.0 this would warn but then set the window_bits value, this - * meant that negative window bits values could be selected which would cause + /* Prior to 1.6.0 this would warn but then set the window_bits value. This + * meant that negative window bits values could be selected that would cause * libpng to write a non-standard PNG file with raw deflate or gzip * compressed IDAT or ancillary chunks. Such files can be read and there is * no warning on read, so this seems like a very bad idea. @@ -1463,6 +1464,7 @@ png_set_compression_method(png_structrp png_ptr, int method) png_ptr->zlib_method = method; } +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ /* The following were added to libpng-1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED @@ -2296,7 +2298,9 @@ png_image_write_main(png_voidp argument) * it about 50 times. The speed-up in pngstest was about 10-20% of the * total (user) time on a heavily loaded system. */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED png_set_compression_level(png_ptr, 3); +#endif } /* Check for the cases that currently require a pre-transform on the row diff --git a/media/libpng/pngwtran.c b/media/libpng/pngwtran.c index 09562a787d0..43c9817c34b 100644 --- a/media/libpng/pngwtran.c +++ b/media/libpng/pngwtran.c @@ -1,8 +1,8 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * diff --git a/media/libpng/pngwutil.c b/media/libpng/pngwutil.c index d77f1b84653..fd0d6ef83b2 100644 --- a/media/libpng/pngwutil.c +++ b/media/libpng/pngwutil.c @@ -1,8 +1,8 @@ /* pngwutil.c - utilities to write a PNG file * - * Last changed in libpng 1.6.15 [November 20, 2014] - * Copyright (c) 1998-2014 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 25, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -23,10 +23,10 @@ void PNGAPI png_save_uint_32(png_bytep buf, png_uint_32 i) { - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); + buf[0] = (png_byte)(i >> 24); + buf[1] = (png_byte)(i >> 16); + buf[2] = (png_byte)(i >> 8); + buf[3] = (png_byte)(i ); } /* Place a 16-bit number into a buffer in PNG byte order. @@ -36,8 +36,8 @@ png_save_uint_32(png_bytep buf, png_uint_32 i) void PNGAPI png_save_uint_16(png_bytep buf, unsigned int i) { - buf[0] = (png_byte)((i >> 8) & 0xff); - buf[1] = (png_byte)(i & 0xff); + buf[0] = (png_byte)(i >> 8); + buf[1] = (png_byte)(i ); } #endif @@ -695,7 +695,7 @@ png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) while (*key && key_len < 79) { - png_byte ch = (png_byte)(0xff & *key++); + png_byte ch = (png_byte)*key++; if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) *new_key++ = ch, ++key_len, space = 0; @@ -871,7 +871,7 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, interlace_type=PNG_INTERLACE_NONE; #endif - /* Save the relevent information */ + /* Save the relevant information */ png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->color_type = (png_byte)color_type; png_ptr->interlaced = (png_byte)interlace_type; @@ -1786,7 +1786,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_write_compressed_data_out(png_ptr, &comp); else - png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); png_write_chunk_end(png_ptr); } @@ -2411,7 +2411,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) * been specified by the application, and then writes the row out with the * chosen filter. */ -static void +static void /* PRIVATE */ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_size_t row_bytes); @@ -2550,7 +2550,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { - *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + *dp = (png_byte)((int)*rp - (int)*lp); } best_row = png_ptr->sub_row; @@ -2612,7 +2612,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + v = *dp = (png_byte)((int)*rp - (int)*lp); sum += (v < 128) ? v : 256 - v; @@ -2671,7 +2671,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) pp = prev_row + 1; i < row_bytes; i++, rp++, pp++, dp++) { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + *dp = (png_byte)((int)*rp - (int)*pp); } best_row = png_ptr->up_row; @@ -2722,7 +2722,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, pp = prev_row + 1; i < row_bytes; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; @@ -2780,13 +2780,13 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { - *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); } for (lp = row_buf + 1; i < row_bytes; i++) { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); + *dp++ = + (png_byte)((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)); } best_row = png_ptr->avg_row; } @@ -2835,7 +2835,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); sum += (v < 128) ? v : 256 - v; } @@ -2843,7 +2843,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++) { v = *dp++ = - (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + (png_byte)(((int)*rp++ - ((int)*pp++ + (int)*lp++) / 2)); sum += (v < 128) ? v : 256 - v; @@ -2901,7 +2901,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + *dp++ = (png_byte)((int)*rp++ - (int)*pp++); } for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) @@ -2927,7 +2927,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + *dp++ = (png_byte)((int)*rp++ - p); } best_row = png_ptr->paeth_row; } @@ -2976,7 +2976,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; } @@ -3018,7 +3018,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) p = c; #endif /* SLOW_PAETH */ - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - p); sum += (v < 128) ? v : 256 - v; @@ -3100,6 +3100,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); +#ifdef PNG_WRITE_FILTER_SUPPORTED /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) { @@ -3109,6 +3110,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_ptr->prev_row = png_ptr->row_buf; png_ptr->row_buf = tptr; } +#endif /* WRITE_FILTER */ /* Finish row - updates counters and flushes zlib if last row */ png_write_finish_row(png_ptr); diff --git a/media/libstagefright/binding/Box.cpp b/media/libstagefright/binding/Box.cpp index 500a6d0a9aa..71c79ed739f 100644 --- a/media/libstagefright/binding/Box.cpp +++ b/media/libstagefright/binding/Box.cpp @@ -7,6 +7,7 @@ #include "mp4_demuxer/Box.h" #include "mp4_demuxer/mp4_demuxer.h" #include "mozilla/Endian.h" +#include using namespace mozilla; @@ -91,11 +92,6 @@ Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent) return; } - nsTArray content; - if (!Read(&content, boxRange)) { - return; - } - mRange = boxRange; } @@ -129,7 +125,15 @@ Box::Read(nsTArray* aDest) bool Box::Read(nsTArray* aDest, const MediaByteRange& aRange) { - aDest->SetLength(aRange.mEnd - mChildOffset); + int64_t length; + if (!mContext->mSource->Length(&length)) { + // The HTTP server didn't give us a length to work with. + // Limit the read to 32MiB max. + length = std::min(aRange.mEnd - mChildOffset, uint64_t(32 * 1024 * 1024)); + } else { + length = aRange.mEnd - mChildOffset; + } + aDest->SetLength(length); size_t bytes; if (!mContext->mSource->CachedReadAt(mChildOffset, aDest->Elements(), aDest->Length(), &bytes) || diff --git a/media/libstagefright/binding/DecoderData.cpp b/media/libstagefright/binding/DecoderData.cpp index 721362fd48b..824c47669a2 100644 --- a/media/libstagefright/binding/DecoderData.cpp +++ b/media/libstagefright/binding/DecoderData.cpp @@ -8,7 +8,6 @@ #include "mp4_demuxer/DecoderData.h" #include #include "media/stagefright/MetaData.h" -#include "media/stagefright/MediaBuffer.h" #include "media/stagefright/MediaDefs.h" #include "media/stagefright/Utils.h" #include "mozilla/ArrayUtils.h" @@ -20,7 +19,7 @@ namespace mp4_demuxer { static int32_t -FindInt32(sp& mMetaData, uint32_t mKey) +FindInt32(const MetaData* mMetaData, uint32_t mKey) { int32_t value; if (!mMetaData->findInt32(mKey, &value)) @@ -29,7 +28,7 @@ FindInt32(sp& mMetaData, uint32_t mKey) } static int64_t -FindInt64(sp& mMetaData, uint32_t mKey) +FindInt64(const MetaData* mMetaData, uint32_t mKey) { int64_t value; if (!mMetaData->findInt64(mKey, &value)) @@ -39,7 +38,7 @@ FindInt64(sp& mMetaData, uint32_t mKey) template static bool -FindData(sp& aMetaData, uint32_t aKey, mozilla::Vector* aDest) +FindData(const MetaData* aMetaData, uint32_t aKey, mozilla::Vector* aDest) { const void* data; size_t size; @@ -58,7 +57,7 @@ FindData(sp& aMetaData, uint32_t aKey, mozilla::Vector* aDest) template static bool -FindData(sp& aMetaData, uint32_t aKey, nsTArray* aDest) +FindData(const MetaData* aMetaData, uint32_t aKey, nsTArray* aDest) { const void* data; size_t size; @@ -76,25 +75,15 @@ FindData(sp& aMetaData, uint32_t aKey, nsTArray* aDest) } static bool -FindData(sp& aMetaData, uint32_t aKey, ByteBuffer* aDest) +FindData(const MetaData* aMetaData, uint32_t aKey, ByteBuffer* aDest) { return FindData(aMetaData, aKey, static_cast*>(aDest)); } bool -CryptoFile::DoUpdate(sp& aMetaData) +CryptoFile::DoUpdate(const uint8_t* aData, size_t aLength) { - const void* data; - size_t size; - uint32_t type; - - // There's no point in checking that the type matches anything because it - // isn't set consistently in the MPEG4Extractor. - if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) { - return false; - } - - ByteReader reader(reinterpret_cast(data), size); + ByteReader reader(aData, aLength); while (reader.Remaining()) { PsshInfo psshInfo; if (!reader.ReadArray(psshInfo.uuid, 16)) { @@ -115,34 +104,19 @@ CryptoFile::DoUpdate(sp& aMetaData) } void -CryptoTrack::Update(sp& aMetaData) -{ - valid = aMetaData->findInt32(kKeyCryptoMode, &mode) && - aMetaData->findInt32(kKeyCryptoDefaultIVSize, &iv_size) && - FindData(aMetaData, kKeyCryptoKey, &key); -} - -void -CryptoSample::Update(sp& aMetaData) -{ - CryptoTrack::Update(aMetaData); - valid = valid && FindData(aMetaData, kKeyPlainSizes, &plain_sizes) && - FindData(aMetaData, kKeyEncryptedSizes, &encrypted_sizes) && - FindData(aMetaData, kKeyCryptoIV, &iv); -} - -void -TrackConfig::Update(sp& aMetaData, const char* aMimeType) +TrackConfig::Update(const MetaData* aMetaData, const char* aMimeType) { mime_type = aMimeType; duration = FindInt64(aMetaData, kKeyDuration); media_time = FindInt64(aMetaData, kKeyMediaTime); mTrackId = FindInt32(aMetaData, kKeyTrackID); - crypto.Update(aMetaData); + crypto.valid = aMetaData->findInt32(kKeyCryptoMode, &crypto.mode) && + aMetaData->findInt32(kKeyCryptoDefaultIVSize, &crypto.iv_size) && + FindData(aMetaData, kKeyCryptoKey, &crypto.key); } void -AudioDecoderConfig::Update(sp& aMetaData, const char* aMimeType) +AudioDecoderConfig::Update(const MetaData* aMetaData, const char* aMimeType) { TrackConfig::Update(aMetaData, aMimeType); channel_count = FindInt32(aMetaData, kKeyChannelCount); @@ -175,11 +149,12 @@ bool AudioDecoderConfig::IsValid() { return channel_count > 0 && samples_per_second > 0 && frequency_index > 0 && - (!mime_type.Equals(MEDIA_MIMETYPE_AUDIO_AAC) || aac_profile > 0); + (!mime_type.Equals(MEDIA_MIMETYPE_AUDIO_AAC) || + aac_profile > 0 || extended_profile > 0); } void -VideoDecoderConfig::Update(sp& aMetaData, const char* aMimeType) +VideoDecoderConfig::Update(const MetaData* aMetaData, const char* aMimeType) { TrackConfig::Update(aMetaData, aMimeType); display_width = FindInt32(aMetaData, kKeyDisplayWidth); @@ -197,8 +172,7 @@ VideoDecoderConfig::IsValid() } MP4Sample::MP4Sample() - : mMediaBuffer(nullptr) - , decode_timestamp(0) + : decode_timestamp(0) , composition_timestamp(0) , duration(0) , byte_offset(0) @@ -231,26 +205,6 @@ MP4Sample::Clone() const MP4Sample::~MP4Sample() { - if (mMediaBuffer) { - mMediaBuffer->release(); - } -} - -void -MP4Sample::Update(int64_t& aMediaTime) -{ - sp m = mMediaBuffer->meta_data(); - // XXXbholley - Why don't we adjust decode_timestamp for aMediaTime? - // According to k17e, this code path is no longer used - we should probably remove it. - decode_timestamp = FindInt64(m, kKeyDecodingTime); - composition_timestamp = FindInt64(m, kKeyTime) - aMediaTime; - duration = FindInt64(m, kKeyDuration); - byte_offset = FindInt64(m, kKey64BitFileOffset); - is_sync_point = FindInt32(m, kKeyIsSyncFrame); - data = reinterpret_cast(mMediaBuffer->data()); - size = mMediaBuffer->range_length(); - - crypto.Update(m); } bool @@ -258,25 +212,14 @@ MP4Sample::Pad(size_t aPaddingBytes) { size_t newSize = size + aPaddingBytes; - // If the existing MediaBuffer has enough space then we just recycle it. If - // not then we copy to a new buffer. - uint8_t* newData = mMediaBuffer && newSize <= mMediaBuffer->size() - ? data - : new (fallible) uint8_t[newSize]; + uint8_t* newData = new (fallible) uint8_t[newSize]; if (!newData) { return false; } memset(newData + size, 0, aPaddingBytes); - - if (newData != data) { - memcpy(newData, data, size); - extra_buffer = data = newData; - if (mMediaBuffer) { - mMediaBuffer->release(); - mMediaBuffer = nullptr; - } - } + memcpy(newData, data, size); + extra_buffer = data = newData; return true; } @@ -286,11 +229,7 @@ MP4Sample::Prepend(const uint8_t* aData, size_t aSize) { size_t newSize = size + aSize; - // If the existing MediaBuffer has enough space then we just recycle it. If - // not then we copy to a new buffer. - uint8_t* newData = mMediaBuffer && newSize <= mMediaBuffer->size() - ? data - : new (fallible) uint8_t[newSize]; + uint8_t* newData = new (fallible) uint8_t[newSize]; if (!newData) { return false; } @@ -298,14 +237,7 @@ MP4Sample::Prepend(const uint8_t* aData, size_t aSize) memmove(newData + aSize, data, size); memmove(newData, aData, aSize); size = newSize; - - if (newData != data) { - extra_buffer = data = newData; - if (mMediaBuffer) { - mMediaBuffer->release(); - mMediaBuffer = nullptr; - } - } + extra_buffer = data = newData; return true; } @@ -313,25 +245,14 @@ MP4Sample::Prepend(const uint8_t* aData, size_t aSize) bool MP4Sample::Replace(const uint8_t* aData, size_t aSize) { - // If the existing MediaBuffer has enough space then we just recycle it. If - // not then we copy to a new buffer. - uint8_t* newData = mMediaBuffer && aSize <= mMediaBuffer->size() - ? data - : new (fallible) uint8_t[aSize]; + uint8_t* newData = new (fallible) uint8_t[aSize]; if (!newData) { return false; } memcpy(newData, aData, aSize); size = aSize; - - if (newData != data) { - extra_buffer = data = newData; - if (mMediaBuffer) { - mMediaBuffer->release(); - mMediaBuffer = nullptr; - } - } + extra_buffer = data = newData; return true; } diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index f0f940ce88e..2adc9c71747 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -99,9 +99,10 @@ private: bool MoofParser::BlockingReadNextMoof() { + int64_t length = std::numeric_limits::max(); + mSource->Length(&length); nsTArray byteRanges; - byteRanges.AppendElement( - MediaByteRange(0, std::numeric_limits::max())); + byteRanges.AppendElement(MediaByteRange(0, length)); nsRefPtr stream = new BlockingStream(mSource); BoxContext context(stream, byteRanges); diff --git a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h index 74840d5a3d1..d8770045010 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h +++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h @@ -15,9 +15,7 @@ namespace stagefright { -template class sp; class MetaData; -class MediaBuffer; } namespace mp4_demuxer @@ -46,30 +44,28 @@ struct PsshInfo class CryptoFile { public: - CryptoFile() {} + CryptoFile() : valid(false) {} CryptoFile(const CryptoFile& aCryptoFile) : valid(aCryptoFile.valid) { pssh.AppendElements(aCryptoFile.pssh); } - void Update(stagefright::sp& aMetaData) + void Update(const uint8_t* aData, size_t aLength) { - valid = DoUpdate(aMetaData); + valid = DoUpdate(aData, aLength); } bool valid; nsTArray pssh; private: - bool DoUpdate(stagefright::sp& aMetaData); + bool DoUpdate(const uint8_t* aData, size_t aLength); }; class CryptoTrack { public: CryptoTrack() : valid(false) {} - void Update(stagefright::sp& aMetaData); - bool valid; int32_t mode; int32_t iv_size; @@ -79,26 +75,44 @@ public: class CryptoSample : public CryptoTrack { public: - void Update(stagefright::sp& aMetaData); - nsTArray plain_sizes; nsTArray encrypted_sizes; nsTArray iv; - nsTArray session_ids; }; class TrackConfig { public: - TrackConfig() : mTrackId(0), duration(0), media_time(0) {} + enum TrackType { + kUndefinedTrack, + kAudioTrack, + kVideoTrack, + }; + explicit TrackConfig(TrackType aType) + : mTrackId(0) + , duration(0) + , media_time(0) + , mType(aType) + { + } + nsAutoCString mime_type; uint32_t mTrackId; int64_t duration; int64_t media_time; CryptoTrack crypto; + TrackType mType; - void Update(stagefright::sp& aMetaData, + bool IsAudioConfig() const + { + return mType == kAudioTrack; + } + bool IsVideoConfig() const + { + return mType == kVideoTrack; + } + void Update(const stagefright::MetaData* aMetaData, const char* aMimeType); }; @@ -106,7 +120,8 @@ class AudioDecoderConfig : public TrackConfig { public: AudioDecoderConfig() - : channel_count(0) + : TrackConfig(kAudioTrack) + , channel_count(0) , bits_per_sample(0) , samples_per_second(0) , frequency_index(0) @@ -126,7 +141,7 @@ public: nsRefPtr extra_data; nsRefPtr audio_specific_config; - void Update(stagefright::sp& aMetaData, + void Update(const stagefright::MetaData* aMetaData, const char* aMimeType); bool IsValid(); @@ -138,7 +153,8 @@ class VideoDecoderConfig : public TrackConfig { public: VideoDecoderConfig() - : display_width(0) + : TrackConfig(kVideoTrack) + , display_width(0) , display_height(0) , image_width(0) , image_height(0) @@ -154,7 +170,7 @@ public: nsRefPtr extra_data; // Unparsed AVCDecoderConfig payload. - void Update(stagefright::sp& aMetaData, + void Update(const stagefright::MetaData* aMetaData, const char* aMimeType); bool IsValid(); }; @@ -167,11 +183,8 @@ public: MP4Sample(); virtual ~MP4Sample(); MP4Sample* Clone() const; - void Update(int64_t& aMediaTime); bool Pad(size_t aPaddingBytes); - stagefright::MediaBuffer* mMediaBuffer; - Microseconds decode_timestamp; Microseconds composition_timestamp; Microseconds duration; diff --git a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h index 735999b39e5..92f56db2b80 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h +++ b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h @@ -82,6 +82,7 @@ protected: ~MP4Demuxer(); private: + void UpdateCrypto(const stagefright::MetaData* aMetaData); AudioDecoderConfig mAudioConfig; VideoDecoderConfig mVideoConfig; CryptoFile mCrypto; diff --git a/media/libstagefright/binding/mp4_demuxer.cpp b/media/libstagefright/binding/mp4_demuxer.cpp index 316d95ac564..b2763fc4d63 100644 --- a/media/libstagefright/binding/mp4_demuxer.cpp +++ b/media/libstagefright/binding/mp4_demuxer.cpp @@ -22,17 +22,16 @@ namespace mp4_demuxer struct StageFrightPrivate { - sp mExtractor; - + StageFrightPrivate() : mCanSeek(false) {} sp mAudio; - MediaSource::ReadOptions mAudioOptions; nsAutoPtr mAudioIterator; sp mVideo; - MediaSource::ReadOptions mVideoOptions; nsAutoPtr mVideoIterator; nsTArray> mIndexes; + + bool mCanSeek; }; class DataSourceAdapter : public DataSource @@ -79,7 +78,6 @@ MP4Demuxer::MP4Demuxer(Stream* source, Monitor* aMonitor) , mMonitor(aMonitor) , mNextKeyframeTime(-1) { - mPrivate->mExtractor = new MPEG4Extractor(new DataSourceAdapter(source)); } MP4Demuxer::~MP4Demuxer() @@ -96,7 +94,7 @@ bool MP4Demuxer::Init() { mMonitor->AssertCurrentThreadOwns(); - sp e = mPrivate->mExtractor; + sp e = new MPEG4Extractor(new DataSourceAdapter(mSource)); // Read the number of tracks. If we can't find any, make sure to bail now before // attempting any new reads to make the retry system work. @@ -119,7 +117,7 @@ MP4Demuxer::Init() return false; } mPrivate->mAudio = track; - mAudioConfig.Update(metaData, mimeType); + mAudioConfig.Update(metaData.get(), mimeType); nsRefPtr index = new Index(mPrivate->mAudio->exportIndex(), mSource, mAudioConfig.mTrackId, /* aIsAudio = */ true, mMonitor); @@ -131,7 +129,7 @@ MP4Demuxer::Init() return false; } mPrivate->mVideo = track; - mVideoConfig.Update(metaData, mimeType); + mVideoConfig.Update(metaData.get(), mimeType); nsRefPtr index = new Index(mPrivate->mVideo->exportIndex(), mSource, mVideoConfig.mTrackId, /* aIsAudio = */ false, mMonitor); @@ -140,7 +138,7 @@ MP4Demuxer::Init() } } sp metaData = e->getMetaData(); - mCrypto.Update(metaData); + UpdateCrypto(metaData.get()); int64_t movieDuration; if (!mVideoConfig.duration && !mAudioConfig.duration && @@ -148,10 +146,26 @@ MP4Demuxer::Init() // No duration were found in either tracks, use movie extend header box one. mVideoConfig.duration = mAudioConfig.duration = movieDuration; } + mPrivate->mCanSeek = e->flags() & MediaExtractor::CAN_SEEK; return mPrivate->mAudio.get() || mPrivate->mVideo.get(); } +void +MP4Demuxer::UpdateCrypto(const MetaData* aMetaData) +{ + const void* data; + size_t size; + uint32_t type; + + // There's no point in checking that the type matches anything because it + // isn't set consistently in the MPEG4Extractor. + if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) { + return; + } + mCrypto.Update(reinterpret_cast(data), size); +} + bool MP4Demuxer::HasValidAudio() { @@ -177,7 +191,7 @@ bool MP4Demuxer::CanSeek() { mMonitor->AssertCurrentThreadOwns(); - return mPrivate->mExtractor->flags() & MediaExtractor::CAN_SEEK; + return mPrivate->mCanSeek; } void @@ -186,9 +200,6 @@ MP4Demuxer::SeekAudio(Microseconds aTime) mMonitor->AssertCurrentThreadOwns(); if (mPrivate->mAudioIterator) { mPrivate->mAudioIterator->Seek(aTime); - } else { - mPrivate->mAudioOptions.setSeekTo( - aTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); } } @@ -198,9 +209,6 @@ MP4Demuxer::SeekVideo(Microseconds aTime) mMonitor->AssertCurrentThreadOwns(); if (mPrivate->mVideoIterator) { mPrivate->mVideoIterator->Seek(aTime); - } else { - mPrivate->mVideoOptions.setSeekTo( - aTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); } } @@ -208,29 +216,17 @@ MP4Sample* MP4Demuxer::DemuxAudioSample() { mMonitor->AssertCurrentThreadOwns(); - if (mPrivate->mAudioIterator) { - nsAutoPtr sample(mPrivate->mAudioIterator->GetNext()); - if (sample) { - if (sample->crypto.valid) { - sample->crypto.mode = mAudioConfig.crypto.mode; - sample->crypto.iv_size = mAudioConfig.crypto.iv_size; - sample->crypto.key.AppendElements(mAudioConfig.crypto.key); - } - } - return sample.forget(); - } - - nsAutoPtr sample(new MP4Sample()); - status_t status = - mPrivate->mAudio->read(&sample->mMediaBuffer, &mPrivate->mAudioOptions); - mPrivate->mAudioOptions.clearSeekTo(); - - if (status < 0) { + if (!mPrivate->mAudioIterator) { return nullptr; } - - sample->Update(mAudioConfig.media_time); - + nsAutoPtr sample(mPrivate->mAudioIterator->GetNext()); + if (sample) { + if (sample->crypto.valid) { + sample->crypto.mode = mAudioConfig.crypto.mode; + sample->crypto.iv_size = mAudioConfig.crypto.iv_size; + sample->crypto.key.AppendElements(mAudioConfig.crypto.key); + } + } return sample.forget(); } @@ -238,33 +234,20 @@ MP4Sample* MP4Demuxer::DemuxVideoSample() { mMonitor->AssertCurrentThreadOwns(); - if (mPrivate->mVideoIterator) { - nsAutoPtr sample(mPrivate->mVideoIterator->GetNext()); - if (sample) { - sample->extra_data = mVideoConfig.extra_data; - if (sample->crypto.valid) { - sample->crypto.mode = mVideoConfig.crypto.mode; - sample->crypto.key.AppendElements(mVideoConfig.crypto.key); - } - if (sample->composition_timestamp >= mNextKeyframeTime) { - mNextKeyframeTime = mPrivate->mVideoIterator->GetNextKeyframeTime(); - } - } - return sample.forget(); - } - - nsAutoPtr sample(new MP4Sample()); - status_t status = - mPrivate->mVideo->read(&sample->mMediaBuffer, &mPrivate->mVideoOptions); - mPrivate->mVideoOptions.clearSeekTo(); - - if (status < 0) { + if (!mPrivate->mVideoIterator) { return nullptr; } - - sample->Update(mVideoConfig.media_time); - sample->extra_data = mVideoConfig.extra_data; - + nsAutoPtr sample(mPrivate->mVideoIterator->GetNext()); + if (sample) { + sample->extra_data = mVideoConfig.extra_data; + if (sample->crypto.valid) { + sample->crypto.mode = mVideoConfig.crypto.mode; + sample->crypto.key.AppendElements(mVideoConfig.crypto.key); + } + if (sample->composition_timestamp >= mNextKeyframeTime) { + mNextKeyframeTime = mPrivate->mVideoIterator->GetNextKeyframeTime(); + } + } return sample.forget(); } diff --git a/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h b/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h index 30d969d29fd..2eb898be710 100644 --- a/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h +++ b/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h @@ -201,16 +201,16 @@ public: int32_t left, int32_t top, int32_t right, int32_t bottom); - bool findCString(uint32_t key, const char **value); - bool findInt32(uint32_t key, int32_t *value); - bool findInt64(uint32_t key, int64_t *value); - bool findFloat(uint32_t key, float *value); - bool findPointer(uint32_t key, void **value); + bool findCString(uint32_t key, const char **value) const; + bool findInt32(uint32_t key, int32_t *value) const; + bool findInt64(uint32_t key, int64_t *value) const; + bool findFloat(uint32_t key, float *value) const; + bool findPointer(uint32_t key, void **value) const; bool findRect( uint32_t key, int32_t *left, int32_t *top, - int32_t *right, int32_t *bottom); + int32_t *right, int32_t *bottom) const; bool setData(uint32_t key, uint32_t type, const void *data, size_t size); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MetaData.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MetaData.cpp index c832c9694cb..7486aca3d29 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MetaData.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MetaData.cpp @@ -90,7 +90,7 @@ bool MetaData::setRect( return setData(key, TYPE_RECT, &r, sizeof(r)); } -bool MetaData::findCString(uint32_t key, const char **value) { +bool MetaData::findCString(uint32_t key, const char **value) const { uint32_t type; const void *data; size_t size; @@ -103,7 +103,7 @@ bool MetaData::findCString(uint32_t key, const char **value) { return true; } -bool MetaData::findInt32(uint32_t key, int32_t *value) { +bool MetaData::findInt32(uint32_t key, int32_t *value) const { uint32_t type; const void *data; size_t size; @@ -118,7 +118,7 @@ bool MetaData::findInt32(uint32_t key, int32_t *value) { return true; } -bool MetaData::findInt64(uint32_t key, int64_t *value) { +bool MetaData::findInt64(uint32_t key, int64_t *value) const { uint32_t type; const void *data; size_t size; @@ -133,7 +133,7 @@ bool MetaData::findInt64(uint32_t key, int64_t *value) { return true; } -bool MetaData::findFloat(uint32_t key, float *value) { +bool MetaData::findFloat(uint32_t key, float *value) const { uint32_t type; const void *data; size_t size; @@ -148,7 +148,7 @@ bool MetaData::findFloat(uint32_t key, float *value) { return true; } -bool MetaData::findPointer(uint32_t key, void **value) { +bool MetaData::findPointer(uint32_t key, void **value) const { uint32_t type; const void *data; size_t size; @@ -166,7 +166,7 @@ bool MetaData::findPointer(uint32_t key, void **value) { bool MetaData::findRect( uint32_t key, int32_t *left, int32_t *top, - int32_t *right, int32_t *bottom) { + int32_t *right, int32_t *bottom) const { uint32_t type; const void *data; size_t size; diff --git a/media/libyuv/libyuv.gyp b/media/libyuv/libyuv.gyp index be334ca8bf1..2fafdd6ccb0 100644 --- a/media/libyuv/libyuv.gyp +++ b/media/libyuv/libyuv.gyp @@ -81,6 +81,11 @@ # 'standalone_static_library': 1, 'conditions': [ # TODO(fbarchard): Use gyp define to enable jpeg. + [ 'build_with_mozilla==1', { + 'defines': [ + 'HAVE_JPEG' + ], + }], [ 'OS != "ios" and build_with_mozilla!=1', { 'defines': [ 'HAVE_JPEG' diff --git a/media/libyuv/source/mjpeg_decoder.cc b/media/libyuv/source/mjpeg_decoder.cc index 193b829ba9c..afcdd45259a 100644 --- a/media/libyuv/source/mjpeg_decoder.cc +++ b/media/libyuv/source/mjpeg_decoder.cc @@ -19,7 +19,6 @@ #include #define HAVE_SETJMP #endif -struct FILE; // For jpeglib.h. // C++ build requires extern C for jpeg internals. #ifdef __cplusplus diff --git a/mfbt/Assertions.h b/mfbt/Assertions.h index 6836f2d95a0..c72e020806c 100644 --- a/mfbt/Assertions.h +++ b/mfbt/Assertions.h @@ -141,7 +141,7 @@ MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine) aStr, aFilename, aLine); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); -#ifdef MOZ_DUMP_ASSERTION_STACK +#if defined (MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); @@ -157,7 +157,7 @@ MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); #else fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); -#ifdef MOZ_DUMP_ASSERTION_STACK +#if defined(MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); diff --git a/mfbt/RefPtr.h b/mfbt/RefPtr.h index 6a0915d0640..6c1524e4ad2 100644 --- a/mfbt/RefPtr.h +++ b/mfbt/RefPtr.h @@ -20,6 +20,7 @@ #endif #if defined(MOZILLA_INTERNAL_API) && \ + !defined(MOZILLA_XPCOMRT_API) && \ (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) #define MOZ_REFCOUNTED_LEAK_CHECKING #endif diff --git a/mfbt/Types.h b/mfbt/Types.h index e7e18abb274..a5d936389d9 100644 --- a/mfbt/Types.h +++ b/mfbt/Types.h @@ -89,7 +89,7 @@ * symbols. We add the weak attribute to the import version of the MFBT API * macros to exploit this. */ -# if defined(MOZ_GLUE_IN_PROGRAM) +# if defined(MOZ_GLUE_IN_PROGRAM) && !defined(MOZILLA_XPCOMRT_API) # define MFBT_API __attribute__((weak)) MOZ_IMPORT_API # define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA # else diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index 4761ab697f2..0c2911450d9 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -4,17 +4,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsSocketTransportService2.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "nsSocketTransport2.h" +#include "NetworkActivityMonitor.h" +#include "mozilla/Preferences.h" +#endif // !defined(MOZILLA_XPCOMRT_API) +#include "nsASocketHandler.h" #include "nsError.h" #include "prnetdb.h" #include "prerror.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsServiceManagerUtils.h" -#include "NetworkActivityMonitor.h" #include "nsIObserverService.h" #include "mozilla/Services.h" -#include "mozilla/Preferences.h" #include "mozilla/Likely.h" #include "mozilla/PublicSSL.h" #include "mozilla/ChaosMode.h" @@ -560,7 +563,9 @@ nsSocketTransportService::Shutdown() obsSvc->RemoveObserver(this, "last-pb-context-exited"); } +#if !defined(MOZILLA_XPCOMRT_API) mozilla::net::NetworkActivityMonitor::Shutdown(); +#endif // !defined(MOZILLA_XPCOMRT_API) mInitialized = false; mShuttingDown = false; @@ -634,6 +639,10 @@ nsSocketTransportService::CreateTransport(const char **types, nsIProxyInfo *proxyInfo, nsISocketTransport **result) { +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("nsSocketTransportService::CreateTransport not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE); @@ -645,12 +654,17 @@ nsSocketTransportService::CreateTransport(const char **types, trans.forget(result); return NS_OK; +#endif // defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath, nsISocketTransport **result) { +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("nsSocketTransportService::CreateUnixDomainTransport not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else nsresult rv; NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); @@ -668,6 +682,7 @@ nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath, trans.forget(result); return NS_OK; +#endif // defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP @@ -732,7 +747,9 @@ nsSocketTransportService::Run() SOCKET_LOG(("STS thread init\n")); +#if !defined(MOZILLA_XPCOMRT_API) psm::InitializeSSLServerCertVerificationThreads(); +#endif // !defined(MOZILLA_XPCOMRT_API) gSocketThread = PR_GetCurrentThread(); @@ -901,7 +918,9 @@ nsSocketTransportService::Run() gSocketThread = nullptr; +#if !defined(MOZILLA_XPCOMRT_API) psm::StopSSLServerCertVerificationThreads(); +#endif // !defined(MOZILLA_XPCOMRT_API) SOCKET_LOG(("STS thread exit\n")); return NS_OK; @@ -1085,6 +1104,10 @@ nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration) nsresult nsSocketTransportService::UpdatePrefs() { +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("nsSocketTransportService::UpdatePrefs not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else mSendBufferSize = 0; nsCOMPtr tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -1146,6 +1169,7 @@ nsSocketTransportService::UpdatePrefs() } return NS_OK; +#endif // defined(MOZILLA_XPCOMRT_API) } void @@ -1190,6 +1214,7 @@ nsSocketTransportService::Observe(nsISupports *subject, const char *topic, const char16_t *data) { +#if !defined(MOZILLA_XPCOMRT_API) if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { UpdatePrefs(); return NS_OK; @@ -1203,6 +1228,7 @@ nsSocketTransportService::Observe(nsISupports *subject, return net::NetworkActivityMonitor::Init(blipInterval); } +#endif // !defined(MOZILLA_XPCOMRT_API) if (!strcmp(topic, "last-pb-context-exited")) { nsCOMPtr ev = @@ -1236,7 +1262,9 @@ nsSocketTransportService::ClosePrivateConnections() } } +#if !defined(MOZILLA_XPCOMRT_API) mozilla::ClearPrivateSSLState(); +#endif // !defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP diff --git a/netwerk/base/nsURLHelper.cpp b/netwerk/base/nsURLHelper.cpp index ea88126b7f0..7692a26a5c6 100644 --- a/netwerk/base/nsURLHelper.cpp +++ b/netwerk/base/nsURLHelper.cpp @@ -53,8 +53,10 @@ InitGlobals() } gInitialized = true; +#if !defined(MOZILLA_XPCOMRT_API) Preferences::AddIntVarCache(&gMaxLength, "network.standard-url.max-length", 1048576); +#endif } void @@ -107,6 +109,10 @@ net_GetStdURLParser() nsresult net_GetURLSpecFromDir(nsIFile *aFile, nsACString &result) { +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("net_GetURLSpecFromDir not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else nsAutoCString escPath; nsresult rv = net_GetURLSpecFromActualFile(aFile, escPath); if (NS_FAILED(rv)) @@ -118,11 +124,16 @@ net_GetURLSpecFromDir(nsIFile *aFile, nsACString &result) result = escPath; return NS_OK; +#endif // defined(MOZILLA_XPCOMRT_API) } nsresult net_GetURLSpecFromFile(nsIFile *aFile, nsACString &result) { +#if defined(MOZILLA_XPCOMRT_API) + NS_WARNING("net_GetURLSpecFromFile not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else nsAutoCString escPath; nsresult rv = net_GetURLSpecFromActualFile(aFile, escPath); if (NS_FAILED(rv)) @@ -142,6 +153,7 @@ net_GetURLSpecFromFile(nsIFile *aFile, nsACString &result) result = escPath; return NS_OK; +#endif // defined(MOZILLA_XPCOMRT_API) } //---------------------------------------------------------------------------- diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index 27291c08e3a..f8941f7ac9c 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -6812,7 +6812,7 @@ xxx *.zw -// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-02-27T18:02:08Z +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-04-07T06:02:08Z // aaa : 2015-02-26 American Automobile Association, Inc. aaa @@ -6853,12 +6853,18 @@ ads // adult : 2014-10-16 ICM Registry AD LLC adult +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + // afl : 2014-10-02 Australian Football League afl // africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa africa +// africamagic : 2015-03-05 Electronic Media Network (Pty) Ltd +africamagic + // agency : 2013-11-14 Steel Falls, LLC agency @@ -6979,6 +6985,9 @@ bbc // bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. bbva +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + // bcn : 2014-07-24 Municipi de Barcelona bcn @@ -7303,6 +7312,9 @@ country // coupon : 2015-02-26 Amazon EU S.à r.l. coupon +// coupons : 2015-03-26 Black Island, LLC +coupons + // courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD courses @@ -7438,6 +7450,12 @@ doosan // download : 2014-11-20 dot Support Limited download +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dstv : 2015-03-12 MultiChoice (Proprietary) Limited +dstv + // dubai : 2015-01-01 Dubai Smart Government Department dubai @@ -7528,6 +7546,9 @@ fairwinds // faith : 2014-11-20 dot Faith Limited faith +// family : 2015-04-02 Bitter Galley, LLC +family + // fan : 2014-03-06 fan @@ -7579,6 +7600,9 @@ fit // fitness : 2014-03-06 Brice Orchard, LLC fitness +// flickr : 2015-04-02 Yahoo! Domain Services Inc. +flickr + // flights : 2013-12-05 Fox Station, LLC flights @@ -7609,6 +7633,9 @@ forex // forsale : 2014-05-22 forsale +// forum : 2015-04-02 Fegistry, LLC +forum + // foundation : 2013-12-05 John Dale, LLC foundation @@ -7630,6 +7657,9 @@ furniture // futbol : 2013-09-20 futbol +// fyi : 2015-04-02 Silver Tigers, LLC +fyi + // gal : 2013-11-07 Asociación puntoGAL gal @@ -7654,6 +7684,9 @@ gea // gent : 2014-01-23 COMBELL GROUP NV/SA gent +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + // ggee : 2014-01-09 GMO Internet, Inc. ggee @@ -7714,6 +7747,9 @@ gop // got : 2014-12-18 Amazon EU S.à r.l. got +// gotv : 2015-03-12 MultiChoice (Proprietary) Limited +gotv + // graphics : 2013-09-13 Over Madison, LLC graphics @@ -7783,12 +7819,18 @@ hitachi // hiv : 2014-03-13 dotHIV gemeinnuetziger e.V. hiv +// hockey : 2015-03-19 Half Willow, LLC +hockey + // holdings : 2013-08-27 John Madison, LLC holdings // holiday : 2013-11-07 Goose Woods, LLC holiday +// homedepot : 2015-04-02 Homer TLC, Inc. +homedepot + // homes : 2014-01-09 DERHomes, LLC homes @@ -7804,6 +7846,9 @@ host // hosting : 2014-05-29 Uniregistry, Corp. hosting +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + // hotmail : 2014-12-18 Microsoft Corporation hotmail @@ -7816,6 +7861,9 @@ how // hsbc : 2014-10-24 HSBC Holdings PLC hsbc +// htc : 2015-04-02 HTC corporation +htc + // ibm : 2014-07-31 International Business Machines Corporation ibm @@ -7900,9 +7948,21 @@ jcb // jetzt : 2014-01-09 New TLD Company AB jetzt +// jewelry : 2015-03-05 Wild Bloom, LLC +jewelry + +// jio : 2015-04-02 Affinity Names, Inc. +jio + // jlc : 2014-12-04 Richemont DNS Inc. jlc +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + // joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry joburg @@ -7954,6 +8014,9 @@ krd // kred : 2013-12-19 KredTLD Pty Ltd kred +// kyknet : 2015-03-05 Electronic Media Network (Pty) Ltd +kyknet + // kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen kyoto @@ -7969,6 +8032,9 @@ land // landrover : 2014-11-13 Jaguar Land Rover Ltd landrover +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + // lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico lat @@ -8035,6 +8101,9 @@ link // live : 2014-12-04 Half Woods, LLC live +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + // loan : 2014-11-20 dot Loan Limited loan @@ -8104,6 +8173,9 @@ markets // marriott : 2014-10-09 Marriott Worldwide Corporation marriott +// mba : 2015-04-02 Lone Hollow, LLC +mba + // media : 2014-03-06 Grand Glen, LLC media @@ -8140,6 +8212,9 @@ mini // mma : 2014-11-07 MMA IARD mma +// mnet : 2015-03-05 Electronic Media Network (Pty) Ltd +mnet + // mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. mobily @@ -8188,6 +8263,18 @@ mtn // mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation mtpc +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// multichoice : 2015-03-12 MultiChoice (Proprietary) Limited +multichoice + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// mzansimagic : 2015-03-05 Electronic Media Network (Pty) Ltd +mzansimagic + // nadex : 2014-12-11 IG Group Holdings PLC nadex @@ -8197,6 +8284,9 @@ nagoya // naspers : 2015-02-12 Intelprop (Proprietary) Limited naspers +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + // navy : 2014-03-06 United TLD Holdco Ltd. navy @@ -8215,7 +8305,7 @@ neustar // new : 2014-01-30 Charleston Road Registry Inc. new -// news : 2014-12-18 Hidden Bloom, LLC +// news : 2014-12-18 news // nexus : 2014-07-24 Charleston Road Registry Inc. @@ -8260,6 +8350,9 @@ nyc // obi : 2014-09-25 OBI Group Holding SE & Co. KGaA obi +// office : 2015-03-12 Microsoft Corporation +office + // okinawa : 2013-12-05 BusinessRalliart Inc. okinawa @@ -8284,6 +8377,9 @@ ooo // oracle : 2014-06-19 Oracle Corporation oracle +// orange : 2015-03-12 Orange Brand Services Limited +orange + // organic : 2014-03-27 Afilias Limited organic @@ -8323,6 +8419,9 @@ parts // party : 2014-09-11 Blue Sky Registry Limited party +// passagens : 2015-03-05 Travel Reservations SRL +passagens + // payu : 2015-02-12 MIH PayU B.V. payu @@ -8371,6 +8470,9 @@ pizza // place : 2014-04-24 Snow Galley, LLC place +// play : 2015-03-05 Charleston Road Registry Inc. +play + // plumbing : 2013-09-10 Spring Tigers, LLC plumbing @@ -8419,6 +8521,9 @@ qpon // quebec : 2013-12-19 PointQuébec Inc quebec +// quest : 2015-03-26 Quest ION Limited +quest + // racing : 2014-12-04 Premier Registry Limited racing @@ -8428,6 +8533,9 @@ read // realtor : 2014-05-29 Real Estate Domains LLC realtor +// realty : 2015-03-19 Fegistry, LLC +realty + // recipes : 2013-10-17 Grand Island, LLC recipes @@ -8437,6 +8545,9 @@ red // redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. redstone +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + // rehab : 2014-03-06 United TLD Holdco Ltd. rehab @@ -8449,6 +8560,9 @@ reisen // reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. reit +// reliance : 2015-04-02 Reliance Industries Limited +reliance + // ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. ren @@ -8485,6 +8599,9 @@ rich // ricoh : 2014-11-20 Ricoh Company, Ltd. ricoh +// ril : 2015-04-02 Reliance Industries Limited +ril + // rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO rio @@ -8509,6 +8626,12 @@ rsvp // ruhr : 2013-10-02 regiodot GmbH & Co. KG ruhr +// run : 2015-03-19 Snow Park, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + // ryukyu : 2014-01-09 BusinessRalliart Inc. ryukyu @@ -8551,9 +8674,15 @@ sapo // sarl : 2014-07-03 Delta Orchard, LLC sarl +// sas : 2015-04-02 Research IP LLC +sas + // saxo : 2014-10-31 Saxo Bank A/S saxo +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + // sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION sbs @@ -8623,9 +8752,15 @@ shoes // shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. shouji +// show : 2015-03-05 Snow Beach, LLC +show + // shriram : 2014-01-23 Shriram Capital Ltd. shriram +// sina : 2015-03-12 Sina Corporation +sina + // singles : 2013-08-27 Fern Madison, LLC singles @@ -8647,6 +8782,9 @@ smile // sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F sncf +// soccer : 2015-03-26 Foggy Shadow, LLC +soccer + // social : 2013-11-07 United TLD Holdco Ltd. social @@ -8692,6 +8830,9 @@ star // starhub : 2015-02-05 StarHub Limited starhub +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + // statoil : 2014-12-04 Statoil ASA statoil @@ -8719,6 +8860,9 @@ style // sucks : 2014-12-22 Vox Populi Registry Inc. sucks +// supersport : 2015-03-05 SuperSport International Holdings Proprietary Limited +supersport + // supplies : 2013-12-19 Atomic Fields, LLC supplies @@ -8761,6 +8905,9 @@ taipei // taobao : 2015-01-15 Alibaba Group Holding Limited taobao +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + // tatar : 2014-04-24 Limited Liability Company \ tatar @@ -8770,9 +8917,15 @@ tattoo // tax : 2014-03-20 Storm Orchard, LLC tax +// taxi : 2015-03-19 Pine Falls, LLC +taxi + // tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. tci +// team : 2015-03-05 Atomic Lake, LLC +team + // tech : 2015-01-30 Dot Tech LLC tech @@ -8791,6 +8944,12 @@ temasek // tennis : 2014-12-04 Cotton Bloom, LLC tennis +// thd : 2015-04-02 Homer TLC, Inc. +thd + +// theater : 2015-03-19 Blue Tigers, LLC +theater + // tickets : 2015-02-05 Accent Media Limited tickets @@ -8848,9 +9007,18 @@ trading // training : 2013-11-07 Wild Willow, LLC training +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + // trust : 2014-10-16 trust +// trv : 2015-03-26 Travelers TLD, LLC +trv + // tui : 2014-07-03 TUI AG tui @@ -8899,6 +9067,9 @@ viajes // video : 2014-10-16 video +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + // villas : 2013-12-05 New Sky, LLC villas @@ -8938,6 +9109,9 @@ voto // voyage : 2013-08-27 Ruby House, LLC voyage +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + // wales : 2014-05-08 Nominet UK wales @@ -8959,6 +9133,9 @@ watches // weather : 2015-01-08 The Weather Channel, LLC weather +// weatherchannel : 2015-03-12 The Weather Channel, LLC +weatherchannel + // webcam : 2014-01-23 dot Webcam Limited webcam @@ -8971,6 +9148,9 @@ wed // wedding : 2014-04-24 Top Level Domain Holdings Limited wedding +// weibo : 2015-03-05 Sina Corporation +weibo + // weir : 2015-01-29 Weir Group IP Limited weir @@ -9076,12 +9256,18 @@ xin // xn--80aswg : 2013-07-14 CORE Association сайт +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + // xn--9dbq2a : 2015-01-15 VeriSign Sarl קום // xn--9et52u : 2014-06-12 RISE VICTORY LIMITED 时尚 +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + // xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited 淡马锡 @@ -9262,6 +9448,9 @@ xyz // yachts : 2014-01-09 DERYachts, LLC yachts +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + // yamaxun : 2014-12-18 Amazon EU S.à r.l. yamaxun diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 1990567b3d4..21a181206bc 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -36,7 +36,9 @@ #include "mozilla/Attributes.h" #include "mozilla/VisualEventTracer.h" #include "mozilla/net/NeckoCommon.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "mozilla/net/ChildDNSService.h" +#endif // !defined(MOZILLA_XPCOMRT_API) #include "mozilla/net/DNSListenerProxy.h" #include "mozilla/Services.h" @@ -502,9 +504,11 @@ static nsDNSService *gDNSService; nsIDNSService* nsDNSService::GetXPCOMSingleton() { +#if !defined(MOZILLA_XPCOMRT_API) if (IsNeckoChild()) { return ChildDNSService::GetSingleton(); } +#endif // !defined(MOZILLA_XPCOMRT_API) return GetSingleton(); } @@ -640,7 +644,9 @@ nsDNSService::Init() } } +#if !defined(MOZILLA_XPCOMRT_API) RegisterWeakMemoryReporter(this); +#endif // !defined(MOZILLA_XPCOMRT_API) return rv; } @@ -648,7 +654,9 @@ nsDNSService::Init() NS_IMETHODIMP nsDNSService::Shutdown() { +#if !defined(MOZILLA_XPCOMRT_API) UnregisterWeakMemoryReporter(this); +#endif // !defined(MOZILLA_XPCOMRT_API) nsRefPtr res; { diff --git a/netwerk/dns/prepare_tlds.py b/netwerk/dns/prepare_tlds.py index 6ddf8d63a14..96540362dbc 100644 --- a/netwerk/dns/prepare_tlds.py +++ b/netwerk/dns/prepare_tlds.py @@ -111,3 +111,6 @@ def main(output, effective_tld_filename): exception = boolStr(etld.exception()) wild = boolStr(etld.wild()) output.write('ETLD_ENTRY("%s", %s, %s)\n' % (etld.domain(), exception, wild)) + +if __name__ == '__main__': + main(sys.stdout, sys.argv[1]) diff --git a/netwerk/moz.build b/netwerk/moz.build index a5e732bcd47..3cf12a5a9d6 100644 --- a/netwerk/moz.build +++ b/netwerk/moz.build @@ -16,6 +16,7 @@ DIRS += [ 'protocol', 'system', 'ipc', + 'standalone', ] if CONFIG['MOZ_SRTP']: diff --git a/netwerk/standalone/moz.build b/netwerk/standalone/moz.build new file mode 100644 index 00000000000..112a07ded90 --- /dev/null +++ b/netwerk/standalone/moz.build @@ -0,0 +1,53 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': + Library('necko_standalone') + +src_list = [ + 'nsNetModuleStandalone.cpp', +] + +netwerk_base_src = [ + 'nsDNSPrefetch.cpp', + 'nsNetAddr.cpp', + 'nsSocketTransportService2.cpp', + 'nsURLHelper.cpp', +] +src_list += [ + '%s/netwerk/base/%s' % (TOPSRCDIR, s) for s in netwerk_base_src +] + +netwerk_dns_src = [ + 'nsHostResolver.cpp', + 'DNS.cpp', + 'DNSListenerProxy.cpp', + 'GetAddrInfo.cpp', + 'nameprep.c', + 'nsDNSService2.cpp', + 'nsIDNService.cpp', + 'punycode.c', + 'race.c', +] +src_list += [ + '%s/netwerk/dns/%s' % (TOPSRCDIR, s) for s in netwerk_dns_src +] + +SOURCES += sorted(src_list) + +FAIL_ON_WARNINGS = True + +LOCAL_INCLUDES = [ + '../base', + '../build', + '../dns', +] + +DEFINES['MOZILLA_INTERNAL_API'] = True +DEFINES['MOZILLA_XPCOMRT_API'] = True +DEFINES['MOZILLA_EXTERNAL_LINKAGE'] = True + +include('/ipc/chromium/chromium-config.mozbuild') diff --git a/netwerk/standalone/nsNetModuleStandalone.cpp b/netwerk/standalone/nsNetModuleStandalone.cpp new file mode 100644 index 00000000000..82dfe61840d --- /dev/null +++ b/netwerk/standalone/nsNetModuleStandalone.cpp @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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 "necko-config.h" + +#include "mozilla/ModuleUtils.h" +#include "mozilla/DebugOnly.h" +#include "nsCOMPtr.h" +#include "nsICategoryManager.h" +#include "nsIClassInfoImpl.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsNetCID.h" +#include "nsPIDNSService.h" +#include "nsPISocketTransportService.h" +#include "nscore.h" + +extern const mozilla::Module kNeckoStandaloneModule; + +namespace mozilla { + +nsresult +InitNetModuleStandalone() +{ + nsresult rv; + + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + mozilla::DebugOnly rv = dns->Init(); + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed"); + } else { + NS_WARNING("failed to get dns service"); + } + + nsCOMPtr sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + mozilla::DebugOnly rv = sts->Init(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Socket transport service init failed"); + } else { + NS_WARNING("failed to get socket transport service"); + } + + return NS_OK; +} + +nsresult +ShutdownNetModuleStandalone() +{ + nsresult rv; + + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + mozilla::DebugOnly rv = dns->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed"); + } else { + NS_WARNING("failed to get dns service"); + } + + nsCOMPtr sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + mozilla::DebugOnly rv = sts->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Socket transport service shutdown failed"); + } else { + NS_WARNING("failed to get socket transport service"); + } + + return NS_OK; +} + +} // namespace mozilla + +#include "nsDNSService2.h" +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIDNSService, + nsDNSService::GetXPCOMSingleton) + +#include "nsSocketTransportService2.h" +#undef LOG +#undef LOG_ENABLED +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSocketTransportService, Init) + +// Net module startup hook +static nsresult nsNetStartup() +{ + return NS_OK; +} + +// Net module shutdown hook +static void nsNetShutdown() +{ +} + +NS_DEFINE_NAMED_CID(NS_SOCKETTRANSPORTSERVICE_CID); +NS_DEFINE_NAMED_CID(NS_DNSSERVICE_CID); + +static const mozilla::Module::CIDEntry kNeckoCIDs[] = { + { &kNS_SOCKETTRANSPORTSERVICE_CID, false, nullptr, nsSocketTransportServiceConstructor }, + { &kNS_DNSSERVICE_CID, false, nullptr, nsIDNSServiceConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { + { NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &kNS_SOCKETTRANSPORTSERVICE_CID }, + { NS_DNSSERVICE_CONTRACTID, &kNS_DNSSERVICE_CID }, + { nullptr } +}; + +const mozilla::Module kNeckoStandaloneModule = { + mozilla::Module::kVersion, + kNeckoCIDs, + kNeckoContracts, + nullptr, + nullptr, + nsNetStartup, + nsNetShutdown +}; diff --git a/netwerk/standalone/nsNetModuleStandalone.h b/netwerk/standalone/nsNetModuleStandalone.h new file mode 100644 index 00000000000..6e59cef4eae --- /dev/null +++ b/netwerk/standalone/nsNetModuleStandalone.h @@ -0,0 +1,13 @@ +#ifndef ns_net_module_standalone_h_ +#define ns_net_module_standalone_h_ + +#include + +namespace mozilla { + +nsresult InitNetModuleStandalone(); +nsresult ShutdownNetModuleStandalone(); + +} + +#endif // ns_net_module_standalone_h_ diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 35aa88edbcf..a7fe4f7e01c 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -98,8 +98,14 @@ run-sequentially = hardcoded ports [test_pinning.js] run-sequentially = hardcoded ports [test_ocsp_url.js] +# OCSP requests in this test time out on slow B2G Emulator debug builds. +# See Bug 1147725. +skip-if = toolkit == 'gonk' && debug run-sequentially = hardcoded ports [test_ocsp_fetch_method.js] +# OCSP requests in this test time out on slow B2G Emulator debug builds. +# See Bug 1147725. +skip-if = toolkit == 'gonk' && debug run-sequentially = hardcoded ports [test_ocsp_no_hsts_upgrade.js] run-sequentially = hardcoded ports diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp index 92fe930e34e..79188eb0ade 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -88,20 +88,18 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel) } else if (aSandboxLevel == 2) { jobLevel = sandbox::JOB_RESTRICTED; accessTokenLevel = sandbox::USER_LIMITED; - // Ideally we would have an initialIntegrityLevel of LOW here, but this - // immediately causes a problem with the way PBackground is initialized. - initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM; + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; } else if (aSandboxLevel == 1) { - jobLevel = sandbox::JOB_INTERACTIVE; - accessTokenLevel = sandbox::USER_INTERACTIVE; - // INTEGRITY_LEVEL_LAST effectively means don't change from the integrity - // level of the broker process. - initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST; + jobLevel = sandbox::JOB_NONE; + accessTokenLevel = sandbox::USER_NON_ADMIN; + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; } else { jobLevel = sandbox::JOB_NONE; accessTokenLevel = sandbox::USER_NON_ADMIN; + // INTEGRITY_LEVEL_LAST effectively means don't change from the integrity + // level of the broker process. initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST; delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM; } @@ -119,7 +117,7 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel) result = mPolicy->SetDelayedIntegrityLevel(delayedIntegrityLevel); ret = ret && (sandbox::SBOX_ALL_OK == result); - if (aSandboxLevel > 0) { + if (aSandboxLevel > 1) { result = mPolicy->SetAlternateDesktop(true); ret = ret && (sandbox::SBOX_ALL_OK == result); } @@ -132,6 +130,12 @@ SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel) L"\\??\\pipe\\chrome.*"); ret = ret && (sandbox::SBOX_ALL_OK == result); + // Add the policy for the client side of the crash server pipe. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + L"\\??\\pipe\\gecko-crash-server-pipe.*"); + ret = ret && (sandbox::SBOX_ALL_OK == result); + // The content process needs to be able to duplicate named pipes back to the // broker process, which are File type handles. result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES, diff --git a/services/common/tests/unit/test_load_modules.js b/services/common/tests/unit/test_load_modules.js index 34c1c6fcc5a..1e159dfebcb 100644 --- a/services/common/tests/unit/test_load_modules.js +++ b/services/common/tests/unit/test_load_modules.js @@ -36,7 +36,15 @@ const non_android_healthreport_test_modules = [ function expectImportsToSucceed(mm, base=MODULE_BASE) { for each (let m in mm) { let resource = base + m; - Components.utils.import(resource, {}); + let succeeded = false; + try { + Components.utils.import(resource, {}); + succeeded = true; + } catch (e) {} + + if (!succeeded) { + throw "Importing " + resource + " should have succeeded!"; + } } } @@ -50,26 +58,26 @@ function expectImportsToFail(mm, base=MODULE_BASE) { } catch (e) {} if (succeeded) { - throw "Importing " + m + " should have failed!"; + throw "Importing " + resource + " should have failed!"; } } } function run_test() { expectImportsToSucceed(shared_modules); - expectImportsToSucceed(shared_test_modules, base=TEST_BASE); + expectImportsToSucceed(shared_test_modules, TEST_BASE); if (AppConstants.platform != "android") { expectImportsToSucceed(non_android_modules); - expectImportsToSucceed(non_android_test_modules, base=TEST_BASE); + expectImportsToSucceed(non_android_test_modules, TEST_BASE); if (AppConstants.MOZ_SERVICES_HEALTHREPORT) { expectImportsToSucceed(non_android_healthreport_modules); - expectImportsToSucceed(non_android_healthreport_test_modules, base=TEST_BASE); + expectImportsToSucceed(non_android_healthreport_test_modules, TEST_BASE); } } else { expectImportsToFail(non_android_modules); - expectImportsToFail(non_android_test_modules, base=TEST_BASE); + expectImportsToFail(non_android_test_modules, TEST_BASE); expectImportsToFail(non_android_healthreport_modules); - expectImportsToFail(non_android_healthreport_test_modules, base=TEST_BASE); + expectImportsToFail(non_android_healthreport_test_modules, TEST_BASE); } } diff --git a/testing/marionette/client/marionette/__init__.py b/testing/marionette/client/marionette/__init__.py index 78b88f62dcc..1894eb274cf 100644 --- a/testing/marionette/client/marionette/__init__.py +++ b/testing/marionette/client/marionette/__init__.py @@ -23,4 +23,4 @@ from runner import ( TestManifest, TestResult, TestResultCollection -) +) \ No newline at end of file diff --git a/testing/marionette/client/marionette/marionette_test.py b/testing/marionette/client/marionette/marionette_test.py index a56375dc19b..a1c56370d4d 100644 --- a/testing/marionette/client/marionette/marionette_test.py +++ b/testing/marionette/client/marionette/marionette_test.py @@ -16,7 +16,7 @@ import warnings from marionette_driver.errors import ( - ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException, + MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException, JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException, StaleElementException, ScriptTimeoutException, ElementNotVisibleException, NoSuchFrameException, InvalidElementStateException, NoAlertPresentException, diff --git a/testing/marionette/client/marionette/tests/unit/test_errors.py b/testing/marionette/client/marionette/tests/unit/test_errors.py index f004933f74e..fd3700db533 100644 --- a/testing/marionette/client/marionette/tests/unit/test_errors.py +++ b/testing/marionette/client/marionette/tests/unit/test_errors.py @@ -6,7 +6,6 @@ import sys from marionette import marionette_test from marionette_driver import errors -from marionette_driver.errors import ErrorCodes def fake_cause(): try: @@ -15,29 +14,26 @@ def fake_cause(): return sys.exc_info() message = "foo" -status = ErrorCodes.TIMEOUT cause = fake_cause() stacktrace = "first\nsecond" -class TestMarionetteException(marionette_test.MarionetteTestCase): +class TestExceptionType(marionette_test.MarionetteTestCase): def test_defaults(self): exc = errors.MarionetteException() self.assertIsNone(exc.msg) - self.assertEquals(exc.status, ErrorCodes.MARIONETTE_ERROR) self.assertIsNone(exc.cause) self.assertIsNone(exc.stacktrace) def test_construction(self): exc = errors.MarionetteException( - message=message, status=status, cause=cause, stacktrace=stacktrace) + message=message, cause=cause, stacktrace=stacktrace) self.assertEquals(exc.msg, message) - self.assertEquals(exc.status, status) self.assertEquals(exc.cause, cause) self.assertEquals(exc.stacktrace, stacktrace) def test_str(self): exc = errors.MarionetteException( - message=message, status=status, cause=cause, stacktrace=stacktrace) + message=message, cause=cause, stacktrace=stacktrace) r = str(exc) self.assertIn(message, r) self.assertIn(", caused by %r" % cause[0], r) @@ -55,3 +51,28 @@ class TestMarionetteException(marionette_test.MarionetteTestCase): self.assertEqual(exc.cause, cause) r = str(exc) self.assertIn(", caused by %r" % cause[0], r) + + +class TestLookup(marionette_test.MarionetteTestCase): + def test_by_known_number(self): + self.assertEqual(errors.NoSuchElementException, errors.lookup(7)) + + def test_by_unknown_number(self): + self.assertEqual(errors.MarionetteException, errors.lookup(123456)) + + def test_by_known_string(self): + self.assertEqual(errors.NoSuchElementException, + errors.lookup("no such element")) + + def test_by_unknown_string(self): + self.assertEqual(errors.MarionetteException, errors.lookup("barbera")) + + +class TestAllExceptions(marionette_test.MarionetteTestCase): + def test_properties(self): + for exc in errors.excs: + self.assertTrue(hasattr(exc, "code"), + "expected exception to have attribute `code'") + self.assertTrue(hasattr(exc, "status"), + "expected exception to have attribute `status'") + self.assertIsInstance(exc.code, tuple) diff --git a/testing/marionette/client/marionette/tests/unit/test_marionette.py b/testing/marionette/client/marionette/tests/unit/test_marionette.py index 477fa969341..26d6ce71871 100644 --- a/testing/marionette/client/marionette/tests/unit/test_marionette.py +++ b/testing/marionette/client/marionette/tests/unit/test_marionette.py @@ -15,8 +15,17 @@ class TestHandleError(marionette_test.MarionetteTestCase): def test_known_error_code(self): with self.assertRaises(errors.NoSuchElementException): self.marionette._handle_error( - {"error": {"status": errors.ErrorCodes.NO_SUCH_ELEMENT}}) + {"error": {"status": errors.NoSuchElementException.code[0]}}) + + def test_known_error_status(self): + with self.assertRaises(errors.NoSuchElementException): + self.marionette._handle_error( + {"error": {"status": errors.NoSuchElementException.status}}) def test_unknown_error_code(self): with self.assertRaises(errors.MarionetteException): self.marionette._handle_error({"error": {"status": 123456}}) + + def test_unknown_error_status(self): + with self.assertRaises(errors.MarionetteException): + self.marionette._handle_error({"error": {"status": "barbera"}}) diff --git a/testing/marionette/driver/marionette_driver/errors.py b/testing/marionette/driver/marionette_driver/errors.py index b8b1b1d0473..89e3ab469ca 100644 --- a/testing/marionette/driver/marionette_driver/errors.py +++ b/testing/marionette/driver/marionette_driver/errors.py @@ -4,52 +4,19 @@ import traceback -class ErrorCodes(object): - SUCCESS = 0 - NO_SUCH_ELEMENT = 7 - NO_SUCH_FRAME = 8 - UNKNOWN_COMMAND = 9 - STALE_ELEMENT_REFERENCE = 10 - ELEMENT_NOT_VISIBLE = 11 - INVALID_ELEMENT_STATE = 12 - UNKNOWN_ERROR = 13 - ELEMENT_NOT_ACCESSIBLE = 56 - ELEMENT_IS_NOT_SELECTABLE = 15 - JAVASCRIPT_ERROR = 17 - XPATH_LOOKUP_ERROR = 19 - TIMEOUT = 21 - NO_SUCH_WINDOW = 23 - INVALID_COOKIE_DOMAIN = 24 - UNABLE_TO_SET_COOKIE = 25 - UNEXPECTED_ALERT_OPEN = 26 - NO_ALERT_OPEN = 27 - SCRIPT_TIMEOUT = 28 - INVALID_ELEMENT_COORDINATES = 29 - INVALID_SELECTOR = 32 - MOVE_TARGET_OUT_OF_BOUNDS = 34 - INVALID_XPATH_SELECTOR = 51 - INVALID_XPATH_SELECTOR_RETURN_TYPER = 52 - INVALID_RESPONSE = 53 - FRAME_SEND_NOT_INITIALIZED_ERROR = 54 - FRAME_SEND_FAILURE_ERROR = 55 - SESSION_NOT_CREATED = 71 - UNSUPPORTED_OPERATION = 405 - MARIONETTE_ERROR = 500 class MarionetteException(Exception): + """Raised when a generic non-recoverable exception has occured.""" - def __init__(self, message=None, - status=ErrorCodes.MARIONETTE_ERROR, cause=None, - stacktrace=None): + code = (500,) + status = "webdriver error" + + def __init__(self, message=None, cause=None, stacktrace=None): """Construct new MarionetteException instance. :param message: An optional exception message. - :param status: A WebDriver status code given as an integer. - By default the generic Marionette error code 500 will be - used. - :param cause: An optional tuple of three values giving information about the root exception cause. Expected tuple values are (type, value, traceback). @@ -61,7 +28,6 @@ class MarionetteException(Exception): """ self.msg = message - self.status = status self.cause = cause self.stacktrace = stacktrace @@ -81,72 +47,175 @@ class MarionetteException(Exception): return "".join(traceback.format_exception(self.__class__, msg, tb)) + class InstallGeckoError(MarionetteException): pass + class TimeoutException(MarionetteException): - pass + code = (21,) + status = "timeout" + class InvalidResponseException(MarionetteException): - pass + code = (53,) + status = "invalid response" + class JavascriptException(MarionetteException): - pass + code = (17,) + status = "javascript error" + class NoSuchElementException(MarionetteException): - pass + code = (7,) + status = "no such element" + class XPathLookupException(MarionetteException): - pass + code = (19,) + status = "invalid xpath selector" + class NoSuchWindowException(MarionetteException): - pass + code = (23,) + status = "no such window" + class StaleElementException(MarionetteException): - pass + code = (10,) + status = "stale element reference" + class ScriptTimeoutException(MarionetteException): - pass + code = (28,) + status = "script timeout" + class ElementNotVisibleException(MarionetteException): - def __init__(self, message="Element is not currently visible and may not be manipulated", - status=ErrorCodes.ELEMENT_NOT_VISIBLE, + code = (11,) + status = "element not visible" + + def __init__( + self, message="Element is not currently visible and may not be manipulated", stacktrace=None, cause=None): super(ElementNotVisibleException, self).__init__( - message, status=status, cause=cause, stacktrace=stacktrace) + message, cause=cause, stacktrace=stacktrace) + class ElementNotAccessibleException(MarionetteException): - pass + code = (56,) + status = "element not accessible" + class NoSuchFrameException(MarionetteException): - pass + code = (8,) + status = "no such frame" + class InvalidElementStateException(MarionetteException): - pass + code = (12,) + status = "invalid element state" + class NoAlertPresentException(MarionetteException): - pass + code = (27,) + status = "no such alert" + class InvalidCookieDomainException(MarionetteException): - pass + code = (24,) + status = "invalid cookie domain" + class UnableToSetCookieException(MarionetteException): - pass + code = (25,) + status = "unable to set cookie" + + +class InvalidElementCoordinates(MarionetteException): + code = (29,) + status = "invalid element coordinates" + class InvalidSelectorException(MarionetteException): - pass + code = (32, 51, 52) + status = "invalid selector" + class MoveTargetOutOfBoundsException(MarionetteException): - pass + code = (34,) + status = "move target out of bounds" + class FrameSendNotInitializedError(MarionetteException): - pass + code = (54,) + status = "frame send not initialized" + class FrameSendFailureError(MarionetteException): - pass + code = (55,) + status = "frame send failure" + class UnsupportedOperationException(MarionetteException): - pass + code = (405,) + status = "unsupported operation" + class SessionNotCreatedException(MarionetteException): - pass + code = (33, 71) + status = "session not created" + + +class UnexpectedAlertOpen(MarionetteException): + code = (26,) + status = "unexpected alert open" + +excs = [ + MarionetteException, + TimeoutException, + InvalidResponseException, + JavascriptException, + NoSuchElementException, + XPathLookupException, + NoSuchWindowException, + StaleElementException, + ScriptTimeoutException, + ElementNotVisibleException, + ElementNotAccessibleException, + NoSuchFrameException, + InvalidElementStateException, + NoAlertPresentException, + InvalidCookieDomainException, + UnableToSetCookieException, + InvalidElementCoordinates, + InvalidSelectorException, + MoveTargetOutOfBoundsException, + FrameSendNotInitializedError, + FrameSendFailureError, + UnsupportedOperationException, + SessionNotCreatedException, + UnexpectedAlertOpen, +] + + +def lookup(identifier): + """Finds error exception class by associated Selenium JSON wire + protocol number code, or W3C WebDriver protocol string.""" + + by_code = lambda exc: identifier in exc.code + by_status = lambda exc: exc.status == identifier + + rv = None + if isinstance(identifier, int): + rv = filter(by_code, excs) + elif isinstance(identifier, str): + rv = filter(by_status, excs) + + if not rv: + return MarionetteException + return rv[0] + + +__all__ = excs + ["lookup"] diff --git a/testing/marionette/driver/marionette_driver/marionette.py b/testing/marionette/driver/marionette_driver/marionette.py index 436b89e1265..a7c59026cc3 100644 --- a/testing/marionette/driver/marionette_driver/marionette.py +++ b/testing/marionette/driver/marionette_driver/marionette.py @@ -693,8 +693,7 @@ class Marionette(object): self.session = None self.window = None self.client.close() - raise errors.TimeoutException( - "Connection timed out", status=errors.ErrorCodes.TIMEOUT) + raise errors.TimeoutException("Connection timed out") # Process any emulator commands that are sent from a script # while it's executing. @@ -745,60 +744,11 @@ class Marionette(object): "Malformed packet, expected key 'error' to be a dict: %s" % response) error = response["error"] - status = error.get("status", 500) + status = error.get("status") message = error.get("message") stacktrace = error.get("stacktrace") - # status numbers come from - # http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes - if status == errors.ErrorCodes.NO_SUCH_ELEMENT: - raise errors.NoSuchElementException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.NO_SUCH_FRAME: - raise errors.NoSuchFrameException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.STALE_ELEMENT_REFERENCE: - raise errors.StaleElementException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.ELEMENT_NOT_VISIBLE: - raise errors.ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.ELEMENT_NOT_ACCESSIBLE: - raise errors.ElementNotAccessibleException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.INVALID_ELEMENT_STATE: - raise errors.InvalidElementStateException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.UNKNOWN_ERROR: - raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.ELEMENT_IS_NOT_SELECTABLE: - raise errors.ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.JAVASCRIPT_ERROR: - raise errors.JavascriptException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.XPATH_LOOKUP_ERROR: - raise errors.XPathLookupException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.TIMEOUT: - raise errors.TimeoutException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.NO_SUCH_WINDOW: - raise errors.NoSuchWindowException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.INVALID_COOKIE_DOMAIN: - raise errors.InvalidCookieDomainException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.UNABLE_TO_SET_COOKIE: - raise errors.UnableToSetCookieException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.NO_ALERT_OPEN: - raise errors.NoAlertPresentException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.SCRIPT_TIMEOUT: - raise errors.ScriptTimeoutException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.INVALID_SELECTOR \ - or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR \ - or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER: - raise errors.InvalidSelectorException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS: - raise errors.MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR: - raise errors.FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.FRAME_SEND_FAILURE_ERROR: - raise errors.FrameSendFailureError(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.UNSUPPORTED_OPERATION: - raise errors.UnsupportedOperationException(message=message, status=status, stacktrace=stacktrace) - elif status == errors.ErrorCodes.SESSION_NOT_CREATED: - raise errors.SessionNotCreatedException(message=message, status=status, stacktrace=stacktrace) - else: - raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace) + raise errors.lookup(status)(message, stacktrace=stacktrace) def _reset_timeouts(self): if self.timeout is not None: diff --git a/testing/marionette/error.js b/testing/marionette/error.js index f1888d457d2..db5edcaaf23 100644 --- a/testing/marionette/error.js +++ b/testing/marionette/error.js @@ -124,6 +124,7 @@ this.WebDriverError = function(msg) { Error.call(this, msg); this.name = "WebDriverError"; this.message = msg; + this.status = "webdriver error"; this.code = 500; // overridden }; WebDriverError.prototype = Object.create(Error.prototype); diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index c9e5aabb6d3..7e62da6bd7f 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -15,6 +15,7 @@ if (Cu === undefined) { Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); @@ -551,20 +552,29 @@ Tester.prototype = { // frames and browser intentionally kept alive until shutdown to // eliminate false positives. if (gConfig.testRoot == "browser") { - // Replace the document currently loaded in the browser's sidebar. - // This will prevent false positives for tests that were the last - // to touch the sidebar. They will thus not be blamed for leaking - // a document. - let sidebar = document.getElementById("sidebar"); - sidebar.setAttribute("src", "data:text/html;charset=utf-8,"); - sidebar.docShell.createAboutBlankContentViewer(null); - sidebar.setAttribute("src", "about:blank"); + //Skip if SeaMonkey + if (AppConstants.MOZ_APP_NAME != "seamonkey") { + // Replace the document currently loaded in the browser's sidebar. + // This will prevent false positives for tests that were the last + // to touch the sidebar. They will thus not be blamed for leaking + // a document. + let sidebar = document.getElementById("sidebar"); + sidebar.setAttribute("src", "data:text/html;charset=utf-8,"); + sidebar.docShell.createAboutBlankContentViewer(null); + sidebar.setAttribute("src", "about:blank"); - // Do the same for the social sidebar. - let socialSidebar = document.getElementById("social-sidebar-browser"); - socialSidebar.setAttribute("src", "data:text/html;charset=utf-8,"); - socialSidebar.docShell.createAboutBlankContentViewer(null); - socialSidebar.setAttribute("src", "about:blank"); + // Do the same for the social sidebar. + let socialSidebar = document.getElementById("social-sidebar-browser"); + socialSidebar.setAttribute("src", "data:text/html;charset=utf-8,"); + socialSidebar.docShell.createAboutBlankContentViewer(null); + socialSidebar.setAttribute("src", "about:blank"); + + SelfSupportBackend.uninit(); + CustomizationTabPreloader.uninit(); + SocialFlyout.unload(); + SocialShare.uninit(); + TabView.uninit(); + } // Destroy BackgroundPageThumbs resources. let {BackgroundPageThumbs} = @@ -577,12 +587,6 @@ Tester.prototype = { gBrowser._preloadedBrowser = null; gBrowser.getNotificationBox(browser).remove(); } - - SelfSupportBackend.uninit(); - CustomizationTabPreloader.uninit(); - SocialFlyout.unload(); - SocialShare.uninit(); - TabView.uninit(); } // Schedule GC and CC runs before finishing in order to detect diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index 77d3bbe6310..d91f1c1b917 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -161,7 +161,7 @@ class MochitestRunner(MozbuildObject): from mochitest_options import B2GOptions parser = B2GOptions() - options = parser.parse_args([])[0] + options = parser.parse_args([]) if test_path: if chrome: @@ -322,7 +322,7 @@ class MochitestRunner(MozbuildObject): logging.getLogger().removeHandler(handler) opts = mochitest.MochitestOptions() - options, args = opts.parse_args([]) + options = opts.parse_args([]) options.subsuite = '' flavor = suite @@ -1044,7 +1044,9 @@ class B2GCommands(MachCommandBase): def __init__(self, context): MachCommandBase.__init__(self, context) - for attr in ('b2g_home', 'xre_path', 'device_name', 'get_build_var'): + # These attributes are defined in: + # https://github.com/mozilla-b2g/B2G/blob/master/tools/mach_b2g_bootstrap.py + for attr in ('b2g_home', 'xre_path', 'device_name', 'target_out'): setattr(self, attr, getattr(context, attr, None)) @Command( @@ -1056,9 +1058,10 @@ class B2GCommands(MachCommandBase): is_emulator]) @B2GCommand def run_mochitest_remote(self, test_paths, **kwargs): - if self.get_build_var: + if self.target_out: host_webapps_dir = os.path.join( - self.get_build_var('TARGET_OUT_DATA'), + self.target_out, + 'data', 'local', 'webapps') if not os.path.isdir( diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index 2a59cda5444..f72e6acab82 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -2,14 +2,17 @@ # 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/. +from argparse import ArgumentParser from urlparse import urlparse -import mozinfo -import moznetwork -import optparse +import logging import os import tempfile from mozprofile import DEFAULT_PORTS +import mozinfo +import moznetwork + +from automation import Automation here = os.path.abspath(os.path.dirname(__file__)) @@ -24,8 +27,7 @@ __all__ = ["MochitestOptions", "B2GOptions"] VMWARE_RECORDING_HELPER_BASENAME = "vmwarerecordinghelper" -class MochitestOptions(optparse.OptionParser): - +class MochitestOptions(ArgumentParser): """Usage instructions for runtests.py. All arguments are optional. If --chrome is specified, chrome tests will be run instead of web content tests. @@ -43,23 +45,17 @@ class MochitestOptions(optparse.OptionParser): "help": "close the application when tests are done running", }], [["--appname"], - {"action": "store", - "type": "string", - "dest": "app", + {"dest": "app", "default": None, "help": "absolute path to application, overriding default", }], [["--utility-path"], - {"action": "store", - "type": "string", - "dest": "utilityPath", + {"dest": "utilityPath", "default": build_obj.bindir if build_obj is not None else None, "help": "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)", }], [["--certificate-path"], - {"action": "store", - "type": "string", - "dest": "certPath", + {"dest": "certPath", "help": "absolute path to directory containing certificate store to use testing profile", "default": os.path.join(build_obj.topsrcdir, 'build', 'pgo', 'certs') if build_obj is not None else None, }], @@ -70,19 +66,19 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--timeout"], - {"type": "int", + {"type": int, "dest": "timeout", "help": "per-test timeout in seconds", "default": None, }], [["--total-chunks"], - {"type": "int", + {"type": int, "dest": "totalChunks", "help": "how many chunks to split the tests up into", "default": None, }], [["--this-chunk"], - {"type": "int", + {"type": int, "dest": "thisChunk", "help": "which chunk to run", "default": None, @@ -94,7 +90,7 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--chunk-by-dir"], - {"type": "int", + {"type": int, "dest": "chunkByDir", "help": "group tests together in the same chunk that are in the same top chunkByDir directories", "default": 0, @@ -112,9 +108,7 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--console-level"], - {"action": "store", - "type": "choice", - "dest": "consoleLevel", + {"dest": "consoleLevel", "choices": LOG_LEVELS, "metavar": "LEVEL", "help": "one of %s to determine the level of console " @@ -134,30 +128,22 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--test-path"], - {"action": "store", - "type": "string", - "dest": "testPath", + {"dest": "testPath", "help": "start in the given directory's tests", "default": "", }], [["--bisect-chunk"], - {"action": "store", - "type": "string", - "dest": "bisectChunk", + {"dest": "bisectChunk", "help": "Specify the failing test name to find the previous tests that may be causing the failure.", "default": None, }], [["--start-at"], - {"action": "store", - "type": "string", - "dest": "startAt", + {"dest": "startAt", "help": "skip over tests until reaching the given test", "default": "", }], [["--end-at"], - {"action": "store", - "type": "string", - "dest": "endAt", + {"dest": "endAt", "help": "don't run any tests after the given one", "default": "", }], @@ -168,8 +154,7 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--subsuite"], - {"action": "store", - "dest": "subsuite", + {"dest": "subsuite", "help": "subsuite of tests to run", "default": None, }], @@ -205,7 +190,6 @@ class MochitestOptions(optparse.OptionParser): }], [["--setenv"], {"action": "append", - "type": "string", "dest": "environment", "metavar": "NAME=VALUE", "help": "sets the given variable in the application's " @@ -214,7 +198,6 @@ class MochitestOptions(optparse.OptionParser): }], [["--exclude-extension"], {"action": "append", - "type": "string", "dest": "extensionsToExclude", "help": "excludes the given extension from being installed " "in the test profile", @@ -222,15 +205,13 @@ class MochitestOptions(optparse.OptionParser): }], [["--browser-arg"], {"action": "append", - "type": "string", "dest": "browserArgs", "metavar": "ARG", "help": "provides an argument to the test application", "default": [], }], [["--leak-threshold"], - {"action": "store", - "type": "int", + {"type": int, "dest": "defaultLeakThreshold", "metavar": "THRESHOLD", "help": "fail if the number of bytes leaked in default " @@ -262,17 +243,13 @@ class MochitestOptions(optparse.OptionParser): "default": [], }], [["--profile-path"], - {"action": "store", - "type": "string", - "dest": "profilePath", + {"dest": "profilePath", "help": "Directory where the profile will be stored." "This directory will be deleted after the tests are finished", "default": None, }], [["--testing-modules-dir"], - {"action": "store", - "type": "string", - "dest": "testingModulesDir", + {"dest": "testingModulesDir", "help": "Directory where testing-only JS modules are located.", "default": None, }], @@ -284,8 +261,7 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--repeat"], - {"action": "store", - "type": "int", + {"type": int, "dest": "repeat", "metavar": "REPEAT", "help": "repeats the test or set of tests the given number of times, ie: repeat: 1 will run the test twice.", @@ -299,23 +275,17 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--manifest"], - {"action": "store", - "type": "string", - "dest": "manifestFile", + {"dest": "manifestFile", "help": ".ini format of tests to run.", "default": None, }], [["--testrun-manifest-file"], - {"action": "store", - "type": "string", - "dest": "testRunManifestFile", + {"dest": "testRunManifestFile", "help": "Overrides the default filename of the tests.json manifest file that is created from the manifest and used by the test runners to run the tests. Only useful when running multiple test runs simulatenously on the same machine.", "default": 'tests.json', }], [["--failure-file"], - {"action": "store", - "type": "string", - "dest": "failureFile", + {"dest": "failureFile", "help": "Filename of the output file where we can store a .json list of failures to be run in the future with --run-only-tests.", "default": None, }], @@ -332,15 +302,12 @@ class MochitestOptions(optparse.OptionParser): "default": False, }], [["--httpd-path"], - {"action": "store", - "type": "string", - "dest": "httpdPath", + {"dest": "httpdPath", "default": None, "help": "path to the httpd.js file", }], [["--setpref"], {"action": "append", - "type": "string", "default": [], "dest": "extraPrefs", "metavar": "PREF=VALUE", @@ -377,14 +344,12 @@ class MochitestOptions(optparse.OptionParser): "help": "Run tests with nested_oop preferences and test filtering enabled.", }], [["--dmd-path"], - {"action": "store", - "default": None, + {"default": None, "dest": "dmdPath", "help": "Specifies the path to the directory containing the shared library for DMD.", }], [["--dump-output-directory"], - {"action": "store", - "default": None, + {"default": None, "dest": "dumpOutputDirectory", "help": "Specifies the directory in which to place dumped memory reports.", }], @@ -423,9 +388,7 @@ class MochitestOptions(optparse.OptionParser): "help": "Do not print test log lines unless a failure occurs." }], [["--pidfile"], - {"action": "store", - "type": "string", - "dest": "pidFile", + {"dest": "pidFile", "help": "name of the pidfile to generate", "default": "", }], @@ -436,33 +399,26 @@ class MochitestOptions(optparse.OptionParser): "help": "Use test media device drivers for media testing.", }], [["--gmp-path"], - {"action": "store", - "default": None, + {"default": None, "dest": "gmp_path", "help": "Path to fake GMP plugin. Will be deduced from the binary if not passed.", }], [["--xre-path"], - {"action": "store", - "type": "string", - "dest": "xrePath", + {"dest": "xrePath", "default": None, # individual scripts will set a sane default "help": "absolute path to directory containing XRE (probably xulrunner)", }], [["--symbols-path"], - {"action": "store", - "type": "string", - "dest": "symbolsPath", + {"dest": "symbolsPath", "default": None, "help": "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols", }], [["--debugger"], - {"action": "store", - "dest": "debugger", + {"dest": "debugger", "help": "use the given debugger to launch the application", }], [["--debugger-args"], - {"action": "store", - "dest": "debuggerArgs", + {"dest": "debuggerArgs", "help": "pass the given args to the debugger _before_ the application on the command line", }], [["--debugger-interactive"], @@ -471,31 +427,29 @@ class MochitestOptions(optparse.OptionParser): "help": "prevents the test harness from redirecting stdout and stderr for interactive debuggers", }], [["--max-timeouts"], - { "type": "int", - "dest": "maxTimeouts", - "help": "maximum number of timeouts permitted before halting testing", - "default": None, - }], + {"type": int, + "dest": "maxTimeouts", + "help": "maximum number of timeouts permitted before halting testing", + "default": None, + }], [["--tag"], - { "action": "append", - "dest": "test_tags", - "default": None, - "help": "filter out tests that don't have the given tag. Can be " - "used multiple times in which case the test must contain " - "at least one of the given tags.", - }], + {"action": "append", + "dest": "test_tags", + "default": None, + "help": "filter out tests that don't have the given tag. Can be " + "used multiple times in which case the test must contain " + "at least one of the given tags.", + }], ] def __init__(self, **kwargs): - - optparse.OptionParser.__init__(self, **kwargs) + ArgumentParser.__init__(self, usage=self.__doc__, **kwargs) for option, value in self.mochitest_options: # Allocate new lists so references to original don't get mutated. # allowing multiple uses within a single process. if "default" in value and isinstance(value["default"], list): value["default"] = [] - self.add_option(*option, **value) - self.set_usage(self.__doc__) + self.add_argument(*option, **value) def verifyOptions(self, options, mochitest): """ verify correct options and cleanup paths """ @@ -528,7 +482,7 @@ class MochitestOptions(optparse.OptionParser): if options.xrePath is None: # default xrePath to the app path if not provided # but only if an app path was explicitly provided - if options.app != self.defaults['app']: + if options.app != self.get_default('app'): options.xrePath = os.path.dirname(options.app) if mozinfo.isMac: options.xrePath = os.path.join( @@ -698,9 +652,7 @@ class MochitestOptions(optparse.OptionParser): class B2GOptions(MochitestOptions): b2g_options = [ [["--b2gpath"], - {"action": "store", - "type": "string", - "dest": "b2gPath", + {"dest": "b2gPath", "help": "path to B2G repo or qemu dir", "default": None, }], @@ -711,30 +663,22 @@ class B2GOptions(MochitestOptions): "default": False, }], [["--marionette"], - {"action": "store", - "type": "string", - "dest": "marionette", + {"dest": "marionette", "help": "host:port to use when connecting to Marionette", "default": None, }], [["--emulator"], - {"action": "store", - "type": "string", - "dest": "emulator", + {"dest": "emulator", "help": "Architecture of emulator to use: x86 or arm", "default": None, }], [["--wifi"], - {"action": "store", - "type": "string", - "dest": "wifi", + {"dest": "wifi", "help": "Devine wifi configuration for on device mochitest", "default": False, }], [["--sdcard"], - {"action": "store", - "type": "string", - "dest": "sdcard", + {"dest": "sdcard", "help": "Define size of sdcard: 1MB, 50MB...etc", "default": "10MB", }], @@ -745,89 +689,65 @@ class B2GOptions(MochitestOptions): "default": False, }], [["--adbpath"], - {"action": "store", - "type": "string", - "dest": "adbPath", + {"dest": "adbPath", "help": "path to adb", "default": "adb", }], [["--deviceIP"], - {"action": "store", - "type": "string", - "dest": "deviceIP", + {"dest": "deviceIP", "help": "ip address of remote device to test", "default": None, }], [["--devicePort"], - {"action": "store", - "type": "string", - "dest": "devicePort", + {"dest": "devicePort", "help": "port of remote device to test", "default": 20701, }], [["--remote-logfile"], - {"action": "store", - "type": "string", - "dest": "remoteLogFile", + {"dest": "remoteLogFile", "help": "Name of log file on the device relative to the device root. \ PLEASE ONLY USE A FILENAME.", "default": None, }], [["--remote-webserver"], - {"action": "store", - "type": "string", - "dest": "remoteWebServer", + {"dest": "remoteWebServer", "help": "ip address where the remote web server is hosted at", "default": None, }], [["--http-port"], - {"action": "store", - "type": "string", - "dest": "httpPort", + {"dest": "httpPort", "help": "ip address where the remote web server is hosted at", - "default": None, + "default": DEFAULT_PORTS['http'], }], [["--ssl-port"], - {"action": "store", - "type": "string", - "dest": "sslPort", + {"dest": "sslPort", "help": "ip address where the remote web server is hosted at", - "default": None, + "default": DEFAULT_PORTS['https'], }], [["--gecko-path"], - {"action": "store", - "type": "string", - "dest": "geckoPath", + {"dest": "geckoPath", "help": "the path to a gecko distribution that should \ be installed on the emulator prior to test", "default": None, }], [["--profile"], - {"action": "store", - "type": "string", - "dest": "profile", + {"dest": "profile", "help": "for desktop testing, the path to the \ gaia profile to use", "default": None, }], [["--logdir"], - {"action": "store", - "type": "string", - "dest": "logdir", + {"dest": "logdir", "help": "directory to store log files", "default": None, }], [['--busybox'], - {"action": 'store', - "type": 'string', - "dest": 'busybox', + {"dest": 'busybox', "help": "Path to busybox binary to install on device", "default": None, }], [['--profile-data-dir'], - {"action": 'store', - "type": 'string', - "dest": 'profile_data_dir', + {"dest": 'profile_data_dir', "help": "Path to a directory containing preference and other \ data to be installed into the profile", "default": os.path.join(here, 'profile_data'), @@ -838,15 +758,12 @@ class B2GOptions(MochitestOptions): MochitestOptions.__init__(self) for option in self.b2g_options: - self.add_option(*option[0], **option[1]) + self.add_argument(*option[0], **option[1]) defaults = {} - defaults["httpPort"] = DEFAULT_PORTS['http'] - defaults["sslPort"] = DEFAULT_PORTS['https'] defaults["logFile"] = "mochitest.log" defaults["autorun"] = True defaults["closeWhenDone"] = True - defaults["testPath"] = "" defaults["extensionsToExclude"] = ["specialpowers"] # See dependencies of bug 1038943. defaults["defaultLeakThreshold"] = 5536 @@ -909,3 +826,229 @@ class B2GOptions(MochitestOptions): def elf_arm(self, filename): data = open(filename, 'rb').read(20) return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM + + +class RemoteOptions(MochitestOptions): + remote_options = [ + [["--remote-app-path"], + {"dest": "remoteAppPath", + "help": "Path to remote executable relative to device root using \ + only forward slashes. Either this or app must be specified \ + but not both.", + "default": None, + }], + [["--deviceIP"], + {"dest": "deviceIP", + "help": "ip address of remote device to test", + "default": None, + }], + [["--deviceSerial"], + {"dest": "deviceSerial", + "help": "ip address of remote device to test", + "default": None, + }], + [["--dm_trans"], + {"dest": "dm_trans", + "default": "sut", + "help": "the transport to use to communicate with device: \ + [adb|sut]; default=sut", + }], + [["--devicePort"], + {"dest": "devicePort", + "type": int, + "default": 20701, + "help": "port of remote device to test", + }], + [["--remote-product-name"], + {"dest": "remoteProductName", + "default": "fennec", + "help": "The executable's name of remote product to test - either \ + fennec or firefox, defaults to fennec", + }], + [["--remote-logfile"], + {"dest": "remoteLogFile", + "default": None, + "help": "Name of log file on the device relative to the device \ + root. PLEASE ONLY USE A FILENAME.", + }], + [["--remote-webserver"], + {"dest": "remoteWebServer", + "default": None, + "help": "ip address where the remote web server is hosted at", + }], + [["--http-port"], + {"dest": "httpPort", + "default": DEFAULT_PORTS['http'], + "help": "http port of the remote web server", + }], + [["--ssl-port"], + {"dest": "sslPort", + "default": DEFAULT_PORTS['https'], + "help": "ssl port of the remote web server", + }], + [["--robocop-ini"], + {"dest": "robocopIni", + "default": "", + "help": "name of the .ini file containing the list of tests to run", + }], + [["--robocop"], + {"dest": "robocop", + "default": "", + "help": "name of the .ini file containing the list of tests to run. \ + [DEPRECATED- please use --robocop-ini", + }], + [["--robocop-apk"], + {"dest": "robocopApk", + "default": "", + "help": "name of the Robocop APK to use for ADB test running", + }], + [["--robocop-path"], + {"dest": "robocopPath", + "default": "", + "help": "Path to the folder where robocop.apk is located at. \ + Primarily used for ADB test running. \ + [DEPRECATED- please use --robocop-apk]", + }], + [["--robocop-ids"], + {"dest": "robocopIds", + "default": "", + "help": "name of the file containing the view ID map \ + (fennec_ids.txt)", + }], + [["--remoteTestRoot"], + {"dest": "remoteTestRoot", + "default": None, + "help": "remote directory to use as test root \ + (eg. /mnt/sdcard/tests or /data/local/tests)", + }], + ] + + def __init__(self, automation, **kwargs): + self._automation = automation or Automation() + MochitestOptions.__init__(self) + + for option in self.remote_options: + self.add_argument(*option[0], **option[1]) + + defaults = {} + defaults["logFile"] = "mochitest.log" + defaults["autorun"] = True + defaults["closeWhenDone"] = True + defaults["utilityPath"] = None + self.set_defaults(**defaults) + + def verifyRemoteOptions(self, options, automation): + options_logger = logging.getLogger('MochitestRemote') + + if not options.remoteTestRoot: + options.remoteTestRoot = automation._devicemanager.deviceRoot + + if options.remoteWebServer is None: + if os.name != "nt": + options.remoteWebServer = moznetwork.get_ip() + else: + options_logger.error( + "you must specify a --remote-webserver=") + return None + + options.webServer = options.remoteWebServer + + if (options.dm_trans == 'sut' and options.deviceIP is None): + options_logger.error( + "If --dm_trans = sut, you must provide a device IP") + return None + + if (options.remoteLogFile is None): + options.remoteLogFile = options.remoteTestRoot + \ + '/logs/mochitest.log' + + if (options.remoteLogFile.count('/') < 1): + options.remoteLogFile = options.remoteTestRoot + \ + '/' + options.remoteLogFile + + if (options.remoteAppPath and options.app): + options_logger.error( + "You cannot specify both the remoteAppPath and the app setting") + return None + elif (options.remoteAppPath): + options.app = options.remoteTestRoot + "/" + options.remoteAppPath + elif (options.app is None): + # Neither remoteAppPath nor app are set -- error + options_logger.error("You must specify either appPath or app") + return None + + # Only reset the xrePath if it wasn't provided + if (options.xrePath is None): + options.xrePath = options.utilityPath + + if (options.pidFile != ""): + f = open(options.pidFile, 'w') + f.write("%s" % os.getpid()) + f.close() + + # Robocop specific deprecated options. + if options.robocop: + if options.robocopIni: + options_logger.error( + "can not use deprecated --robocop and replacement --robocop-ini together") + return None + options.robocopIni = options.robocop + del options.robocop + + if options.robocopPath: + if options.robocopApk: + options_logger.error( + "can not use deprecated --robocop-path and replacement --robocop-apk together") + return None + options.robocopApk = os.path.join( + options.robocopPath, + 'robocop.apk') + del options.robocopPath + + # Robocop specific options + if options.robocopIni != "": + if not os.path.exists(options.robocopIni): + options_logger.error( + "Unable to find specified robocop .ini manifest '%s'" % + options.robocopIni) + return None + options.robocopIni = os.path.abspath(options.robocopIni) + + if options.robocopApk != "": + if not os.path.exists(options.robocopApk): + options_logger.error( + "Unable to find robocop APK '%s'" % + options.robocopApk) + return None + options.robocopApk = os.path.abspath(options.robocopApk) + + if options.robocopIds != "": + if not os.path.exists(options.robocopIds): + options_logger.error( + "Unable to find specified robocop IDs file '%s'" % + options.robocopIds) + return None + options.robocopIds = os.path.abspath(options.robocopIds) + + # allow us to keep original application around for cleanup while + # running robocop via 'am' + options.remoteappname = options.app + return options + + def verifyOptions(self, options, mochitest): + # since we are reusing verifyOptions, it will exit if App is not found + temp = options.app + options.app = __file__ + tempPort = options.httpPort + tempSSL = options.sslPort + tempIP = options.webServer + # We are going to override this option later anyway, just pretend + # like it's not set for verification purposes. + options.dumpOutputDirectory = None + options = MochitestOptions.verifyOptions(self, options, mochitest) + options.webServer = tempIP + options.app = temp + options.sslPort = tempSSL + options.httpPort = tempPort + + return options diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 2e836e64a60..38de0f57d3e 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -12,6 +12,7 @@ import sys SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) sys.path.insert(0, SCRIPT_DIR) +from argparse import Namespace from urlparse import urlparse import ctypes import glob @@ -21,7 +22,6 @@ import mozdebug import mozinfo import mozprocess import mozrunner -import optparse import re import shutil import signal @@ -332,7 +332,7 @@ class MochitestServer(object): "Web server used to serve Mochitests, for closer fidelity to the real web." def __init__(self, options, logger): - if isinstance(options, optparse.Values): + if isinstance(options, Namespace): options = vars(options) self._log = logger self._closeWhenDone = options['closeWhenDone'] @@ -2576,7 +2576,7 @@ def main(): # parse command line options parser = MochitestOptions() commandline.add_logging_group(parser) - options, args = parser.parse_args() + options = parser.parse_args() if options is None: # parsing error sys.exit(1) diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index b58d2a9bd99..598e1869ca7 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -496,7 +496,7 @@ def run_desktop_mochitests(parser, options): def main(): parser = B2GOptions() structured.commandline.add_logging_group(parser) - options, args = parser.parse_args() + options = parser.parse_args() if options.desktop: run_desktop_mochitests(parser, options) diff --git a/testing/mochitest/runtestsremote.py b/testing/mochitest/runtestsremote.py index 70a14714f25..e0192afbb9a 100644 --- a/testing/mochitest/runtestsremote.py +++ b/testing/mochitest/runtestsremote.py @@ -4,7 +4,6 @@ import base64 import json -import logging import os import shutil import sys @@ -19,7 +18,7 @@ sys.path.insert( from automation import Automation from remoteautomation import RemoteAutomation, fennecLogcatFilters from runtests import Mochitest, MessageLogger -from mochitest_options import MochitestOptions +from mochitest_options import RemoteOptions from mozlog import structured from manifestparser import TestManifest @@ -27,260 +26,11 @@ from manifestparser.filters import chunk_by_slice import devicemanager import droid import mozinfo -import moznetwork SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) -class RemoteOptions(MochitestOptions): - - def __init__(self, automation, **kwargs): - defaults = {} - self._automation = automation or Automation() - MochitestOptions.__init__(self) - - self.add_option( - "--remote-app-path", - action="store", - type="string", - dest="remoteAppPath", - help="Path to remote executable relative to device root using only forward slashes. Either this or app must be specified but not both") - defaults["remoteAppPath"] = None - - self.add_option("--deviceIP", action="store", - type="string", dest="deviceIP", - help="ip address of remote device to test") - defaults["deviceIP"] = None - - self.add_option("--deviceSerial", action="store", - type="string", dest="deviceSerial", - help="ip address of remote device to test") - defaults["deviceSerial"] = None - - self.add_option( - "--dm_trans", - action="store", - type="string", - dest="dm_trans", - help="the transport to use to communicate with device: [adb|sut]; default=sut") - defaults["dm_trans"] = "sut" - - self.add_option("--devicePort", action="store", - type="string", dest="devicePort", - help="port of remote device to test") - defaults["devicePort"] = 20701 - - self.add_option( - "--remote-product-name", - action="store", - type="string", - dest="remoteProductName", - help="The executable's name of remote product to test - either fennec or firefox, defaults to fennec") - defaults["remoteProductName"] = "fennec" - - self.add_option( - "--remote-logfile", - action="store", - type="string", - dest="remoteLogFile", - help="Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") - defaults["remoteLogFile"] = None - - self.add_option( - "--remote-webserver", - action="store", - type="string", - dest="remoteWebServer", - help="ip address where the remote web server is hosted at") - defaults["remoteWebServer"] = None - - self.add_option("--http-port", action="store", - type="string", dest="httpPort", - help="http port of the remote web server") - defaults["httpPort"] = automation.DEFAULT_HTTP_PORT - - self.add_option("--ssl-port", action="store", - type="string", dest="sslPort", - help="ssl port of the remote web server") - defaults["sslPort"] = automation.DEFAULT_SSL_PORT - - self.add_option( - "--robocop-ini", - action="store", - type="string", - dest="robocopIni", - help="name of the .ini file containing the list of tests to run") - defaults["robocopIni"] = "" - - self.add_option( - "--robocop", - action="store", - type="string", - dest="robocop", - help="name of the .ini file containing the list of tests to run. [DEPRECATED- please use --robocop-ini") - defaults["robocop"] = "" - - self.add_option( - "--robocop-apk", - action="store", - type="string", - dest="robocopApk", - help="name of the Robocop APK to use for ADB test running") - defaults["robocopApk"] = "" - - self.add_option( - "--robocop-path", - action="store", - type="string", - dest="robocopPath", - help="Path to the folder where robocop.apk is located at. Primarily used for ADB test running. [DEPRECATED- please use --robocop-apk]") - defaults["robocopPath"] = "" - - self.add_option( - "--robocop-ids", - action="store", - type="string", - dest="robocopIds", - help="name of the file containing the view ID map (fennec_ids.txt)") - defaults["robocopIds"] = "" - - self.add_option( - "--remoteTestRoot", - action="store", - type="string", - dest="remoteTestRoot", - help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") - defaults["remoteTestRoot"] = None - - defaults["logFile"] = "mochitest.log" - defaults["autorun"] = True - defaults["closeWhenDone"] = True - defaults["testPath"] = "" - defaults["app"] = None - defaults["utilityPath"] = None - - self.set_defaults(**defaults) - - def verifyRemoteOptions(self, options, automation): - options_logger = logging.getLogger('MochitestRemote') - - if not options.remoteTestRoot: - options.remoteTestRoot = automation._devicemanager.deviceRoot - - if options.remoteWebServer is None: - if os.name != "nt": - options.remoteWebServer = moznetwork.get_ip() - else: - options_logger.error( - "you must specify a --remote-webserver=") - return None - - options.webServer = options.remoteWebServer - - if (options.dm_trans == 'sut' and options.deviceIP is None): - options_logger.error( - "If --dm_trans = sut, you must provide a device IP") - return None - - if (options.remoteLogFile is None): - options.remoteLogFile = options.remoteTestRoot + \ - '/logs/mochitest.log' - - if (options.remoteLogFile.count('/') < 1): - options.remoteLogFile = options.remoteTestRoot + \ - '/' + options.remoteLogFile - - # remoteAppPath or app must be specified to find the product to launch - if (options.remoteAppPath and options.app): - options_logger.error( - "You cannot specify both the remoteAppPath and the app setting") - return None - elif (options.remoteAppPath): - options.app = options.remoteTestRoot + "/" + options.remoteAppPath - elif (options.app is None): - # Neither remoteAppPath nor app are set -- error - options_logger.error("You must specify either appPath or app") - return None - - # Only reset the xrePath if it wasn't provided - if (options.xrePath is None): - options.xrePath = options.utilityPath - - if (options.pidFile != ""): - f = open(options.pidFile, 'w') - f.write("%s" % os.getpid()) - f.close() - - # Robocop specific deprecated options. - if options.robocop: - if options.robocopIni: - options_logger.error( - "can not use deprecated --robocop and replacement --robocop-ini together") - return None - options.robocopIni = options.robocop - del options.robocop - - if options.robocopPath: - if options.robocopApk: - options_logger.error( - "can not use deprecated --robocop-path and replacement --robocop-apk together") - return None - options.robocopApk = os.path.join( - options.robocopPath, - 'robocop.apk') - del options.robocopPath - - # Robocop specific options - if options.robocopIni != "": - if not os.path.exists(options.robocopIni): - options_logger.error( - "Unable to find specified robocop .ini manifest '%s'" % - options.robocopIni) - return None - options.robocopIni = os.path.abspath(options.robocopIni) - - if options.robocopApk != "": - if not os.path.exists(options.robocopApk): - options_logger.error( - "Unable to find robocop APK '%s'" % - options.robocopApk) - return None - options.robocopApk = os.path.abspath(options.robocopApk) - - if options.robocopIds != "": - if not os.path.exists(options.robocopIds): - options_logger.error( - "Unable to find specified robocop IDs file '%s'" % - options.robocopIds) - return None - options.robocopIds = os.path.abspath(options.robocopIds) - - # allow us to keep original application around for cleanup while - # running robocop via 'am' - options.remoteappname = options.app - return options - - def verifyOptions(self, options, mochitest): - # since we are reusing verifyOptions, it will exit if App is not found - temp = options.app - options.app = __file__ - tempPort = options.httpPort - tempSSL = options.sslPort - tempIP = options.webServer - # We are going to override this option later anyway, just pretend - # like it's not set for verification purposes. - options.dumpOutputDirectory = None - options = MochitestOptions.verifyOptions(self, options, mochitest) - options.webServer = tempIP - options.app = temp - options.sslPort = tempSSL - options.httpPort = tempPort - - return options - - class MochiRemote(Mochitest): - _automation = None _dm = None localProfile = None @@ -527,7 +277,7 @@ class MochiRemote(Mochitest): for line in data: try: message = json.loads(line) - if not isinstance(message, dict) or not 'action' in message: + if not isinstance(message, dict) or 'action' not in message: continue except ValueError: continue @@ -718,7 +468,7 @@ def main(args): parser = RemoteOptions(auto) structured.commandline.add_logging_group(parser) - options, args = parser.parse_args(args) + options = parser.parse_args(args) if (options.dm_trans == "adb"): if (options.deviceIP): diff --git a/testing/mozbase/mozprocess/mozprocess/processhandler.py b/testing/mozbase/mozprocess/mozprocess/processhandler.py index 0d15ced63e0..a6d2befa12d 100644 --- a/testing/mozbase/mozprocess/mozprocess/processhandler.py +++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py @@ -95,6 +95,16 @@ class ProcessHandlerMixin(object): os.setpgid(0, 0) preexec_fn = setpgidfn + if isinstance(env, dict): + tmp_env = {} + for k, v in env.iteritems(): + if isinstance(k, bytes): + k = k.decode(sys.getfilesystemencoding() or 'utf-8', 'replace') + if isinstance(v, bytes): + v = v.decode(sys.getfilesystemencoding() or 'utf-8', 'replace') + tmp_env[k] = v + env = tmp_env + try: subprocess.Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index f83e8c6e7ee..da88213dcee 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -30,6 +30,7 @@ const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; Cu.importGlobalProperties(["URL"]); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", @@ -54,14 +55,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "History", // refresh instead. const MIN_TRANSACTIONS_FOR_BATCH = 5; -#ifdef XP_MACOSX -// On Mac OSX, the transferable system converts "\r\n" to "\n\n", where we -// really just want "\n". -const NEWLINE= "\n"; -#else -// On other platforms, the transferable system converts "\r\n" to "\n". -const NEWLINE = "\r\n"; -#endif +// On Mac OSX, the transferable system converts "\r\n" to "\n\n", where +// we really just want "\n". On other platforms, the transferable system +// converts "\r\n" to "\n". +const NEWLINE = AppConstants.platform == "macosx" ? "\n" : "\r\n"; function QI_node(aNode, aIID) { var result = null; diff --git a/toolkit/components/places/moz.build b/toolkit/components/places/moz.build index 4c9aa00c713..76e55a3c79c 100644 --- a/toolkit/components/places/moz.build +++ b/toolkit/components/places/moz.build @@ -70,9 +70,6 @@ if CONFIG['MOZ_PLACES']: 'PlacesDBUtils.jsm', 'PlacesSearchAutocompleteProvider.jsm', 'PlacesTransactions.jsm', - ] - - EXTRA_PP_JS_MODULES += [ 'PlacesUtils.jsm', ] diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 83ffe8e943e..5f24c8f9ce2 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7494,6 +7494,12 @@ "kind": "boolean", "description": "Whether a session is set to autostart e10s windows" }, + "E10S_AUTOSTART_STATUS": { + "expires_in_version": "40", + "kind": "enumerated", + "n_values": 6, + "description": "Why e10s is enabled or disabled (0=ENABLED_BY_USER, 1=ENABLED_BY_DEFAULT, 2=DISABLED_BY_USER, 3=DISABLED_IN_SAFE_MODE, 4=DISABLED_FOR_ACCESSIBILITY, 5=DISABLED_FOR_MAC_GFX)" + }, "E10S_WINDOW": { "expires_in_version": "never", "kind": "boolean", diff --git a/toolkit/components/telemetry/Telemetry.h b/toolkit/components/telemetry/Telemetry.h index fa0472a9cf5..9282b954d83 100644 --- a/toolkit/components/telemetry/Telemetry.h +++ b/toolkit/components/telemetry/Telemetry.h @@ -237,7 +237,7 @@ class ProcessedStack; * @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes * @param aAnnotations - Any annotations to be added to the report */ -#if defined(MOZ_ENABLE_PROFILER_SPS) +#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API) void RecordChromeHang(uint32_t aDuration, ProcessedStack &aStack, int32_t aSystemUptime, diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 45e5d815074..da4882c3a6f 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -6,6 +6,7 @@ let Cc = Components.classes; let Ci = Components.interfaces; let Cu = Components.utils; +Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import("resource://gre/modules/RemoteAddonsChild.jsm"); @@ -14,11 +15,11 @@ Cu.import("resource://gre/modules/Timer.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PageThumbUtils", "resource://gre/modules/PageThumbUtils.jsm"); -#ifdef MOZ_CRASHREPORTER -XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", - "@mozilla.org/xre/app-info;1", - "nsICrashReporter"); -#endif +if (AppConstants.MOZ_CRASHREPORTER) { + XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", + "@mozilla.org/xre/app-info;1", + "nsICrashReporter"); +} let FocusSyncHandler = { init: function() { @@ -256,10 +257,8 @@ let WebNavigation = { }, loadURI: function(uri, flags, referrer, referrerPolicy, baseURI) { -#ifdef MOZ_CRASHREPORTER - if (CrashReporter.enabled) + if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) CrashReporter.annotateCrashReport("URL", uri); -#endif if (referrer) referrer = Services.io.newURI(referrer, null, null); if (baseURI) diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index c69e9f143e4..4326ad17ce8 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -31,7 +31,7 @@ toolkit.jar: content/global/directionDetector.html content/global/plugins.html content/global/plugins.css -* content/global/browser-child.js (browser-child.js) + content/global/browser-child.js (browser-child.js) content/global/browser-content.js (browser-content.js) *+ content/global/buildconfig.html (buildconfig.html) * content/global/contentAreaUtils.js (contentAreaUtils.js) diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index a71f4c5a6e8..0da1d924617 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -70,6 +70,24 @@ this.AppConstants = Object.freeze({ false, #endif + MOZ_SANDBOX: +#ifdef MOZ_SANDBOX + true, +#else + false, +#endif + + MOZ_SHARK: +#ifdef XP_MACOSX +#ifdef MOZ_SHARK + true, +#else + false, +#endif +#else + false, +#endif + MOZ_TELEMETRY_REPORTING: #ifdef MOZ_TELEMETRY_REPORTING true, @@ -77,6 +95,13 @@ this.AppConstants = Object.freeze({ false, #endif + MOZ_UPDATER: +#ifdef MOZ_UPDATER + true, +#else + false, +#endif + MOZ_WEBRTC: #ifdef MOZ_WEBRTC true, @@ -84,6 +109,8 @@ this.AppConstants = Object.freeze({ false, #endif +# NOTE! XP_LINUX has to go after MOZ_WIDGET_ANDROID otherwise Android +# builds will be misidentified as linux. platform: #ifdef MOZ_WIDGET_GTK "linux", @@ -97,6 +124,8 @@ this.AppConstants = Object.freeze({ "android", #elif MOZ_WIDGET_GONK "gonk", +#elif XP_LINUX + "linux", #else "other", #endif @@ -122,7 +151,10 @@ this.AppConstants = Object.freeze({ false, #endif + MOZ_APP_NAME: "@MOZ_APP_NAME@", MOZ_APP_VERSION: "@MOZ_APP_VERSION@", - + MOZ_BUILD_APP: "@MOZ_BUILD_APP@", + MOZ_UPDATE_CHANNEL: "@MOZ_UPDATE_CHANNEL@", + MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@", ANDROID_PACKAGE_NAME: "@ANDROID_PACKAGE_NAME@", }); diff --git a/toolkit/modules/CertUtils.jsm b/toolkit/modules/CertUtils.jsm index 00a2c52935d..124e956ca98 100644 --- a/toolkit/modules/CertUtils.jsm +++ b/toolkit/modules/CertUtils.jsm @@ -1,9 +1,7 @@ -#if 0 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -#endif this.EXPORTED_SYMBOLS = [ "BadCertHandler", "checkCert", "readCertPrefs", "validateCert" ]; const Ce = Components.Exception; diff --git a/toolkit/modules/GMPInstallManager.jsm b/toolkit/modules/GMPInstallManager.jsm index 74edfe9c765..2dfaa133884 100644 --- a/toolkit/modules/GMPInstallManager.jsm +++ b/toolkit/modules/GMPInstallManager.jsm @@ -25,6 +25,7 @@ Cu.import("resource://gre/modules/osfile.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/GMPUtils.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); this.EXPORTED_SYMBOLS = ["GMPInstallManager", "GMPExtractor", "GMPDownloader", "GMPAddon"]; @@ -72,112 +73,112 @@ XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() { } if (osVersion) { -#ifdef XP_WIN - const BYTE = ctypes.uint8_t; - const WORD = ctypes.uint16_t; - const DWORD = ctypes.uint32_t; - const WCHAR = ctypes.char16_t; - const BOOL = ctypes.int; - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx - const SZCSDVERSIONLENGTH = 128; - const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', - [ - {dwOSVersionInfoSize: DWORD}, - {dwMajorVersion: DWORD}, - {dwMinorVersion: DWORD}, - {dwBuildNumber: DWORD}, - {dwPlatformId: DWORD}, - {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, - {wServicePackMajor: WORD}, - {wServicePackMinor: WORD}, - {wSuiteMask: WORD}, - {wProductType: BYTE}, - {wReserved: BYTE} - ]); - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx - const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', - [ - {wProcessorArchitecture: WORD}, - {wReserved: WORD}, - {dwPageSize: DWORD}, - {lpMinimumApplicationAddress: ctypes.voidptr_t}, - {lpMaximumApplicationAddress: ctypes.voidptr_t}, - {dwActiveProcessorMask: DWORD.ptr}, - {dwNumberOfProcessors: DWORD}, - {dwProcessorType: DWORD}, - {dwAllocationGranularity: DWORD}, - {wProcessorLevel: WORD}, - {wProcessorRevision: WORD} - ]); - - let kernel32 = false; - try { - kernel32 = ctypes.open("Kernel32"); - } catch (e) { - LOG("gOSVersion - Unable to open kernel32! " + e); - osVersion += ".unknown (unknown)"; - } - - if(kernel32) { + if (AppConstants.platform == "win") { + const BYTE = ctypes.uint8_t; + const WORD = ctypes.uint16_t; + const DWORD = ctypes.uint32_t; + const WCHAR = ctypes.char16_t; + const BOOL = ctypes.int; + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx + const SZCSDVERSIONLENGTH = 128; + const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', + [ + {dwOSVersionInfoSize: DWORD}, + {dwMajorVersion: DWORD}, + {dwMinorVersion: DWORD}, + {dwBuildNumber: DWORD}, + {dwPlatformId: DWORD}, + {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, + {wServicePackMajor: WORD}, + {wServicePackMinor: WORD}, + {wSuiteMask: WORD}, + {wProductType: BYTE}, + {wReserved: BYTE} + ]); + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx + const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', + [ + {wProcessorArchitecture: WORD}, + {wReserved: WORD}, + {dwPageSize: DWORD}, + {lpMinimumApplicationAddress: ctypes.voidptr_t}, + {lpMaximumApplicationAddress: ctypes.voidptr_t}, + {dwActiveProcessorMask: DWORD.ptr}, + {dwNumberOfProcessors: DWORD}, + {dwProcessorType: DWORD}, + {dwAllocationGranularity: DWORD}, + {wProcessorLevel: WORD}, + {wProcessorRevision: WORD} + ]); + + let kernel32 = false; try { - // Get Service pack info + kernel32 = ctypes.open("Kernel32"); + } catch (e) { + LOG("gOSVersion - Unable to open kernel32! " + e); + osVersion += ".unknown (unknown)"; + } + + if(kernel32) { try { - let GetVersionEx = kernel32.declare("GetVersionExW", - ctypes.default_abi, - BOOL, - OSVERSIONINFOEXW.ptr); - let winVer = OSVERSIONINFOEXW(); - winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; - - if(0 !== GetVersionEx(winVer.address())) { - osVersion += "." + winVer.wServicePackMajor - + "." + winVer.wServicePackMinor; - } else { - LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + // Get Service pack info + try { + let GetVersionEx = kernel32.declare("GetVersionExW", + ctypes.default_abi, + BOOL, + OSVERSIONINFOEXW.ptr); + let winVer = OSVERSIONINFOEXW(); + winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; + + if(0 !== GetVersionEx(winVer.address())) { + osVersion += "." + winVer.wServicePackMajor + + "." + winVer.wServicePackMinor; + } else { + LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + osVersion += ".unknown"; + } + } catch (e) { + LOG("gOSVersion - error getting service pack information. Exception: " + e); osVersion += ".unknown"; } - } catch (e) { - LOG("gOSVersion - error getting service pack information. Exception: " + e); - osVersion += ".unknown"; - } - - // Get processor architecture - let arch = "unknown"; - try { - let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", - ctypes.default_abi, - ctypes.void_t, - SYSTEM_INFO.ptr); - let sysInfo = SYSTEM_INFO(); - // Default to unknown - sysInfo.wProcessorArchitecture = 0xffff; - - GetNativeSystemInfo(sysInfo.address()); - switch(sysInfo.wProcessorArchitecture) { - case 9: - arch = "x64"; - break; - case 6: - arch = "IA64"; - break; - case 0: - arch = "x86"; - break; + + // Get processor architecture + let arch = "unknown"; + try { + let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", + ctypes.default_abi, + ctypes.void_t, + SYSTEM_INFO.ptr); + let sysInfo = SYSTEM_INFO(); + // Default to unknown + sysInfo.wProcessorArchitecture = 0xffff; + + GetNativeSystemInfo(sysInfo.address()); + switch(sysInfo.wProcessorArchitecture) { + case 9: + arch = "x64"; + break; + case 6: + arch = "IA64"; + break; + case 0: + arch = "x86"; + break; + } + } catch (e) { + LOG("gOSVersion - error getting processor architecture. Exception: " + e); + } finally { + osVersion += " (" + arch + ")"; } - } catch (e) { - LOG("gOSVersion - error getting processor architecture. Exception: " + e); } finally { - osVersion += " (" + arch + ")"; + kernel32.close(); } - } finally { - kernel32.close(); } } -#endif try { osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; @@ -201,19 +202,19 @@ XPCOMUtils.defineLazyGetter(this, "gABI", function aus_gABI() { catch (e) { LOG("gABI - XPCOM ABI unknown: updates are not possible."); } -#ifdef XP_MACOSX - // Mac universal build should report a different ABI than either macppc - // or mactel. - let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. - getService(Ci.nsIMacUtils); + if (AppConstants.platform == "macosx") { + // Mac universal build should report a different ABI than either macppc + // or mactel. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); - if (macutils.isUniversalBinary) - abi += "-u-" + macutils.architecturesInBinary; -#ifdef MOZ_SHARK - // Disambiguate optimised and shark nightlies - abi += "-shark" -#endif -#endif + if (macutils.isUniversalBinary) + abi += "-u-" + macutils.architecturesInBinary; + if (AppConstants.MOZ_SHARK) { + // Disambiguate optimised and shark nightlies + abi += "-shark" + } + } return abi; }); diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index e4de6169d6e..49a86731485 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -8,6 +8,7 @@ const {utils: Cu} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); @@ -141,13 +142,12 @@ LightweightThemeConsumer.prototype = { footer.removeAttribute("lwthemefooter"); } -#ifdef XP_MACOSX // On OS X, we extend the lightweight theme into the titlebar, which means setting // the chromemargin attribute. Some XUL applications already draw in the titlebar, // so we need to save the chromemargin value before we overwrite it with the value // that lets us draw in the titlebar. We stash this value on the root attribute so // that XUL applications have the ability to invalidate the saved value. - if (stateChanging) { + if (AppConstants.platform == "macosx" && stateChanging) { if (!root.hasAttribute("chromemargin-nonlwtheme")) { root.setAttribute("chromemargin-nonlwtheme", root.getAttribute("chromemargin")); } @@ -163,7 +163,6 @@ LightweightThemeConsumer.prototype = { } } } -#endif Services.obs.notifyObservers(this._win, "lightweight-theme-window-updated", JSON.stringify(aData)); } diff --git a/toolkit/modules/ResetProfile.jsm b/toolkit/modules/ResetProfile.jsm index c4c2567d9f2..52c35c79474 100644 --- a/toolkit/modules/ResetProfile.jsm +++ b/toolkit/modules/ResetProfile.jsm @@ -7,10 +7,12 @@ this.EXPORTED_SYMBOLS = ["ResetProfile"]; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -#expand const MOZ_APP_NAME = "__MOZ_APP_NAME__"; -#expand const MOZ_BUILD_APP = "__MOZ_BUILD_APP__"; Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); + +const MOZ_APP_NAME = AppConstants.MOZ_APP_NAME; +const MOZ_BUILD_APP = AppConstants.MOZ_BUILD_APP; this.ResetProfile = { /** diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index 17e912ca727..86733efbc99 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -10,10 +10,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); - -#ifdef MOZ_CRASHREPORTER -Cu.import("resource://gre/modules/CrashReports.jsm"); -#endif +Cu.import("resource://gre/modules/AppConstants.jsm"); let Experiments; try { @@ -154,9 +151,8 @@ let dataProviders = { userAgent, }; -#ifdef MOZ_UPDATER - data.updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get(); -#endif + if (AppConstants.MOZ_UPDATER) + data.updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get(); try { data.vendor = Services.prefs.getCharPref("app.support.vendor"); @@ -189,18 +185,6 @@ let dataProviders = { done(data); }, -#ifdef MOZ_CRASHREPORTER - crashes: function crashes(done) { - let reports = CrashReports.getReports(); - let now = new Date(); - let reportsNew = reports.filter(report => (now - report.date < Troubleshoot.kMaxCrashAge)); - let reportsSubmitted = reportsNew.filter(report => (!report.pending)); - let reportsPendingCount = reportsNew.length - reportsSubmitted.length; - let data = {submitted : reportsSubmitted, pending : reportsPendingCount}; - done(data); - }, -#endif - extensions: function extensions(done) { AddonManager.getAddonsByTypes(["extension"], function (extensions) { extensions.sort(function (a, b) { @@ -338,12 +322,9 @@ let dataProviders = { } if (!data.numAcceleratedWindows && gfxInfo) { - let feature = -#ifdef XP_WIN - gfxInfo.FEATURE_DIRECT3D_9_LAYERS; -#else - gfxInfo.FEATURE_OPENGL_LAYERS; -#endif + let win = AppConstants.platform == "win"; + let feature = win ? gfxInfo.FEATURE_DIRECT3D_9_LAYERS : + gfxInfo.FEATURE_OPENGL_LAYERS; data.numAcceleratedWindowsMessage = statusMsgForFeature(feature); } @@ -414,20 +395,20 @@ let dataProviders = { + " -- " + gl.getParameter(ext.UNMASKED_RENDERER_WEBGL); } else { - let feature = -#ifdef XP_WIN + let feature; + if (AppConstants.platform == "win") { // If ANGLE is not available but OpenGL is, we want to report on the // OpenGL feature, because that's what's going to get used. In all // other cases we want to report on the ANGLE feature. - gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE) != - Ci.nsIGfxInfo.FEATURE_STATUS_OK && - gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL) == - Ci.nsIGfxInfo.FEATURE_STATUS_OK ? - Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL : - Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE; -#else - Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL; -#endif + let angle = gfxInfo.getFeatureStatus(gfxInfo.FEATURE_WEBGL_ANGLE) == + gfxInfo.FEATURE_STATUS_OK; + let opengl = gfxInfo.getFeatureStatus(gfxInfo.FEATURE_WEBGL_OPENGL) == + gfxInfo.FEATURE_STATUS_OK; + feature = !angle && opengl ? gfxInfo.FEATURE_WEBGL_OPENGL : + gfxInfo.FEATURE_WEBGL_ANGLE; + } else { + feature = gfxInfo.FEATURE_WEBGL_OPENGL; + } data.webglRendererMessage = statusMsgForFeature(feature); } @@ -500,10 +481,24 @@ let dataProviders = { done({ exists: userJSFile.exists() && userJSFile.fileSize > 0, }); - }, + } +}; -#if defined(XP_LINUX) && defined (MOZ_SANDBOX) - sandbox: function sandbox(done) { +if (AppConstants.MOZ_CRASHREPORTER) { + dataProviders.crashes = function crashes(done) { + let CrashReports = Cu.import("resource://gre/modules/CrashReports.jsm").CrashReports; + let reports = CrashReports.getReports(); + let now = new Date(); + let reportsNew = reports.filter(report => (now - report.date < Troubleshoot.kMaxCrashAge)); + let reportsSubmitted = reportsNew.filter(report => (!report.pending)); + let reportsPendingCount = reportsNew.length - reportsSubmitted.length; + let data = {submitted : reportsSubmitted, pending : reportsPendingCount}; + done(data); + } +} + +if (AppConstants.platform == "linux" && AppConstants.MOZ_SANDBOX) { + dataProviders.sandbox = function sandbox(done) { const keys = ["hasSeccompBPF", "hasSeccompTSync", "hasPrivilegedUserNamespaces", "hasUserNamespaces", "canSandboxContent", "canSandboxMedia"]; @@ -518,5 +513,4 @@ let dataProviders = { } done(data); } -#endif -}; +} diff --git a/toolkit/modules/WindowDraggingUtils.jsm b/toolkit/modules/WindowDraggingUtils.jsm index da292c42204..ea1cdd07b25 100644 --- a/toolkit/modules/WindowDraggingUtils.jsm +++ b/toolkit/modules/WindowDraggingUtils.jsm @@ -2,23 +2,20 @@ * 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/. */ -#ifdef XP_WIN -#define USE_HITTEST -#elifdef MOZ_WIDGET_COCOA -#define USE_HITTEST -#endif +Components.utils.import("resource://gre/modules/AppConstants.jsm"); + +const USE_HITTEST = /^(win|macosx)/i.test(AppConstants.platform); this.EXPORTED_SYMBOLS = [ "WindowDraggingElement" ]; this.WindowDraggingElement = function WindowDraggingElement(elem) { this._elem = elem; this._window = elem.ownerDocument.defaultView; -#ifdef USE_HITTEST - if (!this.isPanel()) + + if (USE_HITTEST && !this.isPanel()) this._elem.addEventListener("MozMouseHittest", this, false); else -#endif - this._elem.addEventListener("mousedown", this, false); + this._elem.addEventListener("mousedown", this, false); }; WindowDraggingElement.prototype = { @@ -60,24 +57,23 @@ WindowDraggingElement.prototype = { }, handleEvent: function(aEvent) { let isPanel = this.isPanel(); -#ifdef USE_HITTEST - if (!isPanel) { + if (USE_HITTEST && !isPanel) { if (this.shouldDrag(aEvent)) aEvent.preventDefault(); return; } -#endif switch (aEvent.type) { case "mousedown": if (!this.shouldDrag(aEvent)) return; -#ifdef MOZ_WIDGET_GTK - // On GTK, there is a toolkit-level function which handles - // window dragging, which must be used. - this._window.beginWindowMove(aEvent, isPanel ? this._elem : null); -#else + if (/^gtk/i.test(AppConstants.MOZ_WIDGET_TOOLKIT)) { + // On GTK, there is a toolkit-level function which handles + // window dragging, which must be used. + this._window.beginWindowMove(aEvent, isPanel ? this._elem : null); + break; + } if (isPanel) { let screenRect = this._elem.getOuterScreenRect(); this._deltaX = aEvent.screenX - screenRect.left; @@ -90,7 +86,6 @@ WindowDraggingElement.prototype = { this._draggingWindow = true; this._window.addEventListener("mousemove", this, false); this._window.addEventListener("mouseup", this, false); -#endif break; case "mousemove": if (this._draggingWindow) { diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 90627d29b67..144368358cf 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -16,6 +16,7 @@ EXTRA_JS_MODULES += [ 'Battery.jsm', 'BinarySearch.jsm', 'BrowserUtils.jsm', + 'CertUtils.jsm', 'CharsetMenu.jsm', 'ClientID.jsm', 'debug.js', @@ -25,6 +26,8 @@ EXTRA_JS_MODULES += [ 'FileUtils.jsm', 'Finder.jsm', 'Geometry.jsm', + 'GMPInstallManager.jsm', + 'GMPUtils.jsm', 'Http.jsm', 'InlineSpellChecker.jsm', 'InlineSpellCheckerContent.jsm', @@ -50,6 +53,8 @@ EXTRA_JS_MODULES += [ 'RemoteSecurityUI.jsm', 'RemoteWebNavigation.jsm', 'RemoteWebProgress.jsm', + 'ResetProfile.jsm', + 'secondscreen/RokuApp.jsm', 'secondscreen/SimpleServiceDiscovery.jsm', 'SelectContentHelper.jsm', 'SelectParentHelper.jsm', @@ -63,25 +68,21 @@ EXTRA_JS_MODULES += [ 'Task.jsm', 'TelemetryTimestamps.jsm', 'Timer.jsm', + 'Troubleshoot.jsm', 'WebChannel.jsm', + 'WindowDraggingUtils.jsm', 'ZipUtils.jsm', ] EXTRA_PP_JS_MODULES += [ - 'CertUtils.jsm', - 'GMPInstallManager.jsm', - 'GMPUtils.jsm', - 'ResetProfile.jsm', - 'secondscreen/RokuApp.jsm', + 'AppConstants.jsm', 'Services.jsm', - 'Troubleshoot.jsm', 'UpdateChannel.jsm', - 'WindowDraggingUtils.jsm', 'WindowsPrefSync.jsm', ] if 'Android' != CONFIG['OS_TARGET']: - EXTRA_PP_JS_MODULES += [ + EXTRA_JS_MODULES += [ 'LightweightThemeConsumer.jsm', ] else: @@ -95,14 +96,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': for var in ('ANDROID_PACKAGE_NAME', 'MOZ_APP_NAME', - 'MOZ_APP_VERSION'): + 'MOZ_APP_VERSION', + 'MOZ_WIDGET_TOOLKIT'): DEFINES[var] = CONFIG[var] for var in ('MOZILLA_OFFICIAL', - 'MOZ_TOOLKIT_SEARCH'): + 'MOZ_TOOLKIT_SEARCH', + 'MOZ_UPDATER'): if CONFIG[var]: DEFINES[var] = True - -EXTRA_PP_JS_MODULES += [ - 'AppConstants.jsm', -] diff --git a/toolkit/modules/secondscreen/RokuApp.jsm b/toolkit/modules/secondscreen/RokuApp.jsm index 15a9ce28018..0f8ed712c2a 100644 --- a/toolkit/modules/secondscreen/RokuApp.jsm +++ b/toolkit/modules/secondscreen/RokuApp.jsm @@ -10,6 +10,7 @@ this.EXPORTED_SYMBOLS = ["RokuApp"]; const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); const WEBRTC_PLAYER_NAME = "WebRTC Player"; const MIRROR_PORT = 8011; @@ -28,11 +29,7 @@ const PROTOCOL_VERSION = 1; function RokuApp(service) { this.service = service; this.resourceURL = this.service.location; -#ifdef RELEASE_BUILD - this.app = "Firefox"; -#else - this.app = "Firefox Nightly"; -#endif + this.app = AppConstants.RELEASE_BUILD ? "Firefox" : "Firefox Nightly"; this.mediaAppID = -1; this.mirrorAppID = -1; } diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 7127d990eb0..536f1385314 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -4606,6 +4606,15 @@ LogE10sBlockedReason(const char *reason) { } #endif +enum { + kE10sEnabledByUser = 0, + kE10sEnabledByDefault = 1, + kE10sDisabledByUser = 2, + kE10sDisabledInSafeMode = 3, + kE10sDisabledForAccessibility = 4, + kE10sDisabledForMacGfx = 5, +}; + bool mozilla::BrowserTabsRemoteAutostart() { @@ -4616,6 +4625,14 @@ mozilla::BrowserTabsRemoteAutostart() bool optInPref = Preferences::GetBool("browser.tabs.remote.autostart", false); bool trialPref = Preferences::GetBool("browser.tabs.remote.autostart.2", false); bool prefEnabled = optInPref || trialPref; + int status; + if (optInPref) { + status = kE10sEnabledByUser; + } else if (trialPref) { + status = kE10sEnabledByDefault; + } else { + status = kE10sDisabledByUser; + } #if !defined(NIGHTLY_BUILD) // When running tests with 'layers.offmainthreadcomposition.testing.enabled' and // autostart set to true, return enabled. These tests must be allowed to run @@ -4633,8 +4650,10 @@ mozilla::BrowserTabsRemoteAutostart() if (prefEnabled) { if (gSafeMode) { + status = kE10sDisabledInSafeMode; LogE10sBlockedReason("Safe mode"); } else if (disabledForA11y) { + status = kE10sDisabledForAccessibility; LogE10sBlockedReason("An accessibility tool is or was active. See bug 1115956."); } else if (disabledForVR) { LogE10sBlockedReason("Experimental VR interfaces are enabled"); @@ -4677,6 +4696,7 @@ mozilla::BrowserTabsRemoteAutostart() if (accelDisabled) { gBrowserTabsRemoteAutostart = false; + status = kE10sDisabledForMacGfx; #ifdef NIGHTLY_BUILD LogE10sBlockedReason("Hardware acceleration is disabled"); #endif @@ -4685,6 +4705,7 @@ mozilla::BrowserTabsRemoteAutostart() #endif // defined(XP_MACOSX) mozilla::Telemetry::Accumulate(mozilla::Telemetry::E10S_AUTOSTART, gBrowserTabsRemoteAutostart); + mozilla::Telemetry::Accumulate(mozilla::Telemetry::E10S_AUTOSTART_STATUS, status); if (Preferences::GetBool("browser.enabledE10SFromPrompt", false)) { mozilla::Telemetry::Accumulate(mozilla::Telemetry::E10S_STILL_ACCEPTED_FROM_PROMPT, gBrowserTabsRemoteAutostart); diff --git a/tools/profiler/GeckoProfiler.h b/tools/profiler/GeckoProfiler.h index 8ae479f23dd..f17998da63a 100644 --- a/tools/profiler/GeckoProfiler.h +++ b/tools/profiler/GeckoProfiler.h @@ -52,6 +52,8 @@ #include "js/TypeDecls.h" #include "mozilla/GuardObjects.h" #include "mozilla/UniquePtr.h" +#include "mozilla/GuardObjects.h" +#include "ProfilerBacktrace.h" namespace mozilla { class TimeStamp; @@ -65,7 +67,7 @@ enum TracingMetadata { TRACING_EVENT_BACKTRACE }; -#ifndef MOZ_ENABLE_PROFILER_SPS +#if !defined(MOZ_ENABLE_PROFILER_SPS) || defined(MOZILLA_XPCOMRT_API) #include #include diff --git a/tools/profiler/ProfileEntry.cpp b/tools/profiler/ProfileEntry.cpp index ba8fc17bef0..5635d39c2c4 100644 --- a/tools/profiler/ProfileEntry.cpp +++ b/tools/profiler/ProfileEntry.cpp @@ -153,7 +153,6 @@ void ProfileBuffer::deleteExpiredStoredMarkers() { void ProfileBuffer::reset() { mGeneration += 2; mReadPos = mWritePos = 0; - deleteExpiredStoredMarkers(); } #define DYNAMIC_MAX_STRING 512 @@ -232,8 +231,8 @@ public: , mStartedTypeList(false) { } - void readType(const char *keyedBy, const char *name, - const char *location, unsigned lineno) override { + void readType(const char* keyedBy, const char* name, + const char* location, unsigned lineno) override { if (!mStartedTypeList) { mStartedTypeList = true; mWriter.BeginObject(); @@ -255,7 +254,7 @@ public: mWriter.EndObject(); } - void operator()(JS::TrackedTypeSite site, const char *mirType) override { + void operator()(JS::TrackedTypeSite site, const char* mirType) override { if (mStartedTypeList) { mWriter.EndArray(); mStartedTypeList = false; diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 9432600e7b4..77f71fc884a 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -378,7 +378,8 @@ void TableTicker::FlushOnJSShutdown(JSRuntime* aRuntime) for (size_t i = 0; i < sRegisteredThreads->size(); i++) { // Thread not being profiled, skip it. - if (!sRegisteredThreads->at(i)->Profile()) { + if (!sRegisteredThreads->at(i)->Profile() || + sRegisteredThreads->at(i)->IsPendingDelete()) { continue; } diff --git a/widget/cocoa/nsCocoaUtils.mm b/widget/cocoa/nsCocoaUtils.mm index 1dbdf7be50d..c3820bd4859 100644 --- a/widget/cocoa/nsCocoaUtils.mm +++ b/widget/cocoa/nsCocoaUtils.mm @@ -484,8 +484,7 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, ui ceil(height * scaleFactor)); RefPtr drawTarget = gfxPlatform::GetPlatform()-> - CreateOffscreenContentDrawTarget(ToIntSize(scaledSize), - SurfaceFormat::B8G8R8A8); + CreateOffscreenContentDrawTarget(scaledSize, SurfaceFormat::B8G8R8A8); if (!drawTarget) { NS_ERROR("Failed to create DrawTarget"); return NS_ERROR_FAILURE; diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index d397aec01ee..0e19dee579c 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2383,7 +2383,7 @@ nsWindow::UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect) int32_t bufferSize = stride * aBoundsRect.height; nsAutoArrayPtr imageBuffer(new (std::nothrow) uint8_t[bufferSize]); RefPtr drawTarget = gfxPlatform::GetPlatform()-> - CreateDrawTargetForData(imageBuffer, ToIntSize(aBoundsRect.Size()), + CreateDrawTargetForData(imageBuffer, aBoundsRect.Size(), stride, SurfaceFormat::A8); if (drawTarget) { diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 0da0d2113da..4f23db7aafd 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -1090,6 +1090,7 @@ GfxInfo::GetGfxDriverInfo() nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions); + /* Bug 1151721: Black video on youtube, block DXVA for all older intel cards. */ APPEND_TO_DRIVER_BLOCKLIST2(DRIVER_OS_ALL, (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorATI), (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(AMDRadeonHD5800), nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, @@ -1101,6 +1102,11 @@ GfxInfo::GetGfxDriverInfo() nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_EQUAL, V(15,200,1006,0)); + APPEND_TO_DRIVER_BLOCKLIST2(DRIVER_OS_ALL, + (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorIntel), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,15,10,2622)); + /* Bug 1137716: XXX this should really check for the matching Intel piece as well. * Unfortunately, we don't have the infrastructure to do that */ APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2(DRIVER_OS_WINDOWS_7, diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 36df9f42fbc..672dbc8bf0d 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -6841,7 +6841,7 @@ void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode) void nsWindow::ClearTranslucentWindow() { if (mTransparentSurface) { - IntSize size = ToIntSize(mTransparentSurface->GetSize()); + IntSize size = mTransparentSurface->GetSize(); RefPtr drawTarget = gfxPlatform::GetPlatform()-> CreateDrawTargetForSurface(mTransparentSurface, size); drawTarget->ClearRect(Rect(0, 0, size.width, size.height)); diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index f61277a8d7e..20e86eded09 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -353,7 +353,9 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, if (sMultiprocessDescription) { PrintToBuffer("%s ", sMultiprocessDescription); } +#if !defined(MOZILLA_XPCOMRT_API) PrintToBuffer("%d] ", base::GetCurrentProcId()); +#endif // !defined(MOZILLA_XPCOMRT_API) PrintToBuffer("%s: ", sevString); @@ -403,7 +405,7 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, return; case NS_DEBUG_ABORT: { -#if defined(MOZ_CRASHREPORTER) +#if defined(MOZ_CRASHREPORTER) && !defined(MOZILLA_XPCOMRT_API) // Updating crash annotations in the child causes us to do IPC. This can // really cause trouble if we're asserting from within IPC code. So we // have to do without the annotations in that case. @@ -420,7 +422,7 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, #if defined(DEBUG) && defined(_WIN32) RealBreak(); #endif -#ifdef DEBUG +#if defined(DEBUG) && !defined(MOZILLA_XPCOMRT_API) nsTraceRefcnt::WalkTheStack(stderr); #endif Abort(buf.buffer); @@ -445,11 +447,15 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, return; case NS_ASSERT_STACK: +#if !defined(MOZILLA_XPCOMRT_API) nsTraceRefcnt::WalkTheStack(stderr); +#endif // !defined(MOZILLA_XPCOMRT_API) return; case NS_ASSERT_STACK_AND_ABORT: +#if !defined(MOZILLA_XPCOMRT_API) nsTraceRefcnt::WalkTheStack(stderr); +#endif // !defined(MOZILLA_XPCOMRT_API) // Fall through to abort case NS_ASSERT_ABORT: @@ -616,7 +622,7 @@ NS_ErrorAccordingToNSPR() void NS_ABORT_OOM(size_t aSize) { -#ifdef MOZ_CRASHREPORTER +#if defined(MOZ_CRASHREPORTER) && !defined(MOZILLA_XPCOMRT_API) CrashReporter::AnnotateOOMAllocationSize(aSize); #endif MOZ_CRASH(); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index b89cf34fab5..14c31c24c0f 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -516,7 +516,7 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); } -#if defined(MOZ_DMD) +#if defined(MOZ_DMD) && !defined(MOZILLA_XPCOMRT_API) namespace mozilla { namespace dmd { // This runs all the memory reporters in the current process but does nothing diff --git a/xpcom/build/FileLocation.cpp b/xpcom/build/FileLocation.cpp index abe6266ec58..aa63006e301 100644 --- a/xpcom/build/FileLocation.cpp +++ b/xpcom/build/FileLocation.cpp @@ -3,8 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "FileLocation.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "nsZipArchive.h" #include "nsURLHelper.h" +#endif // !defined(MOZILLA_XPCOMRT_API) namespace mozilla { @@ -31,9 +33,12 @@ FileLocation::FileLocation(const FileLocation& aFile, const char* aPath) if (aFile.IsZip()) { if (aFile.mBaseFile) { Init(aFile.mBaseFile, aFile.mPath.get()); - } else { + } +#if !defined(MOZILLA_XPCOMRT_API) + else { Init(aFile.mBaseZip, aFile.mPath.get()); } +#endif if (aPath) { int32_t i = mPath.RFindChar('/'); if (kNotFound == i) { @@ -71,7 +76,9 @@ FileLocation::FileLocation(const FileLocation& aFile, const char* aPath) void FileLocation::Init(nsIFile* aFile) { +#if !defined(MOZILLA_XPCOMRT_API) mBaseZip = nullptr; +#endif //!defined(MOZILLA_XPCOMRT_API) mBaseFile = aFile; mPath.Truncate(); } @@ -79,7 +86,9 @@ FileLocation::Init(nsIFile* aFile) void FileLocation::Init(nsIFile* aFile, const char* aPath) { +#if !defined(MOZILLA_XPCOMRT_API) mBaseZip = nullptr; +#endif // !defined(MOZILLA_XPCOMRT_API) mBaseFile = aFile; mPath = aPath; } @@ -87,7 +96,9 @@ FileLocation::Init(nsIFile* aFile, const char* aPath) void FileLocation::Init(nsZipArchive* aZip, const char* aPath) { +#if !defined(MOZILLA_XPCOMRT_API) mBaseZip = aZip; +#endif // !defined(MOZILLA_XPCOMRT_API) mBaseFile = nullptr; mPath = aPath; } @@ -95,6 +106,7 @@ FileLocation::Init(nsZipArchive* aZip, const char* aPath) void FileLocation::GetURIString(nsACString& aResult) const { +#if !defined(MOZILLA_XPCOMRT_API) if (mBaseFile) { net_GetURLSpecFromActualFile(mBaseFile, aResult); } else if (mBaseZip) { @@ -106,11 +118,13 @@ FileLocation::GetURIString(nsACString& aResult) const aResult += "!/"; aResult += mPath; } +#endif // !defined(MOZILLA_XPCOMRT_API) } already_AddRefed FileLocation::GetBaseFile() { +#if !defined(MOZILLA_XPCOMRT_API) if (IsZip() && mBaseZip) { nsRefPtr handler = mBaseZip->GetFD(); if (handler) { @@ -118,6 +132,7 @@ FileLocation::GetBaseFile() } return nullptr; } +#endif // !defined(MOZILLA_XPCOMRT_API) nsCOMPtr file = mBaseFile; return file.forget(); @@ -137,6 +152,7 @@ FileLocation::Equals(const FileLocation& aFile) const const FileLocation* a = this; const FileLocation* b = &aFile; +#if !defined(MOZILLA_XPCOMRT_API) if (a->mBaseZip) { nsRefPtr handler = a->mBaseZip->GetFD(); a = &handler->mFile; @@ -145,12 +161,15 @@ FileLocation::Equals(const FileLocation& aFile) const nsRefPtr handler = b->mBaseZip->GetFD(); b = &handler->mFile; } +#endif // !defined(MOZILLA_XPCOMRT_API) + return a->Equals(*b); } nsresult FileLocation::GetData(Data& aData) { +#if !defined(MOZILLA_XPCOMRT_API) if (!IsZip()) { return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &aData.mFd.rwget()); } @@ -163,6 +182,7 @@ FileLocation::GetData(Data& aData) if (aData.mItem) { return NS_OK; } +#endif // !defined(MOZILLA_XPCOMRT_API) return NS_ERROR_FILE_UNRECOGNIZED_PATH; } @@ -181,10 +201,13 @@ FileLocation::Data::GetSize(uint32_t* aResult) *aResult = fileInfo.size; return NS_OK; - } else if (mItem) { + } +#if !defined(MOZILLA_XPCOMRT_API) + else if (mItem) { *aResult = mItem->RealSize(); return NS_OK; } +#endif // !defined(MOZILLA_XPCOMRT_API) return NS_ERROR_NOT_INITIALIZED; } @@ -201,13 +224,16 @@ FileLocation::Data::Copy(char* aBuf, uint32_t aLen) totalRead += read; } return NS_OK; - } else if (mItem) { + } +#if !defined(MOZILLA_XPCOMRT_API) + else if (mItem) { nsZipCursor cursor(mItem, mZip, reinterpret_cast(aBuf), aLen, true); uint32_t readLen; cursor.Copy(&readLen); return (readLen == aLen) ? NS_OK : NS_ERROR_FILE_CORRUPTED; } +#endif // !defined(MOZILLA_XPCOMRT_API) return NS_ERROR_NOT_INITIALIZED; } diff --git a/xpcom/build/FileLocation.h b/xpcom/build/FileLocation.h index 62867d3c8d8..4afd6ad57e4 100644 --- a/xpcom/build/FileLocation.h +++ b/xpcom/build/FileLocation.h @@ -87,7 +87,11 @@ public: * Boolean value corresponding to whether the file location is initialized * or not. */ +#if defined(MOZILLA_XPCOMRT_API) + operator bool() const { return mBaseFile; } +#else operator bool() const { return mBaseFile || mBaseZip; } +#endif // defined(MOZILLA_XPCOMRT_API) /** * Returns whether another FileLocation points to the same resource @@ -111,7 +115,9 @@ public: nsresult Copy(char* aBuf, uint32_t aLen); protected: friend class FileLocation; +#if !defined(MOZILLA_XPCOMRT_API) nsZipItem* mItem; +#endif // !defined(MOZILLA_XPCOMRT_API) nsRefPtr mZip; mozilla::AutoFDClose mFd; }; @@ -123,7 +129,9 @@ public: nsresult GetData(Data& aData); private: nsCOMPtr mBaseFile; +#if !defined(MOZILLA_XPCOMRT_API) nsRefPtr mBaseZip; +#endif // !defined(MOZILLA_XPCOMRT_API) nsCString mPath; }; /* class FileLocation */ diff --git a/xpcom/build/ServiceList.h b/xpcom/build/ServiceList.h index 1eadfe3a173..437829f6a26 100644 --- a/xpcom/build/ServiceList.h +++ b/xpcom/build/ServiceList.h @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "mozilla/Services.h" +#if !defined(MOZILLA_XPCOMRT_API) #ifdef ACCESSIBILITY MOZ_SERVICE(AccessibilityService, nsIAccessibilityService, "@mozilla.org/accessibilityService;1") @@ -17,8 +18,10 @@ MOZ_SERVICE(XULOverlayProviderService, nsIXULOverlayProvider, "@mozilla.org/chrome/chrome-registry;1") MOZ_SERVICE(IOService, nsIIOService, "@mozilla.org/network/io-service;1") +#endif // !defined(MOZILLA_XPCOMRT_API) MOZ_SERVICE(ObserverService, nsIObserverService, "@mozilla.org/observer-service;1") +#if !defined(MOZILLA_XPCOMRT_API) MOZ_SERVICE(StringBundleService, nsIStringBundleService, "@mozilla.org/intl/stringbundle;1") MOZ_SERVICE(XPConnect, nsIXPConnect, @@ -44,3 +47,4 @@ MOZ_SERVICE(HistoryService, IHistory, #ifdef MOZ_USE_NAMESPACE } #endif +#endif // !defined(MOZILLA_XPCOMRT_API) diff --git a/xpcom/build/Services.cpp b/xpcom/build/Services.cpp index 724718f20b1..3378a1ed6bb 100644 --- a/xpcom/build/Services.cpp +++ b/xpcom/build/Services.cpp @@ -6,16 +6,17 @@ #include "mozilla/Likely.h" #include "mozilla/Services.h" #include "nsComponentManager.h" +#include "nsIObserverService.h" +#include "nsNetCID.h" +#include "nsObserverService.h" +#include "nsXPCOMPrivate.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "nsIIOService.h" #include "nsIDirectoryService.h" #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif #include "nsIChromeRegistry.h" -#include "nsIObserverService.h" -#include "nsNetCID.h" -#include "nsObserverService.h" -#include "nsXPCOMPrivate.h" #include "nsIStringBundle.h" #include "nsIToolkitChromeRegistry.h" #include "nsIXULOverlayProvider.h" @@ -26,6 +27,7 @@ #include "nsIServiceWorkerManager.h" #include "nsIAsyncShutdown.h" #include "nsIUUIDGenerator.h" +#endif // !defined(MOZILLA_XPCOMRT_API) using namespace mozilla; using namespace mozilla::services; diff --git a/xpcom/components/ManifestParser.h b/xpcom/components/ManifestParser.h index 3f05bc3ebf5..cb4f310c1b2 100644 --- a/xpcom/components/ManifestParser.h +++ b/xpcom/components/ManifestParser.h @@ -7,7 +7,9 @@ #define ManifestParser_h #include "nsComponentManager.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "nsChromeRegistry.h" +#endif // !defined(MOZILLA_XPCOMRT_API) #include "mozilla/FileLocation.h" class nsIFile; diff --git a/xpcom/components/nsCategoryManager.cpp b/xpcom/components/nsCategoryManager.cpp index 0f641a236b5..09f14f7a8a8 100644 --- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -469,7 +469,9 @@ nsCategoryManager::nsCategoryManager() void nsCategoryManager::InitMemoryReporter() { +#if !defined(MOZILLA_XPCOMRT_API) RegisterStrongMemoryReporter(this); +#endif // !defined(MOZILLA_XPCOMRT_API) } nsCategoryManager::~nsCategoryManager() @@ -862,8 +864,10 @@ NS_CreateServicesFromCategory(const char* aCategory, nsCOMPtr instance = do_GetService(contractID); if (!instance) { +#if !defined(MOZILLA_XPCOMRT_API) LogMessage("While creating services from category '%s', could not create service for entry '%s', contract ID '%s'", aCategory, entryString.get(), contractID.get()); +#endif // !defined(MOZILLA_XPCOMRT_API) continue; } @@ -873,8 +877,10 @@ NS_CreateServicesFromCategory(const char* aCategory, if (observer) { observer->Observe(aOrigin, aObserverTopic, EmptyString().get()); } else { +#if !defined(MOZILLA_XPCOMRT_API) LogMessage("While creating services from category '%s', service for entry '%s', contract ID '%s' does not implement nsIObserver.", aCategory, entryString.get(), contractID.get()); +#endif // !defined(MOZILLA_XPCOMRT_API) } } } diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index c5bcd92a046..558aedb4747 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -58,7 +58,10 @@ #include "private/pprthred.h" #include "nsTArray.h" #include "prio.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "ManifestParser.h" +#include "nsNetUtil.h" +#endif // !defined(MOZILLA_XPCOMRT_API) #include "mozilla/Services.h" #include "mozilla/GenericFactory.h" @@ -68,7 +71,6 @@ #include "nsArrayEnumerator.h" #include "nsStringEnumerator.h" #include "mozilla/FileUtils.h" -#include "nsNetUtil.h" #include "nsDataHashtable.h" #include // for placement new @@ -250,6 +252,7 @@ private: } // anonymous namespace +#if !defined(MOZILLA_XPCOMRT_API) // this is safe to call during InitXPCOM static already_AddRefed GetLocationFromDirectoryService(const char* aProp) @@ -286,6 +289,7 @@ CloneAndAppend(nsIFile* aBase, const nsACString& aAppend) f->AppendNative(aAppend); return f.forget(); } +#endif // !defined(MOZILLA_XPCOMRT_API) //////////////////////////////////////////////////////////////////////////////// // nsComponentManagerImpl @@ -318,8 +322,10 @@ nsComponentManagerImpl::nsComponentManagerImpl() nsTArray* nsComponentManagerImpl::sStaticModules; +#if !defined(MOZILLA_XPCOMRT_API) NSMODULE_DEFN(start_kPStaticModules); NSMODULE_DEFN(end_kPStaticModules); +#endif // !defined(MOZILLA_XPCOMRT_API) /* The content between start_kPStaticModules and end_kPStaticModules is gathered * by the linker from various objects containing symbols in a specific section. @@ -335,12 +341,14 @@ nsComponentManagerImpl::InitializeStaticModules() } sStaticModules = new nsTArray; +#if !defined(MOZILLA_XPCOMRT_API) for (const mozilla::Module * const* staticModules = &NSMODULE_NAME(start_kPStaticModules) + 1; staticModules < &NSMODULE_NAME(end_kPStaticModules); ++staticModules) if (*staticModules) { // ASAN adds padding sStaticModules->AppendElement(*staticModules); } +#endif // !defined(MOZILLA_XPCOMRT_API) } nsTArray* @@ -368,26 +376,36 @@ nsComponentManagerImpl::Init() // Initialize our arena PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE); +#if !defined(MOZILLA_XPCOMRT_API) nsCOMPtr greDir = GetLocationFromDirectoryService(NS_GRE_DIR); nsCOMPtr appDir = GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR); +#endif InitializeStaticModules(); +#if !defined(MOZILLA_XPCOMRT_API) nsresult rv = mNativeModuleLoader.Init(); if (NS_FAILED(rv)) { return rv; } nsCategoryManager::GetSingleton()->SuppressNotifications(true); +#endif +#if defined(MOZILLA_XPCOMRT_API) + RegisterModule(&kXPCOMRTModule, nullptr); + RegisterModule(&kNeckoStandaloneModule, nullptr); +#else RegisterModule(&kXPCOMModule, nullptr); +#endif // defined(MOZILLA_XPCOMRT_API) for (uint32_t i = 0; i < sStaticModules->Length(); ++i) { RegisterModule((*sStaticModules)[i], nullptr); } +#if !defined(MOZILLA_XPCOMRT_API) // The overall order in which chrome.manifests are expected to be treated // is the following: // - greDir @@ -432,6 +450,7 @@ nsComponentManagerImpl::Init() nsCategoryManager::GetSingleton()->SuppressNotifications(false); RegisterWeakMemoryReporter(this); +#endif // Unfortunately, we can't register the nsCategoryManager memory reporter // in its constructor (which is triggered by the GetSingleton() call @@ -540,10 +559,12 @@ nsComponentManagerImpl::RegisterCIDEntryLocked( existing = ""; } SafeMutexAutoUnlock unlock(mLock); +#if !defined(MOZILLA_XPCOMRT_API) LogMessage("While registering XPCOM module %s, trying to re-register CID '%s' already registered by %s.", aModule->Description().get(), idstr, existing.get()); +#endif // !defined(MOZILLA_XPCOMRT_API) return; } @@ -569,9 +590,11 @@ nsComponentManagerImpl::RegisterContractIDLocked( aEntry->cid->ToProvidedString(idstr); SafeMutexAutoUnlock unlock(mLock); +#if !defined(MOZILLA_XPCOMRT_API) LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.", aEntry->contractid, idstr); +#endif // !defined(MOZILLA_XPCOMRT_API) return; } @@ -579,6 +602,7 @@ nsComponentManagerImpl::RegisterContractIDLocked( mContractIDs.Put(nsDependentCString(aEntry->contractid), f); } +#if !defined(MOZILLA_XPCOMRT_API) static void CutExtension(nsCString& aPath) { @@ -821,10 +845,12 @@ nsComponentManagerImpl::RereadChromeManifests(bool aChromeOnly) RegisterManifest(l.type, l.location, aChromeOnly); } } +#endif // !defined(MOZILLA_XPCOMRT_API) bool nsComponentManagerImpl::KnownModule::EnsureLoader() { +#if !defined(MOZILLA_XPCOMRT_API) if (!mLoader) { nsCString extension; mFile.GetURIString(extension); @@ -832,6 +858,7 @@ nsComponentManagerImpl::KnownModule::EnsureLoader() mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension); } +#endif // !defined(MOZILLA_XPCOMRT_API) return !!mLoader; } @@ -888,7 +915,9 @@ nsresult nsComponentManagerImpl::Shutdown(void) PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); +#if !defined(MOZILLA_XPCOMRT_API) UnregisterWeakMemoryReporter(this); +#endif // Release all cached factories mContractIDs.Clear(); @@ -904,8 +933,10 @@ nsresult nsComponentManagerImpl::Shutdown(void) sXPTIInfosBook = nullptr; #endif +#if !defined(MOZILLA_XPCOMRT_API) // Unload libraries mNativeModuleLoader.UnloadLibraries(); +#endif // !defined(MOZILLA_XPCOMRT_API) // delete arena for strings and small objects PL_FinishArenaPool(&mArena); @@ -1589,6 +1620,7 @@ nsComponentManagerImpl::GetServiceByContractID(const char* aContractID, return NS_OK; } +#if !defined(MOZILLA_XPCOMRT_API) already_AddRefed nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt) { @@ -1605,6 +1637,7 @@ nsComponentManagerImpl::LoaderForExtension(const nsACString& aExt) return loader.forget(); } +#endif NS_IMETHODIMP nsComponentManagerImpl::RegisterFactory(const nsCID& aClass, @@ -1677,8 +1710,12 @@ nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass, NS_IMETHODIMP nsComponentManagerImpl::AutoRegister(nsIFile* aLocation) { +#if !defined(MOZILLA_XPCOMRT_API) XRE_AddManifestLocation(NS_COMPONENT_LOCATION, aLocation); return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif // !defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP @@ -2014,6 +2051,7 @@ XRE_AddStaticComponent(const mozilla::Module* aComponent) NS_IMETHODIMP nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) { +#if !defined(MOZILLA_XPCOMRT_API) nsString path; nsresult rv = aLocation->GetPath(path); if (NS_FAILED(rv)) { @@ -2027,11 +2065,15 @@ nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) nsCOMPtr manifest = CloneAndAppend(aLocation, NS_LITERAL_CSTRING("chrome.manifest")); return XRE_AddManifestLocation(NS_BOOTSTRAPPED_LOCATION, manifest); +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif // !defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) { +#if !defined(MOZILLA_XPCOMRT_API) nsCOMPtr cr = mozilla::services::GetChromeRegistryService(); if (!cr) { return NS_ERROR_FAILURE; @@ -2061,11 +2103,15 @@ nsComponentManagerImpl::RemoveBootstrappedManifestLocation(nsIFile* aLocation) rv = cr->CheckForNewChrome(); return rv; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif // !defined(MOZILLA_XPCOMRT_API) } NS_IMETHODIMP nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) { +#if !defined(MOZILLA_XPCOMRT_API) NS_ENSURE_ARG_POINTER(aLocations); *aLocations = nullptr; @@ -2089,6 +2135,9 @@ nsComponentManagerImpl::GetManifestLocations(nsIArray** aLocations) locations.forget(aLocations); return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif // !defined(MOZILLA_XPCOMRT_API) } #ifdef MOZ_B2G_LOADER @@ -2137,6 +2186,7 @@ PreloadXPT(nsIFile* aOmnijarFile) #endif /* MOZ_B2G_LOADER */ +#if !defined(MOZILLA_XPCOMRT_API) EXPORT_XPCOM_API(nsresult) XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation) { @@ -2177,4 +2227,5 @@ XRE_AddJarManifestLocation(NSLocationType aType, nsIFile* aLocation) return NS_OK; } +#endif // !defined(MOZILLA_XPCOMRT_API) diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h index b79947bbffe..55ae55751db 100644 --- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -67,7 +67,12 @@ extern const char staticComponentType[]; #endif //////////////////////////////////////////////////////////////////////////////// +#if defined(MOZILLA_XPCOMRT_API) +extern const mozilla::Module kXPCOMRTModule; +extern const mozilla::Module kNeckoStandaloneModule; +#else extern const mozilla::Module kXPCOMModule; +#endif /** * This is a wrapper around mozilla::Mutex which provides runtime diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index 90ab8dce787..120ce18c9d9 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -104,11 +104,13 @@ nsObserverList::NotifyObservers(nsISupports* aSubject, void nsObserverList::UnmarkGrayStrongObservers() { +#if !defined(MOZILLA_XPCOMRT_API) for (uint32_t i = 0; i < mObservers.Length(); ++i) { if (!mObservers[i].isWeakRef) { xpc_TryUnmarkWrappedGrayObject(mObservers[i].asObserver()); } } +#endif // !defined(MOZILLA_XPCOMRT_API) } NS_IMPL_ISUPPORTS(nsObserverEnumerator, nsISimpleEnumerator) diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index 644ce919188..40c403df244 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -205,13 +205,17 @@ nsObserverService::~nsObserverService(void) void nsObserverService::RegisterReporter() { +#if !defined(MOZILLA_XPCOMRT_API) RegisterWeakMemoryReporter(this); +#endif // !defined(MOZILLA_XPCOMRT_API) } void nsObserverService::Shutdown() { +#if !defined(MOZILLA_XPCOMRT_API) UnregisterWeakMemoryReporter(this); +#endif // !defined(MOZILLA_XPCOMRT_API) mShuttingDown = true; diff --git a/xpcom/glue/BlockingResourceBase.cpp b/xpcom/glue/BlockingResourceBase.cpp index 674a06b2b78..887c90a8814 100644 --- a/xpcom/glue/BlockingResourceBase.cpp +++ b/xpcom/glue/BlockingResourceBase.cpp @@ -23,7 +23,7 @@ #include "mozilla/ReentrantMonitor.h" #include "mozilla/Mutex.h" -#ifdef MOZILLA_INTERNAL_API +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) #include "GeckoProfiler.h" #endif //MOZILLA_INTERNAL_API @@ -461,7 +461,7 @@ ReentrantMonitor::Wait(PRIntervalTime aInterval) mChainPrev = 0; nsresult rv; -#ifdef MOZILLA_INTERNAL_API +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) { GeckoProfilerSleepRAII profiler_sleep; #endif //MOZILLA_INTERNAL_API @@ -470,7 +470,7 @@ ReentrantMonitor::Wait(PRIntervalTime aInterval) rv = PR_Wait(mReentrantMonitor, aInterval) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; -#ifdef MOZILLA_INTERNAL_API +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) } #endif //MOZILLA_INTERNAL_API diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index 250a447cefb..fae04af3802 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -144,7 +144,7 @@ private: // Macros for reference-count and constructor logging -#ifdef NS_BUILD_REFCNT_LOGGING +#if defined(NS_BUILD_REFCNT_LOGGING) && !defined(MOZILLA_XPCOMRT_API) #define NS_LOG_ADDREF(_p, _rc, _type, _size) \ NS_LogAddRef((_p), (_rc), (_type), (uint32_t) (_size)) @@ -181,6 +181,11 @@ do { \ NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ } while (0) +#define MOZ_LOG_CTOR(_ptr, _name, _size) \ +do { \ + NS_LogCtor((void*)_ptr, _name, _size); \ +} while (0) + #define MOZ_COUNT_DTOR(_type) \ do { \ MOZ_ASSERT_CLASSNAME(_type); \ @@ -194,6 +199,11 @@ do { \ NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ } while (0) +#define MOZ_LOG_DTOR(_ptr, _name, _size) \ +do { \ + NS_LogDtor((void*)_ptr, _name, _size); \ +} while (0) + /* nsCOMPtr.h allows these macros to be defined by clients * These logging functions require dynamic_cast, so they don't * do anything useful if we don't have dynamic_cast. */ @@ -211,8 +221,10 @@ do { \ #define NS_LOG_RELEASE(_p, _rc, _type) #define MOZ_COUNT_CTOR(_type) #define MOZ_COUNT_CTOR_INHERITED(_type, _base) +#define MOZ_LOG_CTOR(_ptr, _name, _size) #define MOZ_COUNT_DTOR(_type) #define MOZ_COUNT_DTOR_INHERITED(_type, _base) +#define MOZ_LOG_DTOR(_ptr, _name, _size) #endif /* NS_BUILD_REFCNT_LOGGING */ diff --git a/xpcom/libxpcomrt/XPCOMRTInit.cpp b/xpcom/libxpcomrt/XPCOMRTInit.cpp new file mode 100644 index 00000000000..53c15634e20 --- /dev/null +++ b/xpcom/libxpcomrt/XPCOMRTInit.cpp @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 sts=4 ci et: */ +/* 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 "mozilla/Module.h" +#include "mozilla/ModuleUtils.h" +#include "mozilla/NullPtr.h" +#include "mozilla/TimeStamp.h" +#include "nsCategoryManager.h" +#include "nsComponentManager.h" +#include "nsDebugImpl.h" +#include "nsIErrorService.h" +#include "nsMemoryImpl.h" +#include "nsNetCID.h" +#include "nsNetModuleStandalone.h" +#include "nsObserverService.h" +#include "nsThreadManager.h" +#include "nsThreadPool.h" +#include "nsUUIDGenerator.h" +#include "nsXPCOMCIDInternal.h" +#include "nsXPCOMPrivate.h" +#include "TimerThread.h" +#include "XPCOMRTInit.h" + +static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimerImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUUIDGenerator, Init) + +static nsresult +nsThreadManagerGetSingleton(nsISupports* aOuter, + const nsIID& aIID, + void** aInstancePtr) +{ + NS_ASSERTION(aInstancePtr, "null outptr"); + if (NS_WARN_IF(aOuter)) { + return NS_ERROR_NO_AGGREGATION; + } + + return nsThreadManager::get()->QueryInterface(aIID, aInstancePtr); +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsThreadPool) + +nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = nullptr; +bool gXPCOMShuttingDown = false; +bool gXPCOMThreadsShutDown = false; + +#define COMPONENT(NAME, Ctor) static NS_DEFINE_CID(kNS_##NAME##_CID, NS_##NAME##_CID); +#include "XPCOMRTModule.inc" +#undef COMPONENT + +#define COMPONENT(NAME, Ctor) { &kNS_##NAME##_CID, false, nullptr, Ctor }, +const mozilla::Module::CIDEntry kXPCOMCIDEntries[] = { + { &kComponentManagerCID, true, nullptr, nsComponentManagerImpl::Create }, +#include "XPCOMRTModule.inc" + { nullptr } +}; +#undef COMPONENT + +#define COMPONENT(NAME, Ctor) { NS_##NAME##_CONTRACTID, &kNS_##NAME##_CID }, +const mozilla::Module::ContractIDEntry kXPCOMContracts[] = { +#include "XPCOMRTModule.inc" + { nullptr } +}; +#undef COMPONENT + +const mozilla::Module kXPCOMRTModule = { + mozilla::Module::kVersion, kXPCOMCIDEntries, kXPCOMContracts +}; + +nsresult +NS_InitXPCOMRT() +{ + nsresult rv = NS_OK; + + NS_SetMainThread(); + + mozilla::TimeStamp::Startup(); + + rv = nsThreadManager::get()->Init(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Set up the timer globals/timer thread + rv = nsTimerImpl::Startup(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsComponentManagerImpl::gComponentManager = new nsComponentManagerImpl(); + NS_ADDREF(nsComponentManagerImpl::gComponentManager); + + rv = nsComponentManagerImpl::gComponentManager->Init(); + if (NS_FAILED(rv)) { + NS_RELEASE(nsComponentManagerImpl::gComponentManager); + return rv; + } + + mozilla::InitNetModuleStandalone(); + + return NS_OK; +} + +nsresult +NS_ShutdownXPCOMRT() +{ + nsresult rv = NS_OK; + + // Notify observers of xpcom shutting down + { + // Block it so that the COMPtr will get deleted before we hit + // servicemanager shutdown + + nsCOMPtr thread = do_GetCurrentThread(); + + if (NS_WARN_IF(!thread)) { + return NS_ERROR_UNEXPECTED; + } + + nsRefPtr observerService; + CallGetService("@mozilla.org/observer-service;1", + (nsObserverService**)getter_AddRefs(observerService)); + + if (observerService) { + observerService->NotifyObservers(nullptr, + NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, + nullptr); + + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) { + observerService->NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID, + nullptr); + } + } + + // This must happen after the shutdown of media and widgets, which + // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. + NS_ProcessPendingEvents(thread); + + if (observerService) + observerService->NotifyObservers(nullptr, + NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, + nullptr); + + gXPCOMThreadsShutDown = true; + NS_ProcessPendingEvents(thread); + + // Shutdown the timer thread and all timers that might still be alive before + // shutting down the component manager + nsTimerImpl::Shutdown(); + + NS_ProcessPendingEvents(thread); + + // Net module needs to be shutdown before the thread manager or else + // the thread manager will hang waiting for the socket transport + // service to shutdown. + mozilla::ShutdownNetModuleStandalone(); + + // Shutdown all remaining threads. This method does not return until + // all threads created using the thread manager (with the exception of + // the main thread) have exited. + nsThreadManager::get()->Shutdown(); + + NS_ProcessPendingEvents(thread); + } + + mozilla::services::Shutdown(); + + // Shutdown global servicemanager + if (nsComponentManagerImpl::gComponentManager) { + nsComponentManagerImpl::gComponentManager->FreeServices(); + } + + // Shutdown xpcom. This will release all loaders and cause others holding + // a refcount to the component manager to release it. + if (nsComponentManagerImpl::gComponentManager) { + rv = (nsComponentManagerImpl::gComponentManager)->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed."); + } else { + NS_WARNING("Component Manager was never created ..."); + } + + // Finally, release the component manager last because it unloads the + // libraries: + if (nsComponentManagerImpl::gComponentManager) { + nsrefcnt cnt; + NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt); + NS_ASSERTION(cnt == 0, "Component Manager being held past XPCOM shutdown."); + } + nsComponentManagerImpl::gComponentManager = nullptr; + nsCategoryManager::Destroy(); + + return NS_OK; +} diff --git a/xpcom/libxpcomrt/XPCOMRTInit.h b/xpcom/libxpcomrt/XPCOMRTInit.h new file mode 100644 index 00000000000..206298c8cbd --- /dev/null +++ b/xpcom/libxpcomrt/XPCOMRTInit.h @@ -0,0 +1,15 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 sts=4 ci et: */ +/* 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/. */ + +#ifndef XPCOMRT_INIT_H__ +#define XPCOMRT_INIT_H__ + +#include "nsError.h" + +nsresult NS_InitXPCOMRT(); +nsresult NS_ShutdownXPCOMRT(); + +#endif // define XPCOMRT_INIT_H__ diff --git a/xpcom/libxpcomrt/XPCOMRTModule.inc b/xpcom/libxpcomrt/XPCOMRTModule.inc new file mode 100644 index 00000000000..4a3f119c674 --- /dev/null +++ b/xpcom/libxpcomrt/XPCOMRTModule.inc @@ -0,0 +1,8 @@ + COMPONENT(MEMORY, nsMemoryImpl::Create) + COMPONENT(DEBUG, nsDebugImpl::Create) + COMPONENT(CATEGORYMANAGER, nsCategoryManager::Create) + COMPONENT(OBSERVERSERVICE, nsObserverService::Create) + COMPONENT(TIMER, nsTimerImplConstructor) + COMPONENT(THREADMANAGER, nsThreadManagerGetSingleton) + COMPONENT(THREADPOOL, nsThreadPoolConstructor) + COMPONENT(UUID_GENERATOR, nsUUIDGeneratorConstructor) diff --git a/xpcom/libxpcomrt/XPCOMRTStubs.cpp b/xpcom/libxpcomrt/XPCOMRTStubs.cpp new file mode 100644 index 00000000000..09edcd7ad76 --- /dev/null +++ b/xpcom/libxpcomrt/XPCOMRTStubs.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 sts=4 ci et: */ +/* 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 "nsXULAppAPI.h" +#include "mozilla/TimeStamp.h" + + +GeckoProcessType +XRE_GetProcessType() +{ + return GeckoProcessType_Default; +} + +#define PRINT_CALLED fprintf(stderr, "!!! ERROR: function %s defined in file %s should not be called, needs to be correctly implemented.\n", __FUNCTION__, __FILE__) + +class nsAString; +class nsCString; + +namespace base { + class Histogram; +} + +namespace mozilla { +namespace Telemetry { + +#include "mozilla/TelemetryHistogramEnums.h" + +void Accumulate(ID id, uint32_t sample) {} +void Accumulate(ID id, const nsCString& key, uint32_t sample) {} +void Accumulate(const char* name, uint32_t sample) {} +void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end) {} + +base::Histogram* GetHistogramById(ID id) +{ + return nullptr; +} + +base::Histogram* GetKeyedHistogramById(ID id, const nsAString&) +{ + return nullptr; +} + +} // Telemetry +} // mozilla diff --git a/xpcom/libxpcomrt/docs/index.rst b/xpcom/libxpcomrt/docs/index.rst new file mode 100644 index 00000000000..9de1126ceb9 --- /dev/null +++ b/xpcom/libxpcomrt/docs/index.rst @@ -0,0 +1,40 @@ +========================== + XPCOM Standalone Library +========================== + +What it is for +-------------- +The XPCOM standalone library, libxpcomrt, was created to support building the WebRTC +standalone library. The libxpcomrt library contains only the parts of XPCOM that are required +to run WebRTC; parts such as the cycle collector and the startup cache required only by Gecko +are not included. A library containing a small subset of Necko was also +created to support the WebRTC standalone library. + +The libxcomrt library was created specifically to support the WebRTC standalone library. +It is not intended to be used as a general purpose library to add XPCOM functionality to +an application. It is likely that some of the code contained in the libxpcomrt library +has unresolved symbols that may be exposed if used for purposes other than being linked +into the WebRTC standalone library. + +How to use it +------------- +When compiling code utilizing libxpcomrt, both ``MOZILLA_INTERNAL_API`` and ``MOZILLA_XPCOMRT_API`` +must be defined in addition to whatever standard flags are used to compile Gecko. +The library is initialized with ``NS_InitXPCOMRT()`` and shutdown with ``NS_ShutdownXPCOMRT()``. +Both functions are declared in xpcom/libxpcomrt/XPCOMRTInit.h. +Only a small number of services which are required for the WebRTC +standalone library to function are included with libxpcomrt. The dynamic loading of services is not +supported. Including a service through ``NSMODULE_DEFN`` and static linking is also not supported. +The only way to add a service to libxpcomrt is to explicitly start the service during +``nsComponentManagerImpl::Init`` in xpcom/components/nsComponentManager.cpp. +The best method to determine what parts of XPCOM are included in libxpcomrt is to examine the +xpcom/libxpcomrt/moz.build file. It contains all of the XPCOM source files used to build libxpcomrt. +A few of the services that are included are: + +* UUID Generator +* DNS Service +* Socket Transport Service +* IDN Service + +All dependencies on ipc/chromium have been removed. +IO and preference services are not included making this library of limited utility. diff --git a/xpcom/libxpcomrt/moz.build b/xpcom/libxpcomrt/moz.build new file mode 100644 index 00000000000..48c784727ed --- /dev/null +++ b/xpcom/libxpcomrt/moz.build @@ -0,0 +1,154 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': + Library('xpcomrt') + +src_list = [ + 'XPCOMRTInit.cpp', + 'XPCOMRTStubs.cpp', +] + +xpcom_base_src = [ + 'nsDebugImpl.cpp', + 'nsMemoryImpl.cpp', + 'nsUUIDGenerator.cpp', +] +src_list += [ + '%s/xpcom/base/%s' % (TOPSRCDIR, s) for s in xpcom_base_src +] + +xpcom_build_src = [ + 'FileLocation.cpp', + 'Services.cpp', +] +src_list += [ + '%s/xpcom/build/%s' % (TOPSRCDIR, s) for s in xpcom_build_src +] + +xpcom_components_src = [ + 'nsCategoryManager.cpp', + 'nsComponentManager.cpp', +] +src_list += [ + '%s/xpcom/components/%s' % (TOPSRCDIR, s) for s in xpcom_components_src +] + +xpcom_ds_src = [ + 'nsObserverList.cpp', + 'nsObserverService.cpp', + 'nsStringEnumerator.cpp', + 'nsSupportsPrimitives.cpp', +] +if CONFIG['OS_ARCH'] == 'WINNT': + xpcom_ds_src += [ + 'TimeStamp_windows.cpp', + ] +elif CONFIG['HAVE_CLOCK_MONOTONIC']: + xpcom_ds_src += [ + 'TimeStamp_posix.cpp', + ] +elif CONFIG['OS_ARCH'] == 'Darwin': + xpcom_ds_src += [ + 'TimeStamp_darwin.cpp', + ] +elif CONFIG['COMPILE_ENVIRONMENT']: + error('No TimeStamp implementation on this platform. Build will not succeed') +src_list += [ + '%s/xpcom/ds/%s' % (TOPSRCDIR, s) for s in xpcom_ds_src +] + +xpcom_glue_src = [ + 'BlockingResourceBase.cpp', + 'nsArrayEnumerator.cpp', + 'nsClassInfoImpl.cpp', + 'nsCOMArray.cpp', + 'nsCOMPtr.cpp', + 'nsCRTGlue.cpp', + 'nsComponentManagerUtils.cpp', + 'nsEnumeratorUtils.cpp', + 'GenericFactory.cpp', + 'nsID.cpp', + 'nsISupportsImpl.cpp', + 'nsMemory.cpp', + 'nsProxyRelease.cpp', + 'nsQuickSort.cpp', + 'nsTArray.cpp', + 'nsTHashtable.cpp', + 'nsTObserverArray.cpp', + 'nsThreadUtils.cpp', + 'nsWeakReference.cpp', + 'pldhash.cpp', +] +src_list += [ + '%s/xpcom/glue/%s' % (TOPSRCDIR, s) for s in xpcom_glue_src +] + +xpcom_io_src = [ + 'nsNativeCharsetUtils.cpp', +] +src_list += [ + '%s/xpcom/io/%s' % (TOPSRCDIR, s) for s in xpcom_io_src +] + +xpcom_string_src = [ + 'nsDependentSubstring.cpp', + 'nsPromiseFlatString.cpp', + 'nsReadableUtils.cpp', + 'nsString.cpp', + 'nsStringComparator.cpp', + 'nsStringObsolete.cpp', + 'nsSubstring.cpp', + 'nsSubstringTuple.cpp', +] +if CONFIG['INTEL_ARCHITECTURE']: + xpcom_string_src += ['nsUTF8UtilsSSE2.cpp'] +src_list += [ + '%s/xpcom/string/%s' % (TOPSRCDIR, s) for s in xpcom_string_src +] + +xpcom_threads_src = [ + 'LazyIdleThread.cpp', + 'nsEnvironment.cpp', + 'nsEventQueue.cpp', + 'nsMemoryPressure.cpp', + 'nsProcessCommon.cpp', + 'nsThread.cpp', + 'nsThreadManager.cpp', + 'nsThreadPool.cpp', + 'nsTimerImpl.cpp', + 'TimerThread.cpp', +] +src_list += [ + '%s/xpcom/threads/%s' % (TOPSRCDIR, s) for s in xpcom_threads_src +] + + +SOURCES += sorted(src_list) + +if CONFIG['INTEL_ARCHITECTURE']: + sse_string_path = '%s/xpcom/string/nsUTF8UtilsSSE2.cpp' % TOPSRCDIR + SOURCES[sse_string_path].flags += CONFIG['SSE2_FLAGS'] + +GENERATED_INCLUDES += ['..'] +LOCAL_INCLUDES = [ + '../base', + '../build', + '../components', + '../ds', + '../glue', + '../threads', + '/netwerk/standalone/', + '/xpcom/reflect/xptinfo/', +] + +DEFINES['MOZILLA_INTERNAL_API'] = True +DEFINES['MOZILLA_XPCOMRT_API'] = True +DEFINES['MOZILLA_EXTERNAL_LINKAGE'] = True + +include('/ipc/chromium/chromium-config.mozbuild') + +SPHINX_TREES['libxpcomrt'] = 'docs' diff --git a/xpcom/moz.build b/xpcom/moz.build index 565315b23be..3e1a89990c9 100644 --- a/xpcom/moz.build +++ b/xpcom/moz.build @@ -24,6 +24,7 @@ DIRS += [ 'system', '../chrome', 'build', + 'libxpcomrt', ] if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_DEBUG']: diff --git a/xpcom/string/nsSubstring.cpp b/xpcom/string/nsSubstring.cpp index 5c0d75973e2..6c2024e1d49 100644 --- a/xpcom/string/nsSubstring.cpp +++ b/xpcom/string/nsSubstring.cpp @@ -114,11 +114,9 @@ ReleaseData(void* aData, uint32_t aFlags) } else if (aFlags & nsSubstring::F_OWNED) { free(aData); STRING_STAT_INCREMENT(AdoptFree); -#ifdef NS_BUILD_REFCNT_LOGGING // Treat this as destruction of a "StringAdopt" object for leak // tracking purposes. - NS_LogDtor(aData, "StringAdopt", 1); -#endif // NS_BUILD_REFCNT_LOGGING + MOZ_LOG_DTOR(aData, "StringAdopt", 1); } // otherwise, nothing to do. } diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp index 12116b37595..e871583b794 100644 --- a/xpcom/string/nsTSubstring.cpp +++ b/xpcom/string/nsTSubstring.cpp @@ -18,9 +18,7 @@ nsTSubstring_CharT::nsTSubstring_CharT(char_type* aData, size_type aLength, { if (aFlags & F_OWNED) { STRING_STAT_INCREMENT(Adopt); -#ifdef NS_BUILD_REFCNT_LOGGING - NS_LogCtor(mData, "StringAdopt", 1); -#endif + MOZ_LOG_CTOR(mData, "StringAdopt", 1); } } #endif /* XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE */ @@ -460,11 +458,9 @@ nsTSubstring_CharT::Adopt(char_type* aData, size_type aLength) SetDataFlags(F_TERMINATED | F_OWNED); STRING_STAT_INCREMENT(Adopt); -#ifdef NS_BUILD_REFCNT_LOGGING // Treat this as construction of a "StringAdopt" object for leak // tracking purposes. - NS_LogCtor(mData, "StringAdopt", 1); -#endif // NS_BUILD_REFCNT_LOGGING + MOZ_LOG_CTOR(mData, "StringAdopt", 1); } else { SetIsVoid(true); } diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index ce43c3d64bc..c599b5fcbe7 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -179,8 +179,10 @@ LazyIdleThread::EnsureThread() void LazyIdleThread::InitThread() { +#if !defined(MOZILLA_XPCOMRT_API) char aLocal; profiler_register_thread(mName.get(), &aLocal); +#endif // !defined(MOZILLA_XPCOMRT_API) PR_SetCurrentThreadName(mName.get()); @@ -211,7 +213,9 @@ LazyIdleThread::CleanupThread() mThreadIsShuttingDown = true; } +#if !defined(MOZILLA_XPCOMRT_API) profiler_unregister_thread(); +#endif // !defined(MOZILLA_XPCOMRT_API) } void diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 52ac1ca2de8..d6224c6b2d6 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -6,7 +6,9 @@ #include "nsThread.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "base/message_loop.h" +#endif // !defined(MOZILLA_XPCOMRT_API) // Chromium's logging can sometimes leak through... #ifdef LOG @@ -21,13 +23,16 @@ #include "pratom.h" #include "prlog.h" #include "nsIObserverService.h" +#if !defined(MOZILLA_XPCOMRT_API) #include "mozilla/HangMonitor.h" #include "mozilla/IOInterposer.h" #include "mozilla/ipc/MessageChannel.h" +#include "mozilla/ipc/BackgroundChild.h" +#endif // defined(MOZILLA_XPCOMRT_API) #include "mozilla/Services.h" #include "nsXPCOMPrivate.h" #include "mozilla/ChaosMode.h" -#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/TimeStamp.h" #ifdef MOZ_CRASHREPORTER #include "nsServiceManagerUtils.h" @@ -264,7 +269,9 @@ public: NS_IMETHOD Run() { mThread->mShutdownContext = mShutdownContext; +#if !defined(MOZILLA_XPCOMRT_API) MessageLoop::current()->Quit(); +#endif // !defined(MOZILLA_XPCOMRT_API) return NS_OK; } private: @@ -315,7 +322,9 @@ SetupCurrentThreadForChaosMode() /*static*/ void nsThread::ThreadFunc(void* aArg) { +#if !defined(MOZILLA_XPCOMRT_API) using mozilla::ipc::BackgroundChild; +#endif // !defined(MOZILLA_XPCOMRT_API) nsThread* self = static_cast(aArg); // strong reference self->mThread = PR_GetCurrentThread(); @@ -328,7 +337,9 @@ nsThread::ThreadFunc(void* aArg) static_cast(nsThreadManager::get()->GetCurrentThreadStatusInfo()); #endif +#if !defined(MOZILLA_XPCOMRT_API) mozilla::IOInterposer::RegisterCurrentThread(); +#endif // !defined(MOZILLA_XPCOMRT_API) // Wait for and process startup event nsCOMPtr event; @@ -340,6 +351,11 @@ nsThread::ThreadFunc(void* aArg) event = nullptr; { +#if defined(MOZILLA_XPCOMRT_API) + while(!self->mShutdownContext) { + NS_ProcessNextEvent(); + } +#else // Scope for MessageLoop. nsAutoPtr loop( new MessageLoop(MessageLoop::TYPE_MOZILLA_NONMAINTHREAD)); @@ -348,6 +364,7 @@ nsThread::ThreadFunc(void* aArg) loop->Run(); BackgroundChild::CloseForCurrentThread(); +#endif // defined(MOZILLA_XPCOMRT_API) // Do NS_ProcessPendingEvents but with special handling to set // mEventsAreDoomed atomically with the removal of the last event. The key @@ -370,7 +387,9 @@ nsThread::ThreadFunc(void* aArg) } } +#if !defined(MOZILLA_XPCOMRT_API) mozilla::IOInterposer::UnregisterCurrentThread(); +#endif // !defined(MOZILLA_XPCOMRT_API) // Inform the threadmanager that this thread is going away nsThreadManager::get()->UnregisterCurrentThread(self); @@ -736,9 +755,11 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) { LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, aMayWait, mRunningEvent)); +#if !defined(MOZILLA_XPCOMRT_API) // If we're on the main thread, we shouldn't be dispatching CPOWs. MOZ_RELEASE_ASSERT(mIsMainThread != MAIN_THREAD || !ipc::ParentProcessIsBlocked()); +#endif // !defined(MOZILLA_XPCOMRT_API) if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) { return NS_ERROR_NOT_SAME_THREAD; @@ -754,9 +775,11 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) // and repeat the nested event loop since its state change hasn't happened yet. bool reallyWait = aMayWait && (mRunningEvent > 0 || !ShuttingDown()); +#if !defined(MOZILLA_XPCOMRT_API) if (MAIN_THREAD == mIsMainThread && reallyWait) { HangMonitor::Suspend(); } +#endif // !defined(MOZILLA_XPCOMRT_API) // Fire a memory pressure notification, if we're the main thread and one is // pending. @@ -835,9 +858,11 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) if (event) { LOG(("THRD(%p) running [%p]\n", this, event.get())); +#if !defined(MOZILLA_XPCOMRT_API) if (MAIN_THREAD == mIsMainThread) { HangMonitor::NotifyActivity(); } +#endif // !defined(MOZILLA_XPCOMRT_API) event->Run(); } else if (aMayWait) { MOZ_ASSERT(ShuttingDown(), diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index 221a0c7f20f..0d4b98ced03 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -563,8 +563,10 @@ nsTimerImpl::Fire() } #endif +#if !defined(MOZILLA_XPCOMRT_API) PROFILER_LABEL("Timer", "Fire", js::ProfileEntry::Category::OTHER); +#endif #ifdef MOZ_TASK_TRACER // mTracedTask is an instance of FakeTracedTask created by