diff --git a/accessible/src/base/TextAttrs.cpp b/accessible/src/base/TextAttrs.cpp index 3c963fc58877..9ae0c665025e 100644 --- a/accessible/src/base/TextAttrs.cpp +++ b/accessible/src/base/TextAttrs.cpp @@ -621,7 +621,7 @@ TextAttrsMgr::FontWeightTextAttr:: if (font->IsSyntheticBold()) return 700; -#ifdef MOZ_PANGO +#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT) // On Linux, font->GetStyle()->weight will give the absolute weight requested // of the font face. The Linux code uses the gfxFontEntry constructor which // doesn't initialize the weight field. diff --git a/addon-sdk/source/lib/sdk/test/harness.js b/addon-sdk/source/lib/sdk/test/harness.js index 5bb12a59f890..84362075898e 100644 --- a/addon-sdk/source/lib/sdk/test/harness.js +++ b/addon-sdk/source/lib/sdk/test/harness.js @@ -377,11 +377,7 @@ function getPotentialLeaks() { let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - let enm = mgr.enumerateReporters(); - while (enm.hasMoreElements()) { - let mr = enm.getNext().QueryInterface(Ci.nsIMemoryReporter); - mr.collectReports(logReporter, null); - } + mgr.getReportsForThisProcess(logReporter, null); return { compartments: compartments, windows: windows }; } diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js index f6fdca0bbea0..0b163cbd44f9 100644 --- a/b2g/components/ContentPermissionPrompt.js +++ b/b2g/components/ContentPermissionPrompt.js @@ -5,7 +5,7 @@ "use strict" function debug(str) { - //dump("-*- ContentPermissionPrompt: " + str + "\n"); + //dump("-*- ContentPermissionPrompt: " + s + "\n"); } const Ci = Components.interfaces; @@ -13,14 +13,11 @@ const Cr = Components.results; const Cu = Components.utils; const Cc = Components.classes; -const PROMPT_FOR_UNKNOWN = ["audio-capture", - "desktop-notification", - "geolocation", - "video-capture"]; +const PROMPT_FOR_UNKNOWN = ["geolocation", "desktop-notification", + "audio-capture"]; // Due to privary issue, permission requests like GetUserMedia should prompt // every time instead of providing session persistence. -const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"]; -const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"]; +const PERMISSION_NO_SESSION = ["audio-capture"]; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -44,21 +41,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "@mozilla.org/telephony/audiomanager;1", "nsIAudioManager"); -/** - * aTypesInfo is an array of {permission, access, action, deny} which keeps - * the information of each permission. This arrary is initialized in - * ContentPermissionPrompt.prompt and used among functions. - * - * aTypesInfo[].permission : permission name - * aTypesInfo[].access : permission name + request.access - * aTypesInfo[].action : the default action of this permission - * aTypesInfo[].deny : true if security manager denied this app's origin - * principal. - * Note: - * aTypesInfo[].permission will be sent to prompt only when - * aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false. - */ -function rememberPermission(aTypesInfo, aPrincipal, aSession) +function rememberPermission(aPermission, aPrincipal, aSession) { function convertPermToAllow(aPerm, aPrincipal) { @@ -66,13 +49,12 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession) permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm); if (type == Ci.nsIPermissionManager.PROMPT_ACTION || (type == Ci.nsIPermissionManager.UNKNOWN_ACTION && - PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) { - debug("add " + aPerm + " to permission manager with ALLOW_ACTION"); + PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) { if (!aSession) { permissionManager.addFromPrincipal(aPrincipal, aPerm, Ci.nsIPermissionManager.ALLOW_ACTION); - } else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) { + } else if (PERMISSION_NO_SESSION.indexOf(aPermission) < 0) { permissionManager.addFromPrincipal(aPrincipal, aPerm, Ci.nsIPermissionManager.ALLOW_ACTION, @@ -81,18 +63,14 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession) } } - for (let i in aTypesInfo) { - // Expand the permission to see if we have multiple access properties - // to convert - let perm = aTypesInfo[i].permission; - let access = PermissionsTable[perm].access; - if (access) { - for (let idx in access) { - convertPermToAllow(perm + "-" + access[idx], aPrincipal); - } - } else { - convertPermToAllow(perm, aPrincipal); + // Expand the permission to see if we have multiple access properties to convert + let access = PermissionsTable[aPermission].access; + if (access) { + for (let idx in access) { + convertPermToAllow(aPermission + "-" + access[idx], aPrincipal); } + } else { + convertPermToAllow(aPermission, aPrincipal); } } @@ -100,66 +78,23 @@ function ContentPermissionPrompt() {} ContentPermissionPrompt.prototype = { - handleExistingPermission: function handleExistingPermission(request, - typesInfo) { - typesInfo.forEach(function(type) { - type.action = - Services.perms.testExactPermissionFromPrincipal(request.principal, - type.access); - if (type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION && - PROMPT_FOR_UNKNOWN.indexOf(type.access) >= 0) { - type.action = Ci.nsIPermissionManager.PROMPT_ACTION; - } - }); - - // If all permissions are allowed already, call allow() without prompting. - let checkAllowPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) { - return true; - } - return false; - } - if (typesInfo.every(checkAllowPermission)) { - debug("all permission requests are allowed"); + handleExistingPermission: function handleExistingPermission(request) { + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let result = Services.perms.testExactPermissionFromPrincipal(request.principal, access); + if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { request.allow(); return true; } - - // If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel() - // without prompting. - let checkDenyPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.DENY_ACTION || - type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) { - return true; - } - return false; - } - if (typesInfo.every(checkDenyPermission)) { - debug("all permission requests are denied"); + if (result == Ci.nsIPermissionManager.DENY_ACTION || + result == Ci.nsIPermissionManager.UNKNOWN_ACTION && PROMPT_FOR_UNKNOWN.indexOf(access) < 0) { request.cancel(); return true; } return false; }, - // multiple requests should be audio and video - checkMultipleRequest: function checkMultipleRequest(typesInfo) { - if (typesInfo.length == 1) { - return true; - } else if (typesInfo.length > 1) { - let checkIfAllowMultiRequest = function(type) { - return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1); - } - if (typesInfo.every(checkIfAllowMultiRequest)) { - debug("legal multiple requests"); - return true; - } - } - - return false; - }, - - handledByApp: function handledByApp(request, typesInfo) { + handledByApp: function handledByApp(request) { if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID || request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) { // This should not really happen @@ -171,94 +106,49 @@ ContentPermissionPrompt.prototype = { .getService(Ci.nsIAppsService); let app = appsService.getAppByLocalId(request.principal.appId); - // Check each permission if it's denied by permission manager with app's - // URL. - let notDenyAppPrincipal = function(type) { - let url = Services.io.newURI(app.origin, null, null); - let principal = secMan.getAppCodebasePrincipal(url, - request.principal.appId, - /*mozbrowser*/false); - let result = Services.perms.testExactPermissionFromPrincipal(principal, - type.access); + let url = Services.io.newURI(app.origin, null, null); + let principal = secMan.getAppCodebasePrincipal(url, request.principal.appId, + /*mozbrowser*/false); + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let result = Services.perms.testExactPermissionFromPrincipal(principal, access); - if (result == Ci.nsIPermissionManager.ALLOW_ACTION || - result == Ci.nsIPermissionManager.PROMPT_ACTION) { - type.deny = false; - } - return !type.deny; - } - if (typesInfo.filter(notDenyAppPrincipal).length === 0) { - request.cancel(); - return true; + if (result == Ci.nsIPermissionManager.ALLOW_ACTION || + result == Ci.nsIPermissionManager.PROMPT_ACTION) { + return false; } - return false; + request.cancel(); + return true; }, - handledByPermissionType: function handledByPermissionType(request, typesInfo) { - for (let i in typesInfo) { - if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) && - permissionSpecificChecker[typesInfo[i].permission](request)) { - return true; - } - } - - return false; + handledByPermissionType: function handledByPermissionType(request) { + return permissionSpecificChecker.hasOwnProperty(request.type) + ? permissionSpecificChecker[request.type](request) + : false; }, _id: 0, prompt: function(request) { if (secMan.isSystemPrincipal(request.principal)) { request.allow(); - return; + return true; } - // Initialize the typesInfo and set the default value. - let typesInfo = []; - let perms = request.types.QueryInterface(Ci.nsIArray); - for (let idx = 0; idx < perms.length; idx++) { - let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType); - let tmp = { - permission: perm.type, - access: (perm.access && perm.access !== "unused") ? - perm.type + "-" + perm.access : perm.type, - deny: true, - action: Ci.nsIPermissionManager.UNKNOWN_ACTION - }; - typesInfo.push(tmp); - } - if (typesInfo.length == 0) { - request.cancel(); - return; - } - - if(!this.checkMultipleRequest(typesInfo)) { - request.cancel(); - return; - } - - if (this.handledByApp(request, typesInfo) || - this.handledByPermissionType(request, typesInfo)) { + if (this.handledByApp(request) || + this.handledByPermissionType(request)) { return; } // returns true if the request was handled - if (this.handleExistingPermission(request, typesInfo)) { + if (this.handleExistingPermission(request)) return; - } - - // prompt PROMPT_ACTION request only. - typesInfo.forEach(function(aType, aIndex) { - if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) { - typesInfo.splice(aIndex); - } - }); let frame = request.element; let requestId = this._id++; if (!frame) { - this.delegatePrompt(request, requestId, typesInfo); + this.delegatePrompt(request, requestId); return; } @@ -273,7 +163,7 @@ ContentPermissionPrompt.prototype = { if (evt.detail.visible === true) return; - self.cancelPrompt(request, requestId, typesInfo); + self.cancelPrompt(request, requestId); cancelRequest(); } @@ -290,7 +180,7 @@ ContentPermissionPrompt.prototype = { // away but the request is still here. frame.addEventListener("mozbrowservisibilitychange", onVisibilityChange); - self.delegatePrompt(request, requestId, typesInfo, function onCallback() { + self.delegatePrompt(request, requestId, function onCallback() { frame.removeEventListener("mozbrowservisibilitychange", onVisibilityChange); }); }; @@ -301,17 +191,22 @@ ContentPermissionPrompt.prototype = { } }, - cancelPrompt: function(request, requestId, typesInfo) { - this.sendToBrowserWindow("cancel-permission-prompt", request, requestId, - typesInfo); + cancelPrompt: function(request, requestId) { + this.sendToBrowserWindow("cancel-permission-prompt", request, requestId); }, - delegatePrompt: function(request, requestId, typesInfo, callback) { + delegatePrompt: function(request, requestId, callback) { + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let principal = request.principal; - this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo, - function(type, remember) { + this._permission = access; + this._uri = principal.URI.spec; + this._origin = principal.origin; + + this.sendToBrowserWindow("permission-prompt", request, requestId, function(type, remember) { if (type == "permission-allow") { - rememberPermission(typesInfo, request.principal, !remember); + rememberPermission(request.type, principal, !remember); if (callback) { callback(); } @@ -319,20 +214,14 @@ ContentPermissionPrompt.prototype = { return; } - let addDenyPermission = function(type) { - debug("add " + type.permission + - " to permission manager with DENY_ACTION"); - if (remember) { - Services.perms.addFromPrincipal(request.principal, type.access, - Ci.nsIPermissionManager.DENY_ACTION); - } else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) { - Services.perms.addFromPrincipal(request.principal, type.access, - Ci.nsIPermissionManager.DENY_ACTION, - Ci.nsIPermissionManager.EXPIRE_SESSION, - 0); - } + if (remember) { + Services.perms.addFromPrincipal(principal, access, + Ci.nsIPermissionManager.DENY_ACTION); + } else { + Services.perms.addFromPrincipal(principal, access, + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION, 0); } - typesInfo.forEach(addDenyPermission); if (callback) { callback(); @@ -341,7 +230,7 @@ ContentPermissionPrompt.prototype = { }); }, - sendToBrowserWindow: function(type, request, requestId, typesInfo, callback) { + sendToBrowserWindow: function(type, request, requestId, callback) { let browser = Services.wm.getMostRecentWindow("navigator:browser"); let content = browser.getContentWindow(); if (!content) @@ -364,15 +253,10 @@ ContentPermissionPrompt.prototype = { principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) ? true : request.remember; - let permissions = {}; - for (let i in typesInfo) { - debug("prompt " + typesInfo[i].permission); - permissions[typesInfo[i].permission] = []; - } let details = { type: type, - permissions: permissions, + permission: request.type, id: requestId, origin: principal.origin, isApp: isApp, @@ -405,5 +289,6 @@ ContentPermissionPrompt.prototype = { }; })(); + //module initialization this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]); diff --git a/b2g/components/FilePicker.js b/b2g/components/FilePicker.js index 8a02917a3868..e121a29433e7 100644 --- a/b2g/components/FilePicker.js +++ b/b2g/components/FilePicker.js @@ -47,8 +47,8 @@ FilePicker.prototype = { /* members */ mParent: undefined, - mExtraProps: {}, - mFilterTypes: [], + mExtraProps: undefined, + mFilterTypes: undefined, mFileEnumerator: undefined, mFilePickerShownCallback: undefined, @@ -56,6 +56,8 @@ FilePicker.prototype = { init: function(parent, title, mode) { this.mParent = parent; + this.mExtraProps = {}; + this.mFilterTypes = []; this.mMode = mode; if (mode != Ci.nsIFilePicker.modeOpen && @@ -177,12 +179,13 @@ FilePicker.prototype = { return; } - var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); - var mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, ''); - var name = 'blob'; - if (mimeInfo) { - name += '.' + mimeInfo.primaryExtension; + if (data.result.blob.type) { + let mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + let mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, ''); + if (mimeInfo) { + name += '.' + mimeInfo.primaryExtension; + } } let file = new this.mParent.File(data.result.blob, diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 087f2886b7d7..d35f00941a7c 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "bb23044d4a97be1381be924064817dddbd2ea47b", + "revision": "9f1117fde1d221d998c065a87e0614af6239b585", "repo_path": "/integration/gaia-central" } diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index c5d993f437d1..b458b436b41b 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -2037,21 +2037,13 @@ ContentPermissionPrompt.prototype = { prompt: function CPP_prompt(request) { - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - const kFeatureKeys = { "geolocation" : "geo", "desktop-notification" : "desktop-notification", "pointerLock" : "pointerLock", }; // Make sure that we support the request. - if (!(perm.type in kFeatureKeys)) { + if (!(request.type in kFeatureKeys)) { return; } @@ -2063,7 +2055,7 @@ ContentPermissionPrompt.prototype = { return; var autoAllow = false; - var permissionKey = kFeatureKeys[perm.type]; + var permissionKey = kFeatureKeys[request.type]; var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey); if (result == Ci.nsIPermissionManager.DENY_ACTION) { @@ -2074,7 +2066,7 @@ ContentPermissionPrompt.prototype = { if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { autoAllow = true; // For pointerLock, we still want to show a warning prompt. - if (perm.type != "pointerLock") { + if (request.type != "pointerLock") { request.allow(); return; } @@ -2088,7 +2080,7 @@ ContentPermissionPrompt.prototype = { return; // Show the prompt. - switch (perm.type) { + switch (request.type) { case "geolocation": this._promptGeo(request); break; diff --git a/browser/metro/base/content/helperui/IndexedDB.js b/browser/metro/base/content/helperui/IndexedDB.js index c62fc4734da6..8c347ab5e36f 100644 --- a/browser/metro/base/content/helperui/IndexedDB.js +++ b/browser/metro/base/content/helperui/IndexedDB.js @@ -44,8 +44,6 @@ let IndexedDB = { } let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt); - let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - types.appendElement({type: type, access: "unused"}, false); // If the user waits a long time before responding, we default to UNKNOWN_ACTION. let timeoutId = setTimeout(function() { @@ -62,7 +60,7 @@ let IndexedDB = { } prompt.prompt({ - types: types, + type: type, uri: Services.io.newURI(payload.location, null, null), window: null, element: aMessage.target, diff --git a/browser/metro/components/ContentPermissionPrompt.js b/browser/metro/components/ContentPermissionPrompt.js index c6ac9f5a589a..44a69c2d5662 100644 --- a/browser/metro/components/ContentPermissionPrompt.js +++ b/browser/metro/components/ContentPermissionPrompt.js @@ -56,8 +56,8 @@ ContentPermissionPrompt.prototype = { return chromeWin.Browser.getNotificationBox(request.element); }, - handleExistingPermission: function handleExistingPermission(request, type) { - let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type); + handleExistingPermission: function handleExistingPermission(request) { + let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type); if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { request.allow(); return true; @@ -70,28 +70,20 @@ ContentPermissionPrompt.prototype = { }, prompt: function(request) { - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - // returns true if the request was handled - if (this.handleExistingPermission(request, perm.type)) + if (this.handleExistingPermission(request)) return; let pm = Services.perms; let notificationBox = this.getNotificationBoxForRequest(request); let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); - let notification = notificationBox.getNotificationWithValue(perm.type); + let notification = notificationBox.getNotificationWithValue(request.type); if (notification) return; - let entityName = kEntities[perm.type]; - let icon = kIcons[perm.type] || ""; + let entityName = kEntities[request.type]; + let icon = kIcons[request.type] || ""; let buttons = [{ label: browserBundle.GetStringFromName(entityName + ".allow"), @@ -104,7 +96,7 @@ ContentPermissionPrompt.prototype = { label: browserBundle.GetStringFromName("contentPermissions.alwaysForSite"), accessKey: "", callback: function(notification) { - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION); request.allow(); } }, @@ -112,7 +104,7 @@ ContentPermissionPrompt.prototype = { label: browserBundle.GetStringFromName("contentPermissions.neverForSite"), accessKey: "", callback: function(notification) { - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION); request.cancel(); } }]; @@ -120,12 +112,12 @@ ContentPermissionPrompt.prototype = { let message = browserBundle.formatStringFromName(entityName + ".wantsTo", [request.principal.URI.host], 1); let newBar = notificationBox.appendNotification(message, - perm.type, + request.type, icon, notificationBox.PRIORITY_WARNING_MEDIUM, buttons); - if (perm.type == "geolocation") { + if (request.type == "geolocation") { // Add the "learn more" link. let link = newBar.ownerDocument.createElement("label"); link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore")); diff --git a/configure.in b/configure.in index 2ba11b377ee5..cdc1ba28af4a 100644 --- a/configure.in +++ b/configure.in @@ -3983,7 +3983,6 @@ LIBJPEG_TURBO_ASFLAGS= LIBJPEG_TURBO_X86_ASM= LIBJPEG_TURBO_X64_ASM= LIBJPEG_TURBO_ARM_ASM= -MOZ_PANGO=1 MOZ_PERMISSIONS=1 MOZ_PLACES=1 MOZ_SOCIAL=1 @@ -4731,34 +4730,16 @@ AC_DEFINE_UNQUOTED(MOZ_DISTRIBUTION_ID,"$MOZ_DISTRIBUTION_ID") AC_SUBST(MOZ_DISTRIBUTION_ID) -dnl ======================================================== -dnl complex text support off by default -dnl ======================================================== -MOZ_ARG_DISABLE_BOOL(pango, -[ --disable-pango Disable usage of Pango ], - MOZ_PANGO=, - MOZ_PANGO=1) - dnl ======================================================== dnl = Pango dnl ======================================================== if test "$MOZ_ENABLE_GTK" -o "$MOZ_ENABLE_QT" then - AC_SUBST(MOZ_PANGO) + PKG_CHECK_MODULES(_PANGOCHK, pango >= $PANGO_VERSION) - if test "$MOZ_PANGO" - then - PKG_CHECK_MODULES(_PANGOCHK, pango >= $PANGO_VERSION) - - PKG_CHECK_MODULES(MOZ_PANGO, pango >= $PANGO_VERSION pangoft2 >= $PANGO_VERSION pangocairo >= $PANGO_VERSION) - AC_SUBST(MOZ_PANGO_CFLAGS) - AC_SUBST(MOZ_PANGO_LIBS) - AC_DEFINE(MOZ_PANGO) - else - PKG_CHECK_MODULES(FT2, freetype2 > 6.1.0) - AC_SUBST(FT2_CFLAGS) - AC_SUBST(FT2_LIBS) - fi + PKG_CHECK_MODULES(MOZ_PANGO, pango >= $PANGO_VERSION pangoft2 >= $PANGO_VERSION pangocairo >= $PANGO_VERSION) + AC_SUBST(MOZ_PANGO_CFLAGS) + AC_SUBST(MOZ_PANGO_LIBS) fi dnl ======================================================== diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 982bd0a4506f..01818e9c3ca8 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -642,13 +642,13 @@ nsDOMMemoryFile::DataOwner::sDataOwners; /* static */ bool nsDOMMemoryFile::DataOwner::sMemoryReporterRegistered; -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMMemoryFileDataOwnerMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(DOMMemoryFileDataOwnerMallocSizeOf) class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL - : public MemoryMultiReporter + : public nsIMemoryReporter { public: - nsDOMMemoryFileDataOwnerMemoryReporter() {} + NS_DECL_THREADSAFE_ISUPPORTS NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback, nsISupports *aClosure) @@ -723,6 +723,8 @@ public: } }; +NS_IMPL_ISUPPORTS1(nsDOMMemoryFileDataOwnerMemoryReporter, nsIMemoryReporter) + /* static */ void nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered() { diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 482008417ed1..bf6c2119e09b 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -217,8 +217,6 @@ #include "mozilla/dom/XPathEvaluator.h" #include "nsIDocumentEncoder.h" #include "nsIStructuredCloneContainer.h" -#include "nsIMutableArray.h" -#include "nsContentPermissionHelper.h" using namespace mozilla; using namespace mozilla::dom; @@ -2645,6 +2643,33 @@ nsDocument::InitCSP(nsIChannel* aChannel) #endif nsresult rv; + + // If Document is an app check to see if we already set CSP and return early + // if that is indeed the case. + // + // In general (see bug 947831), we should not be setting CSP on a principal + // that aliases another document. For non-app code this is not a problem + // since we only share the underlying principal with nested browsing + // contexts for which a header cannot be set (e.g., about:blank and + // about:srcodoc iframes) and thus won't try to set the CSP again. This + // check ensures that we do not try to set CSP for an app. + if (applyAppDefaultCSP || applyAppManifestCSP) { + nsCOMPtr csp; + rv = principal->GetCsp(getter_AddRefs(csp)); + NS_ENSURE_SUCCESS(rv, rv); + + if (csp) { +#ifdef PR_LOGGING + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("%s %s %s", + "This document is sharing principal with another document.", + "Since the document is an app, CSP was already set.", + "Skipping attempt to set CSP.")); +#endif + return NS_OK; + } + } + + // create new CSP object csp = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv); if (NS_FAILED(rv)) { @@ -2724,16 +2749,12 @@ nsDocument::InitCSP(nsIChannel* aChannel) } } - if (csp) { - // Copy into principal - nsIPrincipal* principal = GetPrincipal(); - rv = principal->SetCsp(csp); - NS_ENSURE_SUCCESS(rv, rv); + rv = principal->SetCsp(csp); + NS_ENSURE_SUCCESS(rv, rv); #ifdef PR_LOGGING - PR_LOG(gCspPRLog, PR_LOG_DEBUG, - ("Inserted CSP into principal %p", principal)); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("Inserted CSP into principal %p", principal)); #endif - } return NS_OK; } @@ -10731,11 +10752,17 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest, nsIContentPermissionRequest) NS_IMETHODIMP -nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes) +nsPointerLockPermissionRequest::GetType(nsACString& aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "pointerLock"; + return NS_OK; +} + +NS_IMETHODIMP +nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess) +{ + aAccess = "unused"; + return NS_OK; } NS_IMETHODIMP diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 4c1bcb56949c..30cd4b4c29d1 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -1130,13 +1130,11 @@ struct MessageManagerReferentCount namespace mozilla { namespace dom { -class MessageManagerReporter MOZ_FINAL : public MemoryMultiReporter +class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter { public: - MessageManagerReporter() {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCallback, - nsISupports* aData); + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER static const size_t kSuspectReferentCount = 300; protected: @@ -1144,6 +1142,8 @@ protected: MessageManagerReferentCount* aReferentCount); }; +NS_IMPL_ISUPPORTS1(MessageManagerReporter, nsIMemoryReporter) + static PLDHashOperator CollectMessageListenerData(const nsAString& aKey, nsAutoTObserverArray* aListeners, diff --git a/content/canvas/src/WebGLContextReporter.cpp b/content/canvas/src/WebGLContextReporter.cpp index f5207076a742..9349fe98f3ea 100644 --- a/content/canvas/src/WebGLContextReporter.cpp +++ b/content/canvas/src/WebGLContextReporter.cpp @@ -85,7 +85,7 @@ WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport, return NS_OK; } -NS_IMPL_ISUPPORTS_INHERITED0(WebGLMemoryTracker, MemoryMultiReporter) +NS_IMPL_ISUPPORTS1(WebGLMemoryTracker, nsIMemoryReporter) StaticRefPtr WebGLMemoryTracker::sUniqueInstance; @@ -113,7 +113,7 @@ WebGLMemoryTracker::~WebGLMemoryTracker() UnregisterWeakMemoryReporter(this); } -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLBufferMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(WebGLBufferMallocSizeOf) int64_t WebGLMemoryTracker::GetBufferCacheMemoryUsed() { @@ -131,7 +131,7 @@ WebGLMemoryTracker::GetBufferCacheMemoryUsed() { return result; } -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLShaderMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(WebGLShaderMallocSizeOf) int64_t WebGLMemoryTracker::GetShaderSize() { diff --git a/content/canvas/src/WebGLMemoryTracker.h b/content/canvas/src/WebGLMemoryTracker.h index fcb7889f563f..9e83501a6422 100644 --- a/content/canvas/src/WebGLMemoryTracker.h +++ b/content/canvas/src/WebGLMemoryTracker.h @@ -19,9 +19,10 @@ namespace mozilla { -class WebGLMemoryTracker : public MemoryMultiReporter +class WebGLMemoryTracker : public nsIMemoryReporter { - NS_DECL_ISUPPORTS + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER WebGLMemoryTracker(); virtual ~WebGLMemoryTracker(); @@ -55,9 +56,6 @@ class WebGLMemoryTracker : public MemoryMultiReporter } } - NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, - nsISupports* aData); - private: static int64_t GetTextureMemoryUsed() { const ContextsArrayType & contexts = Contexts(); diff --git a/content/media/MediaDecoder.cpp b/content/media/MediaDecoder.cpp index bec0daf389d2..9ca3b7ed2ffc 100644 --- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -54,9 +54,10 @@ PRLogModuleInfo* gMediaDecoderLog; #define DECODER_LOG(type, msg) #endif -class MediaMemoryTracker : public MemoryMultiReporter +class MediaMemoryTracker : public nsIMemoryReporter { - NS_DECL_ISUPPORTS + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER MediaMemoryTracker(); virtual ~MediaMemoryTracker(); @@ -93,14 +94,11 @@ public: sUniqueInstance = nullptr; } } - - NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, - nsISupports* aData); }; StaticRefPtr MediaMemoryTracker::sUniqueInstance; -NS_IMPL_ISUPPORTS_INHERITED0(MediaMemoryTracker, MemoryMultiReporter) +NS_IMPL_ISUPPORTS1(MediaMemoryTracker, nsIMemoryReporter) NS_IMPL_ISUPPORTS1(MediaDecoder, nsIObserver) diff --git a/content/media/webrtc/MediaEngine.h b/content/media/webrtc/MediaEngine.h index c865c27bd69c..f960ce10c71f 100644 --- a/content/media/webrtc/MediaEngine.h +++ b/content/media/webrtc/MediaEngine.h @@ -5,7 +5,6 @@ #ifndef MEDIAENGINE_H_ #define MEDIAENGINE_H_ -#include "mozilla/RefPtr.h" #include "nsIDOMFile.h" #include "DOMMediaStream.h" #include "MediaStreamGraph.h" @@ -36,7 +35,7 @@ enum { kAudioTrack = 2 }; -class MediaEngine : public RefCounted +class MediaEngine { public: virtual ~MediaEngine() {} diff --git a/content/media/webrtc/MediaEngineWebRTC.cpp b/content/media/webrtc/MediaEngineWebRTC.cpp index 6ab4f857b9dd..3023f4fbc388 100644 --- a/content/media/webrtc/MediaEngineWebRTC.cpp +++ b/content/media/webrtc/MediaEngineWebRTC.cpp @@ -101,7 +101,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArrayAppendElement(vSource.get()); } else { - vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i); + vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i, mWindowId); mVideoSources.Put(uuid, vSource); // Hashtable takes ownership. aVSources->AppendElement(vSource); } diff --git a/content/media/webrtc/MediaEngineWebRTC.h b/content/media/webrtc/MediaEngineWebRTC.h index 5733c7072e16..b7ee479caad1 100644 --- a/content/media/webrtc/MediaEngineWebRTC.h +++ b/content/media/webrtc/MediaEngineWebRTC.h @@ -52,7 +52,6 @@ #include "ImageContainer.h" #include "nsGlobalWindow.h" #include "prprf.h" -#include "nsProxyRelease.h" #endif #include "NullTransport.h" @@ -74,7 +73,7 @@ class GetCameraNameRunnable; * mSources, mImageContainer, mSources, mState, mImage, mLastCapture * * MainThread: - * mDOMCameraControl, mCaptureIndex, mCameraThread, mCameraManager, + * mDOMCameraControl, mCaptureIndex, mCameraThread, mWindowId, mCameraManager, * mNativeCameraControl, mPreviewStream, mState, mLastCapture, mWidth, mHeight * * Where mWidth, mHeight, mImage are protected by mMonitor @@ -97,10 +96,11 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource public: #ifdef MOZ_B2G_CAMERA MediaEngineWebRTCVideoSource(nsDOMCameraManager* aCameraManager, - int aIndex) + int aIndex, uint64_t aWindowId) : mCameraManager(aCameraManager) , mNativeCameraControl(nullptr) , mPreviewStream(nullptr) + , mWindowId(aWindowId) , mCallbackMonitor("WebRTCCamera.CallbackMonitor") , mCaptureIndex(aIndex) , mMonitor("WebRTCCamera.Monitor") @@ -223,6 +223,7 @@ private: nsRefPtr mDOMCameraControl; nsRefPtr mNativeCameraControl; nsRefPtr mPreviewStream; + uint64_t mWindowId; mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling nsRefPtr mCameraThread; nsRefPtr mLastCapture; @@ -351,14 +352,15 @@ class MediaEngineWebRTC : public MediaEngine { public: #ifdef MOZ_B2G_CAMERA - MediaEngineWebRTC(nsDOMCameraManager* aCameraManager) + MediaEngineWebRTC(nsDOMCameraManager* aCameraManager, uint64_t aWindowId) : mMutex("mozilla::MediaEngineWebRTC") , mVideoEngine(nullptr) , mVoiceEngine(nullptr) , mVideoEngineInit(false) , mAudioEngineInit(false) - , mHasTabVideoSource(false) , mCameraManager(aCameraManager) + , mWindowId(aWindowId) + , mHasTabVideoSource(false) { AsyncLatencyLogger::Get(true)->AddRef(); mLoadMonitor = new LoadMonitor(); @@ -399,8 +401,6 @@ private: nsRefPtrHashtable mAudioSources; #ifdef MOZ_B2G_CAMERA - // XXX Should use nsMainThreadPtrHandle/etc - // MediaEngine hold this DOM object, and the MediaEngine is hold by Navigator // Their life time is always much longer than this object. Use a raw-pointer // here should be safe. @@ -409,6 +409,7 @@ private: // avoid any bad thing do to addref/release DOM-object on other thread, we use // raw-pointer for now. nsDOMCameraManager* mCameraManager; + uint64_t mWindowId; #endif nsRefPtr mLoadMonitor; diff --git a/content/media/webrtc/MediaEngineWebRTCVideo.cpp b/content/media/webrtc/MediaEngineWebRTCVideo.cpp index 1f79191ce085..2a34df7a2751 100644 --- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp +++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp @@ -312,6 +312,7 @@ nsresult MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) { LOG((__FUNCTION__)); + int error = 0; if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; } @@ -340,7 +341,7 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) } #else mState = kStarted; - int error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this); + error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this); if (error == -1) { return NS_ERROR_FAILURE; } @@ -491,9 +492,12 @@ void MediaEngineWebRTCVideoSource::AllocImpl() { MOZ_ASSERT(NS_IsMainThread()); - ErrorResult rv; - mDOMCameraControl = mCameraManager->GetCameraControl(mCaptureIndex, - this, this, rv); + mDOMCameraControl = new nsDOMCameraControl(mCaptureIndex, + mCameraThread, + this, + this, + nsGlobalWindow::GetInnerWindowWithId(mWindowId)); + mCameraManager->Register(mDOMCameraControl); } void @@ -502,7 +506,6 @@ MediaEngineWebRTCVideoSource::DeallocImpl() { mNativeCameraControl->ReleaseHardware(this, this); mNativeCameraControl = nullptr; - mDOMCameraControl = nullptr; } void diff --git a/content/svg/content/test/mochitest.ini b/content/svg/content/test/mochitest.ini index 88f73f3ed492..56ad45bc9449 100644 --- a/content/svg/content/test/mochitest.ini +++ b/content/svg/content/test/mochitest.ini @@ -45,6 +45,7 @@ support-files = skip-if = true # disabled-for-intermittent-failures--bug-701060 [test_length.xhtml] skip-if = true +[test_lengthParsing.html] [test_nonAnimStrings.xhtml] [test_non-scaling-stroke.html] [test_pathAnimInterpolation.xhtml] diff --git a/content/svg/content/test/test_lengthParsing.html b/content/svg/content/test/test_lengthParsing.html new file mode 100644 index 000000000000..a7a831b2b05d --- /dev/null +++ b/content/svg/content/test/test_lengthParsing.html @@ -0,0 +1,77 @@ + + + + + + Test transform parsing + + + + +Mozilla Bug 946529 +

+ +
+
+
+ + diff --git a/dom/apps/src/PermissionsTable.jsm b/dom/apps/src/PermissionsTable.jsm index faa68b890407..516c7c8f8005 100644 --- a/dom/apps/src/PermissionsTable.jsm +++ b/dom/apps/src/PermissionsTable.jsm @@ -323,11 +323,6 @@ this.PermissionsTable = { geolocation: { privileged: DENY_ACTION, certified: ALLOW_ACTION }, - "video-capture": { - app: PROMPT_ACTION, - privileged: PROMPT_ACTION, - certified: PROMPT_ACTION - }, }; /** diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index 996794ec6353..d20eb4174d0f 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -21,7 +21,6 @@ #include "mozilla/dom/quota/QuotaObject.h" #include "mozilla/dom/quota/UsageInfo.h" #include "mozilla/unused.h" -#include "nsContentUtils.h" #include "nsIAtom.h" #include "nsIFile.h" #include "nsIPrincipal.h" @@ -975,7 +974,7 @@ DeallocEntryChild(PAsmJSCacheEntryChild* aActor) namespace { bool -OpenFile(JS::Handle aGlobal, +OpenFile(nsIPrincipal* aPrincipal, OpenMode aOpenMode, size_t aSizeToWrite, File::AutoClose* aFile) @@ -998,17 +997,14 @@ OpenFile(JS::Handle aGlobal, return false; } - // This assumes a non-worker global. - nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal); - // If we are in a child process, we need to synchronously call into the // parent process to open the file and interact with the QuotaManager. The // child can then map the file into its address space to perform I/O. nsRefPtr file; if (IsMainProcess()) { - file = new SingleProcessRunnable(principal, aOpenMode, aSizeToWrite); + file = new SingleProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite); } else { - file = new ChildProcessRunnable(principal, aOpenMode, aSizeToWrite); + file = new ChildProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite); } if (!file->BlockUntilOpen(aFile)) { @@ -1028,7 +1024,7 @@ static const uint32_t sAsmJSCookie = 0x600d600d; static const size_t sMinCachedModuleLength = 10000; bool -OpenEntryForRead(JS::Handle aGlobal, +OpenEntryForRead(nsIPrincipal* aPrincipal, const jschar* aBegin, const jschar* aLimit, size_t* aSize, @@ -1040,7 +1036,7 @@ OpenEntryForRead(JS::Handle aGlobal, } File::AutoClose file; - if (!OpenFile(aGlobal, eOpenForRead, 0, &file)) { + if (!OpenFile(aPrincipal, eOpenForRead, 0, &file)) { return false; } @@ -1082,7 +1078,7 @@ CloseEntryForRead(JS::Handle global, } bool -OpenEntryForWrite(JS::Handle aGlobal, +OpenEntryForWrite(nsIPrincipal* aPrincipal, const jschar* aBegin, const jschar* aEnd, size_t aSize, @@ -1097,7 +1093,7 @@ OpenEntryForWrite(JS::Handle aGlobal, aSize += sizeof(AsmJSCookieType); File::AutoClose file; - if (!OpenFile(aGlobal, eOpenForWrite, aSize, &file)) { + if (!OpenFile(aPrincipal, eOpenForWrite, aSize, &file)) { return false; } diff --git a/dom/asmjscache/AsmJSCache.h b/dom/asmjscache/AsmJSCache.h index cd40fce74e45..676c9794cd45 100644 --- a/dom/asmjscache/AsmJSCache.h +++ b/dom/asmjscache/AsmJSCache.h @@ -32,10 +32,20 @@ enum OpenMode NUM_OPEN_MODES }; -// Implementation of AsmJSCacheOps, installed by nsJSEnvironment: +// Implementation of AsmJSCacheOps, installed for the main JSRuntime by +// nsJSEnvironment.cpp and DOM Worker JSRuntimes in RuntimeService.cpp. +// +// The Open* functions cannot be called directly from AsmJSCacheOps: they take +// an nsIPrincipal as the first argument instead of a Handle. The +// caller must map the object to an nsIPrincipal. +// +// These methods may be called off the main thread and guarantee not to +// access the given aPrincipal except on the main thread. In exchange, the +// caller must ensure the given principal is alive from when OpenEntryForX is +// called to when CloseEntryForX returns. bool -OpenEntryForRead(JS::Handle aGlobal, +OpenEntryForRead(nsIPrincipal* aPrincipal, const jschar* aBegin, const jschar* aLimit, size_t* aSize, @@ -47,7 +57,7 @@ CloseEntryForRead(JS::Handle aGlobal, const uint8_t* aMemory, intptr_t aHandle); bool -OpenEntryForWrite(JS::Handle aGlobal, +OpenEntryForWrite(nsIPrincipal* aPrincipal, const jschar* aBegin, const jschar* aEnd, size_t aSize, diff --git a/dom/base/nsContentPermissionHelper.cpp b/dom/base/nsContentPermissionHelper.cpp index 0aacfd634742..4ddfbe51aeb9 100644 --- a/dom/base/nsContentPermissionHelper.cpp +++ b/dom/base/nsContentPermissionHelper.cpp @@ -6,156 +6,20 @@ #include "GonkPermission.h" #include "mozilla/dom/ContentParent.h" #endif // MOZ_WIDGET_GONK +#include "nsContentPermissionHelper.h" +#include "nsIContentPermissionPrompt.h" #include "nsCOMPtr.h" #include "nsIDOMElement.h" #include "nsIPrincipal.h" #include "mozilla/dom/Element.h" -#include "mozilla/dom/PContentPermission.h" -#include "mozilla/dom/PermissionMessageUtils.h" -#include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/unused.h" #include "nsComponentManagerUtils.h" -#include "nsArrayUtils.h" -#include "nsIMutableArray.h" -#include "nsContentPermissionHelper.h" using mozilla::unused; // using namespace mozilla::dom; using namespace mozilla; -namespace mozilla { -namespace dom { - -class ContentPermissionRequestParent : public PContentPermissionRequestParent -{ - public: - ContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal); - virtual ~ContentPermissionRequestParent(); - - bool IsBeingDestroyed(); - - nsCOMPtr mPrincipal; - nsCOMPtr mElement; - nsCOMPtr mProxy; - nsTArray mRequests; - - private: - virtual bool Recvprompt(); - virtual void ActorDestroy(ActorDestroyReason why); -}; - -ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray& aRequests, - Element* aElement, - const IPC::Principal& aPrincipal) -{ - MOZ_COUNT_CTOR(ContentPermissionRequestParent); - - mPrincipal = aPrincipal; - mElement = aElement; - mRequests = aRequests; -} - -ContentPermissionRequestParent::~ContentPermissionRequestParent() -{ - MOZ_COUNT_DTOR(ContentPermissionRequestParent); -} - -bool -ContentPermissionRequestParent::Recvprompt() -{ - mProxy = new nsContentPermissionRequestProxy(); - NS_ASSERTION(mProxy, "Alloc of request proxy failed"); - if (NS_FAILED(mProxy->Init(mRequests, this))) { - mProxy->Cancel(); - } - return true; -} - -void -ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) -{ - if (mProxy) { - mProxy->OnParentDestroyed(); - } -} - -bool -ContentPermissionRequestParent::IsBeingDestroyed() -{ - // When TabParent::Destroy() is called, we are being destroyed. It's unsafe - // to send out any message now. - TabParent* tabParent = static_cast(Manager()); - return tabParent->IsDestroyed(); -} - -NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType) - -ContentPermissionType::ContentPermissionType(const nsACString& aType, - const nsACString& aAccess) -{ - mType = aType; - mAccess = aAccess; -} - -ContentPermissionType::~ContentPermissionType() -{ -} - -NS_IMETHODIMP -ContentPermissionType::GetType(nsACString& aType) -{ - aType = mType; - return NS_OK; -} - -NS_IMETHODIMP -ContentPermissionType::GetAccess(nsACString& aAccess) -{ - aAccess = mAccess; - return NS_OK; -} - -uint32_t -ConvertPermissionRequestToArray(nsTArray& aSrcArray, - nsIMutableArray* aDesArray) -{ - uint32_t len = aSrcArray.Length(); - for (uint32_t i = 0; i < len; i++) { - nsRefPtr cpt = - new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access()); - aDesArray->AppendElement(cpt, false); - } - return len; -} - -nsresult -CreatePermissionArray(const nsACString& aType, - const nsACString& aAccess, - nsIArray** aTypesArray) -{ - nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - nsRefPtr permType = new ContentPermissionType(aType, - aAccess); - types->AppendElement(permType, false); - types.forget(aTypesArray); - - return NS_OK; -} - -PContentPermissionRequestParent* -CreateContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal) -{ - return new ContentPermissionRequestParent(aRequests, element, principal); -} - -} // namespace dom -} // namespace mozilla - nsContentPermissionRequestProxy::nsContentPermissionRequestProxy() { MOZ_COUNT_CTOR(nsContentPermissionRequestProxy); @@ -167,12 +31,14 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() } nsresult -nsContentPermissionRequestProxy::Init(const nsTArray& requests, +nsContentPermissionRequestProxy::Init(const nsACString & type, + const nsACString & access, ContentPermissionRequestParent* parent) { NS_ASSERTION(parent, "null parent"); mParent = parent; - mPermissionRequests = requests; + mType = type; + mAccess = access; nsCOMPtr prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); if (!prompt) { @@ -192,14 +58,17 @@ nsContentPermissionRequestProxy::OnParentDestroyed() NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest) NS_IMETHODIMP -nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) +nsContentPermissionRequestProxy::GetType(nsACString & aType) { - nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - if (ConvertPermissionRequestToArray(mPermissionRequests, types)) { - types.forget(aTypes); - return NS_OK; - } - return NS_ERROR_FAILURE; + aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess) +{ + aAccess = mAccess; + return NS_OK; } NS_IMETHODIMP @@ -267,18 +136,10 @@ nsContentPermissionRequestProxy::Allow() } #ifdef MOZ_WIDGET_GONK - uint32_t len = mPermissionRequests.Length(); - for (uint32_t i = 0; i < len; i++) { - if (mPermissionRequests[i].type().Equals("audio-capture")) { - GonkPermissionService::GetInstance()->addGrantInfo( - "android.permission.RECORD_AUDIO", - static_cast(mParent->Manager())->Manager()->Pid()); - } - if (mPermissionRequests[i].type().Equals("video-capture")) { - GonkPermissionService::GetInstance()->addGrantInfo( - "android.permission.CAMERA", - static_cast(mParent->Manager())->Manager()->Pid()); - } + if (mType.Equals("audio-capture")) { + GonkPermissionService::GetInstance()->addGrantInfo( + "android.permission.RECORD_AUDIO", + static_cast(mParent->Manager())->Manager()->Pid()); } #endif @@ -286,3 +147,55 @@ nsContentPermissionRequestProxy::Allow() mParent = nullptr; return NS_OK; } + +namespace mozilla { +namespace dom { + +ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType, + const nsACString& aAccess, + Element* aElement, + const IPC::Principal& aPrincipal) +{ + MOZ_COUNT_CTOR(ContentPermissionRequestParent); + + mPrincipal = aPrincipal; + mElement = aElement; + mType = aType; + mAccess = aAccess; +} + +ContentPermissionRequestParent::~ContentPermissionRequestParent() +{ + MOZ_COUNT_DTOR(ContentPermissionRequestParent); +} + +bool +ContentPermissionRequestParent::Recvprompt() +{ + mProxy = new nsContentPermissionRequestProxy(); + NS_ASSERTION(mProxy, "Alloc of request proxy failed"); + if (NS_FAILED(mProxy->Init(mType, mAccess, this))) { + mProxy->Cancel(); + } + return true; +} + +void +ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) +{ + if (mProxy) { + mProxy->OnParentDestroyed(); + } +} + +bool +ContentPermissionRequestParent::IsBeingDestroyed() +{ + // When TabParent::Destroy() is called, we are being destroyed. It's unsafe + // to send out any message now. + TabParent* tabParent = static_cast(Manager()); + return tabParent->IsDestroyed(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/nsContentPermissionHelper.h b/dom/base/nsContentPermissionHelper.h index 1baf2768b92b..9a750c6efb57 100644 --- a/dom/base/nsContentPermissionHelper.h +++ b/dom/base/nsContentPermissionHelper.h @@ -6,75 +6,60 @@ #define nsContentPermissionHelper_h #include "nsIContentPermissionPrompt.h" -#include "nsTArray.h" -#include "nsIMutableArray.h" +#include "nsString.h" + +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/PContentPermissionRequestParent.h" class nsContentPermissionRequestProxy; -// Forward declare IPC::Principal here which is defined in -// PermissionMessageUtils.h. Include this file will transitively includes -// "windows.h" and it defines -// #define CreateEvent CreateEventW -// #define LoadImage LoadImageW -// That will mess up windows build. -namespace IPC { -class Principal; -} - namespace mozilla { namespace dom { class Element; -class PermissionRequest; -class ContentPermissionRequestParent; -class PContentPermissionRequestParent; -class ContentPermissionType : public nsIContentPermissionType +class ContentPermissionRequestParent : public PContentPermissionRequestParent { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPERMISSIONTYPE + public: + ContentPermissionRequestParent(const nsACString& type, + const nsACString& access, + Element* element, + const IPC::Principal& principal); + virtual ~ContentPermissionRequestParent(); - ContentPermissionType(const nsACString& aType, const nsACString& aAccess); - virtual ~ContentPermissionType(); + bool IsBeingDestroyed(); -protected: + nsCOMPtr mPrincipal; + nsCOMPtr mElement; + nsCOMPtr mProxy; nsCString mType; nsCString mAccess; + + private: + virtual bool Recvprompt(); + virtual void ActorDestroy(ActorDestroyReason why); }; -uint32_t ConvertPermissionRequestToArray(nsTArray& aSrcArray, - nsIMutableArray* aDesArray); - -nsresult CreatePermissionArray(const nsACString& aType, - const nsACString& aAccess, - nsIArray** aTypesArray); - -PContentPermissionRequestParent* -CreateContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal); - } // namespace dom } // namespace mozilla class nsContentPermissionRequestProxy : public nsIContentPermissionRequest { public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPERMISSIONREQUEST - nsContentPermissionRequestProxy(); virtual ~nsContentPermissionRequestProxy(); - nsresult Init(const nsTArray& requests, - mozilla::dom::ContentPermissionRequestParent* parent); + nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent); void OnParentDestroyed(); + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPERMISSIONREQUEST + private: // Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy. mozilla::dom::ContentPermissionRequestParent* mParent; - nsTArray mPermissionRequests; + nsCString mType; + nsCString mAccess; }; - #endif // nsContentPermissionHelper_h + diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 887b4643539b..48f23a01794b 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1687,7 +1687,7 @@ ReportAndDump(JSContext *cx, unsigned argc, JS::Value *vp) dmd::ClearReports(); fprintf(stderr, "DMD: running reporters...\n"); - dmd::RunReporters(); + dmd::RunReportersForThisProcess(); dmd::Writer writer(FpWrite, fp); dmd::Dump(writer); @@ -2831,6 +2831,32 @@ NS_DOMStructuredCloneError(JSContext* cx, xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR); } +static bool +AsmJSCacheOpenEntryForRead(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aLimit, + size_t* aSize, + const uint8_t** aMemory, + intptr_t *aHandle) +{ + nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal); + return asmjscache::OpenEntryForRead(principal, aBegin, aLimit, aSize, aMemory, + aHandle); +} + +static bool +AsmJSCacheOpenEntryForWrite(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aEnd, + size_t aSize, + uint8_t** aMemory, + intptr_t* aHandle) +{ + nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal); + return asmjscache::OpenEntryForWrite(principal, aBegin, aEnd, aSize, aMemory, + aHandle); +} + static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); void @@ -2879,9 +2905,9 @@ nsJSContext::EnsureStatics() // Set up the asm.js cache callbacks static JS::AsmJSCacheOps asmJSCacheOps = { - asmjscache::OpenEntryForRead, + AsmJSCacheOpenEntryForRead, asmjscache::CloseEntryForRead, - asmjscache::OpenEntryForWrite, + AsmJSCacheOpenEntryForWrite, asmjscache::CloseEntryForWrite, asmjscache::GetBuildId }; diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index 699dc742f11c..b626a285aef9 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -166,7 +166,7 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr) } } -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WindowsMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(WindowsMallocSizeOf) // The key is the window ID. typedef nsDataHashtable WindowPaths; diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index afd13708e13a..88eb729aed8d 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7652,8 +7652,13 @@ class CGProxySpecialOperation(CGPerSignatureCall): """ Base class for classes for calling an indexed or named special operation (don't use this directly, use the derived classes below). + + If checkFound is False, will just assert that the prop is found instead of + checking that it is before wrapping the value. """ - def __init__(self, descriptor, operation): + def __init__(self, descriptor, operation, checkFound=True): + self.checkFound = checkFound; + nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation)) operation = descriptor.operations[operation] assert len(operation.signatures()) == 1 @@ -7699,15 +7704,26 @@ class CGProxySpecialOperation(CGPerSignatureCall): return "" wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues)) - wrap = CGIfWrapper(wrap, "found") + if self.checkFound: + wrap = CGIfWrapper(wrap, "found") + else: + wrap = CGList([CGGeneric("MOZ_ASSERT(found);"), wrap], "\n") return "\n" + wrap.define() class CGProxyIndexedOperation(CGProxySpecialOperation): """ Class to generate a call to an indexed operation. + + If doUnwrap is False, the caller is responsible for making sure a variable + named 'self' holds the C++ object somewhere where the code we generate + will see it. + + If checkFound is False, will just assert that the prop is found instead of + checking that it is before wrapping the value. """ - def __init__(self, descriptor, name): - CGProxySpecialOperation.__init__(self, descriptor, name) + def __init__(self, descriptor, name, doUnwrap=True, checkFound=True): + self.doUnwrap = doUnwrap + CGProxySpecialOperation.__init__(self, descriptor, name, checkFound) def define(self): # Our first argument is the id we're getting. argName = self.arguments[0].identifier.name @@ -7716,18 +7732,30 @@ class CGProxyIndexedOperation(CGProxySpecialOperation): setIndex = "" else: setIndex = "uint32_t %s = index;\n" % argName - return (setIndex + - "%s* self = UnwrapProxy(proxy);\n" + + if self.doUnwrap: + unwrap = "%s* self = UnwrapProxy(proxy);\n" + else: + unwrap = "" + return (setIndex + unwrap + CGProxySpecialOperation.define(self)) class CGProxyIndexedGetter(CGProxyIndexedOperation): """ Class to generate a call to an indexed getter. If templateValues is not None the returned value will be wrapped with wrapForType using templateValues. + + If doUnwrap is False, the caller is responsible for making sure a variable + named 'self' holds the C++ object somewhere where the code we generate + will see it. + + If checkFound is False, will just assert that the prop is found instead of + checking that it is before wrapping the value. """ - def __init__(self, descriptor, templateValues=None): + def __init__(self, descriptor, templateValues=None, doUnwrap=True, + checkFound=True): self.templateValues = templateValues - CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter') + CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter', + doUnwrap, checkFound) class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter): """ @@ -8364,65 +8392,55 @@ class CGDOMJSProxyHandler_finalize(ClassMethod): return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") + finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define()) -class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod): +class CGDOMJSProxyHandler_slice(ClassMethod): def __init__(self, descriptor): + assert descriptor.supportsIndexedProperties() + args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'proxy'), - Argument('JS::Handle', 'receiver'), - Argument('uint32_t', 'index'), - Argument('JS::MutableHandle', 'vp'), - Argument('bool*', 'present')] - ClassMethod.__init__(self, "getElementIfPresent", "bool", args) + Argument('uint32_t', 'begin'), + Argument('uint32_t', 'end'), + Argument('JS::Handle', 'array')] + ClassMethod.__init__(self, "slice", "bool", args) self.descriptor = descriptor + def getBody(self): - successCode = ("*present = found;\n" - "return true;") - templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp', + # Just like getOwnPropertyNames we'll assume that we have no holes, so + # we have all properties from 0 to length. If that ever changes + # (unlikely), we'll need to do something a bit more clever with how we + # forward on to our ancestor. + header = CGGeneric( + 'JS::Rooted temp(cx);\n' + 'MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n' + ' "Should not have a XrayWrapper here");\n' + '\n' + '%s* self = UnwrapProxy(proxy);\n' + 'uint32_t length = self->Length();\n' + "// Compute the end of the indices we'll get ourselves\n" + 'uint32_t ourEnd = std::max(begin, std::min(end, length));' % + self.descriptor.nativeType) + + successCode = ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n" + "continue;") + templateValues = {'jsvalRef': 'temp', 'jsvalHandle': '&temp', 'obj': 'proxy', 'successCode': successCode} - if self.descriptor.supportsIndexedProperties(): - get = (CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n" - "// We skip the expando object and any named getters if\n" - "// there is an indexed getter.\n" + - "\n") % (self.descriptor.nativeType) - else: - if self.descriptor.supportsNamedProperties(): - get = CGProxyNamedGetter(self.descriptor, templateValues, - "UINT_TO_JSVAL(index)").define() - get += """ + get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False) -JS::Rooted expando(cx, GetExpandoObject(proxy)); -if (expando) { - bool isPresent; - if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) { - return false; - } - if (isPresent) { - *present = true; - return true; - } -} -""" + getOurElements = CGWrapper( + CGIndenter(get), + pre="for (uint32_t index = begin; index < ourEnd; ++index) {\n", + post="\n}") - return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), - "Should not have a XrayWrapper here"); + getProtoElements = CGIfWrapper( + CGGeneric("JS::Rooted proto(cx);\n" + "if (!js::GetObjectProto(cx, proxy, &proto)) {\n" + " return false;\n" + "}\n" + "return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array);"), + "end > ourEnd") -""" + get + """ -JS::Rooted proto(cx); -if (!js::GetObjectProto(cx, proxy, &proto)) { - return false; -} -if (proto) { - bool isPresent; - if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) { - return false; - } - *present = isPresent; - return true; -} - -*present = false; -// Can't Debug_SetValueRangeToCrashOnTouch because it's not public -return true;""" + return CGList([header, getOurElements, getProtoElements, + CGGeneric("return true;")], "\n\n").define(); class CGDOMJSProxyHandler_getInstance(ClassMethod): def __init__(self): @@ -8446,9 +8464,11 @@ class CGDOMJSProxyHandler(CGClass): CGDOMJSProxyHandler_className(descriptor), CGDOMJSProxyHandler_finalizeInBackground(descriptor), CGDOMJSProxyHandler_finalize(descriptor), - CGDOMJSProxyHandler_getElementIfPresent(descriptor), CGDOMJSProxyHandler_getInstance(), CGDOMJSProxyHandler_delete(descriptor)] + if descriptor.supportsIndexedProperties(): + methods.append(CGDOMJSProxyHandler_slice(descriptor)) + CGClass.__init__(self, 'DOMProxyHandler', bases=[ClassBase('mozilla::dom::DOMProxyHandler')], constructors=constructors, diff --git a/dom/camera/DOMCameraManager.cpp b/dom/camera/DOMCameraManager.cpp index 694fb6db4b73..3734e73e7f70 100644 --- a/dom/camera/DOMCameraManager.cpp +++ b/dom/camera/DOMCameraManager.cpp @@ -105,31 +105,6 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow) return cameraManager.forget(); } -nsDOMCameraControl* -nsDOMCameraManager::GetCameraControl(uint32_t aDeviceNum, - nsICameraGetCameraCallback* onSuccess, - nsICameraErrorCallback* onError, - ErrorResult& aRv) -{ - aRv = NS_OK; - - // reuse the same camera thread to conserve resources - if (!mCameraThread) { - aRv = NS_NewThread(getter_AddRefs(mCameraThread)); - if (aRv.Failed()) { - return nullptr; - } - } - - // Creating this object will trigger the onSuccess handler - nsDOMCameraControl* cameraControl = new nsDOMCameraControl(aDeviceNum, mCameraThread, - onSuccess, onError, mWindow); - if (cameraControl) { - Register(cameraControl); - } - return cameraControl; -} - void nsDOMCameraManager::GetCamera(const CameraSelector& aOptions, nsICameraGetCameraCallback* onSuccess, @@ -141,10 +116,22 @@ nsDOMCameraManager::GetCamera(const CameraSelector& aOptions, cameraId = 1; } + // reuse the same camera thread to conserve resources + if (!mCameraThread) { + aRv = NS_NewThread(getter_AddRefs(mCameraThread)); + if (aRv.Failed()) { + return; + } + } + DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__); + // Creating this object will trigger the onSuccess handler nsRefPtr cameraControl = - GetCameraControl(cameraId, onSuccess, onError.WasPassed() ? onError.Value() : nullptr, aRv); + new nsDOMCameraControl(cameraId, mCameraThread, + onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow); + + Register(cameraControl); } void diff --git a/dom/camera/DOMCameraManager.h b/dom/camera/DOMCameraManager.h index 7dc8d343e285..5758a475fd42 100644 --- a/dom/camera/DOMCameraManager.h +++ b/dom/camera/DOMCameraManager.h @@ -49,11 +49,6 @@ public: CreateInstance(nsPIDOMWindow* aWindow); static bool IsWindowStillActive(uint64_t aWindowId); - // Build us an nsDOMCameraControl - mozilla::nsDOMCameraControl* GetCameraControl(uint32_t aDeviceNum, - nsICameraGetCameraCallback* onSuccess, - nsICameraErrorCallback* onError, - mozilla::ErrorResult& aRv); void Register(mozilla::nsDOMCameraControl* aDOMCameraControl); void OnNavigation(uint64_t aWindowId); diff --git a/dom/camera/GonkRecorder.cpp b/dom/camera/GonkRecorder.cpp index 44594eb75337..39f5c0dfe3c1 100644 --- a/dom/camera/GonkRecorder.cpp +++ b/dom/camera/GonkRecorder.cpp @@ -28,7 +28,7 @@ #define RE_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) #include -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 # include #endif #include @@ -683,7 +683,7 @@ status_t GonkRecorder::start() { status = startAMRRecording(); break; -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 case OUTPUT_FORMAT_AAC_ADIF: case OUTPUT_FORMAT_AAC_ADTS: status = startAACRecording(); @@ -735,7 +735,7 @@ sp GonkRecorder::createAudioSource() { case AUDIO_ENCODER_AMR_WB: mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; break; -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 case AUDIO_ENCODER_AAC: mime = MEDIA_MIMETYPE_AUDIO_AAC; encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC); @@ -780,7 +780,7 @@ sp GonkRecorder::createAudioSource() { return audioEncoder; } -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 status_t GonkRecorder::startAACRecording() { // FIXME: // Add support for OUTPUT_FORMAT_AAC_ADIF @@ -871,7 +871,7 @@ status_t GonkRecorder::startMPEG2TSRecording() { sp writer = new MPEG2TSWriter(mOutputFd); if (mAudioSource != AUDIO_SOURCE_CNT) { -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 if (mAudioEncoder != AUDIO_ENCODER_AAC && mAudioEncoder != AUDIO_ENCODER_HE_AAC && mAudioEncoder != AUDIO_ENCODER_AAC_ELD) { @@ -1257,7 +1257,7 @@ status_t GonkRecorder::setupVideoEncoder( uint32_t encoder_flags = 0; if (mIsMetaDataStoredInVideoBuffers) { -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers; #else encoder_flags |= OMXCodec::kHardwareCodecsOnly; @@ -1293,7 +1293,7 @@ status_t GonkRecorder::setupAudioEncoder(const sp& writer) { switch(mAudioEncoder) { case AUDIO_ENCODER_AMR_NB: case AUDIO_ENCODER_AMR_WB: -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 case AUDIO_ENCODER_AAC: case AUDIO_ENCODER_HE_AAC: case AUDIO_ENCODER_AAC_ELD: diff --git a/dom/camera/GonkRecorder.h b/dom/camera/GonkRecorder.h index d34e01e5cfb9..d99cf8ccc716 100644 --- a/dom/camera/GonkRecorder.h +++ b/dom/camera/GonkRecorder.h @@ -129,7 +129,7 @@ private: sp *meta); status_t startMPEG4Recording(); status_t startAMRRecording(); -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 status_t startAACRecording(); #endif status_t startRawAudioRecording(); diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index e1b8234b9739..0a6601d98f08 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -49,7 +49,6 @@ #include "nsIStringBundle.h" #include "nsIDocument.h" #include -#include "nsContentPermissionHelper.h" #include "mozilla/dom/DeviceStorageBinding.h" @@ -1734,14 +1733,17 @@ nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType) } NS_IMETHODIMP -nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes) +nsDOMDeviceStorageCursor::GetType(nsACString & aType) { - nsCString type; - nsresult rv = - DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); - NS_ENSURE_SUCCESS(rv, rv); + return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, + aType); +} - return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes); +NS_IMETHODIMP +nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess) +{ + aAccess = NS_LITERAL_CSTRING("read"); + return NS_OK; } NS_IMETHODIMP @@ -2249,10 +2251,8 @@ public: if (NS_FAILED(rv)) { return rv; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(type, access)); child->SendPContentPermissionRequestConstructor( - this, permArray, IPC::Principal(mPrincipal)); + this, type, access, IPC::Principal(mPrincipal)); Sendprompt(); return NS_OK; @@ -2266,23 +2266,26 @@ public: return NS_OK; } - NS_IMETHODIMP GetTypes(nsIArray** aTypes) + NS_IMETHOD GetType(nsACString & aType) { nsCString type; - nsresult rv = - DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); + nsresult rv + = DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, + aType); if (NS_FAILED(rv)) { return rv; } + return NS_OK; + } - nsCString access; - rv = DeviceStorageTypeChecker::GetAccessForRequest( - DeviceStorageRequestType(mRequestType), access); + NS_IMETHOD GetAccess(nsACString & aAccess) + { + nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest( + DeviceStorageRequestType(mRequestType), aAccess); if (NS_FAILED(rv)) { return rv; } - - return CreatePermissionArray(type, access, aTypes); + return NS_OK; } NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal) @@ -3296,10 +3299,8 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath, if (aRv.Failed()) { return nullptr; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read"))); - child->SendPContentPermissionRequestConstructor(r, - permArray, + child->SendPContentPermissionRequestConstructor(r, type, + NS_LITERAL_CSTRING("read"), IPC::Principal(mPrincipal)); r->Sendprompt(); diff --git a/dom/inputmethod/forms.js b/dom/inputmethod/forms.js index 685db1f64db2..be99a96e2552 100644 --- a/dom/inputmethod/forms.js +++ b/dom/inputmethod/forms.js @@ -396,7 +396,6 @@ let FormAssistant = { range = getSelectionRange(this.focusedElement); if (range[0] !== this.selectionStart || range[1] !== this.selectionEnd) { - this.sendKeyboardState(this.focusedElement); this.updateSelection(); } break; diff --git a/dom/interfaces/base/nsIContentPermissionPrompt.idl b/dom/interfaces/base/nsIContentPermissionPrompt.idl index c51f5ed0bb72..0fdda0ea66e1 100644 --- a/dom/interfaces/base/nsIContentPermissionPrompt.idl +++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl @@ -7,13 +7,15 @@ interface nsIPrincipal; interface nsIDOMWindow; interface nsIDOMElement; -interface nsIArray; /** - * Interface provides the request type and its access. + * Interface allows access to a content to request + * permission to perform a privileged operation such as + * geolocation. */ -[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)] -interface nsIContentPermissionType : nsISupports { +[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)] +interface nsIContentPermissionRequest : nsISupports { + /** * The type of the permission request, such as * "geolocation". @@ -25,22 +27,8 @@ interface nsIContentPermissionType : nsISupports { * "read". */ readonly attribute ACString access; -}; -/** - * Interface allows access to a content to request - * permission to perform a privileged operation such as - * geolocation. - */ -[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)] -interface nsIContentPermissionRequest : nsISupports { /** - * The array will include the request types. Elements of this array are - * nsIContentPermissionType object. - */ - readonly attribute nsIArray types; - - /* * The principal of the permission request. */ readonly attribute nsIPrincipal principal; diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 5e9bc6b1defb..222afea3570f 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -497,19 +497,12 @@ ContentChild::RecvPMemoryReportRequestConstructor( GetProcessName(process); AppendProcessId(process); - // Run each reporter. The callback will turn each measurement into a + // Run the reporters. The callback will turn each measurement into a // MemoryReport. - nsCOMPtr e; - mgr->EnumerateReporters(getter_AddRefs(e)); nsRefPtr wrappedReports = new MemoryReportsWrapper(&reports); nsRefPtr cb = new MemoryReportCallback(process); - bool more; - while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) { - nsCOMPtr r; - e->GetNext(getter_AddRefs(r)); - r->CollectReports(cb, wrappedReports); - } + mgr->GetReportsForThisProcess(cb, wrappedReports); child->Send__delete__(child, generation, reports); return true; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 3530938b25b1..ea43d0ecf114 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -193,15 +193,15 @@ MemoryReportRequestParent::~MemoryReportRequestParent() } // A memory reporter for ContentParent objects themselves. -class ContentParentsMemoryReporter MOZ_FINAL : public MemoryMultiReporter +class ContentParentsMemoryReporter MOZ_FINAL : public nsIMemoryReporter { public: - ContentParentsMemoryReporter() {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* cb, - nsISupports* aClosure); + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER }; +NS_IMPL_ISUPPORTS1(ContentParentsMemoryReporter, nsIMemoryReporter) + NS_IMETHODIMP ContentParentsMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb, nsISupports* aClosure) diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index bb280652edb9..a05812452e47 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -16,7 +16,6 @@ include protocol PIndexedDB; include DOMTypes; include JavaScriptTypes; include URIParams; -include PContentPermission; using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h"; @@ -207,8 +206,10 @@ parent: * Initiates an asynchronous request for permission for the * provided principal. * - * @param aRequests - * The array of permissions to request. + * @param aType + * The type of permission to request. + * @param aAccess + * Access type. "read" for example. * @param aPrincipal * The principal of the request. * @@ -216,7 +217,7 @@ parent: * principals that can live in the content process should * provided. */ - PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal); + PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal); PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures, int32_t[] aIntParams, nsString[] aStringParams); @@ -345,6 +346,13 @@ child: */ HandleLongTap(CSSIntPoint point); + /** + * Notifies the child that the parent has begun or finished transforming + * the visible child content area. Useful for showing/hiding scrollbars. + */ + NotifyTransformBegin(ViewID aViewId); + NotifyTransformEnd(ViewID aViewId); + /** * Sending an activate message moves focus to the child. */ diff --git a/dom/ipc/PContentPermission.ipdlh b/dom/ipc/PContentPermission.ipdlh deleted file mode 100644 index 5db4f3b669f6..000000000000 --- a/dom/ipc/PContentPermission.ipdlh +++ /dev/null @@ -1,14 +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/. */ - -namespace mozilla { -namespace dom { - -struct PermissionRequest { - nsCString type; - nsCString access; -}; - -} // namespace dom -} // namespace mozilla diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index f37b5e6d71c5..f79ba31946c2 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1157,11 +1157,12 @@ TabChild::ArraysToParams(const InfallibleTArray& aIntParams, #ifdef DEBUG PContentPermissionRequestChild* TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor, - const InfallibleTArray& aRequests, + const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal) { PCOMContentPermissionRequestChild* child = static_cast(aActor); - PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal); + PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal); child->mIPCOpen = true; return request; } @@ -1659,6 +1660,32 @@ TabChild::RecvHandleLongTap(const CSSIntPoint& aPoint) return true; } +bool +TabChild::RecvNotifyTransformBegin(const ViewID& aViewId) +{ + nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId); + if (sf) { + nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sf); + if (scrollbarOwner) { + scrollbarOwner->ScrollbarActivityStarted(); + } + } + return true; +} + +bool +TabChild::RecvNotifyTransformEnd(const ViewID& aViewId) +{ + nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId); + if (sf) { + nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sf); + if (scrollbarOwner) { + scrollbarOwner->ScrollbarActivityStopped(); + } + } + return true; +} + bool TabChild::RecvActivate() { @@ -2013,8 +2040,7 @@ TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog) } PContentPermissionRequestChild* -TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal) +TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&) { NS_RUNTIMEABORT("unused"); return nullptr; diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index a4c3b1655e3a..b546cd1dae33 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -217,6 +217,8 @@ public: virtual bool RecvHandleDoubleTap(const CSSIntPoint& aPoint); virtual bool RecvHandleSingleTap(const CSSIntPoint& aPoint); virtual bool RecvHandleLongTap(const CSSIntPoint& aPoint); + virtual bool RecvNotifyTransformBegin(const ViewID& aViewId); + virtual bool RecvNotifyTransformEnd(const ViewID& aViewId); virtual bool RecvActivate(); virtual bool RecvDeactivate(); virtual bool RecvMouseEvent(const nsString& aType, @@ -278,11 +280,13 @@ public: #ifdef DEBUG virtual PContentPermissionRequestChild* SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor, - const InfallibleTArray& aRequests, + const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal); #endif /* DEBUG */ - virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray& aRequests, + virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal); virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index e69c2530dd70..54d7cadb833f 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -15,7 +15,6 @@ #include "mozilla/BrowserElementParent.h" #include "mozilla/docshell/OfflineCacheUpdateParent.h" #include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/Hal.h" #include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/layers/CompositorParent.h" @@ -522,6 +521,20 @@ void TabParent::HandleLongTap(const CSSIntPoint& aPoint, int32_t aModifiers) } } +void TabParent::NotifyTransformBegin(ViewID aViewId) +{ + if (!mIsDestroyed) { + unused << SendNotifyTransformBegin(aViewId); + } +} + +void TabParent::NotifyTransformEnd(ViewID aViewId) +{ + if (!mIsDestroyed) { + unused << SendNotifyTransformEnd(aViewId); + } +} + void TabParent::Activate() { @@ -580,10 +593,9 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor) } PContentPermissionRequestParent* -TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal) +TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal) { - return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal); + return new ContentPermissionRequestParent(type, access, mFrameElement, principal); } bool diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 150a477e114b..68c45f3f39d2 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -196,6 +196,8 @@ public: void HandleDoubleTap(const CSSIntPoint& aPoint, int32_t aModifiers); void HandleSingleTap(const CSSIntPoint& aPoint, int32_t aModifiers); void HandleLongTap(const CSSIntPoint& aPoint, int32_t aModifiers); + void NotifyTransformBegin(ViewID aViewId); + void NotifyTransformEnd(ViewID aViewId); void Activate(); void Deactivate(); @@ -225,8 +227,7 @@ public: virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor); virtual PContentPermissionRequestParent* - AllocPContentPermissionRequestParent(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal); + AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal); virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor); virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent( diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index d9026c8758fc..e1b4c5429d06 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -68,7 +68,6 @@ IPDL_SOURCES += [ 'PBrowser.ipdl', 'PContent.ipdl', 'PContentDialog.ipdl', - 'PContentPermission.ipdlh', 'PContentPermissionRequest.ipdl', 'PCrashReporter.ipdl', 'PDocumentRenderer.ipdl', diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 1934f8593ef0..fcbe21e34047 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -41,7 +41,7 @@ #include "MediaEngineWebRTC.h" #endif -#ifdef MOZ_B2G +#ifdef MOZ_WIDGET_GONK #include "MediaPermissionGonk.h" #endif @@ -756,7 +756,7 @@ public: , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) - , mBackend(nullptr) + , mBackendChosen(false) , mManager(MediaManager::GetInstance()) {} @@ -778,11 +778,15 @@ public: , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) + , mBackendChosen(true) , mBackend(aBackend) , mManager(MediaManager::GetInstance()) {} ~GetUserMediaRunnable() { + if (mBackendChosen) { + delete mBackend; + } } NS_IMETHOD @@ -790,15 +794,14 @@ public: { NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread"); - MediaEngine* backend = mBackend; // Was a backend provided? - if (!backend) { - backend = mManager->GetBackend(mWindowID); + if (!mBackendChosen) { + mBackend = mManager->GetBackend(mWindowID); } // Was a device provided? if (!mDeviceChosen) { - nsresult rv = SelectDevice(backend); + nsresult rv = SelectDevice(); if (rv != NS_OK) { return rv; } @@ -870,10 +873,10 @@ public: } nsresult - SelectDevice(MediaEngine* backend) + SelectDevice() { if (mConstraints.mPicture || mConstraints.mVideo) { - ScopedDeletePtr sources (GetSources(backend, + ScopedDeletePtr sources (GetSources(mBackend, mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices)); if (!sources->Length()) { @@ -887,7 +890,7 @@ public: } if (mConstraints.mAudio) { - ScopedDeletePtr sources (GetSources(backend, + ScopedDeletePtr sources (GetSources(mBackend, mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices)); if (!sources->Length()) { @@ -981,8 +984,9 @@ private: MediaEnginePrefs mPrefs; bool mDeviceChosen; + bool mBackendChosen; - RefPtr mBackend; + MediaEngine* mBackend; nsRefPtr mManager; // get ref to this when creating the runnable }; @@ -1262,10 +1266,10 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, // Force MediaManager to startup before we try to access it from other threads // Hack: should init singleton earlier unless it's expensive (mem or CPU) (void) MediaManager::Get(); -#ifdef MOZ_B2G +#ifdef MOZ_WIDGET_GONK // Initialize MediaPermissionManager before send out any permission request. (void) MediaPermissionManager::GetInstance(); -#endif //MOZ_B2G +#endif //MOZ_WIDGET_GONK } // Store the WindowID in a hash table and mark as active. The entry is removed @@ -1411,11 +1415,11 @@ MediaManager::GetBackend(uint64_t aWindowId) MutexAutoLock lock(mMutex); if (!mBackend) { #if defined(MOZ_WEBRTC) -#ifndef MOZ_B2G_CAMERA + #ifndef MOZ_B2G_CAMERA mBackend = new MediaEngineWebRTC(mPrefs); -#else - mBackend = new MediaEngineWebRTC(mCameraManager); -#endif + #else + mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId); + #endif #else mBackend = new MediaEngineDefault(); #endif diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 263f89831efd..f326119db671 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -513,7 +513,9 @@ private: // Make private because we want only one instance of this class MediaManager(); - ~MediaManager() {} + ~MediaManager() { + delete mBackend; + } nsresult MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo, bool* aAudio); @@ -528,11 +530,11 @@ private: Mutex mMutex; // protected with mMutex: - RefPtr mBackend; + MediaEngine* mBackend; static StaticRefPtr sSingleton; -#ifdef MOZ_B2G_CAMERA +#ifdef MOZ_WIDGET_GONK nsRefPtr mCameraManager; #endif }; diff --git a/dom/media/MediaPermissionGonk.cpp b/dom/media/MediaPermissionGonk.cpp index ecf2a1889db1..a4f18ed0ae6b 100644 --- a/dom/media/MediaPermissionGonk.cpp +++ b/dom/media/MediaPermissionGonk.cpp @@ -20,36 +20,14 @@ #include "mozilla/dom/MediaStreamTrackBinding.h" #include "nsISupportsPrimitives.h" #include "nsServiceManagerUtils.h" -#include "nsArrayUtils.h" -#include "nsContentPermissionHelper.h" #include "mozilla/dom/PermissionMessageUtils.h" #define AUDIO_PERMISSION_NAME "audio-capture" -#define VIDEO_PERMISSION_NAME "video-capture" - -using namespace mozilla::dom; namespace mozilla { static MediaPermissionManager *gMediaPermMgr = nullptr; -static uint32_t -ConvertArrayToPermissionRequest(nsIArray* aSrcArray, - nsTArray& aDesArray) -{ - uint32_t len = 0; - aSrcArray->GetLength(&len); - for (uint32_t i = 0; i < len; i++) { - nsCOMPtr cpt = do_QueryElementAt(aSrcArray, i); - nsAutoCString type; - nsAutoCString access; - cpt->GetType(type); - cpt->GetAccess(access); - aDesArray.AppendElement(PermissionRequest(type, access)); - } - return len; -} - // Helper function for notifying permission granted static nsresult NotifyPermissionAllow(const nsAString &aCallID, nsTArray > &aDevices) @@ -115,7 +93,6 @@ public: private: bool mAudio; // Request for audio permission - bool mVideo; // Request for video permission nsRefPtr mRequest; nsTArray > mDevices; // candiate device list }; @@ -131,7 +108,6 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtrGetConstraints(constraints); mAudio = constraints.mAudio; - mVideo = constraints.mVideo; for (uint32_t i = 0; i < aDevices.Length(); ++i) { nsCOMPtr device(aDevices[i]); @@ -140,34 +116,10 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - if (mAudio) { - nsCOMPtr AudioType = - new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused")); - types->AppendElement(AudioType, false); - } - if (mVideo) { - nsCOMPtr VideoType = - new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused")); - types->AppendElement(VideoType, false); - } - NS_IF_ADDREF(*aTypes = types); - - return NS_OK; -} - NS_IMETHODIMP MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) { @@ -183,6 +135,24 @@ MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) return NS_OK; } +NS_IMETHODIMP +MediaPermissionRequest::GetType(nsACString &aType) +{ + if (mAudio) { + aType = AUDIO_PERMISSION_NAME; + return NS_OK; + } + + return NS_OK; +} + +NS_IMETHODIMP +MediaPermissionRequest::GetAccess(nsACString &aAccess) +{ + aAccess = "unused"; + return NS_OK; +} + NS_IMETHODIMP MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow) { @@ -308,12 +278,13 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr &req) dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell()); NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); - nsCOMPtr typeArray; - rv = req->GetTypes(getter_AddRefs(typeArray)); + nsAutoCString type; + rv = req->GetType(type); NS_ENSURE_SUCCESS(rv, rv); - nsTArray permArray; - ConvertArrayToPermissionRequest(typeArray, permArray); + nsAutoCString access; + rv = req->GetAccess(access); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr principal; rv = req->GetPrincipal(getter_AddRefs(principal)); @@ -321,7 +292,8 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr &req) req->AddRef(); child->SendPContentPermissionRequestConstructor(req, - permArray, + type, + access, IPC::Principal(principal)); req->Sendprompt(); diff --git a/dom/messages/SystemMessagePermissionsChecker.jsm b/dom/messages/SystemMessagePermissionsChecker.jsm index 80f76d78e4d8..ee6b98ad58ff 100644 --- a/dom/messages/SystemMessagePermissionsChecker.jsm +++ b/dom/messages/SystemMessagePermissionsChecker.jsm @@ -110,7 +110,6 @@ this.SystemMessagePermissionsTable = { "nfc-powerlevel-change": { "settings": ["read", "write"] }, - "rtsp-open-video": {}, }; this.SystemMessagePermissionsChecker = { diff --git a/dom/mobilemessage/src/gonk/MmsService.js b/dom/mobilemessage/src/gonk/MmsService.js index b12cbe3eadc4..5cd4ad57d699 100644 --- a/dom/mobilemessage/src/gonk/MmsService.js +++ b/dom/mobilemessage/src/gonk/MmsService.js @@ -256,11 +256,13 @@ MmsConnection.prototype = { let networkManager = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager); let activeNetwork = networkManager.active; - if (activeNetwork.serviceId != this.serviceId) { + + let rilNetwork = activeNetwork.QueryInterface(Ci.nsIRilNetworkInterface); + if (rilNetwork.serviceId != this.serviceId) { + if (DEBUG) debug("Sevice ID between active/MMS network doesn't match."); return; } - let rilNetwork = activeNetwork.QueryInterface(Ci.nsIRilNetworkInterface); // Set up the MMS APN setting based on the connected MMS network, // which is going to be used for the HTTP requests later. this.setApnSetting(rilNetwork); diff --git a/dom/permission/tests/file_framework.js b/dom/permission/tests/file_framework.js index dddb278ead69..e05d479946ae 100644 --- a/dom/permission/tests/file_framework.js +++ b/dom/permission/tests/file_framework.js @@ -169,7 +169,11 @@ function expandPermissions(aPerms) { aPerms.forEach(function(el) { var access = permTable[el].access ? "readwrite" : null; var expanded = SpecialPowers.unwrap(expand(el, access)); - perms = perms.concat(expanded.slice(0)); + // COW arrays don't behave array-like enough, to allow + // using expanded.slice(0) here. + for (let i = 0; i < expanded.length; i++) { + perms.push(expanded[i]); + } }); return perms; diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index 07d5991b7bf5..314c4f7360e6 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -386,11 +386,17 @@ nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) } NS_IMETHODIMP -nsGeolocationRequest::GetTypes(nsIArray** aTypes) +nsGeolocationRequest::GetType(nsACString & aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "geolocation"; + return NS_OK; +} + +NS_IMETHODIMP +nsGeolocationRequest::GetAccess(nsACString & aAccess) +{ + aAccess = "unused"; + return NS_OK; } NS_IMETHODIMP @@ -1447,15 +1453,12 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request) return false; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"), - NS_LITERAL_CSTRING("unused"))); - // Retain a reference so the object isn't deleted without IPDL's knowledge. // Corresponding release occurs in DeallocPContentPermissionRequest. request->AddRef(); child->SendPContentPermissionRequestConstructor(request, - permArray, + NS_LITERAL_CSTRING("geolocation"), + NS_LITERAL_CSTRING("unused"), IPC::Principal(mPrincipal)); request->Sendprompt(); diff --git a/dom/src/notification/DesktopNotification.cpp b/dom/src/notification/DesktopNotification.cpp index b69b34c46d60..857b116ae534 100644 --- a/dom/src/notification/DesktopNotification.cpp +++ b/dom/src/notification/DesktopNotification.cpp @@ -15,7 +15,6 @@ #include "PCOMContentPermissionRequestChild.h" #include "nsIScriptSecurityManager.h" #include "nsServiceManagerUtils.h" -#include "PermissionMessageUtils.h" namespace mozilla { namespace dom { @@ -180,12 +179,9 @@ DesktopNotification::Init() // Corresponding release occurs in DeallocPContentPermissionRequest. nsRefPtr copy = request; - nsTArray permArray; - permArray.AppendElement(PermissionRequest( - NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"))); child->SendPContentPermissionRequestConstructor(copy.forget().get(), - permArray, + NS_LITERAL_CSTRING("desktop-notification"), + NS_LITERAL_CSTRING("unused"), IPC::Principal(mPrincipal)); request->Sendprompt(); @@ -357,11 +353,17 @@ DesktopNotificationRequest::Allow() } NS_IMETHODIMP -DesktopNotificationRequest::GetTypes(nsIArray** aTypes) +DesktopNotificationRequest::GetType(nsACString & aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "desktop-notification"; + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetAccess(nsACString & aAccess) +{ + aAccess = "unused"; + return NS_OK; } } // namespace dom diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index 16d16880b924..51835ffece53 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -24,7 +24,6 @@ #include "nsDOMJSUtils.h" #include "nsIScriptSecurityManager.h" #include "mozilla/dom/PermissionMessageUtils.h" -#include "nsContentPermissionHelper.h" #ifdef MOZ_B2G #include "nsIDOMDesktopNotification.h" #endif @@ -268,11 +267,9 @@ NotificationPermissionRequest::Run() // Corresponding release occurs in DeallocPContentPermissionRequest. AddRef(); - nsTArray permArray; - permArray.AppendElement(PermissionRequest( - NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"))); - child->SendPContentPermissionRequestConstructor(this, permArray, + NS_NAMED_LITERAL_CSTRING(type, "desktop-notification"); + NS_NAMED_LITERAL_CSTRING(access, "unused"); + child->SendPContentPermissionRequestConstructor(this, type, access, IPC::Principal(mPrincipal)); Sendprompt(); @@ -345,11 +342,17 @@ NotificationPermissionRequest::CallCallback() } NS_IMETHODIMP -NotificationPermissionRequest::GetTypes(nsIArray** aTypes) +NotificationPermissionRequest::GetAccess(nsACString& aAccess) { - return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aAccess.AssignLiteral("unused"); + return NS_OK; +} + +NS_IMETHODIMP +NotificationPermissionRequest::GetType(nsACString& aType) +{ + aType.AssignLiteral("desktop-notification"); + return NS_OK; } bool diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index df5740dfeae8..cf5efc67ec23 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2761,9 +2761,10 @@ this.PDU_CDMA_MSG_TYPE_BROADCAST = 0x01; // Broadcast this.PDU_CDMA_MSG_TYPE_ACK = 0x02; // Acknowledge // SMS Teleservice Identitifier, as defined in 3GPP2 N.S0005, Table 175 -this.PDU_CDMA_MSG_TELESERIVCIE_ID_SMS = 0x1002; // SMS -this.PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT = 0x1005; // Wireless Enhanced Messaging Teleservice - // required for fragmented SMS +this.PDU_CDMA_MSG_TELESERIVCIE_ID_SMS = 0x1002; // SMS +this.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP = 0x1004; // WAP +this.PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT = 0x1005; // Wireless Enhanced Messaging Teleservice + // required for fragmented SMS // SMS Service Category, as defined in 3GPP2 C.R1001-D, Table 9.3.1-1 this.PDU_CDMA_MSG_CATEGORY_UNSPEC = 0x00; // Unknown/Unspecified diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 49871103b60f..0d26627e9a9b 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -4312,6 +4312,61 @@ let RIL = { return PDU_FCS_OK; }, + /** + * Helper for processing CDMA SMS WAP Push Message + * + * @param message + * decoded WAP message from CdmaPDUHelper. + * + * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. + */ + _processCdmaSmsWapPush: function _processCdmaSmsWapPush(message) { + if (!message.data) { + if (DEBUG) debug("no data inside WAP Push message."); + return PDU_FCS_OK; + } + + // See 6.5. MAPPING OF WDP TO CDMA SMS in WAP-295-WDP. + // + // Field | Length (bits) + // ----------------------------------------- + // MSG_TYPE | 8 + // TOTAL_SEGMENTS | 8 + // SEGMENT_NUMBER | 8 + // DATAGRAM | (NUM_FIELDS – 3) * 8 + let index = 0; + if (message.data[index++] !== 0) { + if (DEBUG) debug("Ignore a WAP Message which is not WDP."); + return PDU_FCS_OK; + } + + // 1. Originator Address in SMS-TL + Message_Id in SMS-TS are used to identify a unique WDP datagram. + // 2. TOTAL_SEGMENTS, SEGMENT_NUMBER are used to verify that a complete + // datagram has been received and is ready to be passed to a higher layer. + message.header = { + segmentRef: message.msgId, + segmentMaxSeq: message.data[index++], + segmentSeq: message.data[index++] + 1 // It's zero-based in CDMA WAP Push. + }; + + if (message.header.segmentSeq > message.header.segmentMaxSeq) { + if (DEBUG) debug("Wrong WDP segment info."); + return PDU_FCS_OK; + } + + // Ports are only specified in 1st segment. + if (message.header.segmentSeq == 1) { + message.header.originatorPort = message.data[index++] << 8; + message.header.originatorPort |= message.data[index++]; + message.header.destinationPort = message.data[index++] << 8; + message.header.destinationPort |= message.data[index++]; + } + + message.data = message.data.subarray(index); + + return this._processSmsMultipart(message); + }, + /** * Helper for processing received multipart SMS. * @@ -4347,6 +4402,22 @@ let RIL = { delete original.body; } options.receivedSegments++; + + // The port information is only available in 1st segment for CDMA WAP Push. + // If the segments of a WAP Push are not received in sequence + // (e.g., SMS with seq == 1 is not the 1st segment received by the device), + // we have to retrieve the port information from 1st segment and + // save it into the cached options.header. + if (original.teleservice === PDU_CDMA_MSG_TELESERIVCIE_ID_WAP && seq === 1) { + if (!options.header.originatorPort && original.header.originatorPort) { + options.header.originatorPort = original.header.originatorPort; + } + + if (!options.header.destinationPort && original.header.destinationPort) { + options.header.destinationPort = original.header.destinationPort; + } + } + if (options.receivedSegments < options.segmentMaxSeq) { if (DEBUG) { debug("Got segment no." + seq + " of a multipart SMS: " @@ -6215,7 +6286,9 @@ RIL[UNSOLICITED_RESPONSE_CDMA_NEW_SMS] = function UNSOLICITED_RESPONSE_CDMA_NEW_ let [message, result] = CdmaPDUHelper.processReceivedSms(length); if (message) { - if (message.subMsgType === PDU_CDMA_MSG_TYPE_DELIVER_ACK) { + if (message.teleservice === PDU_CDMA_MSG_TELESERIVCIE_ID_WAP) { + result = this._processCdmaSmsWapPush(message); + } else if (message.subMsgType === PDU_CDMA_MSG_TYPE_DELIVER_ACK) { result = this._processCdmaSmsStatusReport(message); } else { result = this._processSmsMultipart(message); @@ -7997,6 +8070,25 @@ let BitBufferHelper = { return result; }, + backwardReadPilot: function backwardReadPilot(length) { + if (length <= 0) { + return; + } + + // Zero-based position. + let bitIndexToRead = this.readIndex * 8 - this.readCacheSize - length; + + if (bitIndexToRead < 0) { + return; + } + + // Update readIndex, readCache, readCacheSize accordingly. + let readBits = bitIndexToRead % 8; + this.readIndex = Math.floor(bitIndexToRead / 8) + ((readBits) ? 1 : 0); + this.readCache = (readBits) ? this.readBuffer[this.readIndex - 1] : 0; + this.readCacheSize = (readBits) ? (8 - readBits) : 0; + }, + writeBits: function writeBits(value, length) { if (length <= 0 || length > 32) { return; @@ -8463,17 +8555,17 @@ let CdmaPDUHelper = { // Bearer Data Sub-Parameter: User Data let userData = message[PDU_CDMA_MSG_USERDATA_BODY]; - [message.header, message.body, message.encoding] = - (userData)? [userData.header, userData.body, userData.encoding] - : [null, null, null]; + [message.header, message.body, message.encoding, message.data] = + (userData) ? [userData.header, userData.body, userData.encoding, userData.data] + : [null, null, null, null]; // Bearer Data Sub-Parameter: Message Status // Success Delivery (0) if both Message Status and User Data are absent. // Message Status absent (-1) if only User Data is available. let msgStatus = message[PDU_CDMA_MSG_USER_DATA_MSG_STATUS]; [message.errorClass, message.msgStatus] = - (msgStatus)? [msgStatus.errorClass, msgStatus.msgStatus] - : ((message.body)? [-1, -1]: [0, 0]); + (msgStatus) ? [msgStatus.errorClass, msgStatus.msgStatus] + : ((message.body) ? [-1, -1] : [0, 0]); // Transform message to GSM msg let msg = { @@ -8489,7 +8581,7 @@ let CdmaPDUHelper = { replace: false, header: message.header, body: message.body, - data: null, + data: message.data, timestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP], language: message[PDU_CDMA_LANGUAGE_INDICATOR], status: null, @@ -8502,7 +8594,8 @@ let CdmaPDUHelper = { subMsgType: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgType, msgId: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgId, errorClass: message.errorClass, - msgStatus: message.msgStatus + msgStatus: message.msgStatus, + teleservice: message.teleservice }; return msg; @@ -8939,6 +9032,15 @@ let CdmaPDUHelper = { msgBodySize -= result.header.length; } + // Store original payload if enconding is OCTET for further handling of WAP Push, etc. + if (encoding === PDU_CDMA_MSG_CODING_OCTET && msgBodySize > 0) { + result.data = new Uint8Array(msgBodySize); + for (let i = 0; i < msgBodySize; i++) { + result.data[i] = BitBufferHelper.readBits(8); + } + BitBufferHelper.backwardReadPilot(8 * msgBodySize); + } + // Decode sms content result.body = this.decodeCdmaPDUMsg(encoding, msgType, msgBodySize); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js index 920ba05404bc..1d31c36f62c7 100644 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js +++ b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js @@ -26,6 +26,164 @@ function _getWorker() { }; } +/* + * Helper function to covert a HEX string to a byte array. + * + * @param hexString + * A hexadecimal string of which the length is even. + */ +function hexStringToBytes(hexString) { + let bytes = []; + + let length = hexString.length; + + for (let i = 0; i < length; i += 2) { + bytes.push(Number.parseInt(hexString.substr(i, 2), 16)); + } + + return bytes; +} + +/* + * Helper function to covert a byte array to a HEX string. + * + * @param bytes + * Could be a regular byte array or Uint8Array. + */ +function bytesToHexString(bytes) { + let hexString = ""; + let hex; + + for (let i = 0; i < bytes.length; i++) { + hex = bytes[i].toString(16).toUpperCase(); + if (hex.length === 1) { + hexString += "0"; + } + hexString += hex; + } + + return hexString; +} + +/* + * Helper function to ecode Opaque UserData + * + * @param msg_type + * PDU_CDMA_MSG_TYPE_SUBMIT or PDU_CDMA_MSG_TYPE_DELIVER + * @param data + * The byte array of opaque data to be encoded. + */ +function encodeOpaqueUserData(bitBufferHelper, options) { + let bearerDataBuffer = []; + bitBufferHelper.startWrite(bearerDataBuffer); + + // Msg-Id + bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); + bitBufferHelper.writeBits(3, 8); + bitBufferHelper.writeBits(options.msg_type, 4); // MSG_TYPE + bitBufferHelper.writeBits(1, 16); // MSG_ID + bitBufferHelper.flushWithPadding(); // HEADER_IND (1) + RESERVED (3) + + // User Data + bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); + let dataLength = options.data.length; + bitBufferHelper.writeBits(2 + dataLength, 8); // 2 bytes for MSG_ENCODING, NUM_FIELDS + bitBufferHelper.writeBits(PDU_CDMA_MSG_CODING_OCTET, 5); //MSG_ENCODING + // MSG_TYPE is omitted if MSG_ENCODING is CODING_OCTET + bitBufferHelper.writeBits(dataLength, 8); // NUM_FIELDS + for (let i = 0; i < dataLength; i++) { // CHARi + bitBufferHelper.writeBits(options.data[i], 8); + } + bitBufferHelper.flushWithPadding(); // RESERVED (3 filling bits) + + return bearerDataBuffer; +} + +function newSmsParcel(cdmaPduHelper, pdu) { + return newIncomingParcel(-1, + RESPONSE_TYPE_UNSOLICITED, + UNSOLICITED_RESPONSE_CDMA_NEW_SMS, + pduToParcelData(cdmaPduHelper, pdu)); +} + +/* + * Helper function to encode PDU into Parcel. + * See ril_cdma_sms.h for the structure definition of RIL_CDMA_SMS_Message + * + * @param teleservice + * The Teleservice-Id of this PDU. + * See PDU_CDMA_MSG_TELESERIVCIE_ID_XXX in ril_const.js. + * @param address + * The Orginating or Destinating address. + * @param bearerData + * The byte array of the encoded bearer data. + */ +function pduToParcelData(cdmaPduHelper, pdu) { + + let addrInfo = cdmaPduHelper.encodeAddr(pdu.address); + // Teleservice, isServicePresent, ServiceCategory, + // addrInfo {digitMode, numberMode, numberType, numberPlan, address.length, address} + // Sub Address + // bearerData length, bearerData. + let dataLength = 4 + 4 + 4 + + (5 + addrInfo.address.length) * 4 + + 3 * 4 + + 4 + pdu.bearerData.length * 4; + + let data = new Uint8Array(dataLength); + let offset = 0; + + function writeInt(value) { + data[offset++] = value & 0xFF; + data[offset++] = (value >> 8) & 0xFF; + data[offset++] = (value >> 16) & 0xFF; + data[offset++] = (value >> 24) & 0xFF; + } + + function writeByte(value) { + data[offset++] = value & 0xFF; + data[offset++] = 0; + data[offset++] = 0; + data[offset++] = 0; + } + + // Teleservice + writeInt(pdu.teleservice); + + // isServicePresent + writeByte(0); + + // ServiceCategory + writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); + + // AddrInfo + writeByte(addrInfo.digitMode); + writeByte(addrInfo.numberMode); + writeByte(addrInfo.numberType); + writeByte(addrInfo.numberPlan); + let addressLength = addrInfo.address.length; + writeByte(addressLength); + for (let i = 0; i < addressLength; i++) { + writeByte(addrInfo.address[i]); + } + + // Subaddress + writeByte(0); + writeByte(0); + writeByte(0); + + // Bearer Data Length + let dataLength = pdu.bearerData.length; + writeByte(dataLength); + + // Bearer Data + for (let i = 0; i < dataLength; i++) { + writeByte(pdu.bearerData[i]); + } + + return data; +} + /** * Verify CDMA SMS Delivery ACK Message. */ @@ -73,7 +231,7 @@ add_test(function test_processCdmaSmsStatusReport() { let postedMessage = workerHelper.postedMessage; // Check if pending token is removed. - do_check_true((errorClass === 2)? !!sentSmsMap[msgId]: !sentSmsMap[msgId]); + do_check_true((errorClass === 2) ? !!sentSmsMap[msgId] : !sentSmsMap[msgId]); // Check the response message accordingly. if (errorClass === -1) { @@ -98,3 +256,67 @@ add_test(function test_processCdmaSmsStatusReport() { run_next_test(); }); + +/** + * Verify WAP Push over CDMA SMS Message. + */ +add_test(function test_processCdmaSmsWapPush() { + let workerHelper = _getWorker(), + worker = workerHelper.worker, + bitBufferHelper = worker.BitBufferHelper, + cdmaPduHelper = worker.CdmaPDUHelper; + + function test_CdmaSmsWapPdu(wdpData, reversed) { + let orig_address = "0987654321", + hexString, + fullDataHexString = ""; + + for (let i = 0; i < wdpData.length; i++) { + let dataIndex = (reversed) ? (wdpData.length - i - 1) : i; + hexString = "00"; // MSG_TYPE + hexString += bytesToHexString([wdpData.length]); // TOTAL_SEG + hexString += bytesToHexString([dataIndex]); // SEG_NUM (zero-based) + if ((dataIndex === 0)) { + hexString += "23F00B84"; // SOURCE_PORT, DEST_PORT for 1st segment + } + hexString += wdpData[dataIndex]; // WDP DATA + + do_print("hexString: " + hexString); + + fullDataHexString += wdpData[i]; + + let pdu = { + teleservice: PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, + address: orig_address, + bearerData: encodeOpaqueUserData(bitBufferHelper, + { msg_type: PDU_CDMA_MSG_TYPE_DELIVER, + data: hexStringToBytes(hexString) }) + }; + + worker.onRILMessage(newSmsParcel(cdmaPduHelper, pdu)); + } + + let postedMessage = workerHelper.postedMessage; + + do_print("fullDataHexString: " + fullDataHexString); + + do_check_eq("sms-received", postedMessage.rilMessageType); + do_check_eq(PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, postedMessage.teleservice); + do_check_eq(orig_address, postedMessage.sender); + do_check_eq(0x23F0, postedMessage.header.originatorPort); + do_check_eq(0x0B84, postedMessage.header.destinationPort); + do_check_eq(fullDataHexString, bytesToHexString(postedMessage.fullData)); + } + + // Verify Single WAP PDU + test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F"]); + + // Verify Concatenated WAP PDUs + test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F", "0F0E0D0C0B0A09080706050403020100"]); + + // Verify Concatenated WAP PDUs received in reversed order. + // Note: the port information is only available in 1st segment in CDMA WAP Push. + test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F", "0F0E0D0C0B0A09080706050403020100"], true); + + run_next_test(); +}); \ No newline at end of file diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 82ff35df7075..6ba9895b6367 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -27,6 +27,7 @@ #include "jsfriendapi.h" #include "mozilla/ArrayUtils.h" #include "mozilla/CycleCollectedJSRuntime.h" +#include "mozilla/dom/asmjscache/AsmJSCache.h" #include "mozilla/dom/AtomList.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ErrorEventBinding.h" @@ -766,6 +767,53 @@ CTypesActivityCallback(JSContext* aCx, } } +static nsIPrincipal* +GetPrincipalForAsmJSCacheOp() +{ + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + if (!workerPrivate) { + return nullptr; + } + + // asmjscache::OpenEntryForX guarnatee to only access the given nsIPrincipal + // from the main thread. + return workerPrivate->GetPrincipalDontAssertMainThread(); +} + +static bool +AsmJSCacheOpenEntryForRead(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aLimit, + size_t* aSize, + const uint8_t** aMemory, + intptr_t *aHandle) +{ + nsIPrincipal* principal = GetPrincipalForAsmJSCacheOp(); + if (!principal) { + return false; + } + + return asmjscache::OpenEntryForRead(principal, aBegin, aLimit, aSize, aMemory, + aHandle); +} + +static bool +AsmJSCacheOpenEntryForWrite(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aEnd, + size_t aSize, + uint8_t** aMemory, + intptr_t* aHandle) +{ + nsIPrincipal* principal = GetPrincipalForAsmJSCacheOp(); + if (!principal) { + return false; + } + + return asmjscache::OpenEntryForWrite(principal, aBegin, aEnd, aSize, aMemory, + aHandle); +} + struct WorkerThreadRuntimePrivate : public PerThreadAtomCache { WorkerPrivate* mWorkerPrivate; @@ -808,6 +856,16 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime) }; SetDOMCallbacks(aRuntime, &DOMCallbacks); + // Set up the asm.js cache callbacks + static JS::AsmJSCacheOps asmJSCacheOps = { + AsmJSCacheOpenEntryForRead, + asmjscache::CloseEntryForRead, + AsmJSCacheOpenEntryForWrite, + asmjscache::CloseEntryForWrite, + asmjscache::GetBuildId + }; + JS::SetAsmJSCacheOps(aRuntime, &asmJSCacheOps); + JSContext* workerCx = JS_NewContext(aRuntime, 0); if (!workerCx) { NS_WARNING("Could not create new context!"); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index eb63d6516926..bbf7f0687710 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -94,7 +94,7 @@ using mozilla::AutoSafeJSContext; USING_WORKERS_NAMESPACE using namespace mozilla::dom; -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(JsWorkerMallocSizeOf) namespace { @@ -2006,8 +2006,10 @@ struct WorkerPrivate::TimeoutInfo bool mCanceled; }; -class WorkerPrivate::MemoryReporter MOZ_FINAL : public MemoryMultiReporter +class WorkerPrivate::MemoryReporter MOZ_FINAL : public nsIMemoryReporter { + NS_DECL_THREADSAFE_ISUPPORTS + friend class WorkerPrivate; SharedMutex mMutex; @@ -2119,6 +2121,8 @@ private: } }; +NS_IMPL_ISUPPORTS1(WorkerPrivate::MemoryReporter, nsIMemoryReporter) + template WorkerPrivateParent::WorkerPrivateParent( JSContext* aCx, diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index dd75b74b0762..6777be7247ec 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -600,6 +600,15 @@ public: return mLoadInfo.mPrincipal; } + // This method allows the principal to be retrieved off the main thread. + // Principals are main-thread objects so the caller must ensure that all + // access occurs on the main thread. + nsIPrincipal* + GetPrincipalDontAssertMainThread() const + { + return mLoadInfo.mPrincipal; + } + void SetPrincipal(nsIPrincipal* aPrincipal); diff --git a/dom/workers/moz.build b/dom/workers/moz.build index 03c660da75b7..bc43618166e8 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -60,4 +60,6 @@ LOCAL_INCLUDES += [ '/xpcom/build', ] +include('/ipc/chromium/chromium-config.mozbuild') + FINAL_LIBRARY = 'gklayout' diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 9ed589d387d0..cf7023be972c 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -431,7 +431,6 @@ public: // XXX I expect we will want to move mWidget into this class and implement // these methods properly. virtual nsIWidget* GetWidget() const { return nullptr; } - virtual const nsIntSize& GetWidgetSize() = 0; // Call before and after any rendering not done by this compositor but which // might affect the compositor's internal state or the state of any APIs it diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 53fa38457d51..6091347e7916 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -133,15 +133,6 @@ LayerManager::CreateDrawTarget(const IntSize &aSize, CreateOffscreenCanvasDrawTarget(aSize, aFormat); } -TextureFactoryIdentifier -LayerManager::GetTextureFactoryIdentifier() -{ - //TODO[nrc] make pure virtual when all layer managers use Compositor - NS_ERROR("Should have been overridden"); - return TextureFactoryIdentifier(); -} - - #ifdef DEBUG void LayerManager::Mutated(Layer* aLayer) @@ -184,6 +175,7 @@ Layer::Layer(LayerManager* aManager, void* aImplData) : mIsFixedPosition(false), mMargins(0, 0, 0, 0), mStickyPositionData(nullptr), + mIsScrollbar(false), mDebugColorIndex(0), mAnimationGeneration(0) {} @@ -1278,6 +1270,13 @@ Layer::PrintInfo(nsACString& aTo, const char* aPrefix) if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) { aTo += " [componentAlpha]"; } + if (GetIsScrollbar()) { + if (GetScrollbarDirection() == VERTICAL) { + aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId()); + } else { + aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId()); + } + } if (GetIsFixedPosition()) { aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f]", mAnchor.x, mAnchor.y); } diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 5495036de964..a98f023e4c7c 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -437,12 +437,6 @@ public: virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize) { return true; } - /** - * Returns a TextureFactoryIdentifier which describes properties of the backend - * used to decide what kind of texture and buffer clients to create - */ - virtual TextureFactoryIdentifier GetTextureFactoryIdentifier(); - /** * returns the maximum texture size on this layer backend, or INT32_MAX * if there is no maximum @@ -972,6 +966,29 @@ public: } } + enum ScrollDirection { + VERTICAL, + HORIZONTAL + }; + + /** + * CONSTRUCTION PHASE ONLY + * If a layer is a scrollbar layer, |aScrollId| holds the scroll identifier + * of the scrollable content that the scrollbar is for. + */ + void SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir) + { + if (mIsScrollbar || + mScrollbarTargetId != aScrollId || + mScrollbarDirection != aDir) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this)); + mIsScrollbar = true; + mScrollbarTargetId = aScrollId; + mScrollbarDirection = aDir; + Mutated(); + } + } + // These getters can be used anytime. float GetOpacity() { return mOpacity; } gfxContext::GraphicsOperator GetMixBlendMode() const { return mMixBlendMode; } @@ -996,6 +1013,9 @@ public: FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; } const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; } const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; } + bool GetIsScrollbar() { return mIsScrollbar; } + FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mScrollbarTargetId; } + ScrollDirection GetScrollbarDirection() { return mScrollbarDirection; } Layer* GetMaskLayer() const { return mMaskLayer; } // Note that all lengths in animation data are either in CSS pixels or app @@ -1367,6 +1387,9 @@ protected: LayerRect mInner; }; nsAutoPtr mStickyPositionData; + bool mIsScrollbar; + FrameMetrics::ViewID mScrollbarTargetId; + ScrollDirection mScrollbarDirection; DebugOnly mDebugColorIndex; // If this layer is used for OMTA, then this counter is used to ensure we // stay in sync with the animation manager diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 97e8b485f080..cc934831b3b8 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -220,7 +220,6 @@ CreateBasicDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType, BasicCompositor::BasicCompositor(nsIWidget *aWidget) : mWidget(aWidget) - , mWidgetSize(-1, -1) { MOZ_COUNT_CTOR(BasicCompositor); sBackend = LAYERS_BASIC; @@ -540,7 +539,6 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, nsIntRect intRect; mWidget->GetClientBounds(intRect); Rect rect = Rect(0, 0, intRect.width, intRect.height); - mWidgetSize = intRect.Size(); nsIntRect invalidRect = aInvalidRegion.GetBounds(); mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height); diff --git a/gfx/layers/basic/BasicCompositor.h b/gfx/layers/basic/BasicCompositor.h index ac969937cef0..e4500e6c0d49 100644 --- a/gfx/layers/basic/BasicCompositor.h +++ b/gfx/layers/basic/BasicCompositor.h @@ -119,10 +119,6 @@ public: virtual const char* Name() const { return "Basic"; } virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } - virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE - { - return mWidgetSize; - } gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; } diff --git a/gfx/layers/client/ClientLayerManager.h b/gfx/layers/client/ClientLayerManager.h index 0955238ead53..ddff4448933d 100644 --- a/gfx/layers/client/ClientLayerManager.h +++ b/gfx/layers/client/ClientLayerManager.h @@ -73,7 +73,7 @@ public: virtual already_AddRefed CreateColorLayer(); virtual already_AddRefed CreateRefLayer(); - virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE + TextureFactoryIdentifier GetTextureFactoryIdentifier() { return mForwarder->GetTextureFactoryIdentifier(); } diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 7ade94b70776..95d459b8044c 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -501,9 +501,9 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram mLayerManager->GetCompositor()->SetScreenRenderOffset(offset); gfx3DMatrix transform(gfx3DMatrix(treeTransform) * aLayer->GetTransform()); - // The transform already takes the resolution scale into account. Since we - // will apply the resolution scale again when computing the effective - // transform, we must apply the inverse resolution scale here. + // GetTransform already takes the pre- and post-scale into account. Since we + // will apply the pre- and post-scale again when computing the effective + // transform, we must apply the inverses here. transform.Scale(1.0f/container->GetPreXScale(), 1.0f/container->GetPreYScale(), 1); @@ -524,9 +524,69 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram appliedTransform = true; } + if (container->GetIsScrollbar()) { + ApplyAsyncTransformToScrollbar(container); + } return appliedTransform; } +void +AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer) +{ + // If this layer corresponds to a scrollbar, then search backwards through the + // siblings until we find the container layer with the right ViewID; this is + // the content that this scrollbar is for. Pick up the transient async transform + // from that layer and use it to update the scrollbar position. + // Note that it is possible that the content layer is no longer there; in + // this case we don't need to do anything because there can't be an async + // transform on the content. + for (Layer* scrollTarget = aLayer->GetPrevSibling(); + scrollTarget; + scrollTarget = scrollTarget->GetPrevSibling()) { + if (!scrollTarget->AsContainerLayer()) { + continue; + } + AsyncPanZoomController* apzc = scrollTarget->AsContainerLayer()->GetAsyncPanZoomController(); + if (!apzc) { + continue; + } + const FrameMetrics& metrics = scrollTarget->AsContainerLayer()->GetFrameMetrics(); + if (metrics.mScrollId != aLayer->GetScrollbarTargetContainerId()) { + continue; + } + + gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform()); + gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform(); + gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse(); + + gfx3DMatrix scrollbarTransform; + if (aLayer->GetScrollbarDirection() == Layer::VERTICAL) { + float scale = metrics.CalculateCompositedRectInCssPixels().height / metrics.mScrollableRect.height; + scrollbarTransform.ScalePost(1.f, 1.f / transientTransform.GetYScale(), 1.f); + scrollbarTransform.TranslatePost(gfxPoint3D(0, -transientTransform._42 * scale, 0)); + } + if (aLayer->GetScrollbarDirection() == Layer::HORIZONTAL) { + float scale = metrics.CalculateCompositedRectInCssPixels().width / metrics.mScrollableRect.width; + scrollbarTransform.ScalePost(1.f / transientTransform.GetXScale(), 1.f, 1.f); + scrollbarTransform.TranslatePost(gfxPoint3D(-transientTransform._41 * scale, 0, 0)); + } + + gfx3DMatrix transform = scrollbarTransform * aLayer->GetTransform(); + // GetTransform already takes the pre- and post-scale into account. Since we + // will apply the pre- and post-scale again when computing the effective + // transform, we must apply the inverses here. + transform.Scale(1.0f/aLayer->GetPreXScale(), + 1.0f/aLayer->GetPreYScale(), + 1); + transform.ScalePost(1.0f/aLayer->GetPostXScale(), + 1.0f/aLayer->GetPostYScale(), + 1); + aLayer->AsLayerComposite()->SetShadowTransform(transform); + + return; + } +} + void AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) { diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index d97c3385f64a..705c9f0d794c 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -123,6 +123,11 @@ private: // controller wants another animation frame. bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer, bool* aWantNextFrame); + /** + * Update the shadow trasnform for aLayer assuming that is a scrollbar, + * so that it stays in sync with the content that is being scrolled by APZ. + */ + void ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer); void SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index ea3a6b0e3c74..e16fbb2d6a21 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -203,6 +203,7 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback, EndTransactionFlags aFlags) { NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); + NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here"); mInTransaction = false; if (!mIsCompositorReady) { @@ -240,13 +241,7 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback, // so we don't need to pass any global transform here. mRoot->ComputeEffectiveTransforms(gfx3DMatrix()); - mThebesLayerCallback = aCallback; - mThebesLayerCallbackData = aCallbackData; - Render(); - - mThebesLayerCallback = nullptr; - mThebesLayerCallbackData = nullptr; } mCompositor->SetTargetContext(nullptr); @@ -307,7 +302,7 @@ LayerManagerComposite::RootLayer() const return nullptr; } - return static_cast(mRoot->ImplData()); + return ToLayerComposite(mRoot); } static uint16_t sFrameCount = 0; @@ -723,7 +718,7 @@ LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer, return; } - mCompositable = static_cast(aMaskLayer->ImplData())->GetCompositableHost(); + mCompositable = ToLayerComposite(aMaskLayer)->GetCompositableHost(); if (!mCompositable) { NS_WARNING("Mask layer with no compositable host"); return; @@ -786,25 +781,6 @@ LayerComposite::Destroy() } } -const nsIntSize& -LayerManagerComposite::GetWidgetSize() -{ - return mCompositor->GetWidgetSize(); -} - -void -LayerManagerComposite::SetCompositorID(uint32_t aID) -{ - NS_ASSERTION(mCompositor, "No compositor"); - mCompositor->SetCompositorID(aID); -} - -void -LayerManagerComposite::NotifyShadowTreeTransaction() -{ - mCompositor->NotifyLayersTransaction(); -} - bool LayerManagerComposite::CanUseCanvasLayerForSize(const gfxIntSize &aSize) { @@ -812,18 +788,6 @@ LayerManagerComposite::CanUseCanvasLayerForSize(const gfxIntSize &aSize) aSize.height)); } -TextureFactoryIdentifier -LayerManagerComposite::GetTextureFactoryIdentifier() -{ - return mCompositor->GetTextureFactoryIdentifier(); -} - -int32_t -LayerManagerComposite::GetMaxTextureSize() const -{ - return mCompositor->GetMaxTextureSize(); -} - #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS /*static*/ bool diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index d0097abaf4f6..26c3a1b94906 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -110,8 +110,6 @@ public: } void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget); - void NotifyShadowTreeTransaction(); - virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) MOZ_OVERRIDE; virtual void EndTransaction(DrawThebesLayerCallback aCallback, void* aCallbackData, @@ -119,11 +117,14 @@ public: virtual void SetRoot(Layer* aLayer) MOZ_OVERRIDE { mRoot = aLayer; } + // XXX[nrc]: never called, we should move this logic to ClientLayerManager + // (bug 946926). virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize) MOZ_OVERRIDE; - virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE; - - virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE; + virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE + { + MOZ_CRASH("Call on compositor, not LayerManagerComposite"); + } virtual void ClearCachedResources(Layer* aSubtree = nullptr) MOZ_OVERRIDE; @@ -141,24 +142,16 @@ public: virtual LayersBackend GetBackendType() MOZ_OVERRIDE { - return LAYERS_NONE; + MOZ_CRASH("Shouldn't be called for composited layer manager"); } virtual void GetBackendName(nsAString& name) MOZ_OVERRIDE { - MOZ_ASSERT(false, "Shouldn't be called for composited layer manager"); - name.AssignLiteral("Composite"); + MOZ_CRASH("Shouldn't be called for composited layer manager"); } virtual already_AddRefed CreateOptimalMaskSurface(const gfxIntSize &aSize) MOZ_OVERRIDE; - - DrawThebesLayerCallback GetThebesLayerCallback() const - { return mThebesLayerCallback; } - - void* GetThebesLayerCallbackData() const - { return mThebesLayerCallbackData; } - virtual const char* Name() const MOZ_OVERRIDE { return ""; } enum WorldTransforPolicy { @@ -195,11 +188,9 @@ public: * layermanager. */ virtual TemporaryRef - CreateDrawTarget(const mozilla::gfx::IntSize &aSize, + CreateDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat) MOZ_OVERRIDE; - const nsIntSize& GetWidgetSize(); - /** * Calculates the 'completeness' of the rendering that intersected with the * screen on the last render. This is only useful when progressive tile @@ -217,8 +208,6 @@ public: static void PlatformSyncBeforeReplyUpdate(); - void SetCompositorID(uint32_t aID); - void AddInvalidRegion(const nsIntRegion& aRegion) { mInvalidRegion.Or(mInvalidRegion, aRegion); @@ -245,7 +234,7 @@ private: nsIntRect mRenderBounds; /** Current root layer. */ - LayerComposite *RootLayer() const; + LayerComposite* RootLayer() const; /** * Recursive helper method for use by ComputeRenderIntegrity. Subtracts @@ -275,10 +264,6 @@ private: /** Our more efficient but less powerful alter ego, if one is available. */ nsRefPtr mComposer2D; - /* Thebes layer callbacks; valid at the end of a transaciton, - * while rendering */ - DrawThebesLayerCallback mThebesLayerCallback; - void *mThebesLayerCallbackData; gfxMatrix mWorldMatrix; bool mInTransaction; diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index 5a4601ddec56..601a5b51639c 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -549,6 +549,8 @@ MemoryTextureHost::MemoryTextureHost(uint64_t aID, MemoryTextureHost::~MemoryTextureHost() { DeallocateDeviceData(); + NS_ASSERTION(!mBuffer || (mFlags & TEXTURE_DEALLOCATE_CLIENT), + "Leaking our buffer"); MOZ_COUNT_DTOR(MemoryTextureHost); } diff --git a/gfx/layers/d3d11/CompositorD3D11.h b/gfx/layers/d3d11/CompositorD3D11.h index acd767c5d598..664419788656 100644 --- a/gfx/layers/d3d11/CompositorD3D11.h +++ b/gfx/layers/d3d11/CompositorD3D11.h @@ -139,14 +139,6 @@ public: virtual void NotifyLayersTransaction() MOZ_OVERRIDE { } virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } - virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE - { - NS_ASSERTION(false, "Getting the widget size on windows causes some kind of resizing of buffers. " - "You should not do that outside of BeginFrame, so the best we can do is return " - "the last size we got, that might not be up to date. So you probably shouldn't " - "use this method."); - return mSize; - } ID3D11Device* GetDevice() { return mDevice; } diff --git a/gfx/layers/d3d9/CompositorD3D9.h b/gfx/layers/d3d9/CompositorD3D9.h index ca8d3542e47f..7b96fa561a3b 100644 --- a/gfx/layers/d3d9/CompositorD3D9.h +++ b/gfx/layers/d3d9/CompositorD3D9.h @@ -86,14 +86,6 @@ public: virtual void NotifyLayersTransaction() MOZ_OVERRIDE {} virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } - virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE - { - NS_ASSERTION(false, "Getting the widget size on windows causes some kind of resizing of buffers. " - "You should not do that outside of BeginFrame, so the best we can do is return " - "the last size we got, that might not be up to date. So you probably shouldn't " - "use this method."); - return mSize; - } IDirect3DDevice9* device() const { diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index feddfd71dc9e..a89933239a94 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1647,9 +1647,11 @@ void AsyncPanZoomController::SetState(PanZoomState aNewState) { if (mGeckoContentController) { if (!IsTransformingState(oldState) && IsTransformingState(aNewState)) { - mGeckoContentController->NotifyTransformBegin(); + mGeckoContentController->NotifyTransformBegin( + ScrollableLayerGuid(mLayersId, mFrameMetrics.mPresShellId, mFrameMetrics.mScrollId)); } else if (IsTransformingState(oldState) && !IsTransformingState(aNewState)) { - mGeckoContentController->NotifyTransformEnd(); + mGeckoContentController->NotifyTransformEnd( + ScrollableLayerGuid(mLayersId, mFrameMetrics.mPresShellId, mFrameMetrics.mScrollId)); } } } diff --git a/gfx/layers/ipc/CompositorCocoaWidgetHelper.cpp b/gfx/layers/ipc/CompositorCocoaWidgetHelper.cpp deleted file mode 100644 index 40d7d522093e..000000000000 --- a/gfx/layers/ipc/CompositorCocoaWidgetHelper.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 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 "CompositorParent.h" -#include "CompositorCocoaWidgetHelper.h" -#include "nsDebug.h" - -namespace mozilla { -namespace layers { -namespace compositor { - -LayerManagerComposite* -GetLayerManager(CompositorParent* aParent) -{ - return aParent->GetLayerManager(); -} - - -} -} -} diff --git a/gfx/layers/ipc/CompositorCocoaWidgetHelper.h b/gfx/layers/ipc/CompositorCocoaWidgetHelper.h deleted file mode 100644 index 5da00f767896..000000000000 --- a/gfx/layers/ipc/CompositorCocoaWidgetHelper.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- 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/. */ - -#ifndef mozilla_layers_CompositorCocoaWidgetHelper_h -#define mozilla_layers_CompositorCocoaWidgetHelper_h - -// Note we can't include IPDL-generated headers here, since this file is being -// used as a workaround for Bug 719036. - -namespace mozilla { -namespace layers { - -class CompositorParent; -class LayerManagerComposite; - -namespace compositor { - -// Needed when we cannot directly include CompositorParent.h since it includes -// an IPDL-generated header (e.g. in widget/cocoa/nsChildView.mm; see Bug 719036). -LayerManagerComposite* GetLayerManager(CompositorParent* aParent); - -} -} -} -#endif // mozilla_layers_CompositorCocoaWidgetHelper_h - diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 8ca9f571fe6c..8f8a2f668e06 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -62,6 +62,7 @@ namespace layers { CompositorParent::LayerTreeState::LayerTreeState() : mParent(nullptr) + , mLayerManager(nullptr) { } @@ -237,6 +238,7 @@ CompositorParent::Destroy() // Ensure that the layer manager is destructed on the compositor thread. mLayerManager = nullptr; + mCompositor = nullptr; mCompositionManager = nullptr; mApzcTreeManager->ClearTree(); mApzcTreeManager = nullptr; @@ -263,10 +265,12 @@ CompositorParent::RecvWillStop() LayerTreeState* lts = &it->second; if (lts->mParent == this) { mLayerManager->ClearCachedResources(lts->mRoot); + lts->mLayerManager = nullptr; } } mLayerManager->Destroy(); mLayerManager = nullptr; + mCompositor = nullptr; mCompositionManager = nullptr; } @@ -371,7 +375,9 @@ CompositorParent::ActorDestroy(ActorDestroyReason why) if (mLayerManager) { mLayerManager->Destroy(); mLayerManager = nullptr; + sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr; mCompositionManager = nullptr; + mCompositor = nullptr; } } @@ -394,7 +400,7 @@ CompositorParent::PauseComposition() if (!mPaused) { mPaused = true; - mLayerManager->GetCompositor()->Pause(); + mCompositor->Pause(); } // if anyone's waiting to make sure that composition really got paused, tell them @@ -409,7 +415,7 @@ CompositorParent::ResumeComposition() MonitorAutoLock lock(mResumeCompositionMonitor); - if (!mLayerManager->GetCompositor()->Resume()) { + if (!mCompositor->Resume()) { #ifdef MOZ_WIDGET_ANDROID // We can't get a surface. This could be because the activity changed between // the time resume was scheduled and now. @@ -440,8 +446,8 @@ CompositorParent::SetEGLSurfaceSize(int width, int height) { NS_ASSERTION(mUseExternalSurfaceSize, "Compositor created without UseExternalSurfaceSize provided"); mEGLSurfaceSize.SizeTo(width, height); - if (mLayerManager) { - mLayerManager->GetCompositor()->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height)); + if (mCompositor) { + mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height)); } } @@ -503,7 +509,7 @@ CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint) AutoResolveRefLayers resolve(mCompositionManager); mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId); - mLayerManager->AsLayerManagerComposite()->NotifyShadowTreeTransaction(); + mCompositor->NotifyLayersTransaction(); } ScheduleComposition(); } @@ -697,7 +703,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, } } ScheduleComposition(); - mLayerManager->NotifyShadowTreeTransaction(); + mCompositor->NotifyLayersTransaction(); } void @@ -706,34 +712,32 @@ CompositorParent::InitializeLayerManager(const nsTArray& aBackend NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager"); for (size_t i = 0; i < aBackendHints.Length(); ++i) { - RefPtr layerManager; + RefPtr compositor; if (aBackendHints[i] == LAYERS_OPENGL) { - layerManager = - new LayerManagerComposite(new CompositorOGL(mWidget, - mEGLSurfaceSize.width, - mEGLSurfaceSize.height, - mUseExternalSurfaceSize)); + compositor = new CompositorOGL(mWidget, + mEGLSurfaceSize.width, + mEGLSurfaceSize.height, + mUseExternalSurfaceSize); } else if (aBackendHints[i] == LAYERS_BASIC) { - layerManager = - new LayerManagerComposite(new BasicCompositor(mWidget)); + compositor = new BasicCompositor(mWidget); #ifdef XP_WIN } else if (aBackendHints[i] == LAYERS_D3D11) { - layerManager = - new LayerManagerComposite(new CompositorD3D11(mWidget)); + compositor = new CompositorD3D11(mWidget); } else if (aBackendHints[i] == LAYERS_D3D9) { - layerManager = - new LayerManagerComposite(new CompositorD3D9(this, mWidget)); + compositor = new CompositorD3D9(this, mWidget); #endif } - if (!layerManager) { - continue; - } + MOZ_ASSERT(compositor, "Passed invalid backend hint"); - layerManager->SetCompositorID(mCompositorID); + compositor->SetCompositorID(mCompositorID); + RefPtr layerManager = new LayerManagerComposite(compositor); if (layerManager->Initialize()) { mLayerManager = layerManager; + MOZ_ASSERT(compositor); + mCompositor = compositor; + sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = layerManager; return; } } @@ -765,7 +769,7 @@ CompositorParent::AllocPLayerTransactionParent(const nsTArray& aB mCompositionManager = new AsyncCompositionManager(mLayerManager); *aSuccess = true; - *aTextureFactoryIdentifier = mLayerManager->GetTextureFactoryIdentifier(); + *aTextureFactoryIdentifier = mCompositor->GetTextureFactoryIdentifier(); LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, 0); p->AddIPDLReference(); return p; @@ -851,6 +855,7 @@ void CompositorParent::NotifyChildCreated(uint64_t aChild) { sIndirectLayerTrees[aChild].mParent = this; + sIndirectLayerTrees[aChild].mLayerManager = mLayerManager; } /*static*/ uint64_t @@ -921,6 +926,17 @@ CompositorParent::GetAPZCTreeManager(uint64_t aLayersId) return nullptr; } +float +CompositorParent::ComputeRenderIntegrity() +{ + if (mLayerManager) { + return mLayerManager->ComputeRenderIntegrity(); + } + + return 1.0f; +} + + /** * This class handles layer updates pushed directly from child * processes to the compositor thread. It's associated with a @@ -1071,9 +1087,9 @@ CrossProcessCompositorParent::AllocPLayerTransactionParent(const nsTArrayGetLayerManager(); - *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier(); + if (sIndirectLayerTrees[aId].mLayerManager) { + LayerManagerComposite* lm = sIndirectLayerTrees[aId].mLayerManager; + *aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier(); *aSuccess = true; LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId); p->AddIPDLReference(); diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index c8f2c46d0686..cfe5a425738d 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -47,6 +47,7 @@ namespace layers { class APZCTreeManager; class AsyncCompositionManager; +class Compositor; class LayerManagerComposite; class LayerTransactionParent; @@ -107,8 +108,6 @@ public: void ForceIsFirstPaint(); void Destroy(); - LayerManagerComposite* GetLayerManager() { return mLayerManager; } - void NotifyChildCreated(uint64_t aChild); void AsyncRender(); @@ -203,6 +202,7 @@ public: nsRefPtr mRoot; nsRefPtr mController; CompositorParent* mParent; + LayerManagerComposite* mLayerManager; TargetConfig mTargetConfig; }; @@ -213,6 +213,8 @@ public: */ static const LayerTreeState* GetIndirectShadowTree(uint64_t aId); + float ComputeRenderIntegrity(); + /** * Tell all CompositorParents to update their last refresh to aTime and sample * animations at this time stamp. If aIsTesting is true, the @@ -295,6 +297,7 @@ private: bool CanComposite(); nsRefPtr mLayerManager; + nsRefPtr mCompositor; RefPtr mCompositionManager; nsIWidget* mWidget; CancelableTask *mCurrentCompositeTask; diff --git a/gfx/layers/ipc/GeckoContentController.h b/gfx/layers/ipc/GeckoContentController.h index 4f78217defda..201f97273c28 100644 --- a/gfx/layers/ipc/GeckoContentController.h +++ b/gfx/layers/ipc/GeckoContentController.h @@ -81,8 +81,8 @@ public: * the apzc is modifying the view, including panning, zooming, and * fling. */ - virtual void NotifyTransformBegin() {} - virtual void NotifyTransformEnd() {} + virtual void NotifyTransformBegin(const ScrollableLayerGuid& aGuid) {} + virtual void NotifyTransformEnd(const ScrollableLayerGuid& aGuid) {} GeckoContentController() {} virtual ~GeckoContentController() {} diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index d71dacf16a73..d07fdca9fc7c 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -279,6 +279,10 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray& cset, common.stickyScrollRangeOuter(), common.stickyScrollRangeInner()); } + if (common.isScrollbar()) { + layer->SetScrollbarData(common.scrollbarTargetContainerId(), + static_cast(common.scrollbarDirection())); + } if (PLayerParent* maskLayer = common.maskLayerParent()) { layer->SetMaskLayer(cast(maskLayer)->AsLayer()); } else { diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 4f0a374415a4..83049ab4df8d 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -197,6 +197,9 @@ struct CommonLayerAttributes { uint64_t stickyScrollContainerId; LayerRect stickyScrollRangeOuter; LayerRect stickyScrollRangeInner; + bool isScrollbar; + uint64_t scrollbarTargetContainerId; + uint32_t scrollbarDirection; nullable PLayer maskLayer; // Animated colors will only honored for ColorLayers. Animation[] animations; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index be4f62906cb9..87fe40c5d85d 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -528,6 +528,11 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray* aReplies, bool common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter(); common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner(); } + common.isScrollbar() = mutant->GetIsScrollbar(); + if (mutant->GetIsScrollbar()) { + common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId(); + common.scrollbarDirection() = mutant->GetScrollbarDirection(); + } if (Layer* maskLayer = mutant->GetMaskLayer()) { common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer()); } else { diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 6b5d77857bf3..9af45accae0f 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -128,7 +128,6 @@ EXPORTS.mozilla.layers += [ 'ipc/CompositableForwarder.h', 'ipc/CompositableTransactionParent.h', 'ipc/CompositorChild.h', - 'ipc/CompositorCocoaWidgetHelper.h', 'ipc/CompositorParent.h', 'ipc/GeckoContentController.h', 'ipc/GestureEventListener.h', @@ -240,7 +239,6 @@ UNIFIED_SOURCES += [ 'ipc/Axis.cpp', 'ipc/CompositableTransactionParent.cpp', 'ipc/CompositorChild.cpp', - 'ipc/CompositorCocoaWidgetHelper.cpp', 'ipc/CompositorParent.cpp', 'ipc/GestureEventListener.cpp', 'ipc/ImageBridgeChild.cpp', diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index 72a3db542fd8..e6427a593fba 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -158,9 +158,6 @@ public: virtual bool Resume() MOZ_OVERRIDE; virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; } - virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE { - return mWidgetSize; - } GLContext* gl() const { return mGLContext; } ShaderProgramType GetFBOLayerProgramType() const { diff --git a/gfx/layers/opengl/GLManager.cpp b/gfx/layers/opengl/GLManager.cpp index f6a610c6eb45..6aaa1eb99160 100644 --- a/gfx/layers/opengl/GLManager.cpp +++ b/gfx/layers/opengl/GLManager.cpp @@ -6,7 +6,6 @@ #include "GLManager.h" #include "CompositorOGL.h" // for CompositorOGL #include "GLContext.h" // for GLContext -#include "Layers.h" // for LayerManager #include "mozilla/Assertions.h" // for MOZ_CRASH #include "mozilla/Attributes.h" // for MOZ_OVERRIDE #include "mozilla/RefPtr.h" // for RefPtr @@ -15,7 +14,6 @@ #include "mozilla/layers/LayersTypes.h" #include "mozilla/mozalloc.h" // for operator new, etc #include "nsAutoPtr.h" // for nsRefPtr -#include "nsISupportsImpl.h" // for LayerManager::AddRef, etc using namespace mozilla::gl; @@ -49,21 +47,14 @@ private: }; /* static */ GLManager* -GLManager::CreateGLManager(LayerManager* aManager) +GLManager::CreateGLManager(LayerManagerComposite* aManager) { - if (!aManager) { - return nullptr; + if (aManager && + Compositor::GetBackend() == LAYERS_OPENGL) { + return new GLManagerCompositor(static_cast( + aManager->GetCompositor())); } - if (aManager->GetBackendType() == LAYERS_NONE) { - if (Compositor::GetBackend() == LAYERS_OPENGL) { - return new GLManagerCompositor(static_cast( - static_cast(aManager)->GetCompositor())); - } else { - return nullptr; - } - } - - MOZ_CRASH("Cannot create GLManager for non-GL layer manager"); + return nullptr; } } diff --git a/gfx/layers/opengl/GLManager.h b/gfx/layers/opengl/GLManager.h index 32c84484bc56..8319122a17b9 100644 --- a/gfx/layers/opengl/GLManager.h +++ b/gfx/layers/opengl/GLManager.h @@ -16,7 +16,7 @@ class GLContext; namespace layers { -class LayerManager; +class LayerManagerComposite; /** * Minimal interface to allow widgets to draw using OpenGL. Abstracts @@ -26,7 +26,7 @@ class LayerManager; class GLManager { public: - static GLManager* CreateGLManager(LayerManager* aManager); + static GLManager* CreateGLManager(LayerManagerComposite* aManager); virtual ~GLManager() {} diff --git a/gfx/src/nsRegion.h b/gfx/src/nsRegion.h index f0c5bc5ab1d6..96556680201b 100644 --- a/gfx/src/nsRegion.h +++ b/gfx/src/nsRegion.h @@ -256,8 +256,17 @@ private: nsRegion& Copy (const nsRect& aRect) { - pixman_box32_t box = RectToBox(aRect); - pixman_region32_reset(&mImpl, &box); + // pixman needs to distinguish between an empty region and a region + // with one rect so that it can return a different number of rectangles. + // Empty rect: data = empty_box + // 1 rect: data = NULL + // >1 rect: data = rects + if (aRect.IsEmpty()) { + pixman_region32_clear(&mImpl); + } else { + pixman_box32_t box = RectToBox(aRect); + pixman_region32_reset(&mImpl, &box); + } return *this; } diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 57b4b84c13b0..d3a51f41a36d 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -631,10 +631,10 @@ PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_SKIA) == static int64_t gSurfaceMemoryUsed[gfxSurfaceTypeMax] = { 0 }; -class SurfaceMemoryReporter MOZ_FINAL : public MemoryMultiReporter +class SurfaceMemoryReporter MOZ_FINAL : public nsIMemoryReporter { public: - SurfaceMemoryReporter() { } + NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb, nsISupports *aClosure) @@ -651,8 +651,7 @@ public: } nsresult rv = aCb->Callback(EmptyCString(), nsCString(path), - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_BYTES, + KIND_OTHER, UNITS_BYTES, gSurfaceMemoryUsed[i], nsCString(desc), aClosure); NS_ENSURE_SUCCESS(rv, rv); @@ -663,6 +662,8 @@ public: } }; +NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter, nsIMemoryReporter) + void gfxASurface::RecordMemoryUsedForSurfaceType(gfxSurfaceType aType, int32_t aBytes) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 06423086c986..3957e9214a77 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1360,7 +1360,9 @@ gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, * shaped-word caches to free up memory. */ -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FontCacheMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(FontCacheMallocSizeOf) + +NS_IMPL_ISUPPORTS1(gfxFontCache::MemoryReporter, nsIMemoryReporter) NS_IMETHODIMP gfxFontCache::MemoryReporter::CollectReports diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 4ce69ad4a328..83379a71eb82 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -951,13 +951,11 @@ public: FontCacheSizes* aSizes) const; protected: - class MemoryReporter MOZ_FINAL : public mozilla::MemoryMultiReporter + class MemoryReporter MOZ_FINAL : public nsIMemoryReporter { public: - MemoryReporter() {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb, - nsISupports* aClosure); + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER }; // Observer for notifications that the font cache cares about diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index b7bb7a790f01..2d41ba02306b 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -71,10 +71,9 @@ gfxFontListPrefObserver::Observe(nsISupports *aSubject, return NS_OK; } -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FontListMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf) -gfxPlatformFontList::MemoryReporter::MemoryReporter() -{} +NS_IMPL_ISUPPORTS1(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter) NS_IMETHODIMP gfxPlatformFontList::MemoryReporter::CollectReports @@ -91,23 +90,20 @@ gfxPlatformFontList::MemoryReporter::CollectReports aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("explicit/gfx/font-list"), - nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, - sizes.mFontListSize, + KIND_HEAP, UNITS_BYTES, sizes.mFontListSize, NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."), aClosure); aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"), - nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, - sizes.mCharMapsSize, + KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize, NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."), aClosure); if (sizes.mFontTableCacheSize) { aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("explicit/gfx/font-tables"), - nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, - sizes.mFontTableCacheSize, + KIND_HEAP, UNITS_BYTES, sizes.mFontTableCacheSize, NS_LITERAL_CSTRING("Memory used for cached font metrics and layout tables."), aClosure); } diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 6b95f8b1efc3..a35777107368 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -178,12 +178,11 @@ public: void RemoveCmap(const gfxCharacterMap *aCharMap); protected: - class MemoryReporter MOZ_FINAL : public mozilla::MemoryMultiReporter + class MemoryReporter MOZ_FINAL : public nsIMemoryReporter { public: - MemoryReporter(); - NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb, - nsISupports *aClosure); + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER }; gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true); diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 648167a3ef19..3ec8d8240a9d 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -3,10 +3,8 @@ * 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 MOZ_PANGO #define PANGO_ENABLE_BACKEND #define PANGO_ENABLE_ENGINE -#endif #include "gfxPlatformGtk.h" #include "prenv.h" @@ -14,16 +12,10 @@ #include "nsUnicharUtils.h" #include "nsUnicodeProperties.h" #include "gfxFontconfigUtils.h" -#ifdef MOZ_PANGO #include "gfxPangoFonts.h" #include "gfxContext.h" #include "gfxUserFontSet.h" #include "gfxFT2FontBase.h" -#else -#include -#include FT_FREETYPE_H -#include "gfxFT2Fonts.h" -#endif #include "mozilla/gfx/2D.h" @@ -56,16 +48,6 @@ using namespace mozilla::unicode; gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr; -#ifndef MOZ_PANGO -typedef nsDataHashtable > FontTable; -typedef nsDataHashtable > > PrefFontTable; -static FontTable *gPlatformFonts = nullptr; -static FontTable *gPlatformFontAliases = nullptr; -static PrefFontTable *gPrefFonts = nullptr; -static gfxSparseBitSet *gCodepointsWithNoFonts = nullptr; -static FT_Library gPlatformFTLibrary = nullptr; -#endif - static cairo_user_data_key_t cairo_gdk_drawable_key; #ifdef MOZ_X11 @@ -80,17 +62,6 @@ gfxPlatformGtk::gfxPlatformGtk() sUseXRender = mozilla::Preferences::GetBool("gfx.xrender.enabled"); #endif -#ifndef MOZ_PANGO - FT_Init_FreeType(&gPlatformFTLibrary); - gPlatformFonts = new FontTable(); - gPlatformFonts->Init(100); - gPlatformFontAliases = new FontTable(); - gPlatformFontAliases->Init(100); - gPrefFonts = new PrefFontTable(); - gPrefFonts->Init(100); - gCodepointsWithNoFonts = new gfxSparseBitSet(); - UpdateFontList(); -#endif uint32_t canvasMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA); uint32_t contentMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA); InitBackendPrefs(canvasMask, BACKEND_CAIRO, @@ -102,28 +73,7 @@ gfxPlatformGtk::~gfxPlatformGtk() gfxFontconfigUtils::Shutdown(); sFontconfigUtils = nullptr; -#ifdef MOZ_PANGO gfxPangoFontGroup::Shutdown(); -#else - delete gPlatformFonts; - gPlatformFonts = nullptr; - delete gPlatformFontAliases; - gPlatformFontAliases = nullptr; - delete gPrefFonts; - gPrefFonts = nullptr; - delete gCodepointsWithNoFonts; - gCodepointsWithNoFonts = nullptr; - -#ifdef NS_FREE_PERMANENT_DATA - // do cairo cleanup *before* closing down the FTLibrary, - // otherwise we'll crash when the gfxPlatform destructor - // calls it (bug 605009) - cairo_debug_reset_static_data(); - - FT_Done_FreeType(gPlatformFTLibrary); - gPlatformFTLibrary = nullptr; -#endif -#endif #if 0 // It would be nice to do this (although it might need to be after @@ -187,8 +137,6 @@ gfxPlatformGtk::CreateOffscreenSurface(const gfxIntSize& size, return newSurface.forget(); } -#ifdef MOZ_PANGO - nsresult gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, @@ -270,188 +218,6 @@ gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) return true; } -#else - -nsresult -gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray& aListOfFonts) -{ - return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily, - aListOfFonts); -} - -nsresult -gfxPlatformGtk::UpdateFontList() -{ - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *fs = nullptr; - int32_t result = -1; - - pat = FcPatternCreate(); - os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, FC_WEIGHT, FC_SLANT, FC_WIDTH, nullptr); - - fs = FcFontList(nullptr, pat, os); - - - for (int i = 0; i < fs->nfont; i++) { - char *str; - - if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - - //printf("Family: %s\n", str); - - nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get()); - nsAutoString key(name); - ToLowerCase(key); - nsRefPtr ff; - if (!gPlatformFonts->Get(key, &ff)) { - ff = new FontFamily(name); - gPlatformFonts->Put(key, ff); - } - - FontEntry *fe = new FontEntry(ff->Name()); - ff->AddFontEntry(fe); - - if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) { - fe->mFilename = nsDependentCString(str); - //printf(" - file: %s\n", str); - } - - int x; - if (FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &x) == FcResultMatch) { - //printf(" - index: %d\n", x); - fe->mFTFontIndex = x; - } else { - fe->mFTFontIndex = 0; - } - - fe->mWeight = gfxFontconfigUtils::GetThebesWeight(fs->fonts[i]); - //printf(" - weight: %d\n", fe->mWeight); - - fe->mItalic = false; - if (FcPatternGetInteger(fs->fonts[i], FC_SLANT, 0, &x) == FcResultMatch) { - switch (x) { - case FC_SLANT_ITALIC: - case FC_SLANT_OBLIQUE: - fe->mItalic = true; - } - //printf(" - slant: %d\n", x); - } - - //if (FcPatternGetInteger(fs->fonts[i], FC_WIDTH, 0, &x) == FcResultMatch) - //printf(" - width: %d\n", x); - // XXX deal with font-stretch stuff later - } - - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (fs) - FcFontSetDestroy(fs); - - return sFontconfigUtils->UpdateFontList(); -} - -nsresult -gfxPlatformGtk::ResolveFontName(const nsAString& aFontName, - FontResolverCallback aCallback, - void *aClosure, - bool& aAborted) -{ - - nsAutoString name(aFontName); - ToLowerCase(name); - - nsRefPtr ff; - if (gPlatformFonts->Get(name, &ff) || - gPlatformFontAliases->Get(name, &ff)) { - aAborted = !(*aCallback)(ff->Name(), aClosure); - return NS_OK; - } - - nsAutoCString utf8Name = NS_ConvertUTF16toUTF8(aFontName); - - FcPattern *npat = FcPatternCreate(); - FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get()); - FcObjectSet *nos = FcObjectSetBuild(FC_FAMILY, nullptr); - FcFontSet *nfs = FcFontList(nullptr, npat, nos); - - for (int k = 0; k < nfs->nfont; k++) { - FcChar8 *str; - if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))); - ToLowerCase(altName); - if (gPlatformFonts->Get(altName, &ff)) { - //printf("Adding alias: %s -> %s\n", utf8Name.get(), str); - gPlatformFontAliases->Put(name, ff); - aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))), aClosure); - goto DONE; - } - } - - FcPatternDestroy(npat); - FcObjectSetDestroy(nos); - FcFontSetDestroy(nfs); - - { - npat = FcPatternCreate(); - FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get()); - FcPatternDel(npat, FC_LANG); - FcConfigSubstitute(nullptr, npat, FcMatchPattern); - FcDefaultSubstitute(npat); - - nos = FcObjectSetBuild(FC_FAMILY, nullptr); - nfs = FcFontList(nullptr, npat, nos); - - FcResult fresult; - - FcPattern *match = FcFontMatch(nullptr, npat, &fresult); - if (match) - FcFontSetAdd(nfs, match); - - for (int k = 0; k < nfs->nfont; k++) { - FcChar8 *str; - if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))); - ToLowerCase(altName); - if (gPlatformFonts->Get(altName, &ff)) { - //printf("Adding alias: %s -> %s\n", utf8Name.get(), str); - gPlatformFontAliases->Put(name, ff); - aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))), aClosure); - goto DONE; - } - } - } - DONE: - FcPatternDestroy(npat); - FcObjectSetDestroy(nos); - FcFontSetDestroy(nfs); - - return NS_OK; -} - -nsresult -gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) -{ - return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName); -} - -gfxFontGroup * -gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet) -{ - return new gfxFT2FontGroup(aFamilies, aStyle, aUserFontSet); -} - -#endif - static int32_t sDPI = 0; int32_t @@ -637,90 +403,6 @@ gfxPlatformGtk::GetPlatformCMSOutputProfile() } -#ifndef MOZ_PANGO -FT_Library -gfxPlatformGtk::GetFTLibrary() -{ - return gPlatformFTLibrary; -} - -FontFamily * -gfxPlatformGtk::FindFontFamily(const nsAString& aName) -{ - nsAutoString name(aName); - ToLowerCase(name); - - nsRefPtr ff; - if (!gPlatformFonts->Get(name, &ff)) { - return nullptr; - } - return ff.get(); -} - -FontEntry * -gfxPlatformGtk::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle) -{ - nsRefPtr ff = FindFontFamily(aName); - if (!ff) - return nullptr; - - return ff->FindFontEntry(aFontStyle); -} - -static PLDHashOperator -FindFontForCharProc(nsStringHashKey::KeyType aKey, - nsRefPtr& aFontFamily, - void* aUserArg) -{ - GlobalFontMatch *data = (GlobalFontMatch*)aUserArg; - aFontFamily->FindFontForChar(data); - return PL_DHASH_NEXT; -} - -already_AddRefed -gfxPlatformGtk::FindFontForChar(uint32_t aCh, gfxFont *aFont) -{ - if (!gPlatformFonts || !gCodepointsWithNoFonts) - return nullptr; - - // is codepoint with no matching font? return null immediately - if (gCodepointsWithNoFonts->test(aCh)) { - return nullptr; - } - - GlobalFontMatch data(aCh, GetScriptCode(aCh), - (aFont ? aFont->GetStyle() : nullptr)); - - // find fonts that support the character - gPlatformFonts->Enumerate(FindFontForCharProc, &data); - - if (data.mBestMatch) { - nsRefPtr font = - gfxFT2Font::GetOrMakeFont(static_cast(data.mBestMatch.get()), - aFont->GetStyle()); - gfxFont* ret = font.forget().get(); - return already_AddRefed(ret); - } - - // no match? add to set of non-matching codepoints - gCodepointsWithNoFonts->set(aCh); - - return nullptr; -} - -bool -gfxPlatformGtk::GetPrefFontEntries(const nsCString& aKey, nsTArray > *aFontEntryList) -{ - return gPrefFonts->Get(aKey, aFontEntryList); -} - -void -gfxPlatformGtk::SetPrefFontEntries(const nsCString& aKey, nsTArray >& aFontEntryList) -{ - gPrefFonts->Put(aKey, aFontEntryList); -} -#endif - #if (MOZ_WIDGET_GTK == 2) void gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target, diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 0ec4e1c69291..5a5b66adc4a2 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -17,11 +17,6 @@ extern "C" { #endif class gfxFontconfigUtils; -#ifndef MOZ_PANGO -class FontFamily; -class FontEntry; -typedef struct FT_LibraryRec_ *FT_Library; -#endif class gfxPlatformGtk : public gfxPlatform { public: @@ -54,7 +49,6 @@ public: const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet); -#ifdef MOZ_PANGO /** * Look up a local platform font using the full font face name (needed to * support @font-face src local() ) @@ -76,19 +70,6 @@ public: */ virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags); -#endif - -#ifndef MOZ_PANGO - FontFamily *FindFontFamily(const nsAString& aName); - FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle); - already_AddRefed FindFontForChar(uint32_t aCh, gfxFont *aFont); - bool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray > *aFontEntryList); - void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray >& aFontEntryList); -#endif - -#ifndef MOZ_PANGO - FT_Library GetFTLibrary(); -#endif #if (MOZ_WIDGET_GTK == 2) static void SetGdkDrawable(cairo_surface_t *target, diff --git a/gfx/thebes/gfxQtPlatform.cpp b/gfx/thebes/gfxQtPlatform.cpp index 3bad2e41d091..e9768851281a 100644 --- a/gfx/thebes/gfxQtPlatform.cpp +++ b/gfx/thebes/gfxQtPlatform.cpp @@ -27,13 +27,9 @@ #include "gfxQPainterSurface.h" #include "nsUnicodeProperties.h" -#ifdef MOZ_PANGO #include "gfxPangoFonts.h" #include "gfxContext.h" #include "gfxUserFontSet.h" -#else -#include "gfxFT2Fonts.h" -#endif #include "nsUnicharUtils.h" @@ -47,11 +43,6 @@ #include "qcms.h" -#ifndef MOZ_PANGO -#include -#include FT_FREETYPE_H -#endif - #include "mozilla/Preferences.h" using namespace mozilla; @@ -75,16 +66,6 @@ static void do_qt_pixmap_unref (void *data) static gfxImageFormat sOffscreenFormat = gfxImageFormatRGB24; -#ifndef MOZ_PANGO -typedef nsDataHashtable > FontTable; -typedef nsDataHashtable > > PrefFontTable; -static FontTable *gPlatformFonts = nullptr; -static FontTable *gPlatformFontAliases = nullptr; -static PrefFontTable *gPrefFonts = nullptr; -static gfxSparseBitSet *gCodepointsWithNoFonts = nullptr; -static FT_Library gPlatformFTLibrary = nullptr; -#endif - gfxQtPlatform::gfxQtPlatform() { mPrefFonts.Init(50); @@ -92,20 +73,7 @@ gfxQtPlatform::gfxQtPlatform() if (!sFontconfigUtils) sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); -#ifdef MOZ_PANGO g_type_init(); -#else - FT_Init_FreeType(&gPlatformFTLibrary); - - gPlatformFonts = new FontTable(); - gPlatformFonts->Init(100); - gPlatformFontAliases = new FontTable(); - gPlatformFontAliases->Init(100); - gPrefFonts = new PrefFontTable(); - gPrefFonts->Init(100); - gCodepointsWithNoFonts = new gfxSparseBitSet(); - UpdateFontList(); -#endif nsresult rv; // 0 - default gfxQPainterSurface @@ -148,23 +116,7 @@ gfxQtPlatform::~gfxQtPlatform() gfxFontconfigUtils::Shutdown(); sFontconfigUtils = nullptr; -#ifdef MOZ_PANGO gfxPangoFontGroup::Shutdown(); -#else - delete gPlatformFonts; - gPlatformFonts = nullptr; - delete gPlatformFontAliases; - gPlatformFontAliases = nullptr; - delete gPrefFonts; - gPrefFonts = nullptr; - delete gCodepointsWithNoFonts; - gCodepointsWithNoFonts = nullptr; - - cairo_debug_reset_static_data(); - - FT_Done_FreeType(gPlatformFTLibrary); - gPlatformFTLibrary = nullptr; -#endif #if 0 // It would be nice to do this (although it might need to be after @@ -259,103 +211,6 @@ gfxQtPlatform::GetFontList(nsIAtom *aLangGroup, nsresult gfxQtPlatform::UpdateFontList() { -#ifndef MOZ_PANGO - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *fs = nullptr; - - pat = FcPatternCreate(); - os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, FC_WEIGHT, FC_SLANT, FC_WIDTH, nullptr); - - fs = FcFontList(nullptr, pat, os); - - - for (int i = 0; i < fs->nfont; i++) { - char *str; - - if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - - nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get()); - nsAutoString key(name); - ToLowerCase(key); - nsRefPtr ff; - if (!gPlatformFonts->Get(key, &ff)) { - ff = new FontFamily(name); - gPlatformFonts->Put(key, ff); - } - - FontEntry *fe = new FontEntry(ff->Name()); - ff->AddFontEntry(fe); - - if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) { - fe->mFilename = nsDependentCString(str); - } - - int x; - if (FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &x) == FcResultMatch) { - fe->mFTFontIndex = x; - } else { - fe->mFTFontIndex = 0; - } - - if (FcPatternGetInteger(fs->fonts[i], FC_WEIGHT, 0, &x) == FcResultMatch) { - switch(x) { - case 0: - fe->mWeight = 100; - break; - case 40: - fe->mWeight = 200; - break; - case 50: - fe->mWeight = 300; - break; - case 75: - case 80: - fe->mWeight = 400; - break; - case 100: - fe->mWeight = 500; - break; - case 180: - fe->mWeight = 600; - break; - case 200: - fe->mWeight = 700; - break; - case 205: - fe->mWeight = 800; - break; - case 210: - fe->mWeight = 900; - break; - default: - // rough estimate - fe->mWeight = (((x * 4) + 100) / 100) * 100; - break; - } - } - - fe->mItalic = false; - if (FcPatternGetInteger(fs->fonts[i], FC_SLANT, 0, &x) == FcResultMatch) { - switch (x) { - case FC_SLANT_ITALIC: - case FC_SLANT_OBLIQUE: - fe->mItalic = true; - } - } - - // XXX deal with font-stretch (FC_WIDTH) stuff later - } - - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (fs) - FcFontSetDestroy(fs); -#endif - return sFontconfigUtils->UpdateFontList(); } @@ -365,80 +220,8 @@ gfxQtPlatform::ResolveFontName(const nsAString& aFontName, void *aClosure, bool& aAborted) { -#ifdef MOZ_PANGO return sFontconfigUtils->ResolveFontName(aFontName, aCallback, aClosure, aAborted); -#else - nsAutoString name(aFontName); - ToLowerCase(name); - - nsRefPtr ff; - if (gPlatformFonts->Get(name, &ff) || - gPlatformFontAliases->Get(name, &ff)) { - aAborted = !(*aCallback)(ff->Name(), aClosure); - return NS_OK; - } - - nsAutoCString utf8Name = NS_ConvertUTF16toUTF8(aFontName); - - FcPattern *npat = FcPatternCreate(); - FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get()); - FcObjectSet *nos = FcObjectSetBuild(FC_FAMILY, nullptr); - FcFontSet *nfs = FcFontList(nullptr, npat, nos); - - for (int k = 0; k < nfs->nfont; k++) { - FcChar8 *str; - if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))); - ToLowerCase(altName); - if (gPlatformFonts->Get(altName, &ff)) { - gPlatformFontAliases->Put(name, ff); - aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))), aClosure); - goto DONE; - } - } - - FcPatternDestroy(npat); - FcObjectSetDestroy(nos); - FcFontSetDestroy(nfs); - - { - npat = FcPatternCreate(); - FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get()); - FcPatternDel(npat, FC_LANG); - FcConfigSubstitute(nullptr, npat, FcMatchPattern); - FcDefaultSubstitute(npat); - - nos = FcObjectSetBuild(FC_FAMILY, nullptr); - nfs = FcFontList(nullptr, npat, nos); - - FcResult fresult; - - FcPattern *match = FcFontMatch(nullptr, npat, &fresult); - if (match) - FcFontSetAdd(nfs, match); - - for (int k = 0; k < nfs->nfont; k++) { - FcChar8 *str; - if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch) - continue; - nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))); - ToLowerCase(altName); - if (gPlatformFonts->Get(altName, &ff)) { - gPlatformFontAliases->Put(name, ff); - aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast(str))), aClosure); - goto DONE; - } - } - } - DONE: - FcPatternDestroy(npat); - FcObjectSetDestroy(nos); - FcFontSetDestroy(nfs); - - return NS_OK; -#endif } nsresult @@ -452,14 +235,9 @@ gfxQtPlatform::CreateFontGroup(const nsAString &aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet* aUserFontSet) { -#ifdef MOZ_PANGO return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet); -#else - return new gfxFT2FontGroup(aFamilies, aStyle, aUserFontSet); -#endif } -#ifdef MOZ_PANGO gfxFontEntry* gfxQtPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, const nsAString& aFontName) @@ -501,7 +279,6 @@ gfxQtPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) // no format hint set, need to look at data return true; } -#endif qcms_profile* gfxQtPlatform::GetPlatformCMSOutputProfile() @@ -509,91 +286,6 @@ gfxQtPlatform::GetPlatformCMSOutputProfile() return nullptr; } -#ifndef MOZ_PANGO -FT_Library -gfxQtPlatform::GetFTLibrary() -{ - return gPlatformFTLibrary; -} - -FontFamily * -gfxQtPlatform::FindFontFamily(const nsAString& aName) -{ - nsAutoString name(aName); - ToLowerCase(name); - - nsRefPtr ff; - if (!gPlatformFonts->Get(name, &ff)) { - return nullptr; - } - return ff.get(); -} - -FontEntry * -gfxQtPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle) -{ - nsRefPtr ff = FindFontFamily(aName); - if (!ff) - return nullptr; - - return ff->FindFontEntry(aFontStyle); -} - -static PLDHashOperator -FindFontForCharProc(nsStringHashKey::KeyType aKey, - nsRefPtr& aFontFamily, - void* aUserArg) -{ - GlobalFontMatch *data = (GlobalFontMatch*)aUserArg; - aFontFamily->FindFontForChar(data); - return PL_DHASH_NEXT; -} - -already_AddRefed -gfxQtPlatform::FindFontForChar(uint32_t aCh, gfxFont *aFont) -{ - if (!gPlatformFonts || !gCodepointsWithNoFonts) - return nullptr; - - // is codepoint with no matching font? return null immediately - if (gCodepointsWithNoFonts->test(aCh)) { - return nullptr; - } - - GlobalFontMatch data(aCh, GetScriptCode(aCh), - (aFont ? aFont->GetStyle() : nullptr)); - - // find fonts that support the character - gPlatformFonts->Enumerate(FindFontForCharProc, &data); - - if (data.mBestMatch) { - nsRefPtr font = - gfxFT2Font::GetOrMakeFont(static_cast(data.mBestMatch.get()), - aFont->GetStyle()); - gfxFont* ret = font.forget().get(); - return already_AddRefed(ret); - } - - // no match? add to set of non-matching codepoints - gCodepointsWithNoFonts->set(aCh); - - return nullptr; -} - -bool -gfxQtPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray > *array) -{ - return mPrefFonts.Get(aKey, array); -} - -void -gfxQtPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray >& array) -{ - mPrefFonts.Put(aKey, array); -} - -#endif - int32_t gfxQtPlatform::GetDPI() { diff --git a/gfx/thebes/gfxQtPlatform.h b/gfx/thebes/gfxQtPlatform.h index 6012523e89b4..a8fd572fa0ac 100644 --- a/gfx/thebes/gfxQtPlatform.h +++ b/gfx/thebes/gfxQtPlatform.h @@ -16,12 +16,6 @@ class gfxFontconfigUtils; class QWidget; -#ifndef MOZ_PANGO -typedef struct FT_LibraryRec_ *FT_Library; - -class FontFamily; -class FontEntry; -#endif class gfxQtPlatform : public gfxPlatform { public: @@ -63,7 +57,6 @@ public: const gfxFontStyle *aStyle, gfxUserFontSet* aUserFontSet); -#ifdef MOZ_PANGO /** * Look up a local platform font using the full font face name (needed to * support @font-face src local() ) @@ -85,22 +78,9 @@ public: */ virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags); -#endif - -#ifndef MOZ_PANGO - FontFamily *FindFontFamily(const nsAString& aName); - FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle); - already_AddRefed FindFontForChar(uint32_t aCh, gfxFont *aFont); - bool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray > *aFontEntryList); - void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray >& aFontEntryList); -#endif void ClearPrefFonts() { mPrefFonts.Clear(); } -#ifndef MOZ_PANGO - FT_Library GetFTLibrary(); -#endif - RenderMode GetRenderMode() { return mRenderMode; } void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 85ca86070959..c17ece953d75 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -209,7 +209,7 @@ typedef HRESULT (WINAPI*D3D11CreateDeviceFunc)( ID3D11DeviceContext *ppImmediateContext ); -class GPUAdapterReporter : public MemoryMultiReporter +class GPUAdapterReporter : public nsIMemoryReporter { // Callers must Release the DXGIAdapter after use or risk mem-leak static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter) @@ -229,7 +229,7 @@ class GPUAdapterReporter : public MemoryMultiReporter } public: - GPUAdapterReporter() {} + NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb, @@ -339,6 +339,8 @@ public: } }; +NS_IMPL_ISUPPORTS1(GPUAdapterReporter, nsIMemoryReporter) + static __inline void BuildKeyNameFromFontName(nsAString &aName) { diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 066ecbde1965..cf2bccefc98d 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -103,6 +103,7 @@ elif CONFIG['MOZ_WIDGET_GTK']: EXPORTS += [ 'gfxFT2FontBase.h', 'gfxGdkNativeRenderer.h', + 'gfxPangoFonts.h', 'gfxPDFSurface.h', 'gfxPlatformGtk.h', 'gfxPSSurface.h', @@ -113,6 +114,7 @@ elif CONFIG['MOZ_WIDGET_GTK']: 'gfxFT2FontBase.cpp', 'gfxFT2Utils.cpp', 'gfxGdkNativeRenderer.cpp', + 'gfxPangoFonts.cpp', 'gfxPDFSurface.cpp', 'gfxPlatformGtk.cpp', 'gfxPSSurface.cpp', @@ -129,16 +131,6 @@ elif CONFIG['MOZ_WIDGET_GTK']: 'gfxXlibSurface.cpp', ] - if CONFIG['MOZ_PANGO']: - EXPORTS += ['gfxPangoFonts.h'] - SOURCES += [ - 'gfxPangoFonts.cpp', - ] - else: - EXPORTS += ['gfxFT2Fonts.h'] - SOURCES += [ - 'gfxPangoFonts.cpp', - ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'os2': EXPORTS += [ 'gfxOS2Fonts.h', @@ -157,6 +149,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'os2': elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': EXPORTS += [ 'gfxFT2FontBase.h', + 'gfxPangoFonts.h', 'gfxPDFSurface.h', 'gfxQPainterSurface.h', 'gfxQtNativeRenderer.h', @@ -166,6 +159,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': 'gfxFontconfigUtils.cpp', 'gfxFT2FontBase.cpp', 'gfxFT2Utils.cpp', + 'gfxPangoFonts.cpp', 'gfxPDFSurface.cpp', 'gfxQPainterSurface.cpp', 'gfxQtPlatform.cpp', @@ -181,16 +175,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': 'gfxXlibSurface.cpp', ] - if CONFIG['MOZ_PANGO']: - EXPORTS += ['gfxPangoFonts.h'] - SOURCES += [ - 'gfxPangoFonts.cpp', - ] - else: - EXPORTS += ['gfxFT2Fonts.h'] - SOURCES += [ - 'gfxFT2Fonts.cpp', - ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXPORTS += [ 'gfxD2DSurface.h', diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index c76c038d034f..a986ad8e6bd3 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -349,7 +349,7 @@ Decoder::PostFrameStop(FrameBlender::FrameAlpha aFrameAlpha /* = FrameBlender::k } mCurrentFrame->SetFrameDisposalMethod(aDisposalMethod); - mCurrentFrame->SetTimeout(aTimeout); + mCurrentFrame->SetRawTimeout(aTimeout); mCurrentFrame->SetBlendMethod(aBlendMethod); mCurrentFrame->ImageUpdated(mCurrentFrame->GetRect()); diff --git a/image/src/FrameAnimator.cpp b/image/src/FrameAnimator.cpp index 36c31eb00f92..bb1f720ed27d 100644 --- a/image/src/FrameAnimator.cpp +++ b/image/src/FrameAnimator.cpp @@ -13,36 +13,36 @@ using namespace mozilla; FrameAnimator::FrameAnimator(FrameBlender& aFrameBlender) : mCurrentAnimationFrameIndex(0) - , mLoopCount(-1) + , mLoopCounter(-1) , mFrameBlender(aFrameBlender) , mAnimationMode(imgIContainer::kNormalAnimMode) , mDoneDecoding(false) { } -uint32_t +int32_t FrameAnimator::GetSingleLoopTime() const { // If we aren't done decoding, we don't know the image's full play time. if (!mDoneDecoding) { - return 0; + return -1; } // If we're not looping, a single loop time has no meaning if (mAnimationMode != imgIContainer::kNormalAnimMode) { - return 0; + return -1; } uint32_t looptime = 0; for (uint32_t i = 0; i < mFrameBlender.GetNumFrames(); ++i) { - int32_t timeout = mFrameBlender.RawGetFrame(i)->GetTimeout(); - if (timeout > 0) { + int32_t timeout = mFrameBlender.GetTimeoutForFrame(i); + if (timeout >= 0) { looptime += static_cast(timeout); } else { // If we have a frame that never times out, we're probably in an error // case, but let's handle it more gracefully. NS_WARNING("Negative frame timeout - how did this happen?"); - return 0; + return -1; } } @@ -52,9 +52,8 @@ FrameAnimator::GetSingleLoopTime() const TimeStamp FrameAnimator::GetCurrentImgFrameEndTime() const { - imgFrame* currentFrame = mFrameBlender.RawGetFrame(mCurrentAnimationFrameIndex); TimeStamp currentFrameTime = mCurrentAnimationFrameTime; - int64_t timeout = currentFrame->GetTimeout(); + int32_t timeout = mFrameBlender.GetTimeoutForFrame(mCurrentAnimationFrameIndex); if (timeout < 0) { // We need to return a sentinel value in this case, because our logic @@ -82,7 +81,7 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) uint32_t currentFrameIndex = mCurrentAnimationFrameIndex; uint32_t nextFrameIndex = currentFrameIndex + 1; - uint32_t timeout = 0; + int32_t timeout = 0; RefreshResult ret; @@ -101,17 +100,22 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) // If we're done decoding the next frame, go ahead and display it now and // reinit with the next frame's delay time. if (mFrameBlender.GetNumFrames() == nextFrameIndex) { - // End of Animation, unless we are looping forever + // End of an animation loop... - // If animation mode is "loop once", it's time to stop animating - if (mAnimationMode == imgIContainer::kLoopOnceAnimMode || mLoopCount == 0) { + // If we are not looping forever, initialize the loop counter + if (mLoopCounter < 0 && mFrameBlender.GetLoopCount() >= 0) { + mLoopCounter = mFrameBlender.GetLoopCount(); + } + + // If animation mode is "loop once", or we're at end of loop counter, it's time to stop animating + if (mAnimationMode == imgIContainer::kLoopOnceAnimMode || mLoopCounter == 0) { ret.animationFinished = true; } nextFrameIndex = 0; - if (mLoopCount > 0) { - mLoopCount--; + if (mLoopCounter > 0) { + mLoopCounter--; } // If we're done, exit early. @@ -120,11 +124,11 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) } } - timeout = mFrameBlender.GetFrame(nextFrameIndex)->GetTimeout(); + timeout = mFrameBlender.GetTimeoutForFrame(nextFrameIndex); } // Bad data - if (!(timeout > 0)) { + if (timeout < 0) { ret.animationFinished = true; ret.error = true; } @@ -246,12 +250,6 @@ FrameAnimator::UnionFirstFrameRefreshArea(const nsIntRect& aRect) mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, aRect); } -void -FrameAnimator::SetLoopCount(int loopcount) -{ - mLoopCount = loopcount; -} - uint32_t FrameAnimator::GetCurrentAnimationFrameIndex() const { diff --git a/image/src/FrameAnimator.h b/image/src/FrameAnimator.h index 9580b082f13d..743e5f86ced3 100644 --- a/image/src/FrameAnimator.h +++ b/image/src/FrameAnimator.h @@ -75,12 +75,6 @@ public: */ void ResetAnimation(); - /** - * Number of times to loop the image. - * @note -1 means forever. - */ - void SetLoopCount(int32_t aLoopCount); - /** * The animation mode of the image. * @@ -125,9 +119,10 @@ private: // methods * Gets the length of a single loop of this image, in milliseconds. * * If this image is not finished decoding, is not animated, or it is animated - * but does not loop, returns 0. + * but does not loop, returns -1. Can return 0 in the case of an animated image + * that has a 0ms delay between its frames and does not loop. */ - uint32_t GetSingleLoopTime() const; + int32_t GetSingleLoopTime() const; /** * Advances the animation. Typically, this will advance a single frame, but it @@ -161,7 +156,7 @@ private: // data uint32_t mCurrentAnimationFrameIndex; //! number of loops remaining before animation stops (-1 no stop) - int32_t mLoopCount; + int32_t mLoopCounter; //! All the frames of the image, shared with our owner FrameBlender& mFrameBlender; diff --git a/image/src/FrameBlender.cpp b/image/src/FrameBlender.cpp index 9542f7ba2819..1410be47791a 100644 --- a/image/src/FrameBlender.cpp +++ b/image/src/FrameBlender.cpp @@ -19,6 +19,7 @@ namespace image { FrameBlender::FrameBlender(FrameSequence* aSequenceToUse /* = nullptr */) : mFrames(aSequenceToUse) , mAnim(nullptr) + , mLoopCount(-1) { if (!mFrames) { mFrames = new FrameSequence(); @@ -66,6 +67,40 @@ FrameBlender::GetNumFrames() const return mFrames->GetNumFrames(); } +int32_t +FrameBlender::GetTimeoutForFrame(uint32_t framenum) const +{ + const int32_t timeout = RawGetFrame(framenum)->GetRawTimeout(); + // Ensure a minimal time between updates so we don't throttle the UI thread. + // consider 0 == unspecified and make it fast but not too fast. Unless we have + // a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug 207059. + // The behavior of recent IE and Opera versions seems to be: + // IE 6/Win: + // 10 - 50ms go 100ms + // >50ms go correct speed + // Opera 7 final/Win: + // 10ms goes 100ms + // >10ms go correct speed + // It seems that there are broken tools out there that set a 0ms or 10ms + // timeout when they really want a "default" one. So munge values in that + // range. + if (timeout >= 0 && timeout <= 10 && mLoopCount != 0) + return 100; + return timeout; +} + +void +FrameBlender::SetLoopCount(int32_t aLoopCount) +{ + mLoopCount = aLoopCount; +} + +int32_t +FrameBlender::GetLoopCount() const +{ + return mLoopCount; +} + void FrameBlender::RemoveFrame(uint32_t framenum) { @@ -381,8 +416,8 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, // Set timeout of CompositeFrame to timeout of frame we just composed // Bug 177948 - int32_t timeout = nextFrame->GetTimeout(); - mAnim->compositingFrame->SetTimeout(timeout); + int32_t timeout = nextFrame->GetRawTimeout(); + mAnim->compositingFrame->SetRawTimeout(timeout); // Tell the image that it is fully 'downloaded'. nsresult rv = mAnim->compositingFrame->ImageUpdated(mAnim->compositingFrame->GetRect()); diff --git a/image/src/FrameBlender.h b/image/src/FrameBlender.h index f1f47e2d25f5..94ecf6761eed 100644 --- a/image/src/FrameBlender.h +++ b/image/src/FrameBlender.h @@ -59,6 +59,20 @@ public: /* The total number of frames in this image. */ uint32_t GetNumFrames() const; + /* + * Returns the frame's adjusted timeout. If the animation loops and the timeout + * falls in between a certain range then the timeout is adjusted so that + * it's never 0. If the animation does not loop then no adjustments are made. + */ + int32_t GetTimeoutForFrame(uint32_t framenum) const; + + /* + * Set number of times to loop the image. + * @note -1 means loop forever. + */ + void SetLoopCount(int32_t aLoopCount); + int32_t GetLoopCount() const; + void Discard(); void SetSize(nsIntSize aSize) { mSize = aSize; } @@ -169,6 +183,7 @@ private: // data nsRefPtr mFrames; nsIntSize mSize; Anim* mAnim; + int32_t mLoopCount; }; } // namespace image diff --git a/image/src/Image.cpp b/image/src/Image.cpp index 5d380c51a93f..7d4872e4ca23 100644 --- a/image/src/Image.cpp +++ b/image/src/Image.cpp @@ -29,8 +29,8 @@ ImageResource::SizeOfData() return 0; // This is not used by memory reporters, but for sizing the cache, which is - // why it uses |moz_malloc_size_of| rather than an - // |NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN|. + // why it uses |moz_malloc_size_of| rather than a + // |MOZ_DEFINE_MALLOC_SIZE_OF|. return uint32_t(HeapSizeOfSourceWithComputedFallback(moz_malloc_size_of) + HeapSizeOfDecodedWithComputedFallback(moz_malloc_size_of) + NonHeapSizeOfDecoded() + diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 4a2efdaa7781..39a8d2b0a3ce 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -814,7 +814,7 @@ RasterImage::GetFirstFrameDelay() if (NS_FAILED(GetAnimated(&animated)) || !animated) return -1; - return mFrameBlender.GetFrame(0)->GetTimeout(); + return mFrameBlender.GetTimeoutForFrame(0); } nsresult @@ -1439,7 +1439,7 @@ RasterImage::StartAnimation() imgFrame* currentFrame = GetCurrentImgFrame(); // A timeout of -1 means we should display this frame forever. - if (currentFrame && currentFrame->GetTimeout() < 0) { + if (currentFrame && mFrameBlender.GetTimeoutForFrame(GetCurrentImgFrameIndex()) < 0) { mAnimationFinished = true; return NS_ERROR_ABORT; } @@ -1536,7 +1536,8 @@ RasterImage::SetLoopCount(int32_t aLoopCount) return; if (mAnim) { - mAnim->SetLoopCount(aLoopCount); + // No need to set this if we're not an animation + mFrameBlender.SetLoopCount(aLoopCount); } } diff --git a/image/src/imgFrame.cpp b/image/src/imgFrame.cpp index f0385b6def51..dfbe11683d9f 100644 --- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -745,28 +745,12 @@ void imgFrame::ApplyDirtToSurfaces() } } -int32_t imgFrame::GetTimeout() const +int32_t imgFrame::GetRawTimeout() const { - // Ensure a minimal time between updates so we don't throttle the UI thread. - // consider 0 == unspecified and make it fast but not too fast. See bug - // 125137, bug 139677, and bug 207059. The behavior of recent IE and Opera - // versions seems to be: - // IE 6/Win: - // 10 - 50ms go 100ms - // >50ms go correct speed - // Opera 7 final/Win: - // 10ms goes 100ms - // >10ms go correct speed - // It seems that there are broken tools out there that set a 0ms or 10ms - // timeout when they really want a "default" one. So munge values in that - // range. - if (mTimeout >= 0 && mTimeout <= 10) - return 100; - else - return mTimeout; + return mTimeout; } -void imgFrame::SetTimeout(int32_t aTimeout) +void imgFrame::SetRawTimeout(int32_t aTimeout) { mTimeout = aTimeout; } diff --git a/image/src/imgFrame.h b/image/src/imgFrame.h index 475d150e114c..06d05001859d 100644 --- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -53,8 +53,8 @@ public: void GetPaletteData(uint32_t **aPalette, uint32_t *length) const; uint32_t* GetPaletteData() const; - int32_t GetTimeout() const; - void SetTimeout(int32_t aTimeout); + int32_t GetRawTimeout() const; + void SetRawTimeout(int32_t aTimeout); int32_t GetFrameDisposalMethod() const; void SetFrameDisposalMethod(int32_t aFrameDisposalMethod); diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index 211ea601fb5f..afb3de240d42 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -48,12 +48,12 @@ using namespace mozilla; using namespace mozilla::image; -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(ImagesMallocSizeOf) -class imgMemoryReporter MOZ_FINAL : public MemoryMultiReporter +class imgMemoryReporter MOZ_FINAL : public nsIMemoryReporter { public: - imgMemoryReporter() {} + NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIMemoryReporterCallback *callback, nsISupports *closure) @@ -212,10 +212,12 @@ private: } }; +NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter) + NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy, - nsIProgressEventSink, - nsIChannelEventSink, - nsIInterfaceRequestor) + nsIProgressEventSink, + nsIChannelEventSink, + nsIInterfaceRequestor) NS_IMETHODIMP nsProgressNotificationProxy::OnProgress(nsIRequest* request, diff --git a/image/test/mochitest/test_bug601470.html b/image/test/mochitest/test_bug601470.html index bc37ea2c2048..2bb348ccc81a 100644 --- a/image/test/mochitest/test_bug601470.html +++ b/image/test/mochitest/test_bug601470.html @@ -30,11 +30,7 @@ window.onload = function() { amount += aAmount; } - var e = mgr.enumerateReporters(); - while (e.hasMoreElements()) { - var mr = e.getNext().QueryInterface(SpecialPowers.Ci.nsIMemoryReporter); - mr.collectReports(handleReport, null); - } + mgr.getReportsForThisProcess(handleReport, null); ok(amount > 0, "we should be using a nonzero amount of memory"); ok(true, "yay, didn't crash!"); diff --git a/js/public/Class.h b/js/public/Class.h index 539f0da320e9..67021d24f0f9 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -347,9 +347,6 @@ typedef bool (* ElementIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index, JS::MutableHandleValue vp); typedef bool -(* ElementIfPresentOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, - uint32_t index, JS::MutableHandleValue vp, bool* present); -typedef bool (* SpecialIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, HandleSpecialId sid, JS::MutableHandleValue vp); typedef bool @@ -383,6 +380,10 @@ typedef bool typedef bool (* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id); +typedef bool +(* SliceOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end, + JS::HandleObject result); // result is actually preallocted. + typedef JSObject * (* ObjectOp)(JSContext *cx, JS::HandleObject obj); typedef void @@ -459,7 +460,6 @@ struct ObjectOps GenericIdOp getGeneric; PropertyIdOp getProperty; ElementIdOp getElement; - ElementIfPresentOp getElementIfPresent; /* can be null */ SpecialIdOp getSpecial; StrictGenericIdOp setGeneric; StrictPropertyIdOp setProperty; @@ -472,6 +472,7 @@ struct ObjectOps DeleteSpecialOp deleteSpecial; WatchOp watch; UnwatchOp unwatch; + SliceOp slice; // Optimized slice, can be null. JSNewEnumerateOp enumerate; ObjectOp thisObject; @@ -480,7 +481,7 @@ struct ObjectOps #define JS_NULL_OBJECT_OPS \ {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \ nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \ - nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} } // namespace js diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 25c90e664857..cc08df785f8e 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2081,15 +2081,6 @@ TypedDatum::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiv bool TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp) -{ - bool present; - return obj_getElementIfPresent(cx, obj, receiver, index, vp, &present); -} - -bool -TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj, - HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present) { RootedObject type(cx, GetType(*obj)); TypeRepresentation *typeRepr = typeRepresentation(*type); @@ -2106,8 +2097,6 @@ TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj, { JS_ASSERT(IsArrayTypedDatum(*obj)); - *present = true; - if (index >= DatumLength(*obj)) { vp.setUndefined(); return true; @@ -2123,12 +2112,11 @@ TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj, RootedObject proto(cx, obj->getProto()); if (!proto) { - *present = false; vp.setUndefined(); return true; } - return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present); + return JSObject::getElement(cx, proto, receiver, index, vp); } bool @@ -2499,7 +2487,6 @@ const Class TypedObject::class_ = { TypedDatum::obj_getGeneric, TypedDatum::obj_getProperty, TypedDatum::obj_getElement, - TypedDatum::obj_getElementIfPresent, TypedDatum::obj_getSpecial, TypedDatum::obj_setGeneric, TypedDatum::obj_setProperty, @@ -2511,6 +2498,7 @@ const Class TypedObject::class_ = { TypedDatum::obj_deleteElement, TypedDatum::obj_deleteSpecial, nullptr, nullptr, // watch/unwatch + nullptr, /* slice */ TypedDatum::obj_enumerate, nullptr, /* thisObject */ } @@ -2666,7 +2654,6 @@ const Class TypedHandle::class_ = { TypedDatum::obj_getGeneric, TypedDatum::obj_getProperty, TypedDatum::obj_getElement, - TypedDatum::obj_getElementIfPresent, TypedDatum::obj_getSpecial, TypedDatum::obj_setGeneric, TypedDatum::obj_setProperty, @@ -2678,6 +2665,7 @@ const Class TypedHandle::class_ = { TypedDatum::obj_deleteElement, TypedDatum::obj_deleteSpecial, nullptr, nullptr, // watch/unwatch + nullptr, // slice TypedDatum::obj_enumerate, nullptr, /* thisObject */ } diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index c2807b2a4d28..8fd511c9eff0 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -293,9 +293,6 @@ class TypedDatum : public JSObject static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, MutableHandleValue vp); - static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj, - HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present); static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, bool strict); static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, diff --git a/js/src/configure.in b/js/src/configure.in index e83c5795b54e..2e75f7146fca 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -1053,8 +1053,10 @@ MOZ_ARG_ENABLE_BOOL(address-sanitizer, if test -n "$MOZ_ASAN"; then MOZ_LLVM_HACKS=1 AC_DEFINE(MOZ_ASAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) fi AC_SUBST(MOZ_ASAN) +AC_SUBST(LLVM_SYMBOLIZER) dnl ======================================================== dnl = Enable hacks required for LLVM instrumentations diff --git a/js/src/jit-test/tests/arrays/slice.js b/js/src/jit-test/tests/arrays/slice.js new file mode 100644 index 000000000000..ad4f66f63311 --- /dev/null +++ b/js/src/jit-test/tests/arrays/slice.js @@ -0,0 +1,37 @@ +let invoked = false; +Object.defineProperty(Array.prototype, '0', {set: function () { + invoked = true; +}}); + +let result = [1, 2, 3].slice(1); +assertEq(invoked, false); + +let proxy = new Proxy({}, { + get: function (target, name, proxy) { + switch (name) { + case "length": + return 2; + case "0": + return 15; + case "1": + // Should not invoke [[Get]] for this hole. + default: + assertEq(false, true); + } + }, + has: function (target, name) { + switch (name) { + case "0": + return true; + case "1": + return false; + default: + assertEq(false, true); + } + } +}) +result = Array.prototype.slice.call(proxy, 0); +assertEq(result.length, 2); +assertEq(0 in result, true); +assertEq(1 in result, false); +assertEq(result[0], 15); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 1a75dd2b1b11..958ef02dabf7 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -496,10 +496,8 @@ ICTypeMonitor_Fallback::resetMonitorStubChain(Zone *zone) // We are removing edges from monitored stubs to gcthings (IonCode). // Perform one final trace of all monitor stubs for incremental GC, // as it must know about those edges. - if (hasFallbackStub_) { - for (ICStub *s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next()) - s->trace(zone->barrierTracer()); - } + for (ICStub *s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next()) + s->trace(zone->barrierTracer()); } firstMonitorStub_ = this; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 273b82591284..d926c63af280 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3393,25 +3393,6 @@ JS_ForwardGetElementTo(JSContext *cx, JSObject *objArg, uint32_t index, JSObject return JSObject::getElement(cx, obj, onBehalfOf, index, vp); } -JS_PUBLIC_API(bool) -JS_GetElementIfPresent(JSContext *cx, JSObject *objArg, uint32_t index, JSObject *onBehalfOfArg, - MutableHandleValue vp, bool* present) -{ - RootedObject obj(cx, objArg); - RootedObject onBehalfOf(cx, onBehalfOfArg); - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, 0); - - bool isPresent; - if (!JSObject::getElementIfPresent(cx, obj, onBehalfOf, index, vp, &isPresent)) - return false; - - *present = isPresent; - return true; -} - JS_PUBLIC_API(bool) JS_GetProperty(JSContext *cx, JSObject *objArg, const char *name, MutableHandleValue vp) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 2a59b62c57a0..9c9d992eed22 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3040,15 +3040,6 @@ extern JS_PUBLIC_API(bool) JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf, JS::MutableHandle vp); -/* - * Get the property with name given by |index|, if it has one. If - * not, |*present| will be set to false and the value of |vp| must not - * be relied on. - */ -extern JS_PUBLIC_API(bool) -JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf, - JS::MutableHandle vp, bool* present); - extern JS_PUBLIC_API(bool) JS_SetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandle vp); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 4ea544ab402b..002af3e2435c 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -134,7 +134,7 @@ js::StringIsArrayIndex(JSLinearString *str, uint32_t *indexp) } static bool -DoubleIndexToId(JSContext *cx, double index, MutableHandleId id) +ToId(JSContext *cx, double index, MutableHandleId id) { if (index == uint32_t(index)) return IndexToId(cx, uint32_t(index), id.address()); @@ -143,18 +143,26 @@ DoubleIndexToId(JSContext *cx, double index, MutableHandleId id) return ValueToId(cx, HandleValue::fromMarkedLocation(&tmp), id); } +static bool +ToId(JSContext *cx, uint32_t index, MutableHandleId id) +{ + return IndexToId(cx, index, id.address()); +} + /* * If the property at the given index exists, get its value into location * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp * to JSVAL_VOID. This function assumes that the location pointed by vp is * properly rooted and can be used as GC-protected storage for temporaries. */ +template static inline bool -DoGetElement(JSContext *cx, HandleObject obj, double index, bool *hole, MutableHandleValue vp) +DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver, + IndexType index, bool *hole, MutableHandleValue vp) { RootedId id(cx); - if (!DoubleIndexToId(cx, index, &id)) + if (!ToId(cx, index, &id)) return false; RootedObject obj2(cx); @@ -166,27 +174,13 @@ DoGetElement(JSContext *cx, HandleObject obj, double index, bool *hole, MutableH vp.setUndefined(); *hole = true; } else { - if (!JSObject::getGeneric(cx, obj, obj, id, vp)) + if (!JSObject::getGeneric(cx, obj, receiver, id, vp)) return false; *hole = false; } return true; } -static inline bool -DoGetElement(JSContext *cx, HandleObject obj, uint32_t index, bool *hole, MutableHandleValue vp) -{ - bool present; - if (!JSObject::getElementIfPresent(cx, obj, obj, index, vp, &present)) - return false; - - *hole = !present; - if (*hole) - vp.setUndefined(); - - return true; -} - template static void AssertGreaterThanZero(IndexType index) @@ -203,7 +197,8 @@ AssertGreaterThanZero(uint32_t index) template static bool -GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp) +GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, + IndexType index, bool *hole, MutableHandleValue vp) { AssertGreaterThanZero(index); if (obj->isNative() && index < obj->getDenseInitializedLength()) { @@ -220,7 +215,14 @@ GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, Mutable } } - return DoGetElement(cx, obj, index, hole, vp); + return DoGetElement(cx, obj, receiver, index, hole, vp); +} + +template +static inline bool +GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp) +{ + return GetElement(cx, obj, obj, index, hole, vp); } static bool @@ -296,7 +298,7 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v) } RootedId id(cx); - if (!DoubleIndexToId(cx, index, &id)) + if (!ToId(cx, index, &id)) return false; RootedValue tmp(cx, v); @@ -2680,20 +2682,18 @@ js::array_concat(JSContext *cx, unsigned argc, Value *vp) static bool array_slice(JSContext *cx, unsigned argc, Value *vp) { - uint32_t length, begin, end, slot; - bool hole; - CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; + uint32_t length; if (!GetLengthProperty(cx, obj, &length)) return false; - begin = 0; - end = length; + uint32_t begin = 0; + uint32_t end = length; if (args.length() > 0) { double d; if (!ToInteger(cx, args[0], &d)) @@ -2741,20 +2741,50 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) return true; } - RootedValue value(cx); - for (slot = begin; slot < end; slot++) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, slot, &hole, &value)) { - return false; + if (js::SliceOp op = obj->getOps()->slice) { + // Ensure that we have dense elements, so that DOM can use js::UnsafeDefineElement. + JSObject::EnsureDenseResult result = narr->ensureDenseElements(cx, 0, end - begin); + if (result == JSObject::ED_FAILED) + return false; + + if (result == JSObject::ED_OK) { + if (!op(cx, obj, begin, end, narr)) + return false; + + args.rval().setObject(*narr); + return true; } - if (!hole && !SetArrayElement(cx, narr, slot - begin, value)) - return false; + + // Fallthrough + JS_ASSERT(result == JSObject::ED_SPARSE); } + + if (!SliceSlowly(cx, obj, obj, begin, end, narr)) + return false; + args.rval().setObject(*narr); return true; } +JS_FRIEND_API(bool) +js::SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver, + uint32_t begin, uint32_t end, HandleObject result) +{ + RootedValue value(cx); + for (uint32_t slot = begin; slot < end; slot++) { + bool hole; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, receiver, slot, &hole, &value)) + { + return false; + } + if (!hole && !JSObject::defineElement(cx, result, slot - begin, value)) + return false; + } + return true; +} + /* ES5 15.4.4.20. */ static bool array_filter(JSContext *cx, unsigned argc, Value *vp) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 1d3bdab16a21..225e937108ef 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -1165,6 +1165,14 @@ js::GetObjectMetadata(JSObject *obj) return obj->getMetadata(); } +JS_FRIEND_API(void) +js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value) +{ + JS_ASSERT(obj->isNative()); + JS_ASSERT(index < obj->getDenseInitializedLength()); + obj->setDenseElementWithType(cx, index, value); +} + JS_FRIEND_API(bool) js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, JS::Handle descriptor, bool *bp) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 3abf20303ef0..6e41232400cb 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1739,6 +1739,13 @@ SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata JS_FRIEND_API(JSObject *) GetObjectMetadata(JSObject *obj); +JS_FRIEND_API(void) +UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value); + +JS_FRIEND_API(bool) +SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, + uint32_t begin, uint32_t end, JS::HandleObject result); + /* ES5 8.12.8. */ extern JS_FRIEND_API(bool) DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 429aed30eb82..5ff7c870e9c6 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -223,7 +223,7 @@ IdToTypeId(jsid id) if (JSID_IS_STRING(id)) { JSFlatString *str = JSID_TO_FLAT_STRING(id); JS::TwoByteChars cp = str->range(); - if (JS7_ISDEC(cp[0]) || cp[0] == '-') { + if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) { for (size_t i = 1; i < cp.length(); ++i) { if (!JS7_ISDEC(cp[i])) return id; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index b4e1d9dda9e6..00a2ebc25cc8 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -396,7 +396,11 @@ NewPropertyIteratorObject(JSContext *cx, unsigned flags) return &obj->as(); } - return &NewBuiltinClassInstance(cx, &PropertyIteratorObject::class_)->as(); + JSObject *obj = NewBuiltinClassInstance(cx, &PropertyIteratorObject::class_); + if (!obj) + return nullptr; + + return &obj->as(); } NativeIterator * diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 0bac66e85e52..f3fbbf9ef59b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1030,12 +1030,6 @@ class JSObject : public js::ObjectImpl static inline bool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, js::Value *vp); - /* If element is not present (e.g. array hole) *present is set to - false and the contents of *vp are unusable garbage. */ - static inline bool getElementIfPresent(JSContext *cx, js::HandleObject obj, - js::HandleObject receiver, uint32_t index, - js::MutableHandleValue vp, bool *present); - static bool getSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, js::SpecialId sid, js::MutableHandleValue vp) diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 6cdaef257d07..2eb4e64ce7bd 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -583,38 +583,6 @@ JSObject::getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, return getGenericNoGC(cx, obj, receiver, id, vp); } -/* static */ inline bool -JSObject::getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, - uint32_t index, js::MutableHandleValue vp, - bool *present) -{ - js::ElementIfPresentOp op = obj->getOps()->getElementIfPresent; - if (op) - return op(cx, obj, receiver, index, vp, present); - - /* - * For now, do the index-to-id conversion just once, then use - * lookupGeneric/getGeneric. Once lookupElement and getElement stop both - * doing index-to-id conversions, we can use those here. - */ - JS::RootedId id(cx); - if (!js::IndexToId(cx, index, id.address())) - return false; - - JS::RootedObject obj2(cx); - js::RootedShape prop(cx); - if (!lookupGeneric(cx, obj, id, &obj2, &prop)) - return false; - - if (!prop) { - *present = false; - return true; - } - - *present = true; - return getGeneric(cx, obj, receiver, id, vp); -} - inline js::GlobalObject & JSObject::global() const { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 89345e8b62ec..52efb84f3d8c 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -151,27 +151,6 @@ BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver, return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp); } -bool -BaseProxyHandler::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present) -{ - RootedId id(cx); - if (!IndexToId(cx, index, id.address())) - return false; - - assertEnteredPolicy(cx, proxy, id); - - if (!has(cx, proxy, id, present)) - return false; - - if (!*present) { - Debug_SetValueRangeToCrashOnTouch(vp.address(), 1); - return true; - } - - return get(cx, proxy, receiver, id, vp); -} - bool BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) @@ -385,6 +364,34 @@ BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id) return true; } +bool +BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + HandleObject result) +{ + assertEnteredPolicy(cx, proxy, JSID_VOID); + + RootedId id(cx); + RootedValue value(cx); + for (uint32_t index = begin; index < end; index++) { + if (!IndexToId(cx, index, id.address())) + return false; + + bool present; + if (!Proxy::has(cx, proxy, id, &present)) + return false; + + if (present) { + if (!Proxy::get(cx, proxy, proxy, id, &value)) + return false; + + if (!JSObject::defineElement(cx, result, index - begin, value)) + return false; + } + } + + return true; +} + bool DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc, unsigned flags) @@ -2519,41 +2526,6 @@ Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject receiver, Handle return true; } - -bool -Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present) -{ - JS_CHECK_RECURSION(cx, return false); - - RootedId id(cx); - if (!IndexToId(cx, index, id.address())) - return false; - - BaseProxyHandler *handler = proxy->as().handler(); - AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true); - if (!policy.allowed()) - return policy.returnValue(); - - if (!handler->hasPrototype()) { - return handler->getElementIfPresent(cx, proxy, receiver, index, - vp, present); - } - - bool hasOwn; - if (!handler->hasOwn(cx, proxy, id, &hasOwn)) - return false; - - if (hasOwn) { - *present = true; - return proxy->as().handler()->get(cx, proxy, receiver, id, vp); - } - - *present = false; - INVOKE_ON_PROTOTYPE(cx, handler, proxy, - JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present)); -} - bool Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) @@ -2776,6 +2748,18 @@ Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) return proxy->as().handler()->unwatch(cx, proxy, id); } +/* static */ bool +Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + HandleObject result) +{ + JS_CHECK_RECURSION(cx, return false); + BaseProxyHandler *handler = proxy->as().handler(); + AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true); + if (!policy.allowed()) + return policy.returnValue(); + return handler->slice(cx, proxy, begin, end, result); +} + static JSObject * proxy_innerObject(JSContext *cx, HandleObject obj) { @@ -2891,13 +2875,6 @@ proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_ return proxy_GetGeneric(cx, obj, receiver, id, vp); } -static bool -proxy_GetElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present) -{ - return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present); -} - static bool proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, MutableHandleValue vp) @@ -3076,17 +3053,24 @@ proxy_Construct(JSContext *cx, unsigned argc, Value *vp) } static bool -proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable) +proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable) { return Proxy::watch(cx, obj, id, callable); } static bool -proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) +proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id) { return Proxy::unwatch(cx, obj, id); } +static bool +proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + HandleObject result) +{ + return Proxy::slice(cx, proxy, begin, end, result); +} + #define PROXY_CLASS_EXT \ { \ nullptr, /* outerObject */ \ @@ -3128,7 +3112,6 @@ proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) proxy_GetGeneric, \ proxy_GetProperty, \ proxy_GetElement, \ - proxy_GetElementIfPresent, \ proxy_GetSpecial, \ proxy_SetGeneric, \ proxy_SetProperty, \ @@ -3140,6 +3123,7 @@ proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) proxy_DeleteElement, \ proxy_DeleteSpecial, \ proxy_Watch, proxy_Unwatch, \ + proxy_Slice, \ nullptr, /* enumerate */ \ nullptr, /* thisObject */ \ } \ @@ -3186,7 +3170,6 @@ const Class js::OuterWindowProxyObject::class_ = { proxy_GetGeneric, proxy_GetProperty, proxy_GetElement, - proxy_GetElementIfPresent, proxy_GetSpecial, proxy_SetGeneric, proxy_SetProperty, @@ -3198,6 +3181,7 @@ const Class js::OuterWindowProxyObject::class_ = { proxy_DeleteElement, proxy_DeleteSpecial, proxy_Watch, proxy_Unwatch, + proxy_Slice, nullptr, /* enumerate */ nullptr, /* thisObject */ } diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index b8ce7a8668c2..0c6b4d4e2b5e 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -166,8 +166,6 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g); virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); virtual void finalize(JSFreeOp *fop, JSObject *proxy); - virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present); virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); // These two hooks must be overridden, or not overridden, in tandem -- no @@ -176,6 +174,9 @@ class JS_FRIEND_API(BaseProxyHandler) JS::HandleObject callable); virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id); + virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, + HandleObject result); + /* See comment for weakmapKeyDelegateOp in js/Class.h. */ virtual JSObject *weakmapKeyDelegate(JSObject *proxy); virtual bool isScripted() { return false; } @@ -276,8 +277,6 @@ class Proxy static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp); - static bool getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present); static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp); static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props); @@ -296,9 +295,11 @@ class Proxy static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); - static bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable); - static bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id); + static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable); + static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id); + + static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, + HandleObject result); /* IC entry path for handling __noSuchMethod__ on access. */ static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id, diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index b11983f8058b..61f94137e377 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -73,7 +73,7 @@ js::StartOffThreadAsmJSCompile(ExclusiveContext *cx, AsmJSParallelTask *asmData) if (!state.asmJSWorklist.append(asmData)) return false; - state.notifyAll(WorkerThreadState::PRODUCER); + state.notifyOne(WorkerThreadState::PRODUCER); return true; } @@ -501,6 +501,13 @@ WorkerThreadState::notifyAll(CondVar which) PR_NotifyAllCondVar((which == CONSUMER) ? consumerWakeup : producerWakeup); } +void +WorkerThreadState::notifyOne(CondVar which) +{ + JS_ASSERT(isLocked()); + PR_NotifyCondVar((which == CONSUMER) ? consumerWakeup : producerWakeup); +} + bool WorkerThreadState::canStartAsmJSCompile() { diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h index 21082331d3b9..4f3136563cc9 100644 --- a/js/src/jsworkers.h +++ b/js/src/jsworkers.h @@ -95,6 +95,7 @@ class WorkerThreadState void wait(CondVar which, uint32_t timeoutMillis = 0); void notifyAll(CondVar which); + void notifyOne(CondVar which); bool canStartAsmJSCompile(); bool canStartIonCompile(); diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index d285da3e76bd..e28a33acb16b 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -837,14 +837,6 @@ DeadObjectProxy::defaultValue(JSContext *cx, HandleObject obj, JSType hint, Muta return false; } -bool -DeadObjectProxy::getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present) -{ - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); - return false; -} - bool DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) { diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 1bf1e16664b2..5d68b8d17a69 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -208,9 +208,6 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) MOZ_OVERRIDE; - virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp, - bool *present) MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) MOZ_OVERRIDE; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 2a978adf189e..e7dad4b737fc 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -556,7 +556,6 @@ const Class WithObject::class_ = { with_GetGeneric, with_GetProperty, with_GetElement, - nullptr, /* getElementIfPresent */ with_GetSpecial, with_SetGeneric, with_SetProperty, @@ -567,7 +566,8 @@ const Class WithObject::class_ = { with_DeleteProperty, with_DeleteElement, with_DeleteSpecial, - nullptr, nullptr, /* watch/unwatch */ + nullptr, nullptr, /* watch/unwatch */ + nullptr, /* slice */ with_Enumerate, with_ThisObject, } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index ed36d97701c8..74339e88347d 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -1037,16 +1037,6 @@ ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj, return baseops::GetElement(cx, delegate, receiver, index, vp); } -bool -ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present) -{ - RootedObject delegate(cx, ArrayBufferDelegate(cx, obj)); - if (!delegate) - return false; - return JSObject::getElementIfPresent(cx, delegate, receiver, index, vp, present); -} - bool ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, @@ -1494,27 +1484,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject return obj_getProperty(cx, obj, receiver, name, vp); } - static bool - obj_getElementIfPresent(JSContext *cx, HandleObject tarray, HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present) - { - // Fast-path the common case of index < length - if (index < tarray->as().length()) { - // this inline function is specialized for each type - copyIndexToValue(tarray, index, vp); - *present = true; - return true; - } - - RootedObject proto(cx, tarray->getProto()); - if (!proto) { - vp.setUndefined(); - return true; - } - - return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present); - } - static bool setElementTail(JSContext *cx, HandleObject tarray, uint32_t index, MutableHandleValue vp, bool strict) @@ -3480,7 +3449,6 @@ const Class ArrayBufferObject::class_ = { ArrayBufferObject::obj_getGeneric, ArrayBufferObject::obj_getProperty, ArrayBufferObject::obj_getElement, - ArrayBufferObject::obj_getElementIfPresent, ArrayBufferObject::obj_getSpecial, ArrayBufferObject::obj_setGeneric, ArrayBufferObject::obj_setProperty, @@ -3492,8 +3460,9 @@ const Class ArrayBufferObject::class_ = { ArrayBufferObject::obj_deleteElement, ArrayBufferObject::obj_deleteSpecial, nullptr, nullptr, /* watch/unwatch */ + nullptr, /* slice */ ArrayBufferObject::obj_enumerate, - nullptr, /* thisObject */ + nullptr, /* thisObject */ } }; @@ -3643,7 +3612,6 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) _typedArray##Object::obj_getGeneric, \ _typedArray##Object::obj_getProperty, \ _typedArray##Object::obj_getElement, \ - _typedArray##Object::obj_getElementIfPresent, \ _typedArray##Object::obj_getSpecial, \ _typedArray##Object::obj_setGeneric, \ _typedArray##Object::obj_setProperty, \ @@ -3655,8 +3623,9 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) _typedArray##Object::obj_deleteElement, \ _typedArray##Object::obj_deleteSpecial, \ nullptr, nullptr, /* watch/unwatch */ \ + nullptr, /* slice */ \ _typedArray##Object::obj_enumerate, \ - nullptr, /* thisObject */ \ + nullptr, /* thisObject */ \ } \ } diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index e26a5c486fbb..275315ace116 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -107,8 +107,6 @@ class ArrayBufferObject : public JSObject static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp); - static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp, bool *present); static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, MutableHandleValue vp); diff --git a/js/xpconnect/idl/xpccomponents.idl b/js/xpconnect/idl/xpccomponents.idl index e3ce56ab48fa..36e9f0823dd0 100644 --- a/js/xpconnect/idl/xpccomponents.idl +++ b/js/xpconnect/idl/xpccomponents.idl @@ -120,7 +120,7 @@ interface ScheduledGCCallback : nsISupports /** * interface of Components.utils */ -[scriptable, uuid(ef621cac-c818-464a-9fb1-9a35731a7f32)] +[scriptable, uuid(8dd4680f-4f06-4760-a147-292cb307662f)] interface nsIXPCComponents_Utils : nsISupports { @@ -338,12 +338,13 @@ interface nsIXPCComponents_Utils : nsISupports * algorithm. * The return value is the new forwarder function, wrapped into * the caller's compartment. - * The 3rd argument is the name of the property that will - * be set on the target scope, with the forwarder function as - * the value. + * The 3rd argument is an optional options object: + * - defineAs: the name of the property that will + * be set on the target scope, with + * the forwarder function as the value. */ [implicit_jscontext] - jsval exportFunction(in jsval vfunction, in jsval vscope, in jsval vname); + jsval exportFunction(in jsval vfunction, in jsval vscope, [optional] in jsval voptions); /* * To be called from JS only. diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 7107499fad2a..098833cae342 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -243,17 +243,20 @@ IsProxy(JSContext *cx, unsigned argc, jsval *vp) namespace xpc { bool -ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleValue vname, +ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleValue voptions, MutableHandleValue rval) { - if (!vscope.isObject() || !vfunction.isObject() || !vname.isString()) { + bool hasOptions = !voptions.isUndefined(); + if (!vscope.isObject() || !vfunction.isObject() || (hasOptions && !voptions.isObject())) { JS_ReportError(cx, "Invalid argument"); return false; } RootedObject funObj(cx, &vfunction.toObject()); RootedObject targetScope(cx, &vscope.toObject()); - RootedString funName(cx, vname.toString()); + ExportOptions options(cx, hasOptions ? &voptions.toObject() : nullptr); + if (hasOptions && !options.Parse()) + return false; // We can only export functions to scopes those are transparent for us, // so if there is a security wrapper around targetScope we must throw. @@ -268,11 +271,6 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV return false; } - if (JS_GetStringLength(funName) == 0) { - JS_ReportError(cx, "3rd argument should be a non-empty string"); - return false; - } - { // We need to operate in the target scope from here on, let's enter // its compartment. @@ -285,16 +283,28 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV return false; } + RootedId id(cx, options.defineAs); + if (JSID_IS_VOID(id)) { + // If there wasn't any function name specified, + // copy the name from the function being imported. + JSFunction *fun = JS_GetObjectFunction(funObj); + RootedString funName(cx, JS_GetFunctionId(fun)); + if (!funName) + funName = JS_InternString(cx, ""); + + RootedValue vname(cx); + vname.setString(funName); + if (!JS_ValueToId(cx, vname, id.address())) + return false; + } + MOZ_ASSERT(JSID_IS_STRING(id)); + // The function forwarder will live in the target compartment. Since // this function will be referenced from its private slot, to avoid a // GC hazard, we must wrap it to the same compartment. if (!JS_WrapObject(cx, &funObj)) return false; - RootedId id(cx); - if (!JS_ValueToId(cx, vname, id.address())) - return false; - // And now, let's create the forwarder function in the target compartment // for the function the be exported. if (!NewFunctionForwarder(cx, id, funObj, /* doclone = */ true, rval)) { @@ -302,12 +312,16 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV return false; } - // We have the forwarder function in the target compartment, now - // we have to add it to the target scope as a property. - if (!JS_DefinePropertyById(cx, targetScope, id, rval, - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE)) - return false; + // We have the forwarder function in the target compartment. If + // defineAs was set, we also need to define it as a property on + // the target. + if (!JSID_IS_VOID(options.defineAs)) { + if (!JS_DefinePropertyById(cx, targetScope, id, rval, + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_ENUMERATE)) { + return false; + } + } } // Finally we have to re-wrap the exported function back to the caller compartment. @@ -321,19 +335,19 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV * Expected type of the arguments and the return value: * function exportFunction(function funToExport, * object targetScope, - * string name) + * [optional] object options) */ static bool ExportFunction(JSContext *cx, unsigned argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 3) { - JS_ReportError(cx, "Function requires at least 3 arguments"); + if (args.length() < 2) { + JS_ReportError(cx, "Function requires at least 2 arguments"); return false; } - return ExportFunction(cx, args[0], args[1], - args[2], args.rval()); + RootedValue options(cx, args.length() > 2 ? args[2] : UndefinedValue()); + return ExportFunction(cx, args[0], args[1], options, args.rval()); } } /* namespace xpc */ diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index fc8f9ffa3a3a..9202e226724c 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3094,13 +3094,13 @@ nsXPCComponents_Utils::EvalInWindow(const nsAString &source, const Value &window /* jsval exportFunction(in jsval vfunction, in jsval vscope, in jsval vname); */ NS_IMETHODIMP nsXPCComponents_Utils::ExportFunction(const Value &vfunction, const Value &vscope, - const Value &vname, JSContext *cx, Value *rval) + const Value &voptions, JSContext *cx, Value *rval) { RootedValue rfunction(cx, vfunction); RootedValue rscope(cx, vscope); - RootedValue rname(cx, vname); + RootedValue roptions(cx, voptions); RootedValue res(cx); - if (!xpc::ExportFunction(cx, rfunction, rscope, rname, &res)) + if (!xpc::ExportFunction(cx, rfunction, rscope, roptions, &res)) return NS_ERROR_FAILURE; *rval = res; return NS_OK; diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 97a287d2b9da..e92b8571cb71 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1790,7 +1790,7 @@ private: rtTotal += amount; \ } while (0) -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JSMallocSizeOf) +MOZ_DEFINE_MALLOC_SIZE_OF(JSMallocSizeOf) namespace xpc { @@ -2394,10 +2394,10 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats, } // namespace xpc -class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public MemoryMultiReporter +class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter { public: - JSMainRuntimeCompartmentsReporter() {} + NS_DECL_ISUPPORTS typedef js::Vector Paths; @@ -2436,7 +2436,9 @@ class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public MemoryMultiReporter } }; -NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(OrphanMallocSizeOf) +NS_IMPL_ISUPPORTS1(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter) + +MOZ_DEFINE_MALLOC_SIZE_OF(OrphanMallocSizeOf) namespace xpc { diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index ef717521c922..d890b151e9bc 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -720,7 +720,6 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { nullptr, // getGeneric nullptr, // getProperty nullptr, // getElement - nullptr, // getElementIfPresent nullptr, // getSpecial nullptr, // setGeneric nullptr, // setProperty @@ -732,6 +731,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { nullptr, // deleteElement nullptr, // deleteSpecial nullptr, nullptr, // watch/unwatch + nullptr, // slice XPC_WN_JSOp_Enumerate, XPC_WN_JSOp_ThisObject, } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index cb43fa26c53f..25cd00a64d11 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -981,7 +981,6 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* getGeneric */ \ nullptr, /* getProperty */ \ nullptr, /* getElement */ \ - nullptr, /* getElementIfPresent */ \ nullptr, /* getSpecial */ \ nullptr, /* setGeneric */ \ nullptr, /* setProperty */ \ @@ -993,6 +992,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* deleteElement */ \ nullptr, /* deleteSpecial */ \ nullptr, nullptr, /* watch/unwatch */ \ + nullptr, /* slice */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } @@ -1010,7 +1010,6 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* getGeneric */ \ nullptr, /* getProperty */ \ nullptr, /* getElement */ \ - nullptr, /* getElementIfPresent */ \ nullptr, /* getSpecial */ \ nullptr, /* setGeneric */ \ nullptr, /* setProperty */ \ @@ -1022,6 +1021,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS::HandleObject obj); nullptr, /* deleteElement */ \ nullptr, /* deleteSpecial */ \ nullptr, nullptr, /* watch/unwatch */ \ + nullptr, /* slice */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_ThisObject, \ } @@ -3461,6 +3461,19 @@ public: JS::RootedId defineAs; }; +class MOZ_STACK_CLASS ExportOptions : public OptionsBase { +public: + ExportOptions(JSContext *cx = xpc_GetSafeJSContext(), + JSObject* options = nullptr) + : OptionsBase(cx, options) + , defineAs(cx, JSID_VOID) + { } + + virtual bool Parse() { return ParseId("defineAs", &defineAs); }; + + JS::RootedId defineAs; +}; + JSObject * CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal, JS::CompartmentOptions& aOptions); diff --git a/js/xpconnect/tests/mochitest/mochitest.ini b/js/xpconnect/tests/mochitest/mochitest.ini index 4f8006152dde..3561526282f4 100644 --- a/js/xpconnect/tests/mochitest/mochitest.ini +++ b/js/xpconnect/tests/mochitest/mochitest.ini @@ -40,6 +40,7 @@ support-files = # bug 929498 skip-if = os == 'android' [test_asmjs2.html] +[test_asmjs3.html] [test_bug384632.html] [test_bug390488.html] [test_bug393269.html] diff --git a/js/xpconnect/tests/mochitest/test_asmjs3.html b/js/xpconnect/tests/mochitest/test_asmjs3.html new file mode 100644 index 000000000000..ccce0be009a1 --- /dev/null +++ b/js/xpconnect/tests/mochitest/test_asmjs3.html @@ -0,0 +1,67 @@ + + + + + + asm.js browser tests + + + + + asm.js browser tests +

+ +

+
+  
+
+
+
diff --git a/js/xpconnect/tests/unit/test_exportFunction.js b/js/xpconnect/tests/unit/test_exportFunction.js
index 888a6cd44110..2593572ea0dd 100644
--- a/js/xpconnect/tests/unit/test_exportFunction.js
+++ b/js/xpconnect/tests/unit/test_exportFunction.js
@@ -1,9 +1,9 @@
 function run_test() {
   var Cu = Components.utils;
   var epsb = new Cu.Sandbox(["http://example.com", "http://example.org"], { wantExportHelpers: true });
-  subsb = new Cu.Sandbox("http://example.com", { wantGlobalProperties: ["XMLHttpRequest"] });
-  subsb2 = new Cu.Sandbox("http://example.com", { wantGlobalProperties: ["XMLHttpRequest"] });
-  xorigsb = new Cu.Sandbox("http://test.com");
+  var subsb = new Cu.Sandbox("http://example.com", { wantGlobalProperties: ["XMLHttpRequest"] });
+  var subsb2 = new Cu.Sandbox("http://example.com", { wantGlobalProperties: ["XMLHttpRequest"] });
+  var xorigsb = new Cu.Sandbox("http://test.com");
 
   epsb.subsb = subsb;
   epsb.xorigsb = xorigsb;
@@ -32,7 +32,7 @@ function run_test() {
       do_check_true(wasCalled);
       wasCalled = false;
     }
-    exportFunction(funToExport, subsb, "imported");
+    exportFunction(funToExport, subsb, { defineAs: "imported" });
   }.toSource() + ")()", epsb);
 
   subsb.xrayed = Cu.evalInSandbox("(" + function () {
@@ -64,7 +64,7 @@ function run_test() {
   // not subsume the principal of the target.
   Cu.evalInSandbox("(" + function() {
     try{
-      exportFunction(function(){}, this.xorigsb, "denied");
+      exportFunction(function() {}, this.xorigsb, { defineAs: "denied" });
       do_check_true(false);
     } catch (e) {
       do_check_true(e.toString().indexOf('Permission denied') > -1);
@@ -74,8 +74,8 @@ function run_test() {
   // Let's create an object in the target scope and add privileged
   // function to it as a property.
   Cu.evalInSandbox("(" + function() {
-    var newContentObject = createObjectIn(subsb, {defineAs:"importedObject"});
-    exportFunction(funToExport, newContentObject, "privMethod");
+    var newContentObject = createObjectIn(subsb, { defineAs: "importedObject" });
+    exportFunction(funToExport, newContentObject, { defineAs: "privMethod" });
   }.toSource() + ")()", epsb);
 
   Cu.evalInSandbox("(" + function () {
@@ -87,13 +87,27 @@ function run_test() {
   }.toSource() + ")()", epsb);
 
   // exportFunction and createObjectIn should be available from Cu too.
-  var newContentObject = Cu.createObjectIn(subsb, {defineAs:"importedObject2"});
+  var newContentObject = Cu.createObjectIn(subsb, { defineAs: "importedObject2" });
   var wasCalled = false;
-  Cu.exportFunction(function(arg){wasCalled = arg.wasCalled;}, newContentObject, "privMethod");
+  Cu.exportFunction(function(arg) { wasCalled = arg.wasCalled; },
+                    newContentObject, { defineAs: "privMethod" });
 
   Cu.evalInSandbox("(" + function () {
     importedObject2.privMethod({wasCalled: true});
   }.toSource() + ")()", subsb);
 
+  // 3rd argument of exportFunction should be optional.
+  Cu.evalInSandbox("(" + function() {
+    subsb.imported2 = exportFunction(funToExport, subsb);
+  }.toSource() + ")()", epsb);
+
+  Cu.evalInSandbox("(" + function () {
+    imported2(42, tobecloned, native, mixed);
+  }.toSource() + ")()", subsb);
+
+  Cu.evalInSandbox("(" + function() {
+    checkIfCalled();
+  }.toSource() + ")()", epsb);
+
   do_check_true(wasCalled, true);
 }
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp
index dd16513e958b..10d88343dcc3 100644
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3259,9 +3259,10 @@ bool nsDisplayBlendContainer::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplay
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
-                                     uint32_t aFlags)
+                                     uint32_t aFlags, ViewID aScrollTarget)
     : nsDisplayWrapList(aBuilder, aFrame, aList)
-    , mFlags(aFlags) {
+    , mFlags(aFlags)
+    , mScrollTarget(aScrollTarget) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
@@ -3279,6 +3280,12 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
   nsRefPtr layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
+  if (mFlags & VERTICAL_SCROLLBAR) {
+    layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL);
+  }
+  if (mFlags & HORIZONTAL_SCROLLBAR) {
+    layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL);
+  }
 
   if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
     mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h
index f5e686e3b322..eee8f08ace42 100644
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2575,16 +2575,22 @@ public:
    * nsDisplayOwnLayer constructor flags
    */
   enum {
-    GENERATE_SUBDOC_INVALIDATIONS = 0x01
+    GENERATE_SUBDOC_INVALIDATIONS = 0x01,
+    VERTICAL_SCROLLBAR = 0x02,
+    HORIZONTAL_SCROLLBAR = 0x04
   };
 
   /**
    * @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
    * Add UserData to the created ContainerLayer, so that invalidations
    * for this layer are send to our nsPresContext.
+   * @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR
+   * is set in the flags, this parameter should be the ViewID of the
+   * scrollable content this scrollbar is for.
    */
   nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                    nsDisplayList* aList, uint32_t aFlags = 0);
+                    nsDisplayList* aList, uint32_t aFlags = 0,
+                    ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOwnLayer();
 #endif
@@ -2606,6 +2612,7 @@ public:
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 private:
   uint32_t mFlags;
+  ViewID mScrollTarget;
 };
 
 /**
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index 57fa60d1463d..97239c0bc0b8 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2058,13 +2058,15 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
 
 static void
 AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest,
-            nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer)
+            nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer,
+            uint32_t aFlags, mozilla::layers::FrameMetrics::ViewID aScrollTargetId)
 {
   if (aSource->IsEmpty())
     return;
   if (aOwnLayer) {
     aDest->AppendNewToTop(
-        new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource));
+        new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource,
+                                         aFlags, aScrollTargetId));
   } else {
     aDest->AppendToTop(aSource);
   }
@@ -2113,6 +2115,10 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
     scrollParts.AppendElement(kid);
   }
 
+  mozilla::layers::FrameMetrics::ViewID scrollTargetId = aCreateLayer
+    ? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
+    : mozilla::layers::FrameMetrics::NULL_SCROLL_ID;
+
   scrollParts.Sort(HoveredStateComparator());
 
   for (uint32_t i = 0; i < scrollParts.Length(); ++i) {
@@ -2129,11 +2135,19 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
     nsDisplayList* dest = appendToPositioned ?
       aLists.PositionedDescendants() : aLists.BorderBackground();
 
+    uint32_t flags = 0;
+    if (scrollParts[i] == mVScrollbarBox) {
+      flags |= nsDisplayOwnLayer::VERTICAL_SCROLLBAR;
+    }
+    if (scrollParts[i] == mHScrollbarBox) {
+      flags |= nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR;
+    }
+
     // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
     // partList.PositionedDescendants().
     ::AppendToTop(aBuilder, dest,
                   partList.PositionedDescendants(), scrollParts[i],
-                  aCreateLayer);
+                  aCreateLayer, flags, scrollTargetId);
   }
 }
 
@@ -2425,6 +2439,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   scrolledContent.MoveTo(aLists);
 
   // Now display overlay scrollbars and the resizer, if we have one.
+#ifdef MOZ_WIDGET_GONK
+  // TODO: only layerize the overlay scrollbars if this scrollframe can be
+  // panned asynchronously. For now just always layerize on B2G because.
+  // that's where we want the layerized scrollbars
+  createLayersForScrollbars = true;
+#endif
   AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
                       true);
 }
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp
index c65ff48db0a9..65d97c5c5875 100644
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -615,6 +615,36 @@ public:
     return mHaveZoomConstraints;
   }
 
+  virtual void NotifyTransformBegin(const ScrollableLayerGuid& aGuid)
+  {
+    if (MessageLoop::current() != mUILoop) {
+      mUILoop->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &RemoteContentController::NotifyTransformBegin,
+                          aGuid));
+      return;
+    }
+    if (mRenderFrame) {
+      TabParent* browser = static_cast(mRenderFrame->Manager());
+      browser->NotifyTransformBegin(aGuid.mScrollId);
+    }
+  }
+
+  virtual void NotifyTransformEnd(const ScrollableLayerGuid& aGuid)
+  {
+    if (MessageLoop::current() != mUILoop) {
+      mUILoop->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &RemoteContentController::NotifyTransformEnd,
+                          aGuid));
+      return;
+    }
+    if (mRenderFrame) {
+      TabParent* browser = static_cast(mRenderFrame->Manager());
+      browser->NotifyTransformEnd(aGuid.mScrollId);
+    }
+  }
+
 private:
   void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics)
   {
@@ -647,7 +677,8 @@ RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader,
   nsRefPtr lm = GetFrom(mFrameLoader);
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetBackendType() == LAYERS_CLIENT) {
-    *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
+    *aTextureFactoryIdentifier =
+      static_cast(lm.get())->GetTextureFactoryIdentifier();
   } else {
     *aTextureFactoryIdentifier = TextureFactoryIdentifier();
   }
diff --git a/mfbt/TypeTraits.h b/mfbt/TypeTraits.h
index 1ccd0c85d17f..493e44abed7d 100644
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -130,6 +130,23 @@ struct IsPointer : FalseType {};
 template
 struct IsPointer : TrueType {};
 
+/**
+ * IsLvalueReference determines whether a type is an lvalue reference.
+ *
+ * mozilla::IsLvalueReference::value is false;
+ * mozilla::IsLvalueReference::value is false;
+ * mozilla::IsLvalueReference::value is false;
+ * mozilla::IsLvalueReference::value is false;
+ * mozilla::IsLvalueReference::value is false;
+ * mozilla::IsLvalueReference::value is true;
+ * mozilla::IsLvalueReference::value is false.
+ */
+template
+struct IsLvalueReference : FalseType {};
+
+template
+struct IsLvalueReference : TrueType {};
+
 namespace detail {
 
 // __is_enum is a supported extension across all of our supported compilers.
@@ -424,16 +441,6 @@ struct IsConvertible
   : IntegralConstant::value>
 {};
 
-/**
- * Is IsLvalueReference is true if its template param is T& and is false if
- * its type is T or T&&.
- */
-template
-struct IsLvalueReference : FalseType {};
-
-template
-struct IsLvalueReference : TrueType {};
-
 /* 20.9.7 Transformations between types [meta.trans] */
 
 /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
diff --git a/mobile/android/components/ContentPermissionPrompt.js b/mobile/android/components/ContentPermissionPrompt.js
index ca8feb92729f..096972962345 100644
--- a/mobile/android/components/ContentPermissionPrompt.js
+++ b/mobile/android/components/ContentPermissionPrompt.js
@@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
 
-  handleExistingPermission: function handleExistingPermission(request, type, isApp) {
-    let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
+  handleExistingPermission: function handleExistingPermission(request, isApp) {
+    let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
       request.allow();
       return true;
@@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = {
       return true;
     }
 
-    if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
+    if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) {
       request.cancel();
       return true;
     }
@@ -62,16 +62,8 @@ ContentPermissionPrompt.prototype = {
   prompt: function(request) {
     let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID;
 
-    // Only allow exactly one permission rquest here.
-    let types = request.types.QueryInterface(Ci.nsIArray);
-    if (types.length != 1) {
-      request.cancel();
-      return;
-    }
-    let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
-
     // Returns true if the request was handled
-    if (this.handleExistingPermission(request, perm.type, isApp))
+    if (this.handleExistingPermission(request, isApp))
        return;
 
     let chromeWin = this.getChromeForRequest(request);
@@ -80,17 +72,17 @@ ContentPermissionPrompt.prototype = {
       return;
 
     let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-    let entityName = kEntities[perm.type];
+    let entityName = kEntities[request.type];
 
     let buttons = [{
       label: browserBundle.GetStringFromName(entityName + ".allow"),
       callback: function(aChecked) {
         // If the user checked "Don't ask again", make a permanent exception
         if (aChecked) {
-          Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
+          Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
         } else if (isApp || entityName == "desktopNotification") {
           // Otherwise allow the permission for the current session (if the request comes from an app or if it's a desktop-notification request)
-          Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
+          Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
         }
 
         request.allow();
@@ -101,7 +93,7 @@ ContentPermissionPrompt.prototype = {
       callback: function(aChecked) {
         // If the user checked "Don't ask again", make a permanent exception
         if (aChecked)
-          Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
+          Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
 
         request.cancel();
       }
diff --git a/modules/libpref/src/Preferences.cpp b/modules/libpref/src/Preferences.cpp
index 5d532c3af8df..44f382bfaa63 100644
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -223,13 +223,11 @@ Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeO
   return n;
 }
 
-class PreferenceServiceReporter MOZ_FINAL : public MemoryMultiReporter
+class PreferenceServiceReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
-  PreferenceServiceReporter() {}
-
-  NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCallback,
-                            nsISupports* aData);
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMEMORYREPORTER
 
 protected:
   static const uint32_t kSuspectReferentCount = 1000;
@@ -238,6 +236,8 @@ protected:
                                         void* aClosure);
 };
 
+NS_IMPL_ISUPPORTS1(PreferenceServiceReporter, nsIMemoryReporter)
+
 struct PreferencesReferentCount {
   PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
   size_t numStrong;
@@ -285,6 +285,8 @@ PreferenceServiceReporter::CountReferents(PrefCallback* aKey,
   return PL_DHASH_NEXT;
 }
 
+MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
+
 NS_IMETHODIMP
 PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
                                           nsISupports* aClosure)
@@ -300,7 +302,7 @@ PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
 
   REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
          nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
-         Preferences::SizeOfIncludingThisAndOtherStuff(MallocSizeOf),
+         Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
          "Memory used by the preferences system.");
 
   nsPrefBranch* rootBranch =
diff --git a/netwerk/base/src/nsServerSocket.cpp b/netwerk/base/src/nsServerSocket.cpp
index 2a8dd33dc874..56872ed8c6f0 100644
--- a/netwerk/base/src/nsServerSocket.cpp
+++ b/netwerk/base/src/nsServerSocket.cpp
@@ -13,6 +13,7 @@
 #include "prio.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Endian.h"
 #include "mozilla/net/DNS.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
@@ -521,7 +522,7 @@ nsServerSocket::GetPort(int32_t *aResult)
   else
     return NS_ERROR_FAILURE;
 
-  *aResult = (int32_t) PR_ntohs(port);
+  *aResult = static_cast(NetworkEndian::readUint16(&port));
   return NS_OK;
 }
 
diff --git a/netwerk/base/src/nsUDPSocket.cpp b/netwerk/base/src/nsUDPSocket.cpp
index dab5bdf4cd99..b8df89644bdd 100644
--- a/netwerk/base/src/nsUDPSocket.cpp
+++ b/netwerk/base/src/nsUDPSocket.cpp
@@ -3,6 +3,9 @@
  * 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/Attributes.h"
+#include "mozilla/Endian.h"
+
 #include "nsSocketTransport2.h"
 #include "nsUDPSocket.h"
 #include "nsProxyRelease.h"
@@ -11,7 +14,6 @@
 #include "nsNetCID.h"
 #include "prnetdb.h"
 #include "prio.h"
-#include "mozilla/Attributes.h"
 #include "nsNetAddr.h"
 #include "nsNetSegmentUtils.h"
 #include "NetworkActivityMonitor.h"
@@ -519,7 +521,7 @@ nsUDPSocket::GetPort(int32_t *aResult)
   else
     return NS_ERROR_NOT_INITIALIZED;
 
-  *aResult = (int32_t) PR_ntohs(port);
+  *aResult = static_cast(NetworkEndian::readUint16(&port));
   return NS_OK;
 }
 
diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp
index 350d8ce26364..d18b0db47b73 100644
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1071,8 +1071,8 @@ private:
  *****************************************************************************/
 nsCacheService *   nsCacheService::gService = nullptr;
 
-NS_IMPL_ISUPPORTS_INHERITED2(nsCacheService, MemoryMultiReporter,
-                             nsICacheService, nsICacheServiceInternal)
+NS_IMPL_ISUPPORTS3(nsCacheService, nsICacheService, nsICacheServiceInternal,
+                   nsIMemoryReporter)
 
 nsCacheService::nsCacheService()
     : mObserver(nullptr),
@@ -3184,6 +3184,8 @@ nsCacheService::LeavePrivateBrowsing()
     }
 }
 
+MOZ_DEFINE_MALLOC_SIZE_OF(DiskCacheDeviceMallocSizeOf)
+
 NS_IMETHODIMP
 nsCacheService::CollectReports(nsIHandleReportCallback* aHandleReport,
                                nsISupports* aData)
@@ -3192,7 +3194,7 @@ nsCacheService::CollectReports(nsIHandleReportCallback* aHandleReport,
     if (mDiskDevice) {
         nsCacheServiceAutoLock
             lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
-        disk = mDiskDevice->SizeOfIncludingThis(MallocSizeOf);
+        disk = mDiskDevice->SizeOfIncludingThis(DiskCacheDeviceMallocSizeOf);
     }
 
     size_t memory = mMemoryDevice ? mMemoryDevice->TotalSize() : 0;
diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h
index 73052250da25..8aac230506f4 100644
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -62,13 +62,14 @@ private:
  *  nsCacheService
  ******************************************************************************/
 
-class nsCacheService : public mozilla::MemoryMultiReporter,
-                       public nsICacheServiceInternal
+class nsCacheService : public nsICacheServiceInternal,
+                       public nsIMemoryReporter
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSICACHESERVICE
     NS_DECL_NSICACHESERVICEINTERNAL
+    NS_DECL_NSIMEMORYREPORTER
 
     nsCacheService();
     virtual ~nsCacheService();
@@ -223,9 +224,6 @@ public:
 
     typedef bool (*DoomCheckFn)(nsCacheEntry* entry);
 
-    NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData);
-
 private:
     friend class nsCacheServiceAutoLock;
     friend class nsOfflineCacheDevice;
diff --git a/netwerk/protocol/http/SpdySession3.cpp b/netwerk/protocol/http/SpdySession3.cpp
index dc133617f3ce..756644bd343c 100644
--- a/netwerk/protocol/http/SpdySession3.cpp
+++ b/netwerk/protocol/http/SpdySession3.cpp
@@ -7,12 +7,12 @@
 // HttpLog.h should generally be included first
 #include "HttpLog.h"
 
+#include "mozilla/Endian.h"
 #include "mozilla/Telemetry.h"
 #include "nsHttp.h"
 #include "nsHttpHandler.h"
 #include "nsILoadGroup.h"
 #include "prprf.h"
-#include "prnetdb.h"
 #include "SpdyPush3.h"
 #include "SpdySession3.h"
 #include "SpdyStream3.h"
@@ -652,8 +652,7 @@ SpdySession3::GeneratePing(uint32_t aID)
   packet[6] = 0;
   packet[7] = 4;                                  /* length */
 
-  aID = PR_htonl(aID);
-  memcpy(packet + 8, &aID, 4);
+  NetworkEndian::writeUint32(packet + 8, aID);
 
   LogIO(this, nullptr, "Generate Ping", packet, 12);
   FlushOutputQueue();
@@ -679,10 +678,8 @@ SpdySession3::GenerateRstStream(uint32_t aStatusCode, uint32_t aID)
   packet[6] = 0;
   packet[7] = 8;                                  /* length */
 
-  aID = PR_htonl(aID);
-  memcpy(packet + 8, &aID, 4);
-  aStatusCode = PR_htonl(aStatusCode);
-  memcpy(packet + 12, &aStatusCode, 4);
+  NetworkEndian::writeUint32(packet + 8, aID);
+  NetworkEndian::writeUint32(packet + 12, aStatusCode);
 
   LogIO(this, nullptr, "Generate Reset", packet, 16);
   FlushOutputQueue();
@@ -709,8 +706,7 @@ SpdySession3::GenerateGoAway(uint32_t aStatusCode)
   // need to be set non zero
 
   // bytes 12-15 are the status code.
-  aStatusCode = PR_htonl(aStatusCode);
-  memcpy(packet + 12, &aStatusCode, 4);
+  NetworkEndian::writeUint32(packet + 12, aStatusCode);
 
   LogIO(this, nullptr, "Generate GoAway", packet, 16);
   FlushOutputQueue();
@@ -756,8 +752,7 @@ SpdySession3::GenerateSettings()
     packet[12 + 8 * numberOfEntries] = PERSISTED_VALUE;
     packet[15 + 8 * numberOfEntries] = SETTINGS_TYPE_CWND;
     LOG(("SpdySession3::GenerateSettings %p sending CWND %u\n", this, cwnd));
-    cwnd = PR_htonl(cwnd);
-    memcpy(packet + 16 + 8 * numberOfEntries, &cwnd, 4);
+    NetworkEndian::writeUint32(packet + 16 + 8 * numberOfEntries, cwnd);
     numberOfEntries++;
   }
 
@@ -765,8 +760,7 @@ SpdySession3::GenerateSettings()
   // a window update with it in order to use larger initial windows with pulled
   // streams.
   packet[15 + 8 * numberOfEntries] = SETTINGS_TYPE_INITIAL_WINDOW;
-  uint32_t rwin = PR_htonl(mPushAllowance);
-  memcpy(packet + 16 + 8 * numberOfEntries, &rwin, 4);
+  NetworkEndian::writeUint32(packet + 16 + 8 * numberOfEntries, mPushAllowance);
   numberOfEntries++;
 
   uint32_t dataLen = 4 + 8 * numberOfEntries;
@@ -943,9 +937,9 @@ SpdySession3::HandleSynStream(SpdySession3 *self)
   }
 
   uint32_t streamID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
   uint32_t associatedID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[3]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 3 * sizeof(uint32_t));
   uint8_t flags = reinterpret_cast(self->mInputFrameBuffer.get())[4];
 
   LOG3(("SpdySession3::HandleSynStream %p recv SYN_STREAM (push) "
@@ -1124,7 +1118,7 @@ SpdySession3::HandleSynReply(SpdySession3 *self)
   LOG3(("SpdySession3::HandleSynReply %p lookup via streamID in syn_reply.\n",
         self));
   uint32_t streamID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
   nsresult rv = self->SetInputFrameDataStream(streamID);
   if (NS_FAILED(rv))
     return rv;
@@ -1256,10 +1250,10 @@ SpdySession3::HandleRstStream(SpdySession3 *self)
   uint8_t flags = reinterpret_cast(self->mInputFrameBuffer.get())[4];
 
   uint32_t streamID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
 
   self->mDownstreamRstReason =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[3]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 3 * sizeof(uint32_t));
 
   LOG3(("SpdySession3::HandleRstStream %p RST_STREAM Reason Code %u ID %x "
         "flags %x", self, self->mDownstreamRstReason, streamID, flags));
@@ -1319,7 +1313,7 @@ SpdySession3::HandleSettings(SpdySession3 *self)
   }
 
   uint32_t numEntries =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
 
   // Ensure frame is large enough for supplied number of entries
   // Each entry is 8 bytes, frame data is reduced by 4 to account for
@@ -1338,8 +1332,8 @@ SpdySession3::HandleSettings(SpdySession3 *self)
       (self->mInputFrameBuffer.get()) + 12 + index * 8;
 
     uint32_t flags = setting[0];
-    uint32_t id = PR_ntohl(reinterpret_cast(setting)[0]) & 0xffffff;
-    uint32_t value =  PR_ntohl(reinterpret_cast(setting)[1]);
+    uint32_t id = NetworkEndian::readUint32(setting) & 0xffffff;
+    uint32_t value = NetworkEndian::readUint32(setting + 1 * sizeof(uint32_t));
 
     LOG3(("Settings ID %d, Flags %X, Value %d", id, flags, value));
 
@@ -1425,7 +1419,7 @@ SpdySession3::HandlePing(SpdySession3 *self)
   }
 
   uint32_t pingID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
 
   LOG3(("SpdySession3::HandlePing %p PING ID 0x%X.", self, pingID));
 
@@ -1455,7 +1449,7 @@ SpdySession3::HandleGoAway(SpdySession3 *self)
 
   self->mShouldGoAway = true;
   self->mGoAwayID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
   self->mCleanShutdown = true;
 
   // Find streams greater than the last-good ID and mark them for deletion
@@ -1488,7 +1482,8 @@ SpdySession3::HandleGoAway(SpdySession3 *self)
 
   LOG3(("SpdySession3::HandleGoAway %p GOAWAY Last-Good-ID 0x%X status 0x%X "
         "live streams=%d\n", self, self->mGoAwayID,
-        PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[3]),
+        NetworkEndian::readUint32(self->mInputFrameBuffer +
+                                  3 * sizeof(uint32_t)),
         self->mStreamTransactionHash.Count()));
 
   self->ResetDownstreamState();
@@ -1507,7 +1502,7 @@ SpdySession3::HandleHeaders(SpdySession3 *self)
   }
 
   uint32_t streamID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
   LOG3(("SpdySession3::HandleHeaders %p HEADERS for Stream 0x%X.\n",
         self, streamID));
   nsresult rv = self->SetInputFrameDataStream(streamID);
@@ -1585,10 +1580,10 @@ SpdySession3::HandleWindowUpdate(SpdySession3 *self)
   }
 
   uint32_t delta =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[3]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 3 * sizeof(uint32_t));
   delta &= 0x7fffffff;
   uint32_t streamID =
-    PR_ntohl(reinterpret_cast(self->mInputFrameBuffer.get())[2]);
+    NetworkEndian::readUint32(self->mInputFrameBuffer + 2 * sizeof(uint32_t));
   streamID &= 0x7fffffff;
 
   LOG3(("SpdySession3::HandleWindowUpdate %p len=%d for Stream 0x%X.\n",
@@ -1898,7 +1893,7 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
     // For both control and data frames the second 32 bit word of the header
     // is 8-flags, 24-length. (network byte order)
     mInputFrameDataSize =
-      PR_ntohl(reinterpret_cast(mInputFrameBuffer.get())[1]);
+      NetworkEndian::readUint32(mInputFrameBuffer + 1 * sizeof(uint32_t));
     mInputFrameDataSize &= 0x00ffffff;
     mInputFrameDataRead = 0;
 
@@ -1909,12 +1904,11 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
 
       // The first 32 bit word of the header is
       // 1 ctrl - 15 version - 16 type
-      uint16_t version =
-        PR_ntohs(reinterpret_cast(mInputFrameBuffer.get())[0]);
+      uint16_t version = NetworkEndian::readUint16(mInputFrameBuffer);
       version &= 0x7fff;
 
       mFrameControlType =
-        PR_ntohs(reinterpret_cast(mInputFrameBuffer.get())[1]);
+        NetworkEndian::readUint16(mInputFrameBuffer + sizeof(uint16_t));
 
       LOG3(("SpdySession3::WriteSegments %p - Control Frame Identified "
             "type %d version %d data len %d",
@@ -1934,8 +1928,7 @@ SpdySession3::WriteSegments(nsAHttpSegmentWriter *writer,
                             mInputFrameDataSize >> 10);
       mLastDataReadEpoch = mLastReadEpoch;
 
-      uint32_t streamID =
-        PR_ntohl(reinterpret_cast(mInputFrameBuffer.get())[0]);
+      uint32_t streamID = NetworkEndian::readUint32(mInputFrameBuffer);
       rv = SetInputFrameDataStream(streamID);
       if (NS_FAILED(rv)) {
         LOG(("SpdySession3::WriteSegments %p lookup streamID 0x%X failed. "
@@ -2193,10 +2186,8 @@ SpdySession3::UpdateLocalRwin(SpdyStream3 *stream,
   packet[3] = CONTROL_TYPE_WINDOW_UPDATE;
   packet[7] = dataLen;
 
-  uint32_t id = PR_htonl(stream->StreamID());
-  memcpy(packet + 8, &id, 4);
-  toack = PR_htonl(toack);
-  memcpy(packet + 12, &toack, 4);
+  NetworkEndian::writeUint32(packet + 8, stream->StreamID());
+  NetworkEndian::writeUint32(packet + 12, toack);
 
   LogIO(this, stream, "Window Update", packet, 8 + dataLen);
   FlushOutputQueue();
diff --git a/netwerk/protocol/http/SpdyStream3.cpp b/netwerk/protocol/http/SpdyStream3.cpp
index 1d2150e8ed35..918c69e744cc 100644
--- a/netwerk/protocol/http/SpdyStream3.cpp
+++ b/netwerk/protocol/http/SpdyStream3.cpp
@@ -7,6 +7,7 @@
 // HttpLog.h should generally be included first
 #include "HttpLog.h"
 
+#include "mozilla/Endian.h"
 #include "mozilla/Telemetry.h"
 #include "nsHttp.h"
 #include "nsHttpHandler.h"
@@ -338,12 +339,11 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
   mTxInlineFrame[3] = SpdySession3::CONTROL_TYPE_SYN_STREAM;
   // 4 to 7 are length and flags, we'll fill that in later
 
-  uint32_t networkOrderID = PR_htonl(mStreamID);
-  memcpy(mTxInlineFrame + 8, &networkOrderID, 4);
+  NetworkEndian::writeUint32(mTxInlineFrame + 8, mStreamID);
 
   // this is the associated-to field, which is not used sending
   // from the client in the http binding
-  memset (mTxInlineFrame + 12, 0, 4);
+  memset(mTxInlineFrame + 12, 0, 4);
 
   // Priority flags are the E0 mask of byte 16.
   // 0 is highest priority, 7 is lowest.
@@ -469,8 +469,8 @@ SpdyStream3::ParseHttpRequestHeaders(const char *buf,
   CompressFlushFrame();
 
   // 4 to 7 are length and flags, which we can now fill in
-  (reinterpret_cast(mTxInlineFrame.get()))[1] =
-    PR_htonl(mTxInlineFrameUsed - 8);
+  NetworkEndian::writeUint32(mTxInlineFrame + 1 * sizeof(uint32_t),
+                             mTxInlineFrameUsed - 8);
 
   MOZ_ASSERT(!mTxInlineFrame[4], "Size greater than 24 bits");
 
@@ -768,9 +768,8 @@ SpdyStream3::GenerateDataFrameHeader(uint32_t dataLength, bool lastFrame)
   MOZ_ASSERT(!mTxStreamFrameSize, "stream frame not empty");
   MOZ_ASSERT(!(dataLength & 0xff000000), "datalength > 24 bits");
 
-  (reinterpret_cast(mTxInlineFrame.get()))[0] = PR_htonl(mStreamID);
-  (reinterpret_cast(mTxInlineFrame.get()))[1] =
-    PR_htonl(dataLength);
+  NetworkEndian::writeUint32(mTxInlineFrame, mStreamID);
+  NetworkEndian::writeUint32(mTxInlineFrame + 1 * sizeof(uint32_t), dataLength);
 
   MOZ_ASSERT(!(mTxInlineFrame[0] & 0x80), "control bit set unexpectedly");
   MOZ_ASSERT(!mTxInlineFrame[4], "flag bits set unexpectedly");
@@ -1065,7 +1064,7 @@ SpdyStream3::FindHeader(nsCString name,
     return NS_ERROR_ILLEGAL_VALUE;
 
   do {
-    uint32_t numPairs = PR_ntohl(reinterpret_cast(nvpair)[-1]);
+    uint32_t numPairs = NetworkEndian::readUint32(nvpair - 1 * sizeof(uint32_t));
 
     for (uint32_t index = 0; index < numPairs; ++index) {
       if (lastHeaderByte < nvpair + 4)
@@ -1147,7 +1146,7 @@ SpdyStream3::ConvertHeaders(nsACString &aHeadersOut)
     return NS_ERROR_ILLEGAL_VALUE;
 
   do {
-    uint32_t numPairs = PR_ntohl(reinterpret_cast(nvpair)[-1]);
+    uint32_t numPairs = NetworkEndian::readUint32(nvpair - 1 * sizeof(uint32_t));
 
     for (uint32_t index = 0; index < numPairs; ++index) {
       if (lastHeaderByte < nvpair + 4)
@@ -1285,10 +1284,11 @@ SpdyStream3::CompressToFrame(uint32_t data)
 {
   // convert the data to 4 byte network byte order and write that
   // to the compressed stream
-  data = PR_htonl(data);
+  unsigned char databuf[sizeof(data)];
+  NetworkEndian::writeUint32(databuf, data);
 
-  mZlib->next_in = reinterpret_cast (&data);
-  mZlib->avail_in = 4;
+  mZlib->next_in = databuf;
+  mZlib->avail_in = sizeof(databuf);
   ExecuteCompress(Z_NO_FLUSH);
 }
 
@@ -1299,11 +1299,12 @@ SpdyStream3::CompressToFrame(const char *data, uint32_t len)
   // Format calls for a network ordered 32 bit length
   // followed by the utf8 string
 
-  uint32_t networkLen = PR_htonl(len);
+  unsigned char lenbuf[sizeof(len)];
+  NetworkEndian::writeUint32(lenbuf, len);
 
   // write out the length
-  mZlib->next_in = reinterpret_cast (&networkLen);
-  mZlib->avail_in = 4;
+  mZlib->next_in = lenbuf;
+  mZlib->avail_in = sizeof(lenbuf);
   ExecuteCompress(Z_NO_FLUSH);
 
   // write out the data
diff --git a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
index f9b895af4131..4a4256542132 100644
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
@@ -229,8 +229,9 @@ void RTSPSource::performPause() {
     for (size_t i = 0; i < mTracks.size(); ++i) {
       TrackInfo *info = &mTracks.editItemAt(i);
       info->mLatestPausedUnit = 0;
-      mLatestPausedUnit = 0;
     }
+    mLatestPausedUnit = 0;
+
     mState = PAUSING;
     mHandler->pause();
 }
@@ -259,8 +260,8 @@ void RTSPSource::performSeek(int64_t seekTimeUs) {
     for (size_t i = 0; i < mTracks.size(); ++i) {
       TrackInfo *info = &mTracks.editItemAt(i);
       info->mLatestPausedUnit = 0;
-      mLatestPausedUnit = 0;
     }
+    mLatestPausedUnit = 0;
 
     LOGI("performSeek: %llu", seekTimeUs);
     mState = SEEKING;
@@ -328,6 +329,14 @@ void RTSPSource::onMessageReceived(const sp &msg) {
         case RtspConnectionHandler::kWhatSeekDone:
         {
             mState = PLAYING;
+            // Even if we have reset mLatestPausedUnit in performSeek(),
+            // it's still possible that kWhatPausedDone event may arrive
+            // because of previous performPause() command.
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                TrackInfo *info = &mTracks.editItemAt(i);
+                info->mLatestPausedUnit = 0;
+            }
+            mLatestPausedUnit = 0;
             break;
         }
 
diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp
index 7d884a63251c..7643dcabaca8 100644
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -7,6 +7,11 @@
 #include "WebSocketLog.h"
 #include "WebSocketChannel.h"
 
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Endian.h"
+#include "mozilla/MathAlgorithms.h"
+
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsICryptoHash.h"
@@ -40,9 +45,6 @@
 #include "nsAlgorithm.h"
 #include "nsProxyRelease.h"
 #include "nsNetUtil.h"
-#include "mozilla/Atomics.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/MathAlgorithms.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 
@@ -1232,9 +1234,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
       }
 
       // copy this in case it is unaligned
-      uint64_t tempLen;
-      memcpy(&tempLen, mFramePtr + 2, 8);
-      payloadLength64 = PR_ntohll(tempLen);
+      payloadLength64 = NetworkEndian::readInt64(mFramePtr + 2);
     }
 
     payload = mFramePtr + framingLength;
@@ -1259,9 +1259,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
       // frames to the client, but it is allowed
       LOG(("WebSocketChannel:: Client RECEIVING masked frame."));
 
-      uint32_t mask;
-      memcpy(&mask, payload - 4, 4);
-      mask = PR_ntohl(mask);
+      uint32_t mask = NetworkEndian::readUint32(payload - 4);
       ApplyMask(mask, payload, payloadLength);
     }
 
@@ -1375,8 +1373,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
 
         mServerCloseCode = CLOSE_NO_STATUS;
         if (payloadLength >= 2) {
-          memcpy(&mServerCloseCode, payload, 2);
-          mServerCloseCode = PR_ntohs(mServerCloseCode);
+          mServerCloseCode = NetworkEndian::readUint16(payload);
           LOG(("WebSocketChannel:: close recvd code %u\n", mServerCloseCode));
           uint16_t msglen = static_cast(payloadLength - 2);
           if (msglen > 0) {
@@ -1524,10 +1521,10 @@ WebSocketChannel::ApplyMask(uint32_t mask, uint8_t *data, uint64_t len)
 
   uint32_t *iData = (uint32_t *) data;
   uint32_t *end = iData + (len / 4);
-  mask = PR_htonl(mask);
+  NetworkEndian::writeUint32(&mask, mask);
   for (; iData < end; iData++)
     *iData ^= mask;
-  mask = PR_ntohl(mask);
+  mask = NetworkEndian::readUint32(&mask);
   data = (uint8_t *)iData;
   len  = len % 4;
 
@@ -1657,8 +1654,7 @@ WebSocketChannel::PrimeNewOutgoingMessage()
     // and there isn't an internal error, use that.
     if (NS_SUCCEEDED(mStopOnClose)) {
       if (mScriptCloseCode) {
-        uint16_t temp = PR_htons(mScriptCloseCode);
-        memcpy(payload, &temp, 2);
+        NetworkEndian::writeUint16(payload, mScriptCloseCode);
         mOutHeader[1] += 2;
         mHdrOutToSend = 8;
         if (!mScriptCloseReason.IsEmpty()) {
@@ -1677,8 +1673,7 @@ WebSocketChannel::PrimeNewOutgoingMessage()
         mHdrOutToSend = 6;
       }
     } else {
-      uint16_t temp = PR_htons(ResultToCloseCode(mStopOnClose));
-      memcpy(payload, &temp, 2);
+      NetworkEndian::writeUint16(payload, ResultToCloseCode(mStopOnClose));
       mOutHeader[1] += 2;
       mHdrOutToSend = 8;
     }
@@ -1737,14 +1732,12 @@ WebSocketChannel::PrimeNewOutgoingMessage()
       mHdrOutToSend = 6;
     } else if (mCurrentOut->Length() <= 0xffff) {
       mOutHeader[1] = 126 | kMaskBit;
-      ((uint16_t *)mOutHeader)[1] =
-        PR_htons(mCurrentOut->Length());
+      NetworkEndian::writeUint16(mOutHeader + sizeof(uint16_t),
+                                 mCurrentOut->Length());
       mHdrOutToSend = 8;
     } else {
       mOutHeader[1] = 127 | kMaskBit;
-      uint64_t tempLen = mCurrentOut->Length();
-      tempLen = PR_htonll(tempLen);
-      memcpy(mOutHeader + 2, &tempLen, 8);
+      NetworkEndian::writeUint64(mOutHeader + 2, mCurrentOut->Length());
       mHdrOutToSend = 14;
     }
     payload = mOutHeader + mHdrOutToSend;
@@ -1766,8 +1759,7 @@ WebSocketChannel::PrimeNewOutgoingMessage()
     mask = * reinterpret_cast(buffer);
     NS_Free(buffer);
   } while (!mask);
-  uint32_t temp = PR_htonl(mask);
-  memcpy(payload - 4, &temp, 4);
+  NetworkEndian::writeUint32(payload - sizeof(uint32_t), mask);
 
   LOG(("WebSocketChannel::PrimeNewOutgoingMessage() using mask %08x\n", mask));
 
diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py
index b8f8b61b20d5..d5b9b1501bb7 100644
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1051,6 +1051,14 @@ class RecursiveMakeBackend(CommonBackend):
                 if not obj.dupe_manifest:
                     raise
 
+        for base, pattern, dest in obj.pattern_installs:
+            try:
+                self._install_manifests['tests'].add_pattern_symlink(base,
+                    pattern, dest)
+            except ValueError:
+                if not obj.dupe_manifest:
+                    raise
+
         for dest in obj.external_installs:
             try:
                 self._install_manifests['tests'].add_optional_exists(dest)
diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py
index dfa16a0a0df0..ea8d066044c0 100644
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -361,6 +361,10 @@ class TestManifest(SandboxDerived):
         # path is relative from the tests root directory.
         'installs',
 
+        # A list of pattern matching installs to perform. Entries are
+        # (base, pattern, dest).
+        'pattern_installs',
+
         # Where all files for this manifest flavor are installed in the unified
         # test package directory.
         'install_prefix',
@@ -400,6 +404,7 @@ class TestManifest(SandboxDerived):
         self.manifest_relpath = relpath
         self.dupe_manifest = dupe_manifest
         self.installs = {}
+        self.pattern_installs = []
         self.tests = []
         self.external_installs = set()
 
diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py
index b55d37744868..6d456215cf99 100644
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -15,8 +15,6 @@ from mach.mixin.logging import LoggingMixin
 import mozpack.path as mozpath
 import manifestparser
 
-from mozpack.files import FileFinder
-
 from .data import (
     ConfigFileSubstitution,
     Defines,
@@ -405,8 +403,6 @@ class TreeMetadataEmitter(LoggingMixin):
 
             out_dir = mozpath.join(install_prefix, manifest_reldir)
 
-            finder = FileFinder(base=manifest_dir, find_executables=False)
-
             # "head" and "tail" lists.
             # All manifests support support-files.
             #
@@ -431,22 +427,9 @@ class TreeMetadataEmitter(LoggingMixin):
                     for pattern in value.split():
                         # We only support globbing on support-files because
                         # the harness doesn't support * for head and tail.
-                        #
-                        # While we could feed everything through the finder, we
-                        # don't because we want explicitly listed files that
-                        # no longer exist to raise an error. The finder is also
-                        # slower than simple lookup.
                         if '*' in pattern and thing == 'support-files':
-                            paths = [f[0] for f in finder.find(pattern)]
-                            if not paths:
-                                raise SandboxValidationError('%s support-files '
-                                    'wildcard in %s returns no results.' % (
-                                    pattern, path))
-
-                            for f in paths:
-                                full = mozpath.normpath(mozpath.join(manifest_dir, f))
-                                obj.installs[full] = mozpath.join(out_dir, f)
-
+                            obj.pattern_installs.append(
+                                (manifest_dir, pattern, out_dir))
                         else:
                             full = mozpath.normpath(mozpath.join(manifest_dir,
                                 pattern))
diff --git a/python/mozbuild/mozbuild/test/backend/data/test-manifests-written/xpcshell.ini b/python/mozbuild/mozbuild/test/backend/data/test-manifests-written/xpcshell.ini
index 8dada2a4e5f8..f6a5351e94ed 100644
--- a/python/mozbuild/mozbuild/test/backend/data/test-manifests-written/xpcshell.ini
+++ b/python/mozbuild/mozbuild/test/backend/data/test-manifests-written/xpcshell.ini
@@ -1,3 +1,4 @@
 [DEFAULT]
+support-files = support/**
 
 [xpcshell.js]
diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
index 4c4046de679c..199718ca593f 100644
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -382,6 +382,18 @@ class TestRecursiveMakeBackend(BackendTester):
 
             self.assertEqual(len(o['xpcshell.js']), 1)
 
+    def test_test_manifest_pattern_matches_recorded(self):
+        """Pattern matches in test manifests' support-files should be recorded."""
+        env = self._consume('test-manifests-written', RecursiveMakeBackend)
+        m = InstallManifest(path=os.path.join(env.topobjdir,
+            '_build_manifests', 'install', 'tests'))
+
+        # This is not the most robust test in the world, but it gets the job
+        # done.
+        entries = [e for e in m._dests.keys() if '**' in e]
+        self.assertEqual(len(entries), 1)
+        self.assertIn('support/**', entries[0])
+
     def test_xpidl_generation(self):
         """Ensure xpidl files and directories are written out."""
         env = self._consume('xpidl', RecursiveMakeBackend)
diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
index aafb4f6eaf47..772afc1a8691 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -248,10 +248,8 @@ class TestEmitterBasic(unittest.TestCase):
                 'installs': {
                     'a11y.ini',
                     'test_a11y.js',
-                    # From ** wildcard.
-                    'a11y-support/foo',
-                    'a11y-support/dir1/bar',
                 },
+                'pattern-installs': 1,
             },
             'browser.ini': {
                 'flavor': 'browser-chrome',
@@ -319,6 +317,9 @@ class TestEmitterBasic(unittest.TestCase):
 
                 self.assertIn(path, m['installs'])
 
+            if 'pattern-installs' in m:
+                self.assertEqual(len(o.pattern_installs), m['pattern-installs'])
+
     def test_test_manifest_unmatched_generated(self):
         reader = self.reader('test-manifest-unmatched-generated')
 
diff --git a/python/mozbuild/mozpack/files.py b/python/mozbuild/mozpack/files.py
index 093090f21309..3daaf0055efc 100644
--- a/python/mozbuild/mozpack/files.py
+++ b/python/mozbuild/mozpack/files.py
@@ -556,7 +556,10 @@ class FileFinder(BaseFinder):
         Ignores file names starting with a '.' under the given path. If the
         path itself has leafs starting with a '.', they are not ignored.
         '''
-        for p in os.listdir(os.path.join(self.base, path)):
+        # The sorted makes the output idempotent. Otherwise, we are
+        # likely dependent on filesystem implementation details, such as
+        # inode ordering.
+        for p in sorted(os.listdir(os.path.join(self.base, path))):
             if p.startswith('.'):
                 continue
             for p_, f in self._find(mozpack.path.join(path, p)):
@@ -596,7 +599,8 @@ class FileFinder(BaseFinder):
         elif '*' in pattern[0]:
             if not os.path.exists(os.path.join(self.base, base)):
                 return
-            for p in os.listdir(os.path.join(self.base, base)):
+            # See above comment w.r.t. sorted() and idempotent behavior.
+            for p in sorted(os.listdir(os.path.join(self.base, base))):
                 if p.startswith('.') and not pattern[0].startswith('.'):
                     continue
                 if mozpack.path.match(p, pattern[0]):
diff --git a/python/mozbuild/mozpack/manifests.py b/python/mozbuild/mozpack/manifests.py
index 462e0f9c82f6..e91e14026cc5 100644
--- a/python/mozbuild/mozpack/manifests.py
+++ b/python/mozbuild/mozpack/manifests.py
@@ -6,11 +6,11 @@ from __future__ import unicode_literals
 
 from contextlib import contextmanager
 
-from .copier import FilePurger
 from .files import (
     AbsoluteSymlinkFile,
     ExistingFile,
     File,
+    FileFinder,
 )
 import mozpack.path as mozpath
 
@@ -63,8 +63,15 @@ class InstallManifest(object):
           the FileCopier. No error is raised if the destination path does not
           exist.
 
-    Versions 1 and 2 of the manifest format are similar. Version 2 added
-    optional path support.
+      patternsymlink -- Paths matched by the expression in the source path
+          will be symlinked to the destination directory.
+
+      patterncopy -- Similar to patternsymlink except files are copied, not
+          symlinked.
+
+    Version 1 of the manifest was the initial version.
+    Version 2 added optional path support
+    Version 3 added support for pattern entries.
     """
     FIELD_SEPARATOR = '\x1f'
 
@@ -72,6 +79,8 @@ class InstallManifest(object):
     COPY = 2
     REQUIRED_EXISTS = 3
     OPTIONAL_EXISTS = 4
+    PATTERN_SYMLINK = 5
+    PATTERN_COPY = 6
 
     def __init__(self, path=None, fileobj=None):
         """Create a new InstallManifest entry.
@@ -94,7 +103,7 @@ class InstallManifest(object):
 
     def _load_from_fileobj(self, fileobj):
         version = fileobj.readline().rstrip()
-        if version not in ('1', '2'):
+        if version not in ('1', '2', '3'):
             raise UnreadableInstallManifest('Unknown manifest version: ' %
                 version)
 
@@ -106,7 +115,7 @@ class InstallManifest(object):
             record_type = int(fields[0])
 
             if record_type == self.SYMLINK:
-                dest, source= fields[1:]
+                dest, source = fields[1:]
                 self.add_symlink(source, dest)
                 continue
 
@@ -125,6 +134,16 @@ class InstallManifest(object):
                 self.add_optional_exists(path)
                 continue
 
+            if record_type == self.PATTERN_SYMLINK:
+                _, base, pattern, dest = fields[1:]
+                self.add_pattern_symlink(base, pattern, dest)
+                continue
+
+            if record_type == self.PATTERN_COPY:
+                _, base, pattern, dest = fields[1:]
+                self.add_pattern_copy(base, pattern, dest)
+                continue
+
             raise UnreadableInstallManifest('Unknown record type: %d' %
                 record_type)
 
@@ -158,7 +177,7 @@ class InstallManifest(object):
         It is an error if both are specified.
         """
         with _auto_fileobj(path, fileobj, 'wb') as fh:
-            fh.write('2\n')
+            fh.write('3\n')
 
             for dest in sorted(self._dests):
                 entry = self._dests[dest]
@@ -198,6 +217,29 @@ class InstallManifest(object):
         """
         self._add_entry(dest, (self.OPTIONAL_EXISTS,))
 
+    def add_pattern_symlink(self, base, pattern, dest):
+        """Add a pattern match that results in symlinks being created.
+
+        A ``FileFinder`` will be created with its base set to ``base``
+        and ``FileFinder.find()`` will be called with ``pattern`` to discover
+        source files. Each source file will be symlinked under ``dest``.
+
+        Filenames under ``dest`` are constructed by taking the path fragment
+        after ``base`` and concatenating it with ``dest``. e.g.
+
+           /foo/bar.h -> /foo/bar.h
+        """
+        self._add_entry(mozpath.join(base, pattern, dest),
+            (self.PATTERN_SYMLINK, base, pattern, dest))
+
+    def add_pattern_copy(self, base, pattern, dest):
+        """Add a pattern match that results in copies.
+
+        See ``add_pattern_symlink()`` for usage.
+        """
+        self._add_entry(mozpath.join(base, pattern, dest),
+            (self.PATTERN_COPY, base, pattern, dest))
+
     def _add_entry(self, dest, entry):
         if dest in self._dests:
             raise ValueError('Item already in manifest: %s' % dest)
@@ -231,5 +273,21 @@ class InstallManifest(object):
                 registry.add(dest, ExistingFile(required=False))
                 continue
 
+            if install_type in (self.PATTERN_SYMLINK, self.PATTERN_COPY):
+                _, base, pattern, dest = entry
+                finder = FileFinder(base, find_executables=False)
+                paths = [f[0] for f in finder.find(pattern)]
+
+                if install_type == self.PATTERN_SYMLINK:
+                    cls = AbsoluteSymlinkFile
+                else:
+                    cls = File
+
+                for path in paths:
+                    source = mozpath.join(base, path)
+                    registry.add(mozpath.join(dest, path), cls(source))
+
+                continue
+
             raise Exception('Unknown install type defined in manifest: %d' %
                 install_type)
diff --git a/python/mozbuild/mozpack/test/test_manifests.py b/python/mozbuild/mozpack/test/test_manifests.py
index 667972d3f085..87e3add84dcd 100644
--- a/python/mozbuild/mozpack/test/test_manifests.py
+++ b/python/mozbuild/mozpack/test/test_manifests.py
@@ -29,8 +29,10 @@ class TestInstallManifest(TestWithTmpDir):
         m.add_copy('c_source', 'c_dest')
         m.add_required_exists('e_dest')
         m.add_optional_exists('o_dest')
+        m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')
+        m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')
 
-        self.assertEqual(len(m), 4)
+        self.assertEqual(len(m), 6)
         self.assertIn('s_dest', m)
         self.assertIn('c_dest', m)
         self.assertIn('e_dest', m)
@@ -48,12 +50,20 @@ class TestInstallManifest(TestWithTmpDir):
         with self.assertRaises(ValueError):
             m.add_optional_exists('o_dest')
 
+        with self.assertRaises(ValueError):
+            m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest')
+
+        with self.assertRaises(ValueError):
+            m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest')
+
     def _get_test_manifest(self):
         m = InstallManifest()
         m.add_symlink(self.tmppath('s_source'), 's_dest')
         m.add_copy(self.tmppath('c_source'), 'c_dest')
         m.add_required_exists('e_dest')
         m.add_optional_exists('o_dest')
+        m.add_pattern_symlink('ps_base', '*', 'ps_dest')
+        m.add_pattern_copy('pc_base', '**', 'pc_dest')
 
         return m
 
@@ -67,18 +77,12 @@ class TestInstallManifest(TestWithTmpDir):
         with open(p, 'rb') as fh:
             c = fh.read()
 
-        self.assertEqual(c.count('\n'), 5)
+        self.assertEqual(c.count('\n'), 7)
 
         lines = c.splitlines()
-        self.assertEqual(len(lines), 5)
+        self.assertEqual(len(lines), 7)
 
-        self.assertEqual(lines[0], '2')
-        self.assertEqual(lines[1], '2\x1fc_dest\x1f%s' %
-            self.tmppath('c_source'))
-        self.assertEqual(lines[2], '3\x1fe_dest')
-        self.assertEqual(lines[3], '4\x1fo_dest')
-        self.assertEqual(lines[4], '1\x1fs_dest\x1f%s' %
-            self.tmppath('s_source'))
+        self.assertEqual(lines[0], '3')
 
         m2 = InstallManifest(path=p)
         self.assertEqual(m, m2)
@@ -98,8 +102,28 @@ class TestInstallManifest(TestWithTmpDir):
         self.assertEqual(len(r), 4)
         self.assertEqual(r.paths(), ['c_dest', 'e_dest', 'o_dest', 's_dest'])
 
+    def test_pattern_expansion(self):
+        source = self.tmppath('source')
+        os.mkdir(source)
+        os.mkdir('%s/base' % source)
+        os.mkdir('%s/base/foo' % source)
+
+        with open('%s/base/foo/file1' % source, 'a'):
+            pass
+
+        with open('%s/base/foo/file2' % source, 'a'):
+            pass
+
+        m = InstallManifest()
+        m.add_pattern_symlink('%s/base' % source, '**', 'dest')
+
+        c = FileCopier()
+        m.populate_registry(c)
+        self.assertEqual(c.paths(), ['dest/foo/file1', 'dest/foo/file2'])
+
     def test_or(self):
         m1 = self._get_test_manifest()
+        orig_length = len(m1)
         m2 = InstallManifest()
         m2.add_symlink('s_source2', 's_dest2')
         m2.add_copy('c_source2', 'c_dest2')
@@ -107,7 +131,7 @@ class TestInstallManifest(TestWithTmpDir):
         m1 |= m2
 
         self.assertEqual(len(m2), 2)
-        self.assertEqual(len(m1), 6)
+        self.assertEqual(len(m1), orig_length + 2)
 
         self.assertIn('s_dest2', m1)
         self.assertIn('c_dest2', m1)
diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp
index c575545da106..55c3eabba72a 100644
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -51,6 +51,8 @@
 namespace mozilla {
 namespace scache {
 
+MOZ_DEFINE_MALLOC_SIZE_OF(StartupCacheMallocSizeOf)
+
 NS_IMETHODIMP
 StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport,
                              nsISupports* aData)
@@ -71,7 +73,7 @@ StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport,
          "This memory is likely to be swapped out shortly after start-up.");
 
   REPORT("explicit/startup-cache/data", KIND_HEAP,
-         HeapSizeOfIncludingThis(MallocSizeOf),
+         HeapSizeOfIncludingThis(StartupCacheMallocSizeOf),
          "Memory used by the startup cache for things other than the file "
          "mapping.");
 
@@ -123,7 +125,7 @@ bool StartupCache::gShutdownInitiated;
 bool StartupCache::gIgnoreDiskCache;
 enum StartupCache::TelemetrifyAge StartupCache::gPostFlushAgeAction = StartupCache::IGNORE_AGE;
 
-NS_IMPL_ISUPPORTS_INHERITED0(StartupCache, MemoryMultiReporter)
+NS_IMPL_ISUPPORTS1(StartupCache, nsIMemoryReporter)
 
 StartupCache::StartupCache()
   : mArchive(nullptr), mStartupWriteInitiated(false), mWriteThread(nullptr)
diff --git a/startupcache/StartupCache.h b/startupcache/StartupCache.h
index 2574b98e96bb..e9c69e236361 100644
--- a/startupcache/StartupCache.h
+++ b/startupcache/StartupCache.h
@@ -97,14 +97,15 @@ class StartupCacheListener MOZ_FINAL : public nsIObserver
   NS_DECL_NSIOBSERVER
 };
 
-class StartupCache : public mozilla::MemoryMultiReporter
+class StartupCache : public nsIMemoryReporter
 {
 
 friend class StartupCacheListener;
 friend class StartupCacheWrapper;
 
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIMEMORYREPORTER
 
   // StartupCache methods. See above comments for a more detailed description.
 
@@ -130,9 +131,6 @@ public:
   static StartupCache* GetSingleton();
   static void DeleteSingleton();
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData);
-
   // This measures all the heap memory used by the StartupCache, i.e. it
   // excludes the mapping.
   size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp
index 7f1c4b4df01c..2c8b9244cb93 100644
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -200,11 +200,11 @@ Service::CollectReports(nsIHandleReportCallback *aHandleReport,
 ////////////////////////////////////////////////////////////////////////////////
 //// Service
 
-NS_IMPL_ISUPPORTS_INHERITED2(
+NS_IMPL_ISUPPORTS3(
   Service,
-  MemoryMultiReporter,
   mozIStorageService,
-  nsIObserver
+  nsIObserver,
+  nsIMemoryReporter
 )
 
 Service *Service::gService = nullptr;
@@ -386,8 +386,8 @@ namespace {
 // how much memory SQLite is using.  And we can compare that against what
 // SQLite reports it is using.
 
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(SqliteMallocSizeOfOnAlloc)
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(SqliteMallocSizeOfOnFree)
+MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc)
+MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree)
 
 #endif
 
diff --git a/storage/src/mozStorageService.h b/storage/src/mozStorageService.h
index 6e68148f698d..fa87576428f2 100644
--- a/storage/src/mozStorageService.h
+++ b/storage/src/mozStorageService.h
@@ -25,9 +25,9 @@ namespace mozilla {
 namespace storage {
 
 class Connection;
-class Service : public MemoryMultiReporter
-              , public mozIStorageService
+class Service : public mozIStorageService
               , public nsIObserver
+              , public nsIMemoryReporter
 {
 public:
   /**
@@ -57,9 +57,7 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZISTORAGESERVICE
   NS_DECL_NSIOBSERVER
-
-  NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
-                            nsISupports *aData);
+  NS_DECL_NSIMEMORYREPORTER
 
   /**
    * Obtains an already AddRefed pointer to XPConnect.  This is used by
diff --git a/testing/marionette/client/marionette/emulator.py b/testing/marionette/client/marionette/emulator.py
index fac31fe5bdda..c63b043cb4de 100644
--- a/testing/marionette/client/marionette/emulator.py
+++ b/testing/marionette/client/marionette/emulator.py
@@ -345,6 +345,26 @@ waitFor(
         # setup DNS fix for networking
         self._run_adb(['shell', 'setprop', 'net.dns1', '10.0.2.3'])
 
+    def wait_for_homescreen(self, marionette):
+        print 'waiting for homescreen...'
+
+        created_session = False
+        if not marionette.session:
+            marionette.start_session()
+            created_session = True
+
+        marionette.set_context(marionette.CONTEXT_CONTENT)
+        marionette.execute_async_script("""
+window.addEventListener('mozbrowserloadend', function loaded(aEvent) {
+  if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) {
+    window.removeEventListener('mozbrowserloadend', loaded);
+    marionetteScriptFinished();
+  }
+});""", script_timeout=60000)
+        print '...done'
+        if created_session:
+            marionette.delete_session()
+
     def setup(self, marionette, gecko_path=None, busybox=None):
         if busybox:
             self.install_busybox(busybox)
diff --git a/testing/marionette/client/marionette/marionette_test.py b/testing/marionette/client/marionette/marionette_test.py
index 28278ecc1799..aa8d06dacc73 100644
--- a/testing/marionette/client/marionette/marionette_test.py
+++ b/testing/marionette/client/marionette/marionette_test.py
@@ -354,16 +354,17 @@ class MarionetteJSTestCase(CommonTestCase):
     inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
     match_re = re.compile(r"test_(.*)\.js$")
 
-    def __init__(self, marionette_weakref, methodName='runTest', jsFile=None):
+    def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs):
         assert(jsFile)
         self.jsFile = jsFile
         self._marionette_weakref = marionette_weakref
         self.marionette = None
+        self.oop = kwargs.pop('oop')
         CommonTestCase.__init__(self, methodName)
 
     @classmethod
     def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
-        suite.addTest(cls(weakref.ref(marionette), jsFile=filepath))
+        suite.addTest(cls(weakref.ref(marionette), jsFile=filepath, **kwargs))
 
     def runTest(self):
         if self.marionette.session is None:
@@ -395,6 +396,47 @@ class MarionetteJSTestCase(CommonTestCase):
                 head = open(os.path.join(os.path.dirname(self.jsFile), head_js), 'r')
                 js = head.read() + js;
 
+        if self.oop:
+            print 'running oop'
+            result = self.marionette.execute_async_script("""
+let setReq = navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
+setReq.onsuccess = function() {
+    let appsReq = navigator.mozApps.mgmt.getAll();
+    appsReq.onsuccess = function() {
+        let apps = appsReq.result;
+        for (let i = 0; i < apps.length; i++) {
+            let app = apps[i];
+            if (app.manifest.name === 'Test Container') {
+                app.launch();
+                window.addEventListener('apploadtime', function apploadtime(){
+                    window.removeEventListener('apploadtime', apploadtime);
+                    marionetteScriptFinished(true);
+                });
+                return;
+            }
+        }
+        marionetteScriptFinished(false);
+    }
+    appsReq.onerror = function() {
+        marionetteScriptFinished(false);
+    }
+}
+setReq.onerror = function() {
+    marionetteScriptFinished(false);
+}""", script_timeout=60000)
+            self.assertTrue(result)
+
+            self.marionette.switch_to_frame(
+                self.marionette.find_element(
+                    'css selector',
+                    'iframe[src*="app://test-container.gaiamobile.org/index.html"]'
+                ))
+
+            main_process = self.marionette.execute_script("""
+                return SpecialPowers.isMainProcess();
+                """)
+            self.assertFalse(main_process)
+
         context = self.context_re.search(js)
         if context:
             context = context.group(3)
diff --git a/testing/marionette/client/marionette/runtests.py b/testing/marionette/client/marionette/runtests.py
index 9b4cd6258760..0d32d5a42fa3 100644
--- a/testing/marionette/client/marionette/runtests.py
+++ b/testing/marionette/client/marionette/runtests.py
@@ -575,6 +575,22 @@ class MarionetteTestRunner(object):
 
         if not self.marionette:
             self.start_marionette()
+            if self.emulator:
+                self.marionette.emulator.wait_for_homescreen(self.marionette)
+
+        testargs = {}
+        if self.type is not None:
+            testtypes = self.type.replace('+', ' +').replace('-', ' -').split()
+            for atype in testtypes:
+                if atype.startswith('+'):
+                    testargs.update({ atype[1:]: 'true' })
+                elif atype.startswith('-'):
+                    testargs.update({ atype[1:]: 'false' })
+                else:
+                    testargs.update({ atype: 'true' })
+        oop = testargs.get('oop', False)
+        if isinstance(oop, basestring):
+            oop = False if oop == 'false' else 'true'
 
         filepath = os.path.abspath(test)
 
@@ -597,22 +613,12 @@ class MarionetteTestRunner(object):
         suite = unittest.TestSuite()
 
         if file_ext == '.ini':
-            testargs = {}
-            if self.type is not None:
-                testtypes = self.type.replace('+', ' +').replace('-', ' -').split()
-                for atype in testtypes:
-                    if atype.startswith('+'):
-                        testargs.update({ atype[1:]: 'true' })
-                    elif atype.startswith('-'):
-                        testargs.update({ atype[1:]: 'false' })
-                    else:
-                        testargs.update({ atype: 'true' })
-
             manifest = TestManifest()
             manifest.read(filepath)
 
-            all_tests = manifest.active_tests(disabled=False)
-            manifest_tests = manifest.active_tests(disabled=False,
+            all_tests = manifest.active_tests(exists=False, disabled=False)
+            manifest_tests = manifest.active_tests(exists=False,
+                                                   disabled=False,
                                                    device=self.device,
                                                    app=self.appName)
             skip_tests = list(set([x['path'] for x in all_tests]) -
@@ -633,9 +639,10 @@ class MarionetteTestRunner(object):
                     return
             return
 
-        self.logger.info('TEST-START %s' % os.path.basename(test))
+            self.logger.info('TEST-START %s' % os.path.basename(test))
 
         self.test_kwargs['expected'] = expected
+        self.test_kwargs['oop'] = oop
         for handler in self.test_handlers:
             if handler.match(os.path.basename(test)):
                 handler.add_tests_to_suite(mod_name,
diff --git a/testing/specialpowers/content/MockPermissionPrompt.jsm b/testing/specialpowers/content/MockPermissionPrompt.jsm
index e07f8e0021a8..7c18e9efcf11 100644
--- a/testing/specialpowers/content/MockPermissionPrompt.jsm
+++ b/testing/specialpowers/content/MockPermissionPrompt.jsm
@@ -34,18 +34,9 @@ this.MockPermissionPrompt = {
   init: function() {
     this.reset();
     if (!registrar.isCIDRegistered(newClassID)) {
-      try {
-        oldClassID = registrar.contractIDToCID(CONTRACT_ID);
-        oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
-      } catch (ex) {
-        oldClassID = "";
-        oldFactory = null;
-        dump("TEST-INFO | can't get permission prompt registered component, " +
-            "assuming there is none");
-      }
-      if (oldFactory) {
-        registrar.unregisterFactory(oldClassID, oldFactory);
-      }
+      oldClassID = registrar.contractIDToCID(CONTRACT_ID);
+      oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
+      registrar.unregisterFactory(oldClassID, oldFactory);
       registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
     }
   },
@@ -70,17 +61,14 @@ MockPermissionPromptInstance.prototype = {
 
   prompt: function(request) {
 
-    let perms = request.types.QueryInterface(Ci.nsIArray);
-    for (let idx = 0; idx < perms.length; idx++) {
-      let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
-      if (Services.perms.testExactPermissionFromPrincipal(
-           request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
-        request.cancel();
-        return;
-      }
+    this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal,
+                                                                        request.type);
+    if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) {
+      request.allow();
+    }
+    else {
+      request.cancel();
     }
-
-    request.allow();
   }
 };
 
diff --git a/testing/xpcshell/xpcshell_b2g.ini b/testing/xpcshell/xpcshell_b2g.ini
index f9e0c2eb7da2..60948a7f0039 100644
--- a/testing/xpcshell/xpcshell_b2g.ini
+++ b/testing/xpcshell/xpcshell_b2g.ini
@@ -4,6 +4,7 @@
 
 [include:dom/apps/tests/unit/xpcshell.ini]
 [include:dom/mobilemessage/tests/xpcshell.ini]
+[include:dom/network/tests/unit_stats/xpcshell.ini]
 [include:dom/system/gonk/tests/xpcshell.ini]
 [include:toolkit/devtools/apps/tests/unit/xpcshell.ini]
 [include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
index d1e26bb493b4..1ff60fa277af 100644
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -171,11 +171,7 @@
                 domSize, styleSize, otherSize, totalSize,
                 jsMilliseconds, nonJSMilliseconds);
 
-  let e = mgr.enumerateReporters();
-  while (e.hasMoreElements()) {
-    let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
-    r.collectReports(handleReport, null);
-  }
+  mgr.getReportsForThisProcess(handleReport, null);
 
   function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
   {
diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
index 02608edb1222..cdb19238f48a 100644
--- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
+++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
@@ -40,11 +40,7 @@
   // them.  It shouldn't crash.
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
-  e = mgr.enumerateReporters();
-  while (e.hasMoreElements()) {
-    let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
-    r.collectReports(function(){}, null);
-  }
+  mgr.getReportsForThisProcess(function(){}, null);
 
   // If we haven't crashed, we've passed, but the test harness requires that
   // we explicitly check something.
diff --git a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
index b309b3f18de9..9dcad2264937 100644
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
@@ -250,7 +250,7 @@ nsUrlClassifierPrefixSet::Contains(uint32_t aPrefix, bool* aFound)
   return NS_OK;
 }
 
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(UrlClassifierMallocSizeOf)
+MOZ_DEFINE_MALLOC_SIZE_OF(UrlClassifierMallocSizeOf)
 
 NS_IMETHODIMP
 nsUrlClassifierPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport,
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 1a3d22d30c4a..5965d633312c 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -121,7 +121,8 @@
 #endif
 
 #ifdef NECKO_PROTOCOL_rtsp
-#include "nsISystemMessagesInternal.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIMessageManager.h"
 #endif
 
 using namespace mozilla;
@@ -605,41 +606,29 @@ private:
 } // anonymous namespace
 
 /**
- * This function broadcasts a system message in order to launch video app for
- * rtsp scheme. This is Gonk-specific behavior.
+ * This function sends a message. This 'content-handler' message is handled in
+ * b2g/chrome/content/shell.js where it starts an activity request that will
+ * open the video app.
  */
 void nsExternalHelperAppService::LaunchVideoAppForRtsp(nsIURI* aURI)
 {
-  NS_NAMED_LITERAL_STRING(msgType, "rtsp-open-video");
+  bool rv;
 
-  // Make the url is rtsp.
-  bool isRTSP = false;
-  aURI->SchemeIs("rtsp", &isRTSP);
-  NS_ASSERTION(isRTSP, "Not rtsp protocol! Something goes wrong here");
+  // Get a system principal.
+  nsCOMPtr securityManager =
+    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(securityManager);
 
-  // Construct jsval for system message.
+  nsCOMPtr principal;
+  securityManager->GetSystemPrincipal(getter_AddRefs(principal));
+  NS_ENSURE_TRUE_VOID(principal);
+
+  // Construct the message in jsVal format.
   AutoSafeJSContext cx;
   AutoClearPendingException helper(cx);
   JS::Rooted msgObj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
   NS_ENSURE_TRUE_VOID(msgObj);
   JS::Rooted jsVal(cx);
-  bool rv;
-
-  // Set the "url" and "title" properties of the message.
-  // In the case of RTSP streaming, the title is the same as the url.
-  {
-    nsAutoCString spec;
-    aURI->GetAsciiSpec(spec);
-    JSString *urlStr = JS_NewStringCopyN(cx, spec.get(), spec.Length());
-    NS_ENSURE_TRUE_VOID(urlStr);
-    jsVal.setString(urlStr);
-
-    rv = JS_SetProperty(cx, msgObj, "url", jsVal);
-    NS_ENSURE_TRUE_VOID(rv);
-
-    rv = JS_SetProperty(cx, msgObj, "title", jsVal);
-    NS_ENSURE_TRUE_VOID(rv);
-  }
 
   // Set the "type" property of the message. This is a fake MIME type.
   {
@@ -647,18 +636,29 @@ void nsExternalHelperAppService::LaunchVideoAppForRtsp(nsIURI* aURI)
     JSString *typeStr = JS_NewStringCopyN(cx, mimeType.get(), mimeType.Length());
     NS_ENSURE_TRUE_VOID(typeStr);
     jsVal.setString(typeStr);
+    rv = JS_SetProperty(cx, msgObj, "type", jsVal);
+    NS_ENSURE_TRUE_VOID(rv);
+  }
+  // Set the "url" and "title" properties of the message.
+  // They are the same in the case of RTSP streaming.
+  {
+    nsAutoCString spec;
+    aURI->GetSpec(spec);
+    JSString *urlStr = JS_NewStringCopyN(cx, spec.get(), spec.Length());
+    NS_ENSURE_TRUE_VOID(urlStr);
+    jsVal.setString(urlStr);
+    rv = JS_SetProperty(cx, msgObj, "url", jsVal);
+    NS_ENSURE_TRUE_VOID(rv);
+    rv = JS_SetProperty(cx, msgObj, "title", jsVal);
   }
-  rv = JS_SetProperty(cx, msgObj, "type", jsVal);
-  NS_ENSURE_TRUE_VOID(rv);
-
-  // Broadcast system message.
-  nsCOMPtr systemMessenger =
-    do_GetService("@mozilla.org/system-message-internal;1");
-  NS_ENSURE_TRUE_VOID(systemMessenger);
   jsVal.setObject(*msgObj);
-  systemMessenger->BroadcastMessage(msgType, jsVal, JS::UndefinedValue());
 
-  return;
+  // Send the message.
+  nsCOMPtr cpmm =
+    do_GetService("@mozilla.org/childprocessmessagemanager;1");
+  NS_ENSURE_TRUE_VOID(cpmm);
+  cpmm->SendAsyncMessage(NS_LITERAL_STRING("content-handler"),
+    jsVal, JSVAL_NULL, principal, cx, 2);
 }
 #endif
 
diff --git a/webapprt/ContentPermission.js b/webapprt/ContentPermission.js
index 463522304fc7..c0cf06993b99 100644
--- a/webapprt/ContentPermission.js
+++ b/webapprt/ContentPermission.js
@@ -30,25 +30,17 @@ ContentPermission.prototype = {
   },
 
   prompt: function(request) {
-    // Only allow exactly one permission rquest here.
-    let types = request.types.QueryInterface(Ci.nsIArray);
-    if (types.length != 1) {
-      request.cancel();
-      return;
-    }
-    let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
-
     // Reuse any remembered permission preferences
     let result =
       Services.perms.testExactPermissionFromPrincipal(request.principal,
-                                                      perm.type);
+                                                      request.type);
 
     // We used to use the name "geo" for the geolocation permission, now we're
     // using "geolocation".  We need to check both to support existing
     // installations.
     if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
          result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
-        perm.type == "geolocation") {
+        request.type == "geolocation") {
       let geoResult = Services.perms.testExactPermission(request.principal.URI,
                                                          "geo");
       // We override the result only if the "geo" permission was allowed or
@@ -64,7 +56,7 @@ ContentPermission.prototype = {
       return;
     } else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
                (result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
-                UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
+                UNKNOWN_FAIL.indexOf(request.type) >= 0)) {
       request.cancel();
       return;
     }
@@ -79,16 +71,16 @@ ContentPermission.prototype = {
     let remember = {value: false};
     let choice = Services.prompt.confirmEx(
       chromeWin,
-      bundle.formatStringFromName(perm.type + ".title", [name], 1),
-      bundle.GetStringFromName(perm.type + ".description"),
+      bundle.formatStringFromName(request.type + ".title", [name], 1),
+      bundle.GetStringFromName(request.type + ".description"),
       // Set both buttons to strings with the cancel button being default
       Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
         Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
         Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
-      bundle.GetStringFromName(perm.type + ".allow"),
-      bundle.GetStringFromName(perm.type + ".deny"),
+      bundle.GetStringFromName(request.type + ".allow"),
+      bundle.GetStringFromName(request.type + ".deny"),
       null,
-      bundle.GetStringFromName(perm.type + ".remember"),
+      bundle.GetStringFromName(request.type + ".remember"),
       remember);
 
     let action = Ci.nsIPermissionManager.ALLOW_ACTION;
@@ -98,10 +90,10 @@ ContentPermission.prototype = {
 
     if (remember.value) {
       // Persist the choice if the user wants to remember
-      Services.perms.addFromPrincipal(request.principal, perm.type, action);
+      Services.perms.addFromPrincipal(request.principal, request.type, action);
     } else {
       // Otherwise allow the permission for the current session
-      Services.perms.addFromPrincipal(request.principal, perm.type, action,
+      Services.perms.addFromPrincipal(request.principal, request.type, action,
                                       Ci.nsIPermissionManager.EXPIRE_SESSION);
     }
 
diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp
index ae33928593f4..5ff850c3814d 100644
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2328,7 +2328,7 @@ nsWindow::GetIMEUpdatePreference()
 }
 
 void
-nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect)
+nsWindow::DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect)
 {
     JNIEnv *env = GetJNIForThread();
     NS_ABORT_IF_FALSE(env, "No JNI environment at DrawWindowUnderlay()!");
@@ -2362,7 +2362,7 @@ nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect)
 }
 
 void
-nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
+nsWindow::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect)
 {
     PROFILER_LABEL("nsWindow", "DrawWindowOverlay");
     JNIEnv *env = GetJNIForThread();
@@ -2430,11 +2430,7 @@ float
 nsWindow::ComputeRenderIntegrity()
 {
     if (sCompositorParent) {
-        mozilla::layers::LayerManagerComposite* manager =
-          static_cast(sCompositorParent->GetLayerManager());
-        if (manager) {
-            return manager->ComputeRenderIntegrity();
-        }
+        return sCompositorParent->ComputeRenderIntegrity();
     }
 
     return 1.f;
diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h
index 1a84c79bf445..28ce60a3bff2 100644
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -153,8 +153,8 @@ public:
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
 
     virtual bool NeedsPaint();
-    virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect);
-    virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
+    virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect);
+    virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect);
 
     virtual mozilla::layers::CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight) MOZ_OVERRIDE;
 
diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h
index 3d19739a7510..d3a355ed6775 100644
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -549,9 +549,9 @@ public:
   virtual gfxASurface* GetThebesSurface();
   virtual void PrepareWindowEffects() MOZ_OVERRIDE;
   virtual void CleanupWindowEffects() MOZ_OVERRIDE;
-  virtual bool PreRender(LayerManager* aManager) MOZ_OVERRIDE;
-  virtual void PostRender(LayerManager* aManager) MOZ_OVERRIDE;
-  virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) MOZ_OVERRIDE;
+  virtual bool PreRender(LayerManagerComposite* aManager) MOZ_OVERRIDE;
+  virtual void PostRender(LayerManagerComposite* aManager) MOZ_OVERRIDE;
+  virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) MOZ_OVERRIDE;
 
   virtual void UpdateThemeGeometries(const nsTArray& aThemeGeometries);
 
diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm
index bb949b80a79c..73e172bf4104 100644
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -63,7 +63,6 @@
 #include "GLContext.h"
 #include "GLUploadHelpers.h"
 #include "mozilla/layers/GLManager.h"
-#include "mozilla/layers/CompositorCocoaWidgetHelper.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/BasicCompositor.h"
 #include "gfxUtils.h"
@@ -2047,7 +2046,7 @@ nsChildView::CleanupWindowEffects()
 }
 
 bool
-nsChildView::PreRender(LayerManager* aManager)
+nsChildView::PreRender(LayerManagerComposite* aManager)
 {
   nsAutoPtr manager(GLManager::CreateGLManager(aManager));
   if (!manager) {
@@ -2069,7 +2068,7 @@ nsChildView::PreRender(LayerManager* aManager)
 }
 
 void
-nsChildView::PostRender(LayerManager* aManager)
+nsChildView::PostRender(LayerManagerComposite* aManager)
 {
   nsAutoPtr manager(GLManager::CreateGLManager(aManager));
   if (!manager) {
@@ -2081,7 +2080,7 @@ nsChildView::PostRender(LayerManager* aManager)
 }
 
 void
-nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
+nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect)
 {
   nsAutoPtr manager(GLManager::CreateGLManager(aManager));
   if (manager) {
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
index 78e07e4b3728..3f7585228cee 100644
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -13,10 +13,8 @@
 #include 
 #include 
 
-#ifdef MOZ_PANGO
 #include 
 #include 
-#endif
 
 #include 
 #include "gfxPlatformGtk.h"
@@ -700,7 +698,6 @@ nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
     return res;
 }
 
-#ifdef MOZ_PANGO
 static void
 GetSystemFontInfo(GtkWidget *aWidget,
                   nsString *aFontName,
@@ -804,24 +801,6 @@ GetSystemFontInfo(LookAndFeel::FontID aID,
     }
 }
 
-#else // not MOZ_PANGO
-
-static void
-GetSystemFontInfo(LookAndFeel::FontID /*unused */,
-                  nsString *aFontName,
-                  gfxFontStyle *aFontStyle)
-{
-    /* FIXME: DFB FT2 Hardcoding the system font info for now. */
-    aFontStyle->style      = NS_FONT_STYLE_NORMAL;
-    aFontStyle->weight     = NS_FONT_WEIGHT_NORMAL;
-    aFontStyle->size       = 40/3;
-    aFontStyle->stretch    = NS_FONT_STRETCH_NORMAL;
-    aFontStyle->systemFont = true;
-    aFontName->AssignLiteral("\"Sans\"");
-}
-
-#endif // not MOZ_PANGO
-
 bool
 nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
                            gfxFontStyle& aFontStyle,
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
index 80050c3286e0..498d5647e79d 100644
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -41,6 +41,7 @@ namespace layers {
 class Composer2D;
 class CompositorChild;
 class LayerManager;
+class LayerManagerComposite;
 class PLayerTransactionChild;
 }
 namespace gfx {
@@ -96,8 +97,8 @@ typedef void* nsNativeWidget;
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0xa1f684e6, 0x2ae1, 0x4513, \
-  { 0xb6, 0x89, 0xf4, 0xd4, 0xfe, 0x9d, 0x2c, 0xdb } }
+{ 0x746cb189, 0x9793, 0x4e53, \
+  { 0x89, 0x47, 0x78, 0x56, 0xb6, 0xcd, 0x9f, 0x71 } }
 
 /*
  * Window shadow styles
@@ -464,6 +465,7 @@ class nsIWidget : public nsISupports {
     typedef mozilla::layers::Composer2D Composer2D;
     typedef mozilla::layers::CompositorChild CompositorChild;
     typedef mozilla::layers::LayerManager LayerManager;
+    typedef mozilla::layers::LayerManagerComposite LayerManagerComposite;
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
     typedef mozilla::widget::NotificationToIME NotificationToIME;
@@ -1216,38 +1218,36 @@ class nsIWidget : public nsISupports {
     virtual void CleanupWindowEffects() = 0;
 
     /**
-     * Called before rendering using OpenGL. Returns false when the widget is
+     * Called before rendering using OMTC. Returns false when the widget is
      * not ready to be rendered (for example while the window is closed).
      *
      * Always called from the compositing thread, which may be the main-thread if
      * OMTC is not enabled.
      */
-    virtual bool PreRender(LayerManager* aManager) = 0;
+    virtual bool PreRender(LayerManagerComposite* aManager) = 0;
 
     /**
-     * Called after rendering using OpenGL. Not called when rendering was
+     * Called after rendering using OMTC. Not called when rendering was
      * cancelled by a negative return value from PreRender.
      *
      * Always called from the compositing thread, which may be the main-thread if
      * OMTC is not enabled.
      */
-    virtual void PostRender(LayerManager* aManager) = 0;
+    virtual void PostRender(LayerManagerComposite* aManager) = 0;
 
     /**
      * Called before the LayerManager draws the layer tree.
      *
-     * Always called from the compositing thread, which may be the main-thread if
-     * OMTC is not enabled.
+     * Always called from the compositing thread.
      */
-    virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) = 0;
+    virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) = 0;
 
     /**
      * Called after the LayerManager draws the layer tree
      *
-     * Always called from the compositing thread, which may be the main-thread if
-     * OMTC is not enabled.
+     * Always called from the compositing thread.
      */
-    virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) = 0;
+    virtual void DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) = 0;
 
     /**
      * Return a DrawTarget for the window which can be composited into.
diff --git a/widget/windows/winrt/APZController.cpp b/widget/windows/winrt/APZController.cpp
index 4003d462985b..3abb8d480023 100644
--- a/widget/windows/winrt/APZController.cpp
+++ b/widget/windows/winrt/APZController.cpp
@@ -334,7 +334,7 @@ class TransformedEndEvent : public nsRunnable
 };
 
 void
-APZController::NotifyTransformBegin()
+APZController::NotifyTransformBegin(const ScrollableLayerGuid& aGuid)
 {
   if (NS_IsMainThread()) {
     MetroUtils::FireObserver("apzc-transform-begin", L"");
@@ -345,7 +345,7 @@ APZController::NotifyTransformBegin()
 }
 
 void
-APZController::NotifyTransformEnd()
+APZController::NotifyTransformEnd(const ScrollableLayerGuid& aGuid)
 {
   if (NS_IsMainThread()) {
     MetroUtils::FireObserver("apzc-transform-end", L"");
diff --git a/widget/windows/winrt/APZController.h b/widget/windows/winrt/APZController.h
index cff4bc322370..9cca9bb2e7d8 100644
--- a/widget/windows/winrt/APZController.h
+++ b/widget/windows/winrt/APZController.h
@@ -37,8 +37,8 @@ public:
   virtual void HandleLongTap(const mozilla::CSSIntPoint& aPoint, int32_t aModifiers);
   virtual void SendAsyncScrollDOMEvent(bool aIsRoot, const mozilla::CSSRect &aContentRect, const mozilla::CSSSize &aScrollableSize);
   virtual void PostDelayedTask(Task* aTask, int aDelayMs);
-  virtual void NotifyTransformBegin();
-  virtual void NotifyTransformEnd();
+  virtual void NotifyTransformBegin(const ScrollableLayerGuid& aGuid);
+  virtual void NotifyTransformEnd(const ScrollableLayerGuid& aGuid);
   
   void SetWidgetListener(nsIWidgetListener* aWidgetListener);
   void UpdateScrollOffset(const mozilla::layers::ScrollableLayerGuid& aScrollLayerId, CSSIntPoint& aScrollOffset);
diff --git a/widget/xpwidgets/nsBaseWidget.h b/widget/xpwidgets/nsBaseWidget.h
index 7e66bc3a0733..283ecf67b795 100644
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -136,10 +136,10 @@ public:
   virtual void            CreateCompositor(int aWidth, int aHeight);
   virtual void            PrepareWindowEffects() {}
   virtual void            CleanupWindowEffects() {}
-  virtual bool            PreRender(LayerManager* aManager) { return true; }
-  virtual void            PostRender(LayerManager* aManager) {}
-  virtual void            DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {}
-  virtual void            DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {}
+  virtual bool            PreRender(LayerManagerComposite* aManager) { return true; }
+  virtual void            PostRender(LayerManagerComposite* aManager) {}
+  virtual void            DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) {}
+  virtual void            DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) {}
   virtual mozilla::TemporaryRef StartRemoteDrawing();
   virtual void            EndRemoteDrawing() { };
   virtual void            CleanupRemoteDrawing() { };
diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp
index 16d9a02684d7..b6984319c052 100644
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -1071,9 +1071,10 @@ enum ccType {
 
 typedef js::SliceBudget SliceBudget;
 
-class nsCycleCollector : public MemoryMultiReporter
+class nsCycleCollector : public nsIMemoryReporter
 {
     NS_DECL_ISUPPORTS
+    NS_DECL_NSIMEMORYREPORTER
 
     bool mActivelyCollecting;
     // mScanInProgress should be false when we're collecting white objects.
@@ -1138,9 +1139,6 @@ public:
                  nsICycleCollectorListener *aManualListener);
     void Shutdown();
 
-    NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData);
-
     void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                              size_t *aObjectSize,
                              size_t *aGraphNodesSize,
@@ -1166,7 +1164,7 @@ private:
     void CleanupAfterCollection();
 };
 
-NS_IMPL_ISUPPORTS_INHERITED0(nsCycleCollector, MemoryMultiReporter)
+NS_IMPL_ISUPPORTS1(nsCycleCollector, nsIMemoryReporter)
 
 /**
  * GraphWalker is templatized over a Visitor class that must provide
@@ -2596,13 +2594,15 @@ nsCycleCollector::CollectWhite()
 // Memory reporting
 ////////////////////////
 
+MOZ_DEFINE_MALLOC_SIZE_OF(CycleCollectorMallocSizeOf)
+
 NS_IMETHODIMP
 nsCycleCollector::CollectReports(nsIHandleReportCallback* aHandleReport,
                                  nsISupports* aData)
 {
     size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize,
            purpleBufferSize;
-    SizeOfIncludingThis(MallocSizeOf,
+    SizeOfIncludingThis(CycleCollectorMallocSizeOf,
                         &objectSize,
                         &graphNodesSize, &graphEdgesSize,
                         &weakMapsSize,
diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl
index a3acdc6a6315..f8fe7b88a175 100644
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -178,7 +178,7 @@ interface nsIFinishReportingCallback : nsISupports
   void callback(in nsISupports data);
 };
 
-[scriptable, builtinclass, uuid(9245d89e-6523-45f9-bc15-a69789e33cbb)]
+[scriptable, builtinclass, uuid(2b61d644-1520-420a-8f52-d06e615c1ff6)]
 interface nsIMemoryReporterManager : nsISupports
 {
   /*
@@ -187,10 +187,9 @@ interface nsIMemoryReporterManager : nsISupports
   void init();
 
   /*
-   * Register the given nsIMemoryReporter.  After a reporter is registered,
-   * it will be available via enumerateReporters().  The Manager service
-   * will hold a strong reference to the given reporter, and will be
-   * responsible for freeing the reporter at shutdown.
+   * Register the given nsIMemoryReporter.  The Manager service will hold a
+   * strong reference to the given reporter, and will be responsible for freeing
+   * the reporter at shutdown.
    */
   void registerStrongReporter(in nsIMemoryReporter reporter);
 
@@ -214,14 +213,6 @@ interface nsIMemoryReporterManager : nsISupports
   void unblockRegistrationAndRestoreOriginalReporters();
   void registerStrongReporterEvenIfBlocked(in nsIMemoryReporter aReporter);
 
-  /*
-   * Return an enumerator of nsIMemoryReporters that are currently registered
-   * in the current process.  WARNING: this does not do anything with child
-   * processes.  Use getReports() if you want measurements from child
-   * processes.
-   */
-  nsISimpleEnumerator enumerateReporters();
-
   /*
    * Get memory reports for the current process and all child processes.
    * |handleReport| is called for each report, and |finishReporting| is called
@@ -240,6 +231,13 @@ interface nsIMemoryReporterManager : nsISupports
                   in nsIFinishReportingCallback finishReporting,
                   in nsISupports finishReportingData);
 
+  /*
+   * Get memory reports in the current process only.  |handleReport| is called
+   * for each report.
+   */
+  void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport,
+                                in nsISupports handleReportData);
+
   /*
    * The memory reporter manager, for the most part, treats reporters
    * registered with it as a black box.  However, there are some
@@ -248,8 +246,9 @@ interface nsIMemoryReporterManager : nsISupports
    * interesting that we want external code (e.g. telemetry) to be able to rely
    * on them.
    *
-   * Note that these are not reporters and so enumerateReporters() does not
-   * look at them.  However, they can be embedded in a reporter.
+   * Note that these are not reporters and so getReports() and
+   * getReportsForThisProcess() do not look at them.  However, distinguished
+   * amounts can be embedded in a reporter.
    *
    * Access to these attributes can fail.  In particular, some of them are not
    * available on all platforms.
@@ -441,7 +440,7 @@ namespace dmd {
 // This runs all the memory reporters in the current process but does nothing
 // with the results;  i.e. it does the minimal amount of work possible for DMD
 // to do its thing.  It does nothing with child processes.
-void RunReporters();
+void RunReportersForThisProcess();
 }
 }
 
@@ -466,13 +465,12 @@ void RunReporters();
 // will always be zero on some obscure platforms.
 //
 // You might be wondering why we have a macro that creates multiple functions
-// that differ only in their name, instead of a single
-// MemoryReporterMallocSizeOf function.  It's mostly to help with DMD
-// integration, though it sometimes also helps with debugging and temporary ad
-// hoc profiling.  The function name chosen doesn't matter greatly, but it's
-// best to make it similar to the path used by the relevant memory
-// reporter(s).
-#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(fn)                              \
+// that differ only in their name, instead of a single MallocSizeOf function.
+// It's mostly to help with DMD integration, though it sometimes also helps
+// with debugging and temporary ad hoc profiling.  The function name chosen
+// doesn't matter greatly, but it's best to make it similar to the path used by
+// the relevant memory reporter(s).
+#define MOZ_DEFINE_MALLOC_SIZE_OF(fn)                                         \
   static size_t fn(const void* aPtr)                                          \
   {                                                                           \
       MOZ_REPORT(aPtr);                                                       \
@@ -484,13 +482,13 @@ void RunReporters();
 // unreport them as soon as they are freed.  Such allocators are used in cases
 // where we have third-party code that we cannot modify.  The two functions
 // must always be used in tandem.
-#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(fn)                     \
+#define MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(fn)                                \
   static size_t fn(const void* aPtr)                                          \
   {                                                                           \
       MOZ_REPORT_ON_ALLOC(aPtr);                                              \
       return moz_malloc_size_of(aPtr);                                        \
   }
-#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(fn)                      \
+#define MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(fn)                                 \
   static size_t fn(const void* aPtr)                                          \
   {                                                                           \
       return moz_malloc_size_of(aPtr);                                        \
@@ -555,9 +553,9 @@ protected:
     return 0;
   }
 
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(MallocSizeOfOnAlloc)
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(MallocSizeOfOnFree)
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
+  MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
+  MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
 
   const nsCString mPath;
   const int32_t   mKind;
@@ -565,36 +563,6 @@ protected:
   const nsCString mDescription;
 };
 
-// The following base class reduces the amount of boilerplate code required for
-// memory multi-reporters.  You just need to provide the following.
-// - The constant value: name.  It is an argument to the MemoryMultiReporter
-//   constructor.  The name of each multi-reporter should be unique.
-// - A public CollectReports() method.  It can use the MallocSizeOf method if
-//   necessary.  (There is also MallocSizeOfOn{Alloc,Free}, which can be
-//   useful.)
-//
-// The class name of subclasses should match the name, with "Reporter" at
-// the end.  For example:
-// - name == "foo" --> FooMultiReporter
-//
-class MemoryMultiReporter : public nsIMemoryReporter
-{
-public:
-  MemoryMultiReporter() {}
-
-  virtual ~MemoryMultiReporter() {}
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-
-  NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
-                            nsISupports* aClosure) = 0;
-
-protected:
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(MallocSizeOfOnAlloc)
-  NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(MallocSizeOfOnFree)
-};
-
 } // namespace mozilla
 
 %}
diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp
index d857374ed396..1313d5cd06ba 100644
--- a/xpcom/base/nsMemoryInfoDumper.cpp
+++ b/xpcom/base/nsMemoryInfoDumper.cpp
@@ -613,88 +613,82 @@ namespace mozilla {
       return rv; \
   } while (0)
 
-static nsresult
-DumpReport(nsIGZFileWriter *aWriter, bool aIsFirst,
-  const nsACString &aProcess, const nsACString &aPath, int32_t aKind,
-  int32_t aUnits, int64_t aAmount, const nsACString &aDescription)
-{
-  DUMP(aWriter, aIsFirst ? "[" : ",");
-
-  nsAutoCString process;
-  if (aProcess.IsEmpty()) {
-    // If the process is empty, the report originated with the process doing
-    // the dumping.  In that case, generate the process identifier, which is of
-    // the form "$PROCESS_NAME (pid $PID)", or just "(pid $PID)" if we don't
-    // have a process name.  If we're the main process, we let $PROCESS_NAME be
-    // "Main Process".
-    if (XRE_GetProcessType() == GeckoProcessType_Default) {
-      // We're the main process.
-      process.AssignLiteral("Main Process");
-    } else if (ContentChild *cc = ContentChild::GetSingleton()) {
-      // Try to get the process name from ContentChild.
-      cc->GetProcessName(process);
-    }
-    ContentChild::AppendProcessId(process);
-
-  } else {
-    // Otherwise, the report originated with another process and already has a
-    // process name.  Just use that.
-    process = aProcess;
-  }
-
-  DUMP(aWriter, "\n    {\"process\": \"");
-  DUMP(aWriter, process);
-
-  DUMP(aWriter, "\", \"path\": \"");
-  nsCString path(aPath);
-  path.ReplaceSubstring("\\", "\\\\");    /*  --> \\ */
-  path.ReplaceSubstring("\"", "\\\"");    // " --> \"
-  DUMP(aWriter, path);
-
-  DUMP(aWriter, "\", \"kind\": ");
-  DUMP(aWriter, nsPrintfCString("%d", aKind));
-
-  DUMP(aWriter, ", \"units\": ");
-  DUMP(aWriter, nsPrintfCString("%d", aUnits));
-
-  DUMP(aWriter, ", \"amount\": ");
-  DUMP(aWriter, nsPrintfCString("%lld", aAmount));
-
-  nsCString description(aDescription);
-  description.ReplaceSubstring("\\", "\\\\");    /*  --> \\ */
-  description.ReplaceSubstring("\"", "\\\"");    // " --> \"
-  description.ReplaceSubstring("\n", "\\n");     //  --> \n
-  DUMP(aWriter, ", \"description\": \"");
-  DUMP(aWriter, description);
-  DUMP(aWriter, "\"}");
-
-  return NS_OK;
-}
-
 class DumpReportCallback MOZ_FINAL : public nsIHandleReportCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
-  DumpReportCallback() : mIsFirst(true) {}
+  DumpReportCallback(nsGZFileWriter* aWriter)
+    : mIsFirst(true)
+    , mWriter(aWriter)
+  {}
 
   NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
       int32_t aKind, int32_t aUnits, int64_t aAmount,
       const nsACString &aDescription,
       nsISupports *aData)
   {
-    nsCOMPtr writer = do_QueryInterface(aData);
-    if (NS_WARN_IF(!writer))
-      return NS_ERROR_FAILURE;
+    if (mIsFirst) {
+      DUMP(mWriter, "[");
+      mIsFirst = false;
+    } else {
+      DUMP(mWriter, ",");
+    }
 
-    nsresult rv = DumpReport(writer, mIsFirst, aProcess, aPath, aKind, aUnits,
-                             aAmount, aDescription);
-    mIsFirst = false;
-    return rv;
+    nsAutoCString process;
+    if (aProcess.IsEmpty()) {
+      // If the process is empty, the report originated with the process doing
+      // the dumping.  In that case, generate the process identifier, which is of
+      // the form "$PROCESS_NAME (pid $PID)", or just "(pid $PID)" if we don't
+      // have a process name.  If we're the main process, we let $PROCESS_NAME be
+      // "Main Process".
+      if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        // We're the main process.
+        process.AssignLiteral("Main Process");
+      } else if (ContentChild *cc = ContentChild::GetSingleton()) {
+        // Try to get the process name from ContentChild.
+        cc->GetProcessName(process);
+      }
+      ContentChild::AppendProcessId(process);
+
+    } else {
+      // Otherwise, the report originated with another process and already has a
+      // process name.  Just use that.
+      process = aProcess;
+    }
+
+    DUMP(mWriter, "\n    {\"process\": \"");
+    DUMP(mWriter, process);
+
+    DUMP(mWriter, "\", \"path\": \"");
+    nsCString path(aPath);
+    path.ReplaceSubstring("\\", "\\\\");    /*  --> \\ */
+    path.ReplaceSubstring("\"", "\\\"");    // " --> \"
+    DUMP(mWriter, path);
+
+    DUMP(mWriter, "\", \"kind\": ");
+    DUMP(mWriter, nsPrintfCString("%d", aKind));
+
+    DUMP(mWriter, ", \"units\": ");
+    DUMP(mWriter, nsPrintfCString("%d", aUnits));
+
+    DUMP(mWriter, ", \"amount\": ");
+    DUMP(mWriter, nsPrintfCString("%lld", aAmount));
+
+    nsCString description(aDescription);
+    description.ReplaceSubstring("\\", "\\\\");    /*  --> \\ */
+    description.ReplaceSubstring("\"", "\\\"");    // " --> \"
+    description.ReplaceSubstring("\n", "\\n");     //  --> \n
+    DUMP(mWriter, ", \"description\": \"");
+    DUMP(mWriter, description);
+    DUMP(mWriter, "\"}");
+
+    return NS_OK;
   }
 
 private:
   bool mIsFirst;
+  nsRefPtr mWriter;
 };
 
 NS_IMPL_ISUPPORTS1(DumpReportCallback, nsIHandleReportCallback)
@@ -831,23 +825,16 @@ DumpFooter(nsIGZFileWriter* aWriter)
 }
 
 static nsresult
-DumpProcessMemoryReportsToGZFileWriter(nsIGZFileWriter* aWriter)
+DumpProcessMemoryReportsToGZFileWriter(nsGZFileWriter* aWriter)
 {
   nsresult rv = DumpHeader(aWriter);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Process reporters.
-  bool more;
-  nsCOMPtr e;
   nsCOMPtr mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
-  mgr->EnumerateReporters(getter_AddRefs(e));
-  nsRefPtr dumpReport = new DumpReportCallback();
-  while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
-    nsCOMPtr r;
-    e->GetNext(getter_AddRefs(r));
-    r->CollectReports(dumpReport, aWriter);
-  }
+  nsRefPtr dumpReport = new DumpReportCallback(aWriter);
+  mgr->GetReportsForThisProcess(dumpReport, nullptr);
 
   return DumpFooter(aWriter);
 }
@@ -884,7 +871,8 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
   rv = nsMemoryInfoDumper::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
                                         mrFilename,
                                         getter_AddRefs(mrTmpFile));
-  if (NS_WARN_IF(NS_FAILED(rv)))
    return rv;
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
 
   nsRefPtr mrWriter = new nsGZFileWriter();
   rv = mrWriter->Init(mrTmpFile);
@@ -1103,12 +1091,12 @@ nsMemoryInfoDumper::DumpMemoryReportsToNamedFile(
     return rv;
 
   // Process reports and finish up.
-  nsRefPtr dumpReport = new DumpReportCallback();
+  nsRefPtr dumpReport = new DumpReportCallback(mrWriter);
   nsRefPtr finishReporting =
     new FinishReportingCallback(aFinishDumping, aFinishDumpingData);
   nsCOMPtr mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
-  return mgr->GetReports(dumpReport, mrWriter, finishReporting, mrWriter);
+  return mgr->GetReports(dumpReport, nullptr, finishReporting, mrWriter);
 }
 
 #undef DUMP
diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp
index 6f22093ed9d5..d22a0bddc4c1 100644
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -796,10 +796,10 @@ private:
 namespace mozilla {
 namespace dmd {
 
-class DMDReporter MOZ_FINAL : public MemoryMultiReporter
+class DMDReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
-  DMDReporter() {}
+  NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData)
@@ -842,6 +842,8 @@ public:
   }
 };
 
+NS_IMPL_ISUPPORTS1(DMDReporter, nsIMemoryReporter)
+
 } // namespace dmd
 } // namespace mozilla
 
@@ -1003,23 +1005,6 @@ nsMemoryReporterManager::~nsMemoryReporterManager()
     NS_ASSERTION(!mSavedWeakReporters, "failed to restore weak reporters");
 }
 
-NS_IMETHODIMP
-nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
-{
-    // Memory reporters are not necessarily threadsafe, so this function must
-    // be called from the main thread.
-    if (!NS_IsMainThread()) {
-        MOZ_CRASH();
-    }
-
-    mozilla::MutexAutoLock autoLock(mMutex);
-
-    nsRefPtr enumerator =
-        new ReporterEnumerator(mStrongReporters, mWeakReporters);
-    enumerator.forget(aResult);
-    return NS_OK;
-}
-
 //#define DEBUG_CHILD_PROCESS_MEMORY_REPORTING 1
 
 #ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING
@@ -1108,19 +1093,38 @@ nsMemoryReporterManager::GetReports(
     }
 
     // Get reports for this process.
+    GetReportsForThisProcess(aHandleReport, aHandleReportData);
+
+    // If there are no child processes, we can finish up immediately.
+    return (mNumChildProcesses == 0)
+         ? aFinishReporting->Callback(aFinishReportingData)
+         : NS_OK;
+}
+
+NS_IMETHODIMP
+nsMemoryReporterManager::GetReportsForThisProcess(
+    nsIHandleReportCallback* aHandleReport,
+    nsISupports* aHandleReportData)
+{
+    // Memory reporters are not necessarily threadsafe, so this function must
+    // be called from the main thread.
+    if (!NS_IsMainThread()) {
+        MOZ_CRASH();
+    }
+
+    nsRefPtr e;
+    {
+        mozilla::MutexAutoLock autoLock(mMutex);
+        e = new ReporterEnumerator(mStrongReporters, mWeakReporters);
+    }
     bool more;
-    nsCOMPtr e;
-    EnumerateReporters(getter_AddRefs(e));
     while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
         nsCOMPtr r;
         e->GetNext(getter_AddRefs(r));
         r->CollectReports(aHandleReport, aHandleReportData);
     }
 
-    // If there are no child processes, we can finish up immediately.
-    return (mNumChildProcesses == 0)
-         ? aFinishReporting->Callback(aFinishReportingData)
-         : NS_OK;
+    return NS_OK;
 }
 
 // This function has no return value.  If something goes wrong, there's no
@@ -1370,6 +1374,7 @@ public:
     Int64Wrapper() : mValue(0) { }
     int64_t mValue;
 };
+
 NS_IMPL_ISUPPORTS0(Int64Wrapper)
 
 class ExplicitCallback MOZ_FINAL : public nsIHandleReportCallback
@@ -1399,6 +1404,7 @@ public:
         return NS_OK;
     }
 };
+
 NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIHandleReportCallback)
 
 NS_IMETHODIMP
@@ -1421,13 +1427,7 @@ nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
     nsRefPtr handleReport = new ExplicitCallback();
     nsRefPtr wrappedExplicitSize = new Int64Wrapper();
 
-    nsCOMPtr e;
-    EnumerateReporters(getter_AddRefs(e));
-    while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
-        nsCOMPtr r;
-        e->GetNext(getter_AddRefs(r));
-        r->CollectReports(handleReport, wrappedExplicitSize);
-    }
+    GetReportsForThisProcess(handleReport, wrappedExplicitSize);
 
     *aAmount = wrappedExplicitSize->mValue;
 
@@ -1737,7 +1737,6 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow,
 // thread-safe just to be safe.  Memory reporters are created and destroyed
 // infrequently enough that the performance cost should be negligible.
 NS_IMPL_ISUPPORTS1(MemoryUniReporter, nsIMemoryReporter)
-NS_IMPL_ISUPPORTS1(MemoryMultiReporter, nsIMemoryReporter)
 
 namespace mozilla {
 
@@ -1853,27 +1852,18 @@ public:
         return NS_OK;
     }
 };
-NS_IMPL_ISUPPORTS1(
-  DoNothingCallback
-, nsIHandleReportCallback
-)
+
+NS_IMPL_ISUPPORTS1(DoNothingCallback, nsIHandleReportCallback)
 
 void
-RunReporters()
+RunReportersForThisProcess()
 {
     nsCOMPtr mgr =
         do_GetService("@mozilla.org/memory-reporter-manager;1");
 
     nsRefPtr doNothing = new DoNothingCallback();
 
-    bool more;
-    nsCOMPtr e;
-    mgr->EnumerateReporters(getter_AddRefs(e));
-    while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
-        nsCOMPtr r;
-        e->GetNext(getter_AddRefs(r));
-        r->CollectReports(doNothing, nullptr);
-    }
+    mgr->GetReportsForThisProcess(doNothing, nullptr);
 }
 
 } // namespace dmd
diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp
index 506ccb028efc..320a6f4c8719 100644
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -168,11 +168,11 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
 // nsObserverService Implementation
 
 
-NS_IMPL_ISUPPORTS_INHERITED2(
+NS_IMPL_ISUPPORTS3(
     nsObserverService,
-    MemoryMultiReporter,
     nsIObserverService,
-    nsObserverService)
+    nsObserverService,
+    nsIMemoryReporter)
 
 nsObserverService::nsObserverService() :
     mShuttingDown(false)
diff --git a/xpcom/ds/nsObserverService.h b/xpcom/ds/nsObserverService.h
index eba9283d98bc..ebdfcc040d79 100644
--- a/xpcom/ds/nsObserverService.h
+++ b/xpcom/ds/nsObserverService.h
@@ -19,8 +19,8 @@
 class nsIMemoryReporter;
 
 class nsObserverService MOZ_FINAL
-  : public mozilla::MemoryMultiReporter
-  , public nsIObserverService
+  : public nsIObserverService
+  , public nsIMemoryReporter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID)
@@ -29,7 +29,8 @@ public:
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVERSERVICE
-  
+  NS_DECL_NSIMEMORYREPORTER
+
   void Shutdown();
 
   static nsresult
@@ -39,9 +40,6 @@ public:
   // collector will not traverse them.
   NS_IMETHOD UnmarkGrayStrongObservers();
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
-                            nsISupports *aData);
-
 private:
   ~nsObserverService(void);
   void RegisterReporter();
diff --git a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
index 913be5d22d1f..0c2b3911d99e 100644
--- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
+++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
@@ -10,6 +10,7 @@
 
 #include "mozilla/FileUtils.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/StaticPtr.h"
 
 #include "xptiprivate.h"
 #include "nsDependentString.h"
@@ -26,10 +27,7 @@ NS_IMPL_ISUPPORTS_INHERITED1(
   MemoryUniReporter,
   nsIInterfaceInfoManager)
 
-static XPTInterfaceInfoManager* gInterfaceInfoManager = nullptr;
-#ifdef DEBUG
-static int gCallCount = 0;
-#endif
+static StaticRefPtr gInterfaceInfoManager;
 
 size_t
 XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
@@ -62,7 +60,6 @@ XPTInterfaceInfoManager::GetSingleton()
 {
     if (!gInterfaceInfoManager) {
         gInterfaceInfoManager = new XPTInterfaceInfoManager();
-        NS_ADDREF(gInterfaceInfoManager);
         gInterfaceInfoManager->InitMemoryReporter();
     }
     return gInterfaceInfoManager;
@@ -71,7 +68,7 @@ XPTInterfaceInfoManager::GetSingleton()
 void
 XPTInterfaceInfoManager::FreeInterfaceInfoManager()
 {
-    NS_IF_RELEASE(gInterfaceInfoManager);
+    gInterfaceInfoManager = nullptr;
 }
 
 XPTInterfaceInfoManager::XPTInterfaceInfoManager()
@@ -88,11 +85,6 @@ XPTInterfaceInfoManager::~XPTInterfaceInfoManager()
     mWorkingSet.InvalidateInterfaceInfos();
 
     UnregisterWeakMemoryReporter(this);
-
-    gInterfaceInfoManager = nullptr;
-#ifdef DEBUG
-    gCallCount = 0;
-#endif
 }
 
 void