diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 99027513b91..f0cfaeff2be 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -148,6 +148,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebChannel", XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent", "resource:///modules/ReaderParent.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher", + "resource://gre/modules/AddonWatcher.jsm"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -587,6 +590,76 @@ BrowserGlue.prototype = { this._distributionCustomizer.applyPrefDefaults(); }, + _notifySlowAddon: function BG_notifySlowAddon(addonId) { + let addonCallback = function(addon) { + if (!addon) { + Cu.reportError("couldn't look up addon: " + addonId); + return; + } + let win = RecentWindow.getMostRecentBrowserWindow(); + + if (!win) { + return; + } + + let brandBundle = win.document.getElementById("bundle_brand"); + let brandShortName = brandBundle.getString("brandShortName"); + let message = win.gNavigatorBundle.getFormattedString("addonwatch.slow", [addon.name, brandShortName]); + let notificationBox = win.document.getElementById("global-notificationbox"); + let notificationId = 'addon-slow:' + addonId; + let notification = notificationBox.getNotificationWithValue(notificationId); + if(notification) { + notification.label = message; + } else { + let buttons = [ + { + label: win.gNavigatorBundle.getFormattedString("addonwatch.disable.label", [addon.name]), + accessKey: win.gNavigatorBundle.getString("addonwatch.disable.accesskey"), + callback: function() { + addon.userDisabled = true; + if (addon.pendingOperations != addon.PENDING_NONE) { + let restartMessage = win.gNavigatorBundle.getFormattedString("addonwatch.restart.message", [addon.name, brandShortName]); + let restartButton = [ + { + label: win.gNavigatorBundle.getFormattedString("addonwatch.restart.label", [brandShortName]), + accessKey: win.gNavigatorBundle.getString("addonwatch.restart.accesskey"), + callback: function() { + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(appStartup.eForceQuit | appStartup.eRestart); + } + } + ]; + const priority = notificationBox.PRIORITY_WARNING_MEDIUM; + notificationBox.appendNotification(restartMessage, "restart-" + addonId, "", + priority, restartButton); + } + } + }, + { + label: win.gNavigatorBundle.getString("addonwatch.ignoreSession.label"), + accessKey: win.gNavigatorBundle.getString("addonwatch.ignoreSession.accesskey"), + callback: function() { + AddonWatcher.ignoreAddonForSession(addonId); + } + }, + { + label: win.gNavigatorBundle.getString("addonwatch.ignorePerm.label"), + accessKey: win.gNavigatorBundle.getString("addonwatch.ignorePerm.accesskey"), + callback: function() { + AddonWatcher.ignoreAddonPermanently(addonId); + } + }, + ]; + + const priority = notificationBox.PRIORITY_WARNING_MEDIUM; + notificationBox.appendNotification(message, notificationId, "", + priority, buttons); + } + }; + AddonManager.getAddonByID(addonId, addonCallback); + }, + // runs on startup, before the first command line handler is invoked // (i.e. before the first window is opened) _finalUIStartup: function BG__finalUIStartup() { @@ -642,6 +715,8 @@ BrowserGlue.prototype = { #endif Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); + + AddonWatcher.init(this._notifySlowAddon); }, _checkForOldBuildUpdates: function () { @@ -907,6 +982,7 @@ BrowserGlue.prototype = { #endif webrtcUI.uninit(); FormValidationHandler.uninit(); + AddonWatcher.uninit(); }, _initServiceDiscovery: function () { diff --git a/browser/devtools/debugger/test/browser.ini b/browser/devtools/debugger/test/browser.ini index eeba980ae5b..6527fc51604 100644 --- a/browser/devtools/debugger/test/browser.ini +++ b/browser/devtools/debugger/test/browser.ini @@ -103,71 +103,45 @@ support-files = [browser_dbg_aaa_run_first_leaktest.js] skip-if = e10s && debug [browser_dbg_addonactor.js] -skip-if = e10s && debug [browser_dbg_addon-sources.js] -skip-if = e10s && debug [browser_dbg_addon-modules.js] skip-if = e10s # TODO [browser_dbg_addon-modules-unpacked.js] skip-if = e10s # TODO [browser_dbg_addon-panels.js] -skip-if = e10s && debug [browser_dbg_addon-console.js] skip-if = e10s && debug || os == 'win' # bug 1005274 [browser_dbg_auto-pretty-print-01.js] -skip-if = e10s && debug [browser_dbg_auto-pretty-print-02.js] -skip-if = e10s && debug [browser_dbg_bfcache.js] skip-if = e10s || true # bug 1113935 [browser_dbg_blackboxing-01.js] -skip-if = e10s && debug [browser_dbg_blackboxing-02.js] -skip-if = e10s && debug [browser_dbg_blackboxing-03.js] -skip-if = e10s && debug [browser_dbg_blackboxing-04.js] -skip-if = e10s && debug [browser_dbg_blackboxing-05.js] -skip-if = e10s && debug [browser_dbg_blackboxing-06.js] -skip-if = e10s && debug [browser_dbg_breadcrumbs-access.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-01.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-02.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-03.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-04.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-05.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-06.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-07.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-08.js] -skip-if = e10s && debug [browser_dbg_break-on-dom-event-01.js] skip-if = e10s || os == "mac" || e10s # Bug 895426 [browser_dbg_break-on-dom-event-02.js] skip-if = e10s # TODO [browser_dbg_breakpoints-actual-location.js] -skip-if = e10s && debug [browser_dbg_breakpoints-actual-location2.js] -skip-if = e10s && debug [browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js] skip-if = e10s # Bug 1093535 [browser_dbg_breakpoints-button-01.js] -skip-if = e10s && debug [browser_dbg_breakpoints-button-02.js] -skip-if = e10s && debug [browser_dbg_breakpoints-contextmenu-add.js] -skip-if = e10s && debug [browser_dbg_breakpoints-contextmenu.js] -skip-if = e10s && debug [browser_dbg_breakpoints-disabled-reload.js] skip-if = e10s # Bug 1093535 [browser_dbg_breakpoints-editor.js] diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index f3cde721cee..d940a3e9daf 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -40,6 +40,17 @@ addonDownloadRestart=Restart Download;Restart Downloads addonDownloadRestart.accessKey=R addonDownloadCancelTooltip=Cancel +addonwatch.slow=%1$S might be making %2$S run slowly +addonwatch.disable.label=Disable %S +addonwatch.disable.accesskey=D +addonwatch.ignoreSession.label=Ignore for now +addonwatch.ignoreSession.accesskey=I +addonwatch.ignorePerm.label=Ignore permanently +addonwatch.ignorePerm.accesskey=p +addonwatch.restart.message=To disable %1$S you must restart %2$S +addonwatch.restart.label=Restart %S +addonwatch.restart.accesskey=R + # LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart): # Semicolon-separated list of plural forms. See: # http://developer.mozilla.org/en/docs/Localization_and_Plurals diff --git a/build/Makefile.in b/build/Makefile.in index 2a178476742..2339e362439 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -42,16 +42,11 @@ endif endif -# Put a useful .gdbinit in the bin directory, to be picked up automatically -# by GDB when we debug executables there. # NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir. -GDBINIT_FILES := $(topsrcdir)/.gdbinit -GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit -GDBINIT_DEST = $(FINAL_TARGET) - # needs to be absolute to be distinct from $(topsrcdir)/.gdbinit +GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH)) -INSTALL_TARGETS += GDBINIT GDBINIT_OBJDIR +INSTALL_TARGETS += GDBINIT_OBJDIR # Put a .lldbinit in the bin directory and the objdir, to be picked up # automatically by LLDB when we debug executables using either of those two @@ -66,13 +61,6 @@ LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET) INSTALL_TARGETS += LLDBINIT_FINAL_TARGET -ifeq (1_1,$(MOZ_ASAN)_$(CLANG_CL)) -# Install the clang-cl runtime library for ASAN next to the binaries we produce. -CLANG_RT_ASAN_FILES := $(MOZ_CLANG_RT_ASAN_LIB_PATH) -CLANG_RT_ASAN_DEST = $(FINAL_TARGET) -INSTALL_TARGETS += CLANG_RT_ASAN -endif - ifdef MOZTTDIR # Install the Firefox OS fonts. include $(MOZTTDIR)/fonts.mk @@ -81,6 +69,19 @@ MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/ INSTALL_TARGETS += MOZTT endif +ifdef MOZ_VALGRIND +_VALGRIND_DIR = $(DEPTH)/_valgrind +GARBAGE_DIRS += $(_VALGRIND_DIR) + +_VALGRIND_FILES = \ + $(topsrcdir)/build/valgrind/cross-architecture.sup \ + $(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \ + $(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \ + $(NULL) +_VALGRIND_DEST = $(_VALGRIND_DIR) +INSTALL_TARGETS += _VALGRIND +endif + include $(topsrcdir)/config/rules.mk TARGET_DEPTH = .. @@ -99,41 +100,6 @@ endif libs:: automation.py -ifdef MOZ_VALGRIND -_VALGRIND_DIR = $(DEPTH)/_valgrind -GARBAGE_DIRS += $(_VALGRIND_DIR) - -_VALGRIND_FILES = \ - $(topsrcdir)/build/valgrind/cross-architecture.sup \ - $(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \ - $(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \ - $(NULL) - -libs:: $(_VALGRIND_FILES) - $(INSTALL) $^ $(_VALGRIND_DIR) -endif - -ifneq (,$(ENABLE_TESTS)$(MOZ_DMD)) -libs:: $(topsrcdir)/tools/rb/fix_stack_using_bpsyms.py - $(INSTALL) $< $(DIST)/bin - -ifeq ($(OS_ARCH),Darwin) -libs:: $(topsrcdir)/tools/rb/fix_macosx_stack.py - $(INSTALL) $< $(DIST)/bin -endif - -ifeq ($(OS_ARCH),Linux) -libs:: $(topsrcdir)/tools/rb/fix_linux_stack.py - $(INSTALL) $< $(DIST)/bin -endif -endif # ENABLE_TESTS or MOZ_DMD - ifdef ENABLE_TESTS GARBAGE += $(srcdir)/automationutils.pyc endif # ENABLE_TESTS - -ifdef MOZ_DMD -libs:: $(topsrcdir)/memory/replace/dmd/dmd.py - $(INSTALL) $< $(DIST)/bin -endif - diff --git a/build/automationutils.py b/build/automationutils.py index 7ffe3c845ce..c9f67eaaf11 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -445,7 +445,7 @@ class ShutdownLeaks(object): self.leakedWindows = {} self.leakedDocShells = set() self.currentTest = None - self.seenShutdown = False + self.seenShutdown = set() def log(self, message): if message['action'] == 'log': @@ -454,8 +454,9 @@ class ShutdownLeaks(object): self._logWindow(line) elif line[2:10] == "DOCSHELL": self._logDocShell(line) - elif line.startswith("TEST-START | Shutdown"): - self.seenShutdown = True + elif line.startswith("Completed ShutdownLeaks collections in process"): + pid = int(line.split()[-1]) + self.seenShutdown.add(pid) elif message['action'] == 'test_start': fileName = message['test'].replace("chrome://mochitests/content/browser/", "") self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()} @@ -499,7 +500,7 @@ class ShutdownLeaks(object): windows.add(key) else: windows.discard(key) - elif self.seenShutdown and not created: + elif int(pid) in self.seenShutdown and not created: self.leakedWindows[key] = self._parseValue(line, "url") def _logDocShell(self, line): @@ -520,7 +521,7 @@ class ShutdownLeaks(object): docShells.add(key) else: docShells.discard(key) - elif self.seenShutdown and not created: + elif int(pid) in self.seenShutdown and not created: self.leakedDocShells.add(key) def _parseValue(self, line, name): diff --git a/build/moz.build b/build/moz.build index 74728007c54..d30a35c1a05 100644 --- a/build/moz.build +++ b/build/moz.build @@ -48,3 +48,22 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser': PYTHON_UNIT_TESTS += [ 'compare-mozconfig/compare-mozconfigs-wrapper.py', ] + +if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']: + tools_dir = TOPSRCDIR + '/tools/rb/' + FINAL_TARGET_FILES += [tools_dir + 'fix_stack_using_bpsyms.py'] + if CONFIG['OS_ARCH'] == 'Darwin': + FINAL_TARGET_FILES += [tools_dir + 'fix_macosx_stack.py'] + if CONFIG['OS_ARCH'] == 'Linux': + FINAL_TARGET_FILES += [tools_dir + 'fix_linux_stack.py'] + +if CONFIG['MOZ_DMD']: + FINAL_TARGET_FILES += [TOPSRCDIR + '/memory/replace/dmd/dmd.py'] + +# Put a useful .gdbinit in the bin directory, to be picked up automatically +# by GDB when we debug executables there. +FINAL_TARGET_FILES += [TOPSRCDIR + '/.gdbinit'] + +# Install the clang-cl runtime library for ASAN next to the binaries we produce. +if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']: + FINAL_TARGET_FILES += [CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']] diff --git a/caps/moz.build b/caps/moz.build index abee4c002db..26fa9634a59 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -17,6 +17,7 @@ XPIDL_MODULE = 'caps' EXPORTS += [ 'nsJSPrincipals.h', 'nsNullPrincipal.h', + 'nsNullPrincipalURI.h', ] UNIFIED_SOURCES += [ @@ -36,6 +37,8 @@ LOCAL_INCLUDES += [ '/js/xpconnect/src', ] +include('/ipc/chromium/chromium-config.mozbuild') + FINAL_LIBRARY = 'xul' FAIL_ON_WARNINGS = True diff --git a/caps/nsNullPrincipal.cpp b/caps/nsNullPrincipal.cpp index ab1b58dae3c..158b31fd33c 100644 --- a/caps/nsNullPrincipal.cpp +++ b/caps/nsNullPrincipal.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 sts=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/. */ @@ -86,6 +87,24 @@ nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser) mAppId = aAppId; mInMozBrowser = aInMozBrowser; + nsCString str; + nsresult rv = GenerateNullPrincipalURI(str); + NS_ENSURE_SUCCESS(rv, rv); + + mURI = new nsNullPrincipalURI(str); + + return NS_OK; +} + +void +nsNullPrincipal::GetScriptLocation(nsACString &aStr) +{ + mURI->GetSpec(aStr); +} + +nsresult +nsNullPrincipal::GenerateNullPrincipalURI(nsACString &aStr) +{ // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant. nsresult rv; nsCOMPtr uuidgen = @@ -104,28 +123,19 @@ nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser) // Use an nsCString so we only do the allocation once here and then share // with nsJSPrincipals - nsCString str; - str.SetCapacity(prefixLen + suffixLen); + aStr.SetCapacity(prefixLen + suffixLen); - str.Append(NS_NULLPRINCIPAL_PREFIX); - str.Append(chars); + aStr.Append(NS_NULLPRINCIPAL_PREFIX); + aStr.Append(chars); - if (str.Length() != prefixLen + suffixLen) { + if (aStr.Length() != prefixLen + suffixLen) { NS_WARNING("Out of memory allocating null-principal URI"); return NS_ERROR_OUT_OF_MEMORY; } - mURI = new nsNullPrincipalURI(str); - return NS_OK; } -void -nsNullPrincipal::GetScriptLocation(nsACString &aStr) -{ - mURI->GetSpec(aStr); -} - #ifdef DEBUG void nsNullPrincipal::dumpImpl() { diff --git a/caps/nsNullPrincipal.h b/caps/nsNullPrincipal.h index 09f25d0b8ce..1a6034ce9d5 100644 --- a/caps/nsNullPrincipal.h +++ b/caps/nsNullPrincipal.h @@ -31,7 +31,7 @@ class nsNullPrincipal MOZ_FINAL : public nsJSPrincipals { public: nsNullPrincipal(); - + // Our refcount is managed by nsJSPrincipals. Use this macro to avoid an // extra refcount member. @@ -49,6 +49,8 @@ public: virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE; + static nsresult GenerateNullPrincipalURI(nsACString &aStr); + #ifdef DEBUG virtual void dumpImpl() MOZ_OVERRIDE; #endif diff --git a/caps/nsNullPrincipalURI.cpp b/caps/nsNullPrincipalURI.cpp index 629626de67b..4d7a884cd0e 100644 --- a/caps/nsNullPrincipalURI.cpp +++ b/caps/nsNullPrincipalURI.cpp @@ -9,6 +9,8 @@ #include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/ipc/URIParams.h" + #include "nsNetUtil.h" #include "nsEscape.h" #include "nsCRT.h" @@ -17,6 +19,12 @@ //// nsNullPrincipalURI nsNullPrincipalURI::nsNullPrincipalURI(const nsCString &aSpec) +{ + InitializeFromSpec(aSpec); +} + +void +nsNullPrincipalURI::InitializeFromSpec(const nsCString &aSpec) { int32_t dividerPosition = aSpec.FindChar(':'); NS_ASSERTION(dividerPosition != -1, "Malformed URI!"); @@ -44,6 +52,7 @@ NS_INTERFACE_MAP_BEGIN(nsNullPrincipalURI) else NS_INTERFACE_MAP_ENTRY(nsIURI) NS_INTERFACE_MAP_ENTRY(nsISizeOf) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI) NS_INTERFACE_MAP_END //////////////////////////////////////////////////////////////////////////////// @@ -272,6 +281,31 @@ nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs) return NS_OK; } +//////////////////////////////////////////////////////////////////////////////// +//// nsIIPCSerializableURI + +void +nsNullPrincipalURI::Serialize(mozilla::ipc::URIParams &aParams) +{ + aParams = mozilla::ipc::NullPrincipalURIParams(); +} + +bool +nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams) +{ + if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) { + MOZ_ASSERT_UNREACHABLE("unexpected URIParams type"); + return false; + } + + nsCString str; + nsresult rv = nsNullPrincipal::GenerateNullPrincipalURI(str); + NS_ENSURE_SUCCESS(rv, false); + + InitializeFromSpec(str); + return true; +} + //////////////////////////////////////////////////////////////////////////////// //// nsISizeOf diff --git a/caps/nsNullPrincipalURI.h b/caps/nsNullPrincipalURI.h index 72baf06d79e..d87005324bc 100644 --- a/caps/nsNullPrincipalURI.h +++ b/caps/nsNullPrincipalURI.h @@ -16,6 +16,7 @@ #include "nsAutoPtr.h" #include "nsString.h" #include "mozilla/Attributes.h" +#include "nsIIPCSerializableURI.h" #include "mozilla/MemoryReporting.h" // {51fcd543-3b52-41f7-b91b-6b54102236e6} @@ -25,10 +26,12 @@ class nsNullPrincipalURI MOZ_FINAL : public nsIURI , public nsISizeOf + , public nsIIPCSerializableURI { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIURI + NS_DECL_NSIIPCSERIALIZABLEURI // nsISizeOf virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; @@ -36,9 +39,14 @@ public: explicit nsNullPrincipalURI(const nsCString &aSpec); + // NB: This constructor exists only for deserialization. + nsNullPrincipalURI() { } + private: ~nsNullPrincipalURI() {} + void InitializeFromSpec(const nsCString &aSpec); + nsCString mScheme; nsCString mPath; }; diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 24109b8b9a8..1d2d1c96ea6 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -13,13 +13,11 @@ # Valid fields for all descriptors: # * nativeType - The native type (concrete class or XPCOM interface) that # instances of this interface will unwrap to. If not -# specified, defaults to 'mozilla::dom::InterfaceName' for -# non-worker non-external-or-callback interfaces, to +# specified, defaults to 'nsIDOM' followed by the interface +# name for external interfaces, # 'mozilla::dom::workers::InterfaceName' for worker -# non-external interfaces, to 'nsIDOM' followed by the -# interface name for non-worker external-or-callback -# interfaces, and to 'JSObject' for worker external-or-callback -# interfaces. +# non-callback interfaces, and 'mozilla::dom::InterfaceName' +# for everything else. # * headerFile - The file in which the nativeType is declared (defaults # to an educated guess). # * concrete - Indicates whether there exist JS objects with this interface as @@ -31,6 +29,7 @@ # will not be made available on the main thread. # * notflattened - The native type does not have nsIClassInfo, so when # wrapping it the right IID needs to be passed in. +# Only relevant for callback interfaces. # * register - True if this binding should be registered. Defaults to true. # * binaryNames - Dict for mapping method and attribute names to different # names when calling the native methods (defaults to an empty @@ -606,14 +605,10 @@ DOMInterfaces = { 'headerFile': 'IDBEvents.h', }, -'IID': [ -{ +'IID': { 'nativeType': 'nsIJSID', 'headerFile': 'xpcjsid.h', }, -{ - 'workers': True, -}], 'ImageCapture': { 'binaryNames': { 'videoStreamTrack': 'GetVideoStreamTrack' } @@ -623,14 +618,10 @@ DOMInterfaces = { 'wrapperCache': False, }, -'InputStream': [ -{ +'InputStream': { 'nativeType': 'nsIInputStream', 'notflattened': True }, -{ - 'workers': True, -}], 'InstallEvent': { 'headerFile': 'ServiceWorkerEvents.h', @@ -1484,16 +1475,10 @@ DOMInterfaces = { }, }, -'WindowProxy': [ -{ +'WindowProxy': { 'nativeType': 'nsIDOMWindow', 'concrete': False }, -{ - # We need a worker descriptor for WindowProxy because EventTarget exists in - # workers. But it's an external interface, so it'll just map to JSObject*. - 'workers': True -}], 'WindowRoot': { 'nativeType': 'nsWindowRoot' diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index ca2e8f05660..a9192f7fbdf 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -381,7 +381,7 @@ class CGDOMJSClass(CGThing): classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS" traceHook = "JS_GlobalObjectTraceHook" reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS" - if not self.descriptor.workers: + if self.descriptor.interface.identifier.name == "Window": classExtensionAndObjectOps = fill( """ { @@ -4635,10 +4635,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, descriptor = descriptorProvider.getDescriptor( type.unroll().inner.identifier.name) - if descriptor.nativeType == 'JSObject': - # XXXbz Workers code does this sometimes - assert descriptor.workers - return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription) + assert descriptor.nativeType != 'JSObject' if descriptor.interface.isCallback(): name = descriptor.interface.identifier.name @@ -4715,9 +4712,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, exceptionCode, isCallbackReturnValue, firstCap(sourceDescription))) - elif descriptor.workers: - return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription) else: + # Worker descriptors can't end up here, because all of our + # "external" stuff is not exposed in workers. + assert not descriptor.workers # Either external, or new-binding non-castable. We always have a # holder for these, because we don't actually know whether we have # to addref when unwrapping or not. So we just pass an diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py index 3d89c8cc828..25eb14929ea 100644 --- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -305,10 +305,8 @@ class Descriptor(DescriptorProvider): # Read the desc, and fill in the relevant defaults. ifaceName = self.interface.identifier.name if self.interface.isExternal(): - if self.workers: - nativeTypeDefault = "JSObject" - else: - nativeTypeDefault = "nsIDOM" + ifaceName + assert not self.workers + nativeTypeDefault = "nsIDOM" + ifaceName elif self.interface.isCallback(): nativeTypeDefault = "mozilla::dom::" + ifaceName else: diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 1c22c27092f..549c63e6c3f 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1852,6 +1852,12 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, return ok; } +size_t mozilla::RoundUpToMultipleOf(size_t value, size_t multiple) +{ + size_t overshoot = value + multiple - 1; + return overshoot - (overshoot % multiple); +} + //////////////////////////////////////////////////////////////////////////////// WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl) @@ -1875,6 +1881,7 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround() mWebGL.mColorWriteMask[3]); } } + //////////////////////////////////////////////////////////////////////////////// // XPCOM goop diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 4a8d9ed3538..e1ccceb8fc3 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1092,9 +1092,7 @@ protected: GLenum pname); // Returns x rounded to the next highest multiple of y. - static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, - CheckedUint32 y) - { + static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) { return ((x + y - 1) / y) * y; } @@ -1693,6 +1691,8 @@ private: WebGLContext* mWebGL; }; +size_t RoundUpToMultipleOf(size_t value, size_t multiple); + } // namespace mozilla #endif diff --git a/dom/canvas/WebGLContextFramebufferOperations.cpp b/dom/canvas/WebGLContextFramebufferOperations.cpp index 96e0ea026fb..4cab00836f4 100644 --- a/dom/canvas/WebGLContextFramebufferOperations.cpp +++ b/dom/canvas/WebGLContextFramebufferOperations.cpp @@ -49,8 +49,8 @@ WebGLContext::Clear(GLbitfield mask) mShouldPresent = true; } -static GLclampf -GLClampFloat(GLclampf val) +static GLfloat +GLClampFloat(GLfloat val) { if (val < 0.0) return 0.0; @@ -62,18 +62,28 @@ GLClampFloat(GLclampf val) } void -WebGLContext::ClearColor(GLclampf r, GLclampf g, - GLclampf b, GLclampf a) +WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { if (IsContextLost()) return; MakeContextCurrent(); - mColorClearValue[0] = GLClampFloat(r); - mColorClearValue[1] = GLClampFloat(g); - mColorClearValue[2] = GLClampFloat(b); - mColorClearValue[3] = GLClampFloat(a); + + const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) || + IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)); + if (!supportsFloatColorBuffers) { + r = GLClampFloat(r); + g = GLClampFloat(g); + b = GLClampFloat(b); + a = GLClampFloat(a); + } + gl->fClearColor(r, g, b, a); + + mColorClearValue[0] = r; + mColorClearValue[1] = g; + mColorClearValue[2] = b; + mColorClearValue[3] = a; } void diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 7254d1bfe9a..956963771cb 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1863,6 +1863,84 @@ SetFullAlpha(void* data, GLenum format, GLenum type, size_t width, return false; } +static void +ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment, + GLenum destFormat, GLenum destType, void* destBytes) +{ + if (readFormat == destFormat && readType == destType) { + gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes); + return; + } + + if (readFormat == LOCAL_GL_RGBA && + readType == LOCAL_GL_HALF_FLOAT && + destFormat == LOCAL_GL_RGBA && + destType == LOCAL_GL_FLOAT) + { + size_t readBytesPerPixel = sizeof(uint16_t) * 4; + size_t destBytesPerPixel = sizeof(float) * 4; + + size_t readBytesPerRow = readBytesPerPixel * width; + + size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment); + size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width, + pixelStorePackAlignment); + + size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow; + UniquePtr readBuffer(new uint8_t[bytesNeeded]); + + gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get()); + + size_t channelsPerRow = width * 4; + for (size_t j = 0; j < (size_t)height; j++) { + uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride; + float* dst = (float*)(destBytes) + j*destStride; + + uint16_t* srcEnd = src + channelsPerRow; + while (src != srcEnd) { + *dst = unpackFromFloat16(*src); + + ++src; + ++dst; + } + } + + return; + } + + MOZ_CRASH("bad format/type"); +} + +static bool +IsFormatAndTypeUnpackable(GLenum format, GLenum type) +{ + switch (type) { + case LOCAL_GL_UNSIGNED_BYTE: + case LOCAL_GL_FLOAT: + case LOCAL_GL_HALF_FLOAT: + case LOCAL_GL_HALF_FLOAT_OES: + switch (format) { + case LOCAL_GL_ALPHA: + case LOCAL_GL_RGB: + case LOCAL_GL_RGBA: + return true; + default: + return false; + } + + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: + return format == LOCAL_GL_RGBA; + + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: + return format == LOCAL_GL_RGB; + + default: + return false; + } +} + void WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, @@ -1883,59 +1961,61 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (pixels.IsNull()) return ErrorInvalidValue("readPixels: null destination buffer"); + if (!IsFormatAndTypeUnpackable(format, type)) + return ErrorInvalidEnum("readPixels: Bad format or type."); + const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject(); GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; - uint32_t channels = 0; + int channels = 0; // Check the format param switch (format) { - case LOCAL_GL_ALPHA: - channels = 1; - break; - case LOCAL_GL_RGB: - channels = 3; - break; - case LOCAL_GL_RGBA: - channels = 4; - break; - default: - return ErrorInvalidEnum("readPixels: Bad format"); + case LOCAL_GL_ALPHA: + channels = 1; + break; + case LOCAL_GL_RGB: + channels = 3; + break; + case LOCAL_GL_RGBA: + channels = 4; + break; + default: + MOZ_CRASH("bad `format`"); } - uint32_t bytesPerPixel = 0; - int requiredDataType = 0; // Check the type param - bool isReadTypeValid = false; - bool isReadTypeFloat = false; + int bytesPerPixel; + int requiredDataType; switch (type) { - case LOCAL_GL_UNSIGNED_BYTE: - isReadTypeValid = true; - bytesPerPixel = 1*channels; - requiredDataType = js::Scalar::Uint8; - break; - case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: - case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: - case LOCAL_GL_UNSIGNED_SHORT_5_6_5: - isReadTypeValid = true; - bytesPerPixel = 2; - requiredDataType = js::Scalar::Uint16; - break; - case LOCAL_GL_FLOAT: - if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) || - IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) - { - isReadTypeValid = true; - isReadTypeFloat = true; - bytesPerPixel = 4*channels; - requiredDataType = js::Scalar::Float32; - } - break; + case LOCAL_GL_UNSIGNED_BYTE: + bytesPerPixel = 1*channels; + requiredDataType = js::Scalar::Uint8; + break; + + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: + bytesPerPixel = 2; + requiredDataType = js::Scalar::Uint16; + break; + + case LOCAL_GL_FLOAT: + bytesPerPixel = 4*channels; + requiredDataType = js::Scalar::Float32; + break; + + case LOCAL_GL_HALF_FLOAT: + case LOCAL_GL_HALF_FLOAT_OES: + bytesPerPixel = 2*channels; + requiredDataType = js::Scalar::Uint16; + break; + + default: + MOZ_CRASH("bad `type`"); } - if (!isReadTypeValid) - return ErrorInvalidEnum("readPixels: Bad type", type); const ArrayBufferView& pixbuf = pixels.Value(); int dataType = JS_GetArrayBufferViewType(pixbuf.Obj()); @@ -1988,43 +2068,38 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, isSourceTypeFloat = false; } - if (isReadTypeFloat != isSourceTypeFloat) - return ErrorInvalidOperation("readPixels: Invalid type floatness"); - // Check the format and type params to assure they are an acceptable pair (as per spec) - bool isFormatAndTypeValid = false; + const GLenum mainReadFormat = LOCAL_GL_RGBA; + const GLenum mainReadType = isSourceTypeFloat ? LOCAL_GL_FLOAT + : LOCAL_GL_UNSIGNED_BYTE; + + GLenum auxReadFormat = mainReadFormat; + GLenum auxReadType = mainReadType; // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid // combination for glReadPixels(). if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { - GLenum implType = 0; - GLenum implFormat = 0; - - gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, - reinterpret_cast(&implType)); gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, - reinterpret_cast(&implFormat)); - - if (type == implType && format == implFormat) { - isFormatAndTypeValid = true; - } + reinterpret_cast(&auxReadFormat)); + gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, + reinterpret_cast(&auxReadType)); } - switch (format) { - case LOCAL_GL_RGBA: { - switch (type) { - case LOCAL_GL_UNSIGNED_BYTE: - case LOCAL_GL_FLOAT: - isFormatAndTypeValid = true; - break; - } - break; - } - } - - if (!isFormatAndTypeValid) { + const bool mainMatches = (format == mainReadFormat && type == mainReadType); + const bool auxMatches = (format == auxReadFormat && type == auxReadType); + const bool isValid = mainMatches || auxMatches; + if (!isValid) return ErrorInvalidOperation("readPixels: Invalid format/type pair"); + + GLenum readType = type; + if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) { + if (type == LOCAL_GL_FLOAT && + auxReadFormat == format && + auxReadType == LOCAL_GL_HALF_FLOAT) + { + readType = auxReadType; + } } // Now that the errors are out of the way, on to actually reading @@ -2035,7 +2110,10 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) { // the easy case: we're not reading out-of-range pixels - gl->fReadPixels(x, y, width, height, format, type, data); + + // Effectively: gl->fReadPixels(x, y, width, height, format, type, dest); + ReadPixelsAndConvert(gl, x, y, width, height, format, readType, + mPixelStorePackAlignment, format, type, data); } else { // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL @@ -2084,8 +2162,11 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, if (!subrect_data) return ErrorOutOfMemory("readPixels: subrect_data"); - gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, - format, type, subrect_data.get()); + // Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width, + // subrect_height, format, type, subrect_data.get()); + ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height, + format, readType, mPixelStorePackAlignment, format, type, + subrect_data.get()); // notice that this for loop terminates because we already checked that subrect_height is at most height for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) { @@ -3597,7 +3678,7 @@ mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveInternalFormat) } void -WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { +WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { if (IsContextLost()) return; MakeContextCurrent(); diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index fe7f0783f8c..7ea1cff58ba 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -266,6 +266,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) return JS::NumberValue(uint32_t(i)); } case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: { + if (mBoundReadFramebuffer) { + FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus(); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { + ErrorInvalidOperation("getParameter: Read framebuffer must be" + " complete before querying" + " IMPLEMENTATION_COLOR_READ_TYPE."); + return JS::NullValue(); + } + } + GLint i = 0; if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { gl->fGetIntegerv(pname, &i); @@ -275,6 +285,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) return JS::NumberValue(uint32_t(i)); } case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: { + if (mBoundReadFramebuffer) { + FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus(); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { + ErrorInvalidOperation("getParameter: Read framebuffer must be" + " complete before querying" + " IMPLEMENTATION_COLOR_READ_FORMAT."); + return JS::NullValue(); + } + } + GLint i = 0; if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { gl->fGetIntegerv(pname, &i); diff --git a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp index 51329c37dce..7148ef4290d 100644 --- a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp +++ b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp @@ -26,7 +26,8 @@ WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl) gl::GLContext* gl = webgl->GL(); // ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT. - return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float); + return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) || + gl->IsANGLE(); } IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat) diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index eef55251f2e..35551743423 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -129,6 +129,7 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const MOZ_ASSERT(internalformat != LOCAL_GL_NONE); TexType type = TypeFromInternalFormat(internalformat); return type == LOCAL_GL_FLOAT || + type == LOCAL_GL_HALF_FLOAT_OES || type == LOCAL_GL_HALF_FLOAT; } @@ -803,6 +804,7 @@ WebGLFramebuffer::CheckFramebufferStatus() const // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}. FinalizeAttachments(); + // TODO: This should not be unconditionally GL_FRAMEBUFFER. mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); return mStatus; } diff --git a/dom/canvas/WebGLTexelConversions.h b/dom/canvas/WebGLTexelConversions.h index 813b1e8c0b7..269d405e7a6 100644 --- a/dom/canvas/WebGLTexelConversions.h +++ b/dom/canvas/WebGLTexelConversions.h @@ -105,7 +105,7 @@ unpackFromFloat16(uint16_t v) uint16_t exp = (v >> 10) & 0x001F; uint16_t mantissa = v & 0x03FF; - if (exp) { + if (!exp) { // Handle denormalized numbers // Adapted from: OpenGL ES 2.0 Programming Guide Appx. // Converting Float to Half-Float diff --git a/dom/canvas/test/webgl-mochitest.ini b/dom/canvas/test/webgl-mochitest.ini index 14c35d96e44..1e0a0bf9180 100644 --- a/dom/canvas/test/webgl-mochitest.ini +++ b/dom/canvas/test/webgl-mochitest.ini @@ -22,6 +22,8 @@ skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942 [webgl-mochitest/test_texsubimage_float.html] [webgl-mochitest/test_webgl_available.html] skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests +#[webgl-mochitest/test_webgl_color_buffer_float.html] +# We haven't cleaned up the Try results yet, but let's get this on the books first. [webgl-mochitest/test_webgl_conformance.html] skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests [webgl-mochitest/test_webgl_request_context.html] diff --git a/dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html b/dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html new file mode 100644 index 00000000000..94a75fa9156 --- /dev/null +++ b/dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html @@ -0,0 +1,486 @@ + + + + + + + + + + + + + + + + diff --git a/dom/ipc/tests/mochitest.ini b/dom/ipc/tests/mochitest.ini index 5768900e3d3..dc10ecb1d77 100644 --- a/dom/ipc/tests/mochitest.ini +++ b/dom/ipc/tests/mochitest.ini @@ -4,6 +4,8 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s [test_blob_sliced_from_parent_process.html] # This test is only supposed to run in the main process. skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s +[test_cpow_cookies.html] +skip-if = buildapp == 'b2g' || buildapp == 'mulet' [test_NuwaProcessCreation.html] skip-if = toolkit != 'gonk' [test_NuwaProcessDeadlock.html] diff --git a/dom/ipc/tests/test_cpow_cookies.html b/dom/ipc/tests/test_cpow_cookies.html new file mode 100644 index 00000000000..45f5d65dcb6 --- /dev/null +++ b/dom/ipc/tests/test_cpow_cookies.html @@ -0,0 +1,89 @@ + + + + Test for recursive CPOW-getting-cookie bug + + + + + + + + diff --git a/dom/webidl/EventTarget.webidl b/dom/webidl/EventTarget.webidl index 0ad59289c61..d140e882fa1 100644 --- a/dom/webidl/EventTarget.webidl +++ b/dom/webidl/EventTarget.webidl @@ -43,6 +43,6 @@ partial interface EventTarget { // chrome easier. This returns the window which can be used to create // events to fire at this EventTarget, or null if there isn't one. partial interface EventTarget { - [ChromeOnly] + [ChromeOnly, Exposed=Window] readonly attribute WindowProxy? ownerGlobal; }; diff --git a/dom/webidl/WebGLRenderingContext.webidl b/dom/webidl/WebGLRenderingContext.webidl index b5806ae4502..7321528edf5 100644 --- a/dom/webidl/WebGLRenderingContext.webidl +++ b/dom/webidl/WebGLRenderingContext.webidl @@ -520,7 +520,7 @@ interface WebGLRenderingContext { void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer); void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer); void bindTexture(GLenum target, WebGLTexture? texture); - void blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void blendEquation(GLenum mode); void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); void blendFunc(GLenum sfactor, GLenum dfactor); @@ -535,7 +535,7 @@ interface WebGLRenderingContext { [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target); void clear(GLbitfield mask); - void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void clearDepth(GLclampf depth); void clearStencil(GLint s); void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); diff --git a/embedding/components/printingui/mac/nsPrintProgress.cpp b/embedding/components/printingui/mac/nsPrintProgress.cpp index a35b21a5157..29c52daf688 100644 --- a/embedding/components/printingui/mac/nsPrintProgress.cpp +++ b/embedding/components/printingui/mac/nsPrintProgress.cpp @@ -42,55 +42,21 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent, nsIObserver *openDialogObserver, bool *notifyOnOpen) { - m_observer = openDialogObserver; - - nsresult rv = NS_ERROR_FAILURE; - - if (m_dialog) - return NS_ERROR_ALREADY_INITIALIZED; - - if (!dialogURL || !*dialogURL) - return NS_ERROR_INVALID_ARG; - - if (parent) - { - // Set up window.arguments[0]... - nsCOMPtr array; - rv = NS_NewISupportsArray(getter_AddRefs(array)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr ifptr = - do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - ifptr->SetData(static_cast(this)); - ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress)); - - array->AppendElement(ifptr); - - array->AppendElement(parameters); - - // Open the dialog. - nsCOMPtr newWindow; - rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), - NS_LITERAL_STRING("_blank"), - NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), - array, getter_AddRefs(newWindow)); - if (NS_SUCCEEDED(rv)) { - *notifyOnOpen = true; - } - } - - return rv; + MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress " + "implementation for OS X returns " + "NS_ERROR_NOT_IMPLEMENTED, so we should never get " + "here."); + return NS_ERROR_NOT_IMPLEMENTED; } /* void closeProgressDialog (in boolean forceClose); */ NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose) { - m_closeProgress = true; - // XXX Casting bool to nsresult - return OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, - static_cast(forceClose)); + MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress " + "implementation for OS X returns " + "NS_ERROR_NOT_IMPLEMENTED, so we should never get " + "here."); + return NS_ERROR_NOT_IMPLEMENTED; } /* nsIPrompt GetPrompter (); */ diff --git a/embedding/components/printingui/unixshared/nsPrintProgress.cpp b/embedding/components/printingui/unixshared/nsPrintProgress.cpp index 3df417c84e1..66f04b5cd2f 100644 --- a/embedding/components/printingui/unixshared/nsPrintProgress.cpp +++ b/embedding/components/printingui/unixshared/nsPrintProgress.cpp @@ -6,10 +6,16 @@ #include "nsPrintProgress.h" #include "nsIBaseWindow.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIInterfaceRequestorUtils.h" #include "nsISupportsArray.h" +#include "nsIXULWindow.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIComponentManager.h" +#include "nsPIDOMWindow.h" + NS_IMPL_ADDREF(nsPrintProgress) NS_IMPL_RELEASE(nsPrintProgress) @@ -71,12 +77,29 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent, array->AppendElement(parameters); + // We will set the opener of the dialog to be the nsIDOMWindow for the + // browser XUL window itself, as opposed to the content. That way, the + // progress window has access to the opener. + nsCOMPtr pParentWindow = do_QueryInterface(parent); + NS_ENSURE_STATE(pParentWindow); + + nsCOMPtr docShell = pParentWindow->GetDocShell(); + NS_ENSURE_STATE(docShell); + + nsCOMPtr owner; + docShell->GetTreeOwner(getter_AddRefs(owner)); + + nsCOMPtr ownerXULWindow = do_GetInterface(owner); + nsCOMPtr ownerWindow = do_GetInterface(ownerXULWindow); + NS_ENSURE_STATE(ownerWindow); + // Open the dialog. nsCOMPtr newWindow; - rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), - NS_LITERAL_STRING("_blank"), - NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), - array, getter_AddRefs(newWindow)); + + rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), + NS_LITERAL_STRING("_blank"), + NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), + array, getter_AddRefs(newWindow)); } return rv; diff --git a/embedding/components/printingui/win/nsPrintProgress.cpp b/embedding/components/printingui/win/nsPrintProgress.cpp index d711bddb132..1edb75b45f7 100644 --- a/embedding/components/printingui/win/nsPrintProgress.cpp +++ b/embedding/components/printingui/win/nsPrintProgress.cpp @@ -6,11 +6,16 @@ #include "nsPrintProgress.h" #include "nsIBaseWindow.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIInterfaceRequestorUtils.h" #include "nsISupportsArray.h" +#include "nsIXULWindow.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" +#include "nsPIDOMWindow.h" #if 0 NS_IMPL_ADDREF(nsPrintProgress) @@ -100,12 +105,28 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent, array->AppendElement(parameters); + // We will set the opener of the dialog to be the nsIDOMWindow for the + // browser XUL window itself, as opposed to the content. That way, the + // progress window has access to the opener. + nsCOMPtr pParentWindow = do_QueryInterface(parent); + NS_ENSURE_STATE(pParentWindow); + + nsCOMPtr docShell = pParentWindow->GetDocShell(); + NS_ENSURE_STATE(docShell); + + nsCOMPtr owner; + docShell->GetTreeOwner(getter_AddRefs(owner)); + + nsCOMPtr ownerXULWindow = do_GetInterface(owner); + nsCOMPtr ownerWindow = do_GetInterface(ownerXULWindow); + NS_ENSURE_STATE(ownerWindow); + // Open the dialog. nsCOMPtr newWindow; - rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), - NS_LITERAL_STRING("_blank"), - NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), - array, getter_AddRefs(newWindow)); + rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), + NS_LITERAL_STRING("_blank"), + NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), + array, getter_AddRefs(newWindow)); } return rv; diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 6530f1b9fde..86e612e8e61 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -1166,6 +1166,8 @@ public: // This is a little hacky at the moment, but we want to have this data. Bug 1068613. static void SetLogForwarder(LogForwarder* aLogFwd); + static uint32_t GetMaxSurfaceSize(BackendType aType); + static LogForwarder* GetLogForwarder() { return mLogForwarder; } private: diff --git a/gfx/2d/BaseRect.h b/gfx/2d/BaseRect.h index 0b6810cfddd..85a1532910a 100644 --- a/gfx/2d/BaseRect.h +++ b/gfx/2d/BaseRect.h @@ -111,8 +111,8 @@ struct BaseRect { Sub result; result.x = std::max(x, aRect.x); result.y = std::max(y, aRect.y); - result.width = std::min(XMost(), aRect.XMost()) - result.x; - result.height = std::min(YMost(), aRect.YMost()) - result.y; + result.width = std::min(x - result.x + width, aRect.x - result.x + aRect.width); + result.height = std::min(y - result.y + height, aRect.y - result.y + aRect.height); if (result.width < 0 || result.height < 0) { result.SizeTo(0, 0); } diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp index 5889e35bae5..7c9fe38f42d 100644 --- a/gfx/2d/DrawTargetCG.cpp +++ b/gfx/2d/DrawTargetCG.cpp @@ -1693,10 +1693,11 @@ DrawTargetCG::Init(BackendType aType, { // XXX: we should come up with some consistent semantics for dealing // with zero area drawtargets - if (aSize.width <= 0 || aSize.height <= 0 || - // 32767 is the maximum size supported by cairo - // we clamp to that to make it easier to interoperate - aSize.width > 32767 || aSize.height > 32767) { + if (aSize.width <= 0 || + aSize.height <= 0 || + size_t(aSize.width) > GetMaxSurfaceSize() || + size_t(aSize.height) > GetMaxSurfaceSize()) + { gfxWarning() << "Failed to Init() DrawTargetCG because of bad size."; mColorSpace = nullptr; mCg = nullptr; diff --git a/gfx/2d/DrawTargetCG.h b/gfx/2d/DrawTargetCG.h index 36ac3b79873..563446e54a3 100644 --- a/gfx/2d/DrawTargetCG.h +++ b/gfx/2d/DrawTargetCG.h @@ -183,6 +183,13 @@ public: CGContextRef GetCGContext() { return mCg; } + + // 32767 is the maximum size supported by cairo. We clamp to that to make it + // easier to interoperate. + static size_t GetMaxSurfaceSize() { + return 32767; + } + private: void MarkChanged(); diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h index b7776742eaf..9b515f0a422 100644 --- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -170,6 +170,11 @@ public: static cairo_surface_t *GetDummySurface(); + // Cairo hardcodes this as its maximum surface size. + static size_t GetMaxSurfaceSize() { + return 32767; + } + private: // methods // Init cairo surface without doing a cairo_surface_reference() call. bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr); diff --git a/gfx/2d/DrawTargetD2D.h b/gfx/2d/DrawTargetD2D.h index 0acb88e9d67..bf1e0de1ca8 100644 --- a/gfx/2d/DrawTargetD2D.h +++ b/gfx/2d/DrawTargetD2D.h @@ -145,6 +145,10 @@ public: static IDWriteFactory *GetDWriteFactory(); ID2D1RenderTarget *GetRT() { return mRT; } + static uint32_t GetMaxSurfaceSize() { + return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + } + operator std::string() const { std::stringstream stream; stream << "DrawTargetD2D(" << this << ")"; diff --git a/gfx/2d/DrawTargetD2D1.h b/gfx/2d/DrawTargetD2D1.h index d76415a48ad..541dd2a16c4 100644 --- a/gfx/2d/DrawTargetD2D1.h +++ b/gfx/2d/DrawTargetD2D1.h @@ -144,6 +144,10 @@ public: return stream.str(); } + static uint32_t GetMaxSurfaceSize() { + return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + } + static uint64_t mVRAMUsageDT; static uint64_t mVRAMUsageSS; diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index f9e439a6b82..948d3c3bbda 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -449,6 +449,30 @@ Factory::DoesBackendSupportDataDrawtarget(BackendType aType) return false; } +uint32_t +Factory::GetMaxSurfaceSize(BackendType aType) +{ + switch (aType) { + case BackendType::CAIRO: + case BackendType::COREGRAPHICS: + return DrawTargetCairo::GetMaxSurfaceSize(); +#ifdef XP_MACOSX + case BackendType::COREGRAPHICS_ACCELERATED: + return DrawTargetCG::GetMaxSurfaceSize(); +#endif + case BackendType::SKIA: + return INT_MAX; +#ifdef WIN32 + case BackendType::DIRECT2D: + return DrawTargetD2D::GetMaxSurfaceSize(); + case BackendType::DIRECT2D1_1: + return DrawTargetD2D1::GetMaxSurfaceSize(); +#endif + default: + return 0; + } +} + TemporaryRef Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize) { diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp index bc1b5896b73..fbef5612f8d 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -295,7 +295,7 @@ void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLcla if (context) { - context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); + context->getState().setBlendColor(red, green, blue, alpha); } } diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 05406c9f8ed..31b9e64a892 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -886,7 +886,7 @@ public: AFTER_GL_CALL; } - void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { BEFORE_GL_CALL; mSymbols.fBlendColor(red, green, blue, alpha); AFTER_GL_CALL; @@ -986,7 +986,7 @@ public: AFTER_GL_CALL; } - void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { + void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { BEFORE_GL_CALL; mSymbols.fClearColor(r, g, b, a); AFTER_GL_CALL; diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index 91ff5ac71dc..c5bda3d4dda 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -49,7 +49,7 @@ struct GLContextSymbols PFNGLBINDTEXTUREPROC fBindTexture; typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array); PFNGLBINDVERTEXARRAYPROC fBindVertexArray; - typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); PFNGLBLENDCOLORPROC fBlendColor; typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode); PFNGLBLENDEQUATIONPROC fBlendEquation; @@ -73,7 +73,7 @@ struct GLContextSymbols PFNGLCLEARBUFFERIVPROC fClearBufferiv; typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value); PFNGLCLEARBUFFERUIVPROC fClearBufferuiv; - typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf); + typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat); PFNGLCLEARCOLORPROC fClearColor; typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint); PFNGLCLEARSTENCILPROC fClearStencil; diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 25f3fa9f974..676bd88ae0a 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -67,6 +67,9 @@ BasicCompositor::BasicCompositor(nsIWidget *aWidget) { MOZ_COUNT_CTOR(BasicCompositor); SetBackend(LayersBackend::LAYERS_BASIC); + + mMaxTextureSize = + Factory::GetMaxSurfaceSize(gfxPlatform::GetPlatform()->GetContentBackend()); } BasicCompositor::~BasicCompositor() @@ -74,6 +77,12 @@ BasicCompositor::~BasicCompositor() MOZ_COUNT_DTOR(BasicCompositor); } +int32_t +BasicCompositor::GetMaxTextureSize() const +{ + return mMaxTextureSize; +} + void BasicCompositingRenderTarget::BindRenderTarget() { diff --git a/gfx/layers/basic/BasicCompositor.h b/gfx/layers/basic/BasicCompositor.h index 1eb60b690e7..8fd49357258 100644 --- a/gfx/layers/basic/BasicCompositor.h +++ b/gfx/layers/basic/BasicCompositor.h @@ -103,7 +103,7 @@ public: virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; } virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; } - virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; } + virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE; virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { } virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE { @@ -140,6 +140,8 @@ private: gfx::IntRect mInvalidRect; nsIntRegion mInvalidRegion; + + uint32_t mMaxTextureSize; }; } // namespace layers diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index da0ff3cd4a8..25c58a870ac 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -219,6 +219,12 @@ ClientTiledPaintedLayer::IsScrollingOnCompositor(const FrameMetrics& aParentMetr bool ClientTiledPaintedLayer::UseFastPath() { + // The fast path doesn't allow rendering at low resolution. It will draw the low-res + // area at full resolution and cause OOM. + if (gfxPrefs::UseLowPrecisionBuffer()) { + return false; + } + LayerMetricsWrapper scrollAncestor; GetAncestorLayers(&scrollAncestor, nullptr); if (!scrollAncestor) { @@ -227,16 +233,35 @@ ClientTiledPaintedLayer::UseFastPath() const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); bool multipleTransactionsNeeded = gfxPlatform::GetPlatform()->UseProgressivePaint() - || gfxPrefs::UseLowPrecisionBuffer() || !parentMetrics.GetCriticalDisplayPort().IsEmpty(); bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition(); bool isScrollable = parentMetrics.IsScrollable(); - return !multipleTransactionsNeeded || isFixed || !isScrollable -#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ) - || !IsScrollingOnCompositor(parentMetrics) + return !multipleTransactionsNeeded || isFixed || !isScrollable; +} + +bool +ClientTiledPaintedLayer::UseProgressiveDraw() { + // Don't draw progressively in a reftest scenario (that's what the HasShadowTarget() check is for). + if (!gfxPlatform::GetPlatform()->UseProgressivePaint() || ClientManager()->HasShadowTarget()) { + return false; + } + + // XXX We probably want to disable progressive drawing for non active APZ layers in the future + // but we should wait for a proper test case before making this change. + +#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ) + LayerMetricsWrapper scrollAncestor; + GetAncestorLayers(&scrollAncestor, nullptr); + if (!scrollAncestor) { + return true; + } + const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); + + return !IsScrollingOnCompositor(parentMetrics); +#else + return true; #endif - ; } bool @@ -251,10 +276,8 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion, return false; } - // Only draw progressively when the resolution is unchanged, and we're not - // in a reftest scenario (that's what the HasShadowManager() check is for). - if (gfxPlatform::GetPlatform()->UseProgressivePaint() && - !ClientManager()->HasShadowTarget() && + // Only draw progressively when the resolution is unchanged + if (UseProgressiveDraw() && mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) { // Store the old valid region, then clear it before painting. // We clip the old valid region to the visible region, as it only gets @@ -418,36 +441,20 @@ ClientTiledPaintedLayer::RenderLayer() ToClientLayer(GetMaskLayer())->RenderLayer(); } - // For more complex cases we need to calculate a bunch of metrics before we - // can do the paint. - BeginPaint(); - if (mPaintData.mPaintFinished) { - return; - } - // In some cases we can take a fast path and just be done with it. if (UseFastPath()) { TILING_LOG("TILING %p: Taking fast-path\n", this); mValidRegion = neededRegion; - - // Make sure that tiles that fall outside of the visible region or outside of the - // critical displayport are discarded on the first update. Also make sure that we - // only draw stuff inside the critical displayport on the first update. - if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { - mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); - invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); - } - - if (invalidRegion.IsEmpty()) { - EndPaint(); - return; - } - - mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution); mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data); ClientManager()->Hold(this); mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); - EndPaint(); + return; + } + + // For more complex cases we need to calculate a bunch of metrics before we + // can do the paint. + BeginPaint(); + if (mPaintData.mPaintFinished) { return; } diff --git a/gfx/layers/client/ClientTiledPaintedLayer.h b/gfx/layers/client/ClientTiledPaintedLayer.h index de937a1fd60..cbb6fc61910 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.h +++ b/gfx/layers/client/ClientTiledPaintedLayer.h @@ -106,6 +106,13 @@ private: */ bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics); + /** + * Check if we should use progressive draw on this layer. We will + * disable progressive draw based on a preference or if the layer + * is not being scrolled. + */ + bool UseProgressiveDraw(); + /** * Helper function to do the high-precision paint. * This function returns true if it updated the paint buffer. diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index fee69052f4a..bcb7a36ec56 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -745,7 +745,7 @@ BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFla } uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat); - if (!Allocate(bufSize)) { + if (!bufSize || !Allocate(bufSize)) { return false; } diff --git a/gfx/qcms/iccread.c b/gfx/qcms/iccread.c index c17f1c193e7..77a92585161 100644 --- a/gfx/qcms/iccread.c +++ b/gfx/qcms/iccread.c @@ -547,7 +547,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag } num_in_channels = read_u8(src, offset + 8); - num_out_channels = read_u8(src, offset + 8); + num_out_channels = read_u8(src, offset + 9); if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS) return NULL; diff --git a/gfx/tests/gtest/TestRect.cpp b/gfx/tests/gtest/TestRect.cpp index 4d7f3722a67..d98d54b5de0 100644 --- a/gfx/tests/gtest/TestRect.cpp +++ b/gfx/tests/gtest/TestRect.cpp @@ -400,6 +400,25 @@ TestFiniteGfx() return true; } +// We want to test nsRect values that are still in range but where +// the implementation is at risk of overflowing +template +static bool +TestBug1135677() +{ + RectType rect1(1073741344, 1073741344, 1073756696, 1073819936); + RectType rect2(1073741820, 1073741820, 14400, 77640); + RectType dest; + + dest = rect1.Intersect(rect2); + + EXPECT_TRUE(dest.x == 1073741820 && dest.y == 1073741820 && + dest.width == 14400 && dest.height == 77640) << + "[1] Operation should not overflow internally."; + + return true; +} + TEST(Gfx, nsRect) { TestConstructors(); TestEqualityOperator(); @@ -407,6 +426,7 @@ TEST(Gfx, nsRect) { TestIntersects(); TestIntersection(); TestUnion(); + TestBug1135677(); } TEST(Gfx, nsIntRect) { @@ -416,6 +436,7 @@ TEST(Gfx, nsIntRect) { TestIntersects(); TestIntersection(); TestUnion(); + TestBug1135677(); } TEST(Gfx, gfxRect) { @@ -425,5 +446,6 @@ TEST(Gfx, gfxRect) { TestIntersects(); TestIntersection(); TestUnion(); + TestBug1135677(); TestFiniteGfx(); } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 8f672f20a21..a72c56f943d 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -312,7 +312,7 @@ private: DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false); DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false); DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false); - DECL_GFX_PREF(Once, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false); + DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.gralloc.disable", DisableGralloc, bool, false); diff --git a/ipc/glue/URIParams.ipdlh b/ipc/glue/URIParams.ipdlh index 997456d2a6c..964a1fd3fa3 100644 --- a/ipc/glue/URIParams.ipdlh +++ b/ipc/glue/URIParams.ipdlh @@ -64,12 +64,18 @@ struct IconURIParams int32_t iconState; }; +struct NullPrincipalURIParams +{ + // Purposefully empty. Null principal URIs do not round-trip. +}; + union URIParams { SimpleURIParams; StandardURLParams; JARURIParams; IconURIParams; + NullPrincipalURIParams; }; union OptionalURIParams diff --git a/ipc/glue/URIUtils.cpp b/ipc/glue/URIUtils.cpp index 415ea09fb17..ba1a342faca 100644 --- a/ipc/glue/URIUtils.cpp +++ b/ipc/glue/URIUtils.cpp @@ -13,6 +13,7 @@ #include "nsID.h" #include "nsJARURI.h" #include "nsIIconURI.h" +#include "nsNullPrincipalURI.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsThreadUtils.h" @@ -41,7 +42,7 @@ SerializeURI(nsIURI* aURI, nsCOMPtr serializable = do_QueryInterface(aURI); if (!serializable) { - MOZ_CRASH("All IPDL URIs must be serializable scheme!"); + MOZ_CRASH("All IPDL URIs must be serializable!"); } serializable->Serialize(aParams); @@ -90,6 +91,10 @@ DeserializeURI(const URIParams& aParams) serializable = do_CreateInstance(kIconURICID); break; + case URIParams::TNullPrincipalURIParams: + serializable = new nsNullPrincipalURI(); + break; + default: MOZ_CRASH("Unknown params!"); } diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 8ccedfaad93..1fad5618a73 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -355,7 +355,7 @@ class JS_FRIEND_API(BaseProxyHandler) * to add an override in CrossCompartmentWrapper. If you don't, you risk * compartment mismatches. See bug 945826 comment 0. */ -class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler +class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler { public: explicit MOZ_CONSTEXPR DirectProxyHandler(const void *aFamily, bool aHasPrototype = false, diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index 214ce9fcc9c..14534567cb8 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -29,7 +29,7 @@ const Class SymbolObject::class_ = { }; SymbolObject * -SymbolObject::create(JSContext *cx, JS::Symbol *symbol) +SymbolObject::create(JSContext *cx, JS::HandleSymbol symbol) { JSObject *obj = NewBuiltinClassInstance(cx, &class_); if (!obj) diff --git a/js/src/builtin/SymbolObject.h b/js/src/builtin/SymbolObject.h index 080bc4a3936..6ed23e1bb4b 100644 --- a/js/src/builtin/SymbolObject.h +++ b/js/src/builtin/SymbolObject.h @@ -28,7 +28,7 @@ class SymbolObject : public NativeObject * Creates a new Symbol object boxing the given primitive Symbol. The * object's [[Prototype]] is determined from context. */ - static SymbolObject *create(JSContext *cx, JS::Symbol *symbol); + static SymbolObject *create(JSContext *cx, JS::HandleSymbol symbol); JS::Symbol *unbox() const { return getFixedSlot(PRIMITIVE_VALUE_SLOT).toSymbol(); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 318eb53303d..cc55940a6a6 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -183,6 +183,18 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp) if (!JS_SetProperty(cx, info, "intl-api", value)) return false; +#if defined(XP_WIN) + value = BooleanValue(false); +#elif defined(SOLARIS) + value = BooleanValue(false); +#elif defined(XP_UNIX) + value = BooleanValue(true); +#else + value = BooleanValue(false); +#endif + if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) + return false; + args.rval().setObject(*info); return true; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 286f2e7538a..172eb200d87 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2568,7 +2568,7 @@ Parser::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu } funbox->bufEnd = pos().begin + 1; } else { -#if not JS_HAS_EXPR_CLOSURES +#if !JS_HAS_EXPR_CLOSURES MOZ_ASSERT(kind == Arrow); #endif if (tokenStream.hadError()) diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index d23717ae634..7fedae7d864 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -1612,8 +1612,8 @@ RegExpCompiler::Assemble(JSContext *cx, return RegExpCode(); if (reg_exp_too_big_) { - JS_ReportError(cx, "regexp too big"); code.destroy(); + JS_ReportError(cx, "regexp too big"); return RegExpCode(); } diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index 2024e4b5ed0..779c7f523f5 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -33,6 +33,7 @@ #include "jit/arm/Simulator-arm.h" #include "jit/mips/Simulator-mips.h" +#include "js/GCAPI.h" #include "js/HashTable.h" #include "js/Vector.h" @@ -250,8 +251,11 @@ class ExecutableAllocator { void releasePoolPages(ExecutablePool *pool) { MOZ_ASSERT(pool->m_allocation.pages); - if (destroyCallback) + if (destroyCallback) { + // Do not allow GC during the page release callback. + JS::AutoSuppressGCAnalysis nogc; destroyCallback(pool->m_allocation.pages, pool->m_allocation.size); + } systemRelease(pool->m_allocation); MOZ_ASSERT(m_pools.initialized()); m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools diff --git a/js/src/jit/IonOptimizationLevels.cpp b/js/src/jit/IonOptimizationLevels.cpp index 0f2c2038eb8..5c3a23ae26f 100644 --- a/js/src/jit/IonOptimizationLevels.cpp +++ b/js/src/jit/IonOptimizationLevels.cpp @@ -34,7 +34,7 @@ OptimizationInfo::initNormalOptimizationInfo() loopUnrolling_ = true; autoTruncate_ = true; sink_ = true; - registerAllocator_ = RegisterAllocator_LSRA; + registerAllocator_ = RegisterAllocator_Backtracking; inlineMaxTotalBytecodeLength_ = 1000; inliningMaxCallerBytecodeLength_ = 10000; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index d32af161d38..537290f2175 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -145,6 +145,14 @@ JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject pro return obj; } +JS_FRIEND_API(JSObject *) +JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle proto) +{ + // Use an AutoEnterAnalysis to suppress invocation of the metadata callback. + AutoEnterAnalysis enter(cx); + return JS_NewObjectWithGivenProto(cx, clasp, proto); +} + JS_FRIEND_API(JSPrincipals *) JS_GetCompartmentPrincipals(JSCompartment *compartment) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 86e2f2ab9e9..652d7e2e3b3 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -60,6 +60,13 @@ extern JS_FRIEND_API(JSObject *) JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, JS::HandleObject proto, JS::HandleObject parent); +// Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but +// without invoking the metadata callback on it. This allows creation of +// internal bookkeeping objects that are guaranteed to not have metadata +// attached to them. +extern JS_FRIEND_API(JSObject *) +JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle proto); + extern JS_FRIEND_API(uint32_t) JS_ObjectCountDynamicSlots(JS::HandleObject obj); @@ -144,6 +151,24 @@ extern JS_FRIEND_API(JSObject *) JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto, JS::HandleObject parent); +/* + * Copy the own properties of src to dst in a fast way. src and dst must both + * be native and must be in the compartment of cx. They must have the same + * class, the same parent, and the same prototype. Class reserved slots will + * NOT be copied. + * + * dst must not have any properties on it before this function is called. + * + * src must have been allocated via JS_NewObjectWithoutMetadata so that we can + * be sure it has no metadata that needs copying to dst. This also means that + * dst needs to have the compartment global as its parent. This function will + * preserve the existing metadata on dst, if any. + */ +extern JS_FRIEND_API(bool) +JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx, + JS::HandleObject dst, + JS::HandleObject src); + extern JS_FRIEND_API(JSString *) JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 1e5d87a19dc..ef85419deae 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1267,11 +1267,16 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp, /* * Default parent to the parent of the prototype, which was set from - * the parent of the prototype's constructor. + * the parent of the prototype's constructor. If there is no + * prototype, use the global. */ RootedObject parent(cxArg, parentArg); - if (!parent && proto.isObject()) - parent = proto.toObject()->getParent(); + if (!parent) { + if (proto.isObject()) + parent = proto.toObject()->getParent(); + else + parent = cxArg->global(); + } RootedObject obj(cxArg, NewObject(cxArg, group, parent, allocKind, newKind)); if (!obj) @@ -1864,7 +1869,8 @@ js::DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind MOZ_ASSERT(!obj->hasPrivate()); RootedShape shape(cx, obj->lastProperty()); size_t span = shape->slotSpan(); - clone->setLastProperty(cx, shape); + if (!clone->setLastProperty(cx, shape)) + return nullptr; for (size_t i = 0; i < span; i++) { v = obj->getSlot(i); if (v.isObject()) { @@ -1894,6 +1900,58 @@ js::DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind return clone; } +static bool +InitializePropertiesFromCompatibleNativeObject(JSContext *cx, + HandleNativeObject dst, + HandleNativeObject src) +{ + assertSameCompartment(cx, src, dst); + MOZ_ASSERT(src->getClass() == dst->getClass()); + MOZ_ASSERT(src->getParent() == dst->getParent()); + MOZ_ASSERT(dst->getParent() == cx->global()); + MOZ_ASSERT(src->getProto() == dst->getProto()); + MOZ_ASSERT(dst->lastProperty()->getObjectFlags() == 0); + MOZ_ASSERT(!src->getMetadata()); + MOZ_ASSERT(!src->isSingleton()); + + // Save the dst metadata, if any, before we start messing with its shape. + RootedObject dstMetadata(cx, dst->getMetadata()); + + if (!dst->ensureElements(cx, src->getDenseInitializedLength())) + return false; + + uint32_t initialized = src->getDenseInitializedLength(); + for (uint32_t i = 0; i < initialized; ++i) { + dst->setDenseInitializedLength(i + 1); + dst->initDenseElement(i, src->getDenseElement(i)); + } + + MOZ_ASSERT(!src->hasPrivate()); + RootedShape shape(cx, src->lastProperty()); + size_t span = shape->slotSpan(); + if (!dst->setLastProperty(cx, shape)) + return false; + for (size_t i = JSCLASS_RESERVED_SLOTS(src->getClass()); i < span; i++) + dst->setSlot(i, src->getSlot(i)); + + if (dstMetadata) { + if (!js::SetObjectMetadata(cx, dst, dstMetadata)) + return false; + } + + return true; +} + +JS_FRIEND_API(bool) +JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx, + HandleObject dst, + HandleObject src) +{ + return InitializePropertiesFromCompatibleNativeObject(cx, + dst.as(), + src.as()); +} + template bool js::XDRObjectLiteral(XDRState *xdr, MutableHandleNativeObject obj) @@ -3556,7 +3614,8 @@ js::PrimitiveToObject(JSContext *cx, const Value &v) if (v.isBoolean()) return BooleanObject::create(cx, v.toBoolean()); MOZ_ASSERT(v.isSymbol()); - return SymbolObject::create(cx, v.toSymbol()); + RootedSymbol symbol(cx, v.toSymbol()); + return SymbolObject::create(cx, symbol); } /* diff --git a/js/src/moz.build b/js/src/moz.build index cc4400d79b6..c3223ec9173 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -494,6 +494,11 @@ if CONFIG['_MSC_VER']: # Prevent floating point errors caused by VC++ optimizations # XXX We should add this to CXXFLAGS, too? CFLAGS += ['-fp:precise'] + # C4805 warns mixing bool with other integral types in computation. + # But given the conversion from bool is specified, and this is a + # pattern widely used in code in js/src, suppress this warning here. + CXXFLAGS += ['-wd4805'] + CXXFLAGS += ['-we4067', '-we4258', '-we4275'] if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'): OS_LIBS += [ diff --git a/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js b/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js index 57b0eed75f3..cea0cd79956 100644 --- a/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js +++ b/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js @@ -36,5 +36,6 @@ function test() { assertThrows(() => createMappedArrayBuffer("empty.txt", 0, 8), Error); } -test(); +if (getBuildConfiguration()["mapped-array-buffer"]) + test(); reportCompare(0, 0, 'ok'); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 26b54dfb0e4..72debd99e96 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -252,7 +252,7 @@ class ObjectGroup : public gc::TenuredCell } TypeNewScript *anyNewScript(); - void detachNewScript(bool writeBarrier); + void detachNewScript(bool writeBarrier, ObjectGroup *replacement); ObjectGroupFlags flagsDontCheckGeneration() { return flags_; @@ -480,7 +480,7 @@ class ObjectGroup : public gc::TenuredCell void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags); void markUnknown(ExclusiveContext *cx); void maybeClearNewScriptOnOOM(); - void clearNewScript(ExclusiveContext *cx); + void clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement = nullptr); bool isPropertyNonData(jsid id); bool isPropertyNonWritable(jsid id); diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index e55a39a50b5..afcf11d6543 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2765,7 +2765,7 @@ ObjectGroup::anyNewScript() } void -ObjectGroup::detachNewScript(bool writeBarrier) +ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup *replacement) { // Clear the TypeNewScript from this ObjectGroup and, if it has been // analyzed, remove it from the newObjectGroups table so that it will not be @@ -2775,8 +2775,16 @@ ObjectGroup::detachNewScript(bool writeBarrier) MOZ_ASSERT(newScript); if (newScript->analyzed()) { - newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(), - newScript->function()); + ObjectGroupCompartment &objectGroups = newScript->function()->compartment()->objectGroups; + if (replacement) { + MOZ_ASSERT(replacement->newScript()->function() == newScript->function()); + objectGroups.replaceDefaultNewGroup(nullptr, proto(), newScript->function(), + replacement); + } else { + objectGroups.removeDefaultNewGroup(nullptr, proto(), newScript->function()); + } + } else { + MOZ_ASSERT(!replacement); } if (this->newScript()) @@ -2800,13 +2808,13 @@ ObjectGroup::maybeClearNewScriptOnOOM() addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED); // This method is called during GC sweeping, so don't trigger pre barriers. - detachNewScript(/* writeBarrier = */ false); + detachNewScript(/* writeBarrier = */ false, nullptr); js_delete(newScript); } void -ObjectGroup::clearNewScript(ExclusiveContext *cx) +ObjectGroup::clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement /* = nullptr*/) { TypeNewScript *newScript = anyNewScript(); if (!newScript) @@ -2814,15 +2822,17 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx) AutoEnterAnalysis enter(cx); - // Invalidate any Ion code constructing objects of this type. - setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED); + if (!replacement) { + // Invalidate any Ion code constructing objects of this type. + setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED); - // Mark the constructing function as having its 'new' script cleared, so we - // will not try to construct another one later. - if (!newScript->function()->setNewScriptCleared(cx)) - cx->recoverFromOutOfMemory(); + // Mark the constructing function as having its 'new' script cleared, so we + // will not try to construct another one later. + if (!newScript->function()->setNewScriptCleared(cx)) + cx->recoverFromOutOfMemory(); + } - detachNewScript(/* writeBarrier = */ true); + detachNewScript(/* writeBarrier = */ true, replacement); if (cx->isJSContext()) { bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this); @@ -3268,6 +3278,33 @@ TypeNewScript::make(JSContext *cx, ObjectGroup *group, JSFunction *fun) gc::TraceTypeNewScript(group); } +// Make a TypeNewScript with the same initializer list as |newScript| but with +// a new template object. +/* static */ TypeNewScript * +TypeNewScript::makeNativeVersion(JSContext *cx, TypeNewScript *newScript, + PlainObject *templateObject) +{ + MOZ_ASSERT(cx->zone()->types.activeAnalysis); + + ScopedJSDeletePtr nativeNewScript(cx->new_()); + if (!nativeNewScript) + return nullptr; + + nativeNewScript->function_ = newScript->function(); + nativeNewScript->templateObject_ = templateObject; + + Initializer *cursor = newScript->initializerList; + while (cursor->kind != Initializer::DONE) { cursor++; } + size_t initializerLength = cursor - newScript->initializerList + 1; + + nativeNewScript->initializerList = cx->zone()->pod_calloc(initializerLength); + if (!nativeNewScript->initializerList) + return nullptr; + PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength); + + return nativeNewScript.forget(); +} + size_t TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 4724704fbb2..8097294a83e 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -827,8 +827,6 @@ class TypeNewScript private: // Scripted function which this information was computed for. - // If instances of the associated group are created without calling - // 'new' on this function, the new script information is cleared. HeapPtrFunction function_; // Any preliminary objects with the type. The analyses are not performed @@ -902,6 +900,8 @@ class TypeNewScript bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group); static void make(JSContext *cx, ObjectGroup *group, JSFunction *fun); + static TypeNewScript *makeNativeVersion(JSContext *cx, TypeNewScript *newScript, + PlainObject *templateObject); size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; }; diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index c6c634e9aad..7a421d7af79 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -35,6 +35,9 @@ UnboxedLayout::trace(JSTracer *trc) if (nativeShape_) MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape"); + + if (replacementNewGroup_) + MarkObjectGroup(trc, &replacementNewGroup_, "unboxed_layout_replacementNewGroup"); } size_t @@ -172,18 +175,49 @@ UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj) /* static */ bool UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group) { + AutoEnterAnalysis enter(cx); + UnboxedLayout &layout = group->unboxedLayout(); + Rooted proto(cx, group->proto()); MOZ_ASSERT(!layout.nativeGroup()); - // Immediately clear any new script on the group, as - // rollbackPartiallyInitializedObjects() will be confused by the type - // changes we make later on. - group->clearNewScript(cx); + // Immediately clear any new script on the group. This is done by replacing + // the existing new script with one for a replacement default new group. + // This is done so that the size of the replacment group's objects is the + // same as that for the unboxed group, so that we do not see polymorphic + // slot accesses later on for sites that see converted objects from this + // group and objects that were allocated using the replacement new group. + RootedObjectGroup replacementNewGroup(cx); + if (layout.newScript()) { + replacementNewGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); + if (!replacementNewGroup) + return false; - AutoEnterAnalysis enter(cx); + PlainObject *templateObject = NewObjectWithGroup(cx, replacementNewGroup, + cx->global(), layout.getAllocKind(), + MaybeSingletonObject); + if (!templateObject) + return false; - Rooted proto(cx, group->proto()); + for (size_t i = 0; i < layout.properties().length(); i++) { + const UnboxedLayout::Property &property = layout.properties()[i]; + if (!templateObject->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE)) + return false; + MOZ_ASSERT(templateObject->slotSpan() == i + 1); + MOZ_ASSERT(!templateObject->inDictionaryMode()); + } + + TypeNewScript *replacementNewScript = + TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject); + if (!replacementNewScript) + return false; + + replacementNewGroup->setNewScript(replacementNewScript); + gc::TraceTypeNewScript(replacementNewGroup); + + group->clearNewScript(cx, replacementNewGroup); + } size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind()); RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, @@ -214,8 +248,8 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group) TypeSet::TypeList types; if (!property->types.enumerateTypes(&types)) return false; - for (size_t i = 0; i < types.length(); i++) - AddTypePropertyId(cx, nativeGroup, property->id, types[i]); + for (size_t j = 0; j < types.length(); j++) + AddTypePropertyId(cx, nativeGroup, property->id, types[j]); HeapTypeSet *nativeProperty = nativeGroup->maybeGetProperty(property->id); if (nativeProperty->canSetDefinite(i)) nativeProperty->setDefinite(i); @@ -224,6 +258,7 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group) layout.nativeGroup_ = nativeGroup; layout.nativeShape_ = shape; + layout.replacementNewGroup_ = replacementNewGroup; nativeGroup->setOriginalUnboxedGroup(group); diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 7f6549ac6be..291a3abee39 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -71,10 +71,18 @@ class UnboxedLayout : public mozilla::LinkedListElement HeapPtrObjectGroup nativeGroup_; HeapPtrShape nativeShape_; + // If nativeGroup is set and this object originally had a TypeNewScript, + // this points to the default 'new' group which replaced this one (and + // which might itself have been cleared since). This link is only needed to + // keep the replacement group from being GC'ed. If it were GC'ed and a new + // one regenerated later, that new group might have a different allocation + // kind from this group. + HeapPtrObjectGroup replacementNewGroup_; + public: UnboxedLayout(const PropertyVector &properties, size_t size) : size_(size), newScript_(nullptr), traceList_(nullptr), - nativeGroup_(nullptr), nativeShape_(nullptr) + nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr) { properties_.appendAll(properties); } diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index fc22b419dcd..bdee546dd26 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -4319,9 +4319,8 @@ FrameLayerBuilder::PaintItems(nsTArray& aItems, float aXScale, float aYScale, int32_t aCommonClipCount) { -#ifdef MOZ_DUMP_PAINTING DrawTarget& aDrawTarget = *aRC->GetDrawTarget(); -#endif + int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel(); nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel); boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel), @@ -4371,7 +4370,9 @@ FrameLayerBuilder::PaintItems(nsTArray& aItems, } if (cdi->mInactiveLayerManager) { + bool saved = aDrawTarget.GetPermitSubpixelAA(); PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC); + aDrawTarget.SetPermitSubpixelAA(saved); } else { nsIFrame* frame = cdi->mItem->Frame(); frame->AddStateBits(NS_FRAME_PAINTED_THEBES); diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index 7588c3ed7b9..50e5885131b 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -433,7 +433,7 @@ load 835056.html load 836990-1.html load 840480.html load 847242.html -load 852293.html +pref(layers.progressive-paint,false) pref(layers.low-precision-buffer,false) load 852293.html load 860579-1.html pref(layers.force-active,true) load 859526-1.html pref(layers.force-active,true) load 859630-1.html diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index a2a2981822d..128bad41d77 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -2773,12 +2773,40 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } -static void -PaintTreeBody(nsIFrame* aFrame, nsRenderingContext* aCtx, - const nsRect& aDirtyRect, nsPoint aPt) -{ - static_cast(aFrame)->PaintTreeBody(*aCtx, aDirtyRect, aPt); -} +class nsDisplayTreeBody MOZ_FINAL : public nsDisplayItem { +public: + nsDisplayTreeBody(nsDisplayListBuilder* aBuilder, nsFrame* aFrame) : + nsDisplayItem(aBuilder, aFrame), + mDisableSubpixelAA(false) { + MOZ_COUNT_CTOR(nsDisplayTreeBody); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayTreeBody() { + MOZ_COUNT_DTOR(nsDisplayTreeBody); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) MOZ_OVERRIDE + { + gfxContext* ctx = aCtx->ThebesContext(); + gfxContextAutoDisableSubpixelAntialiasing disable(ctx, mDisableSubpixelAA); + static_cast(mFrame)-> + PaintTreeBody(*aCtx, mVisibleRect, ToReferenceFrame()); + } + NS_DISPLAY_DECL_NAME("XULTreeBody", TYPE_XUL_TREE_BODY) + + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE + { + bool snap; + return GetBounds(aBuilder, &snap); + } + virtual void DisableComponentAlpha() MOZ_OVERRIDE { + mDisableSubpixelAA = true; + } + + bool mDisableSubpixelAA; +}; // Painting routines void @@ -2799,8 +2827,7 @@ nsTreeBodyFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return; aLists.Content()->AppendNewToTop(new (aBuilder) - nsDisplayGeneric(aBuilder, this, ::PaintTreeBody, "XULTreeBody", - nsDisplayItem::TYPE_XUL_TREE_BODY)); + nsDisplayTreeBody(aBuilder, this)); } void diff --git a/media/libsoundtouch/src/soundtouch_config.h b/media/libsoundtouch/src/soundtouch_config.h index 9275ba8e6ec..469bb822af0 100644 --- a/media/libsoundtouch/src/soundtouch_config.h +++ b/media/libsoundtouch/src/soundtouch_config.h @@ -5,15 +5,3 @@ #else #define SOUNDTOUCH_INTEGER_SAMPLES 1 #endif - -#ifndef MOZILLA_PRESUME_SSE -#ifdef MOZ_SAMPLE_TYPE_FLOAT32 -#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1 -#endif -#endif - -#ifndef MOZILLA_PRESUME_MMX -#ifdef MOZ_SAMPLE_TYPE_S16 -#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1 -#endif -#endif diff --git a/media/webrtc/signaling/test/FakeMediaStreams.h b/media/webrtc/signaling/test/FakeMediaStreams.h index a7afecbe1b2..b7afbf30e42 100644 --- a/media/webrtc/signaling/test/FakeMediaStreams.h +++ b/media/webrtc/signaling/test/FakeMediaStreams.h @@ -265,7 +265,13 @@ public: explicit Fake_DOMMediaStream(Fake_MediaStream *stream = nullptr) : mMediaStream(stream ? stream : new Fake_MediaStream()) , mVideoTrack(new Fake_MediaStreamTrack(true, this)) - , mAudioTrack(new Fake_MediaStreamTrack(false, this)) {} + , mAudioTrack(new Fake_MediaStreamTrack(false, this)) + { + static size_t counter = 0; + std::ostringstream os; + os << counter++; + mID = os.str(); + } NS_DECL_THREADSAFE_ISUPPORTS diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 0f47f36b1ce..e3312fdd1a4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4477,6 +4477,16 @@ pref("dom.mozSettings.SettingsService.verbose.enabled", false); // readwrite. pref("dom.mozSettings.allowForceReadOnly", false); +// The interval at which to check for slow running addons +#ifdef NIGHTLY_BUILD +pref("browser.addon-watch.interval", 15000); +#else +pref("browser.addon-watch.interval", -1); +#endif +pref("browser.addon-watch.ignore", "[\"mochikit@mozilla.org\",\"special-powers@mozilla.org\"]"); +// the percentage of time addons are allowed to use without being labeled slow +pref("browser.addon-watch.percentage-limit", 5); + // RequestSync API is disabled by default. pref("dom.requestSync.enabled", false); diff --git a/netwerk/cookie/CookieServiceChild.cpp b/netwerk/cookie/CookieServiceChild.cpp index 3edff1aef69..952b8514960 100644 --- a/netwerk/cookie/CookieServiceChild.cpp +++ b/netwerk/cookie/CookieServiceChild.cpp @@ -109,6 +109,13 @@ CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI, *aCookieString = nullptr; + // Fast past: don't bother sending IPC messages about nullprincipal'd + // documents. + nsAutoCString scheme; + aHostURI->GetScheme(scheme); + if (scheme.EqualsLiteral("moz-nullprincipal")) + return NS_OK; + // Determine whether the request is foreign. Failure is acceptable. bool isForeign = true; if (RequireThirdPartyCheck()) @@ -137,6 +144,13 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI, NS_ENSURE_ARG(aHostURI); NS_ENSURE_ARG_POINTER(aCookieString); + // Fast past: don't bother sending IPC messages about nullprincipal'd + // documents. + nsAutoCString scheme; + aHostURI->GetScheme(scheme); + if (scheme.EqualsLiteral("moz-nullprincipal")) + return NS_OK; + // Determine whether the request is foreign. Failure is acceptable. bool isForeign = true; if (RequireThirdPartyCheck()) diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index f4265334659..28abf734dfd 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -60,11 +60,11 @@ class Context(KeyedDefaultDict): lots of empty/default values, you have a data structure with only the values that were read or touched. - Instances of variables classes are created by invoking class_name(), - except when class_name derives from ContextDerivedValue, in which - case class_name(instance_of_the_context) is invoked. - A value is added to those calls when instances are created during - assignment (setitem). + Instances of variables classes are created by invoking ``class_name()``, + except when class_name derives from ``ContextDerivedValue`` or + ``SubContext``, in which case ``class_name(instance_of_the_context)`` or + ``class_name(self)`` is invoked. A value is added to those calls when + instances are created during assignment (setitem). allowed_variables is a dict of the variables that can be set and read in this context instance. Keys in this dict are the strings representing keys @@ -84,6 +84,7 @@ class Context(KeyedDefaultDict): self._all_paths = [] self.config = config self.execution_time = 0 + self._sandbox = None KeyedDefaultDict.__init__(self, self._factory) def push_source(self, path): @@ -272,6 +273,35 @@ class TemplateContext(Context): return Context._validate(self, key, value, True) +class SubContext(Context, ContextDerivedValue): + """A Context derived from another Context. + + Sub-contexts are intended to be used as context managers. + + Sub-contexts inherit paths and other relevant state from the parent + context. + """ + def __init__(self, parent): + assert isinstance(parent, Context) + + Context.__init__(self, allowed_variables=self.VARIABLES, + config=parent.config) + + # Copy state from parent. + for p in parent.source_stack: + self.push_source(p) + self._sandbox = parent._sandbox + + def __enter__(self): + if not self._sandbox or self._sandbox() is None: + raise Exception('a sandbox is required') + + self._sandbox().push_subcontext(self) + + def __exit__(self, exc_type, exc_value, traceback): + self._sandbox().pop_subcontext(self) + + class FinalTargetValue(ContextDerivedValue, unicode): def __new__(cls, context, value=""): if not value: @@ -366,6 +396,27 @@ def ContextDerivedTypedList(type, base_class=List): return _TypedList +# This defines functions that create sub-contexts. +# +# Values are classes that are SubContexts. The class name will be turned into +# a function that when called emits an instance of that class. +# +# Arbitrary arguments can be passed to the class constructor. The first +# argument is always the parent context. It is up to each class to perform +# argument validation. +SUBCONTEXTS = [ +] + +for cls in SUBCONTEXTS: + if not issubclass(cls, SubContext): + raise ValueError('SUBCONTEXTS entry not a SubContext class: %s' % cls) + + if not hasattr(cls, 'VARIABLES'): + raise ValueError('SUBCONTEXTS entry does not have VARIABLES: %s' % cls) + +SUBCONTEXTS = {cls.__name__: cls for cls in SUBCONTEXTS} + + # This defines the set of mutable global variables. # # Each variable is a tuple of: diff --git a/python/mozbuild/mozbuild/frontend/reader.py b/python/mozbuild/mozbuild/frontend/reader.py index c721f366125..330bab3d6dc 100644 --- a/python/mozbuild/mozbuild/frontend/reader.py +++ b/python/mozbuild/mozbuild/frontend/reader.py @@ -62,6 +62,7 @@ from .context import ( VARIABLES, DEPRECATION_HINTS, SPECIAL_VARIABLES, + SUBCONTEXTS, TemplateContext, ) @@ -140,12 +141,14 @@ class MozbuildSandbox(Sandbox): return SPECIAL_VARIABLES[key][0](self._context) if key in FUNCTIONS: return self._create_function(FUNCTIONS[key]) + if key in SUBCONTEXTS: + return self._create_subcontext(SUBCONTEXTS[key]) if key in self.templates: return self._create_template_function(self.templates[key]) return Sandbox.__getitem__(self, key) def __setitem__(self, key, value): - if key in SPECIAL_VARIABLES or key in FUNCTIONS: + if key in SPECIAL_VARIABLES or key in FUNCTIONS or key in SUBCONTEXTS: raise KeyError() if key in self.exports: self._context[key] = value @@ -310,6 +313,14 @@ class MozbuildSandbox(Sandbox): self.templates[name] = func, code, self._context.current_path + @memoize + def _create_subcontext(self, cls): + """Return a function object that creates SubContext instances.""" + def fn(*args, **kwargs): + return cls(self._context, *args, **kwargs) + + return fn + @memoize def _create_function(self, function_def): """Returns a function object for use within the sandbox for the given @@ -736,7 +747,7 @@ class BuildReader(object): read, a new Context is created and emitted. """ path = mozpath.join(self.config.topsrcdir, 'moz.build') - return self.read_mozbuild(path, self.config, read_tiers=True) + return self.read_mozbuild(path, self.config) def all_mozbuild_paths(self): """Iterator over all available moz.build files. @@ -872,8 +883,7 @@ class BuildReader(object): for name, key, value in assignments: yield p, name, key, value - def read_mozbuild(self, path, config, read_tiers=False, descend=True, - metadata={}): + def read_mozbuild(self, path, config, descend=True, metadata={}): """Read and process a mozbuild file, descending into children. This starts with a single mozbuild file, executes it, and descends into @@ -884,10 +894,6 @@ class BuildReader(object): directory, we will open the moz.build file located in that directory in a new Sandbox and process it. - If read_tiers is True (it should only be True for the top-level - mozbuild file in a project), the TIERS variable will be used for - traversal as well. - If descend is True (the default), we will descend into child directories and files per variable values. @@ -900,8 +906,8 @@ class BuildReader(object): """ self._execution_stack.append(path) try: - for s in self._read_mozbuild(path, config, read_tiers=read_tiers, - descend=descend, metadata=metadata): + for s in self._read_mozbuild(path, config, descend=descend, + metadata=metadata): yield s except BuildReaderError as bre: @@ -927,7 +933,7 @@ class BuildReader(object): raise BuildReaderError(list(self._execution_stack), sys.exc_info()[2], other_error=e) - def _read_mozbuild(self, path, config, read_tiers, descend, metadata): + def _read_mozbuild(self, path, config, descend, metadata): path = mozpath.normpath(path) log(self._log, logging.DEBUG, 'read_mozbuild', {'path': path}, 'Reading file: {path}') @@ -1008,11 +1014,12 @@ class BuildReader(object): for gyp_context in gyp_contexts: context['DIRS'].append(mozpath.relpath(gyp_context.objdir, context.objdir)) + sandbox.subcontexts.append(gyp_context) yield context - for gyp_context in gyp_contexts: - yield gyp_context + for subcontext in sandbox.subcontexts: + yield subcontext # Traverse into referenced files. @@ -1051,7 +1058,7 @@ class BuildReader(object): continue for res in self.read_mozbuild(child_path, context.config, - read_tiers=False, metadata=child_metadata): + metadata=child_metadata): yield res self._execution_stack.pop() diff --git a/python/mozbuild/mozbuild/frontend/sandbox.py b/python/mozbuild/mozbuild/frontend/sandbox.py index ead4605dfa5..c793d400404 100644 --- a/python/mozbuild/mozbuild/frontend/sandbox.py +++ b/python/mozbuild/mozbuild/frontend/sandbox.py @@ -22,6 +22,7 @@ from __future__ import unicode_literals import copy import os import sys +import weakref from contextlib import contextmanager @@ -116,12 +117,22 @@ class Sandbox(dict): assert isinstance(self._builtins, ReadOnlyDict) assert isinstance(context, Context) - self._context = context + # Contexts are modeled as a stack because multiple context managers + # may be active. + self._active_contexts = [context] + + # Seen sub-contexts. Will be populated with other Context instances + # that were related to execution of this instance. + self.subcontexts = [] # We need to record this because it gets swallowed as part of # evaluation. self._last_name_error = None + @property + def _context(self): + return self._active_contexts[-1] + def exec_file(self, path): """Execute code at a path in the sandbox. @@ -153,6 +164,9 @@ class Sandbox(dict): if path: self._context.push_source(path) + old_sandbox = self._context._sandbox + self._context._sandbox = weakref.ref(self) + # We don't have to worry about bytecode generation here because we are # too low-level for that. However, we could add bytecode generation via # the marshall module if parsing performance were ever an issue. @@ -190,9 +204,31 @@ class Sandbox(dict): raise SandboxExecutionError(self._context.source_stack, exc[0], exc[1], exc[2]) finally: + self._context._sandbox = old_sandbox if path: self._context.pop_source() + def push_subcontext(self, context): + """Push a SubContext onto the execution stack. + + When called, the active context will be set to the specified context, + meaning all variable accesses will go through it. We also record this + SubContext as having been executed as part of this sandbox. + """ + self._active_contexts.append(context) + if context not in self.subcontexts: + self.subcontexts.append(context) + + def pop_subcontext(self, context): + """Pop a SubContext off the execution stack. + + SubContexts must be pushed and popped in opposite order. This is + validated as part of the function call to ensure proper consumer API + use. + """ + popped = self._active_contexts.pop() + assert popped == context + def __getitem__(self, key): if key.isupper(): try: diff --git a/python/mozbuild/mozbuild/sphinx.py b/python/mozbuild/mozbuild/sphinx.py index 756ac99ce3d..6d73fb40e32 100644 --- a/python/mozbuild/mozbuild/sphinx.py +++ b/python/mozbuild/mozbuild/sphinx.py @@ -101,6 +101,21 @@ def special_reference(v, func, typ, doc): def format_module(m): lines = [] + + for subcontext, cls in sorted(m.SUBCONTEXTS.items()): + lines.extend([ + '.. _mozbuild_subcontext_%s:' % subcontext, + '', + 'Sub-Context: %s' % subcontext, + '=============' + '=' * len(subcontext), + '', + prepare_docstring(cls.__doc__)[0], + '', + ]) + + for k, v in sorted(cls.VARIABLES.items()): + lines.extend(variable_reference(k, *v)) + lines.extend([ 'Variables', '=========', diff --git a/python/mozbuild/mozbuild/test/frontend/test_context.py b/python/mozbuild/mozbuild/test/frontend/test_context.py index 7a1f1d93707..e9698b68d39 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_context.py +++ b/python/mozbuild/mozbuild/test/frontend/test_context.py @@ -11,6 +11,7 @@ from mozbuild.frontend.context import ( Context, FUNCTIONS, SPECIAL_VARIABLES, + SUBCONTEXTS, VARIABLES, ) @@ -256,6 +257,12 @@ class TestSymbols(unittest.TestCase): for func, typ, doc in SPECIAL_VARIABLES.values(): self._verify_doc(doc) + for name, cls in SUBCONTEXTS.items(): + self._verify_doc(cls.__doc__) + + for name, v in cls.VARIABLES.items(): + self._verify_doc(v[2]) + if __name__ == '__main__': main() diff --git a/python/mozbuild/mozpack/path.py b/python/mozbuild/mozpack/path.py index 20e9053e82b..1b71ace78ed 100644 --- a/python/mozbuild/mozpack/path.py +++ b/python/mozbuild/mozpack/path.py @@ -99,12 +99,12 @@ def match(path, pattern): ''' if not pattern: return True - if not pattern in re_cache: - pattern = re.escape(pattern) - pattern = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', pattern) - pattern = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', pattern) - pattern = pattern.replace(r'\*', '[^/]*') + '(?:/.*)?$' - re_cache[pattern] = re.compile(pattern) + if pattern not in re_cache: + p = re.escape(pattern) + p = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', p) + p = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', p) + p = p.replace(r'\*', '[^/]*') + '(?:/.*)?$' + re_cache[pattern] = re.compile(p) return re_cache[pattern].match(path) is not None diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index b38fb7ed2c6..f4ace3c193f 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -1447,16 +1447,11 @@ MarionetteServerConnection.prototype = { return this._browserIds.get(permKey); } - let contentWindow = browser.contentWindowAsCPOW; - if (contentWindow !== null && !Cu.isDeadWrapper(contentWindow)) { - let winId = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils) - .outerWindowID; - if (winId) { - winId += ""; - this._browserIds.set(permKey, winId); - return winId; - } + let winId = browser.outerWindowID; + if (winId) { + winId += ""; + this._browserIds.set(permKey, winId); + return winId; } return null; }, diff --git a/testing/mochitest/ShutdownLeaksCollector.jsm b/testing/mochitest/ShutdownLeaksCollector.jsm new file mode 100644 index 00000000000..f8469b064da --- /dev/null +++ b/testing/mochitest/ShutdownLeaksCollector.jsm @@ -0,0 +1,48 @@ +/* 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/. */ + +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); + +this.EXPORTED_SYMBOLS = ["ContentCollector"]; + +// This listens for the message "browser-test:collect-request". When it gets it, +// it runs some GCs and CCs, then prints out a message indicating the collections +// are complete. Mochitest uses this information to determine when windows and +// docshells should be destroyed. + +var ContentCollector = { + init: function() { + let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsISyncMessageSender); + cpmm.addMessageListener("browser-test:collect-request", this); + }, + + receiveMessage: function(aMessage) { + switch (aMessage.name) { + case "browser-test:collect-request": + Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize"); + + Cu.forceGC(); + Cu.forceCC(); + + Cu.schedulePreciseShrinkingGC(() => { + Cu.forceCC(); + + let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID; + dump("Completed ShutdownLeaks collections in process " + pid + "\n")}); + + let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsISyncMessageSender); + cpmm.removeMessageListener("browser-test:collect-request", this); + + break; + } + } + +}; +ContentCollector.init(); diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index 11cba28e34f..6bf290a07ce 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -88,6 +88,12 @@ function testInit() { } if (gConfig.e10s) { e10s_init(); + let globalMM = Cc["@mozilla.org/globalmessagemanager;1"] + .getService(Ci.nsIMessageListenerManager); + globalMM.loadFrameScript("chrome://mochikit/content/shutdown-leaks-collector.js", true); + } else { + // In non-e10s, only run the ShutdownLeaksCollector in the parent process. + Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm"); } } @@ -575,6 +581,10 @@ Tester.prototype = { // and thus get rid of more false leaks like already terminated workers. Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize"); + let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] + .getService(Ci.nsIMessageBroadcaster); + ppmm.broadcastAsyncMessage("browser-test:collect-request"); + checkForLeakedGlobalWindows(aResults => { if (aResults.length == 0) { this.finish(); diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index 3db85f7f87a..1aba8e9307c 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -10,6 +10,8 @@ mochikit.jar: content/cc-analyzer.js (cc-analyzer.js) content/chrome-harness.js (chrome-harness.js) content/mochitest-e10s-utils.js (mochitest-e10s-utils.js) + content/shutdown-leaks-collector.js (shutdown-leaks-collector.js) + content/ShutdownLeaksCollector.jsm (ShutdownLeaksCollector.jsm) content/harness.xul (harness.xul) content/redirect.html (redirect.html) content/server.js (server.js) diff --git a/testing/mochitest/shutdown-leaks-collector.js b/testing/mochitest/shutdown-leaks-collector.js new file mode 100644 index 00000000000..f754eaafe47 --- /dev/null +++ b/testing/mochitest/shutdown-leaks-collector.js @@ -0,0 +1,7 @@ +/* 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/. */ + +// We run this code in a .jsm rather than here to avoid keeping the current +// compartment alive. +Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm"); diff --git a/testing/web-platform/harness/wptrunner/executors/executormarionette.py b/testing/web-platform/harness/wptrunner/executors/executormarionette.py index 663f95f7ee4..1d03ef6d1ec 100644 --- a/testing/web-platform/harness/wptrunner/executors/executormarionette.py +++ b/testing/web-platform/harness/wptrunner/executors/executormarionette.py @@ -30,10 +30,12 @@ required_files = [("testharness_runner.html", "", False), def do_delayed_imports(): global marionette + global errors try: import marionette + from marionette import errors except ImportError: - import marionette_driver.marionette as marionette + from marionette_driver import marionette, errors class MarionetteTestExecutor(TestExecutor): @@ -153,13 +155,13 @@ class MarionetteTestExecutor(TestExecutor): try: self.marionette.set_script_timeout((timeout + extra_timeout) * 1000) - except IOError, marionette.errors.InvalidResponseException: + except IOError, errors.InvalidResponseException: self.logger.error("Lost marionette connection before starting test") return Stop try: result = self.convert_result(test, self.do_test(test, timeout)) - except marionette.errors.ScriptTimeoutException: + except errors.ScriptTimeoutException: with result_lock: if not result_flag.is_set(): result_flag.set() @@ -179,7 +181,7 @@ class MarionetteTestExecutor(TestExecutor): # else: # break # Now need to check if the browser is still responsive and restart it if not - except (socket.timeout, marionette.errors.InvalidResponseException, IOError): + except (socket.timeout, errors.InvalidResponseException, IOError): # This can happen on a crash # Also, should check after the test if the firefox process is still running # and otherwise ignore any other result and set it to crash @@ -250,7 +252,7 @@ class MarionetteReftestExecutor(MarionetteTestExecutor): full_url = urlparse.urljoin(self.http_server_url, url) try: self.marionette.navigate(full_url) - except marionette.errors.MarionetteException: + except errors.MarionetteException: return {"status": "ERROR", "message": "Failed to load url %s" % (full_url,)} if url_type == "test": diff --git a/testing/web-platform/harness/wptrunner/update/tree.py b/testing/web-platform/harness/wptrunner/update/tree.py index 7b01e30288d..292a45a4fe2 100644 --- a/testing/web-platform/harness/wptrunner/update/tree.py +++ b/testing/web-platform/harness/wptrunner/update/tree.py @@ -124,6 +124,13 @@ class HgTree(object): def commit_patch(self): self.hg("qfinish") + def contains_commit(self, commit): + try: + self.hg("identify", "-r", commit.sha1) + return True + except subprocess.CalledProcessError: + return False + class GitTree(object): name = "git" diff --git a/toolkit/modules/AddonWatcher.jsm b/toolkit/modules/AddonWatcher.jsm new file mode 100644 index 00000000000..d85016db596 --- /dev/null +++ b/toolkit/modules/AddonWatcher.jsm @@ -0,0 +1,96 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["AddonWatcher"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Preferences", + "resource://gre/modules/Preferences.jsm"); + +let AddonWatcher = { + _lastAddonTime: {}, + _timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer), + _callback: null, + _interval: 1500, + _ignoreList: null, + init: function(callback) { + if (!callback) { + return; + } + + if (this._callback) { + return; + } + + this._interval = Preferences.get("browser.addon-watch.interval", 15000); + if (this._interval == -1) { + return; + } + + this._callback = callback; + try { + this._ignoreList = new Set(JSON.parse(Preferences.get("browser.addon-watch.ignore", null))); + } catch (ex) { + // probably some malformed JSON, ignore and carry on + this._ignoreList = new Set(); + } + this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK); + }, + uninit: function() { + if (this._timer) { + this._timer.cancel(); + this._timer = null; + } + }, + _checkAddons: function() { + let compartmentInfo = Cc["@mozilla.org/compartment-info;1"] + .getService(Ci.nsICompartmentInfo); + let compartments = compartmentInfo.getCompartments(); + let count = compartments.length; + let addons = {}; + for (let i = 0; i < count; i++) { + let compartment = compartments.queryElementAt(i, Ci.nsICompartment); + if (compartment.addonId) { + if (addons[compartment.addonId]) { + addons[compartment.addonId] += compartment.time; + } else { + addons[compartment.addonId] = compartment.time; + } + } + } + let limit = this._interval * Preferences.get("browser.addon-watch.percentage-limit", 75) * 10; + for (let addonId in addons) { + if (!this._ignoreList.has(addonId)) { + if (!this._lastAddonTime[addonId]) { + this._lastAddonTime[addonId] = 0; + } + if ((addons[addonId] - this._lastAddonTime[addonId]) > limit) { + this._callback(addonId); + } + this._lastAddonTime[addonId] = addons[addonId]; + } + } + }, + ignoreAddonForSession: function(addonid) { + this._ignoreList.add(addonid); + }, + ignoreAddonPermanently: function(addonid) { + this._ignoreList.add(addonid); + try { + let ignoreList = JSON.parse(Preferences.get("browser.addon-watch.ignore", "[]")) + if (!ignoreList.includes(addonid)) { + ignoreList.push(addonid); + Preferences.set("browser.addon-watch.ignore", JSON.stringify(ignoreList)); + } + } catch (ex) { + Preferences.set("browser.addon-watch.ignore", JSON.stringify([addonid])); + } + } +}; diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 584778a7ccb..b6185800622 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -12,6 +12,7 @@ MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini'] SPHINX_TREES['toolkit_modules'] = 'docs' EXTRA_JS_MODULES += [ + 'AddonWatcher.jsm', 'Battery.jsm', 'BinarySearch.jsm', 'BrowserUtils.jsm', diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js index cced0c94b88..4746d02bfb7 100644 --- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -83,9 +83,20 @@ XPCOMUtils.defineLazyGetter(this, "gPref", function bls_gPref() { QueryInterface(Ci.nsIPrefBranch); }); +// From appinfo in Services.jsm. It is not possible to use the one in +// Services.jsm since it will not successfully QueryInterface nsIXULAppInfo in +// xpcshell tests due to other code calling Services.appinfo before the +// nsIXULAppInfo is created by the tests. XPCOMUtils.defineLazyGetter(this, "gApp", function bls_gApp() { - return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo). - QueryInterface(Ci.nsIXULRuntime); + let appinfo = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); + try { + appinfo.QueryInterface(Ci.nsIXULAppInfo); + } catch (ex if ex instanceof Components.Exception && + ex.result == Cr.NS_NOINTERFACE) { + // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). + } + return appinfo; }); XPCOMUtils.defineLazyGetter(this, "gABI", function bls_gABI() { @@ -396,6 +407,10 @@ Blocklist.prototype = { if (!gBlocklistEnabled) return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). + if (!appVersion && !gApp.version) + return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + if (!appVersion) appVersion = gApp.version; if (!toolkitVersion) @@ -529,9 +544,13 @@ Blocklist.prototype = { pingCountTotal = 1; dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID); - dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version); + // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). + if (gApp.version) + dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version); dsURI = dsURI.replace(/%PRODUCT%/g, gApp.name); - dsURI = dsURI.replace(/%VERSION%/g, gApp.version); + // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). + if (gApp.version) + dsURI = dsURI.replace(/%VERSION%/g, gApp.version); dsURI = dsURI.replace(/%BUILD_ID%/g, gApp.appBuildID); dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI); dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion); @@ -1048,6 +1067,10 @@ Blocklist.prototype = { if (!gBlocklistEnabled) return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't). + if (!appVersion && !gApp.version) + return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + if (!appVersion) appVersion = gApp.version; if (!toolkitVersion)