From 7e3cae8b2cc59b97b1c832ac7248ef46cd2bb5df Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 12 Oct 2015 22:10:10 -0700 Subject: [PATCH 01/79] Bug 1214051 - Reject NaN as a sampling probability, and test the floating point value range harder. r=jimb --- ...Memory-allocationSamplingProbability-01.js | 36 +++++++++++++++---- js/src/vm/DebuggerMemory.cpp | 3 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-01.js b/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-01.js index 32cce6de7c15..6575cfe7485f 100644 --- a/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-01.js +++ b/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-01.js @@ -8,14 +8,38 @@ const root = newGlobal(); const dbg = new Debugger(); const wrappedRoot = dbg.addDebuggee(root); -// Out of range. +var mem = dbg.memory; -assertThrowsInstanceOf(() => dbg.memory.allocationSamplingProbability = -1, +// Out of range, negative +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Number.MAX_VALUE, TypeError); -assertThrowsInstanceOf(() => dbg.memory.allocationSamplingProbability = 2, +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -1, + TypeError); +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Number.MIN_VALUE, TypeError); // In range -dbg.memory.allocationSamplingProbability = 0; -dbg.memory.allocationSamplingProbability = 1; -dbg.memory.allocationSamplingProbability = .5; +mem.allocationSamplingProbability = -0.0; +mem.allocationSamplingProbability = 0.0; +mem.allocationSamplingProbability = Number.MIN_VALUE; +mem.allocationSamplingProbability = 1 / 3; +mem.allocationSamplingProbability = .5; +mem.allocationSamplingProbability = 2 / 3; +mem.allocationSamplingProbability = 1 - Math.pow(2, -53); +mem.allocationSamplingProbability = 1; + +// Out of range, positive +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = 1 + Number.EPSILON, + TypeError); +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = 2, + TypeError); +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = Number.MAX_VALUE, + TypeError); + +// Out of range, non-finite +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = -Infinity, + TypeError); +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = Infinity, + TypeError); +assertThrowsInstanceOf(() => mem.allocationSamplingProbability = NaN, + TypeError); diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index e08b4da6e8f6..950c7524a4e4 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -307,7 +307,8 @@ DebuggerMemory::setAllocationSamplingProbability(JSContext* cx, unsigned argc, V if (!ToNumber(cx, args[0], &probability)) return false; - if (probability < 0.0 || probability > 1.0) { + // Careful! This must also reject NaN. + if (!(0.0 <= probability && probability <= 1.0)) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, "(set allocationSamplingProbability)'s parameter", "not a number between 0 and 1"); From 89fd3f53e8c7f76e1f0b201901af7869f2c9baa8 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 12 Oct 2015 23:09:42 -0700 Subject: [PATCH 02/79] Bug 1213574 - Fix up static scopes inside scripts wrt the static global lexical scope when merging parse task compartments. (r=jandem) --- js/src/jit-test/tests/bug1213574.js | 15 +++++++++++++++ js/src/jsgc.cpp | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 js/src/jit-test/tests/bug1213574.js diff --git a/js/src/jit-test/tests/bug1213574.js b/js/src/jit-test/tests/bug1213574.js new file mode 100644 index 000000000000..8761f8b0733d --- /dev/null +++ b/js/src/jit-test/tests/bug1213574.js @@ -0,0 +1,15 @@ +if (helperThreadCount() === 0) + quit(0); + +var lfGlobal = newGlobal(); +lfGlobal.offThreadCompileScript(`let (x) { throw 42; }`); +try { + lfGlobal.runOffThreadScript(); +} catch (e) { +} + +lfGlobal.offThreadCompileScript(`function f() { { let x = 42; return x; } }`); +try { + lfGlobal.runOffThreadScript(); +} catch (e) { +} diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8c480749edeb..4ed819e84249 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6740,6 +6740,11 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) // Fixup compartment pointers in source to refer to target, and make sure // type information generations are in sync. + // Get the static global lexical scope of the target compartment. Static + // scopes need to be fixed up below. + RootedObject targetStaticGlobalLexicalScope(rt); + targetStaticGlobalLexicalScope = &target->maybeGlobal()->lexicalScope().staticBlock(); + for (ZoneCellIter iter(source->zone(), AllocKind::SCRIPT); !iter.done(); iter.next()) { JSScript* script = iter.get(); MOZ_ASSERT(script->compartment() == source); @@ -6753,6 +6758,20 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) if (IsStaticGlobalLexicalScope(enclosing)) script->fixEnclosingStaticGlobalLexicalScope(); } + + if (script->hasBlockScopes()) { + BlockScopeArray* scopes = script->blockScopes(); + for (uint32_t i = 0; i < scopes->length; i++) { + uint32_t scopeIndex = scopes->vector[i].index; + if (scopeIndex != BlockScopeNote::NoBlockScopeIndex) { + ScopeObject* scope = &script->getObject(scopeIndex)->as(); + MOZ_ASSERT(!IsStaticGlobalLexicalScope(scope)); + JSObject* enclosing = &scope->enclosingScope(); + if (IsStaticGlobalLexicalScope(enclosing)) + scope->setEnclosingScope(targetStaticGlobalLexicalScope); + } + } + } } for (ZoneCellIter iter(source->zone(), AllocKind::BASE_SHAPE); !iter.done(); iter.next()) { From ecb26c53a902c2e0d38e48feac5c97ee88dad9a3 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 12 Oct 2015 23:09:42 -0700 Subject: [PATCH 03/79] Bug 1213552 - Fix typo in using TI to guard against introducing shadowing global lexical bindings. (r=efaust) --- js/src/jit/IonBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index ed140110a33d..add14822c223 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -8200,7 +8200,7 @@ IonBuilder::testGlobalLexicalBinding(PropertyName* name) HeapTypeSetKey lexicalProperty = lexicalKey->property(id); if (!obj->containsPure(name)) { Shape* shape = script()->global().lookupPure(name); - if (!shape || !shape->configurable()) + if (!shape || shape->configurable()) MOZ_ALWAYS_FALSE(lexicalProperty.isOwnProperty(constraints())); obj = &script()->global(); } From 5491f00db4725cea5e3e5743f8b2636ddbc1b1fc Mon Sep 17 00:00:00 2001 From: sajitk Date: Sun, 27 Sep 2015 17:16:00 +0200 Subject: [PATCH 04/79] Bug 996105 - Added tests for registry access. Fixed wrong condition in ReadStringValue code. r=bsmedberg --- xpcom/ds/nsWindowsRegKey.cpp | 2 +- xpcom/tests/unit/test_windows_registry.js | 205 ++++++++++++++++++++++ xpcom/tests/unit/xpcshell.ini | 2 + 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 xpcom/tests/unit/test_windows_registry.js diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp index e254dbda25a8..5ca46f1c7d96 100644 --- a/xpcom/ds/nsWindowsRegKey.cpp +++ b/xpcom/ds/nsWindowsRegKey.cpp @@ -310,7 +310,7 @@ nsWindowsRegKey::ReadStringValue(const nsAString& aName, nsAString& aResult) // This must be a string type in order to fetch the value as a string. // We're being a bit forgiving here by allowing types other than REG_SZ. - if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) { + if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) { return NS_ERROR_FAILURE; } diff --git a/xpcom/tests/unit/test_windows_registry.js b/xpcom/tests/unit/test_windows_registry.js new file mode 100644 index 000000000000..9a17678f830c --- /dev/null +++ b/xpcom/tests/unit/test_windows_registry.js @@ -0,0 +1,205 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const Cr = Components.results; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; +const CC = Components.Constructor; + +const nsIWindowsRegKey = Ci.nsIWindowsRegKey; +let regKeyComponent = Cc["@mozilla.org/windows-registry-key;1"]; + +function run_test() +{ + //* create a key structure in a spot that's normally writable (somewhere under HKCU). + let testKey = regKeyComponent.createInstance(nsIWindowsRegKey); + + // If it's already present because a previous test crashed or didn't clean up properly, clean it up first. + let keyName = BASE_PATH + "\\" + TESTDATA_KEYNAME; + setup_test_run(testKey, keyName); + + //* test that the write* functions write stuff + test_writing_functions(testKey); + + //* check that the valueCount/getValueName functions work for the values we just wrote + test_value_functions(testKey); + + //* check that the get* functions work for the values we just wrote. + test_reading_functions(testKey); + + //* check that the get* functions fail with the right exception codes if we ask for the wrong type or if the value name doesn't exist at all + test_invalidread_functions(testKey); + + //* check that creating/enumerating/deleting child keys works + test_childkey_functions(testKey); + + test_watching_functions(testKey); + + //* clean up + cleanup_test_run(testKey, keyName); +} + +function setup_test_run(testKey, keyName) +{ + do_print("Setup test run"); + try { + testKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_READ); + do_print("Test key exists. Needs cleanup."); + cleanup_test_run(testKey, keyName); + } + catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) + { + } + + testKey.create(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_ALL); +} + +function test_writing_functions(testKey) +{ + strictEqual(testKey.valueCount, 0); + + strictEqual(testKey.hasValue(TESTDATA_STRNAME), false); + testKey.writeStringValue(TESTDATA_STRNAME, TESTDATA_STRVALUE); + strictEqual(testKey.hasValue(TESTDATA_STRNAME), true); + + strictEqual(testKey.hasValue(TESTDATA_INTNAME), false); + testKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE); + + strictEqual(testKey.hasValue(TESTDATA_INT64NAME), false); + testKey.writeInt64Value(TESTDATA_INT64NAME, TESTDATA_INT64VALUE); + + strictEqual(testKey.hasValue(TESTDATA_BINARYNAME), false); + testKey.writeBinaryValue(TESTDATA_BINARYNAME, TESTDATA_BINARYVALUE); +} + +function test_value_functions(testKey) +{ + strictEqual(testKey.valueCount, 4); + strictEqual(testKey.getValueName(0), TESTDATA_STRNAME); + strictEqual(testKey.getValueName(1), TESTDATA_INTNAME); + strictEqual(testKey.getValueName(2), TESTDATA_INT64NAME); + strictEqual(testKey.getValueName(3), TESTDATA_BINARYNAME); +} + +function test_reading_functions(testKey) +{ + strictEqual(testKey.getValueType(TESTDATA_STRNAME), nsIWindowsRegKey.TYPE_STRING); + strictEqual(testKey.readStringValue(TESTDATA_STRNAME), TESTDATA_STRVALUE); + + strictEqual(testKey.getValueType(TESTDATA_INTNAME), nsIWindowsRegKey.TYPE_INT); + strictEqual(testKey.readIntValue(TESTDATA_INTNAME), TESTDATA_INTVALUE); + + strictEqual(testKey.getValueType(TESTDATA_INT64NAME), nsIWindowsRegKey.TYPE_INT64); + strictEqual( testKey.readInt64Value(TESTDATA_INT64NAME), TESTDATA_INT64VALUE); + + strictEqual(testKey.getValueType(TESTDATA_BINARYNAME), nsIWindowsRegKey.TYPE_BINARY); + strictEqual( testKey.readBinaryValue(TESTDATA_BINARYNAME), TESTDATA_BINARYVALUE); +} + +function test_invalidread_functions(testKey) +{ + try { + testKey.readIntValue(TESTDATA_STRNAME); + do_throw("Reading an integer from a string registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + let val = testKey.readStringValue(TESTDATA_INTNAME); + do_throw("Reading an string from an Int registry value should throw." + val); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + testKey.readStringValue(TESTDATA_INT64NAME); + do_throw("Reading an string from an Int64 registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + testKey.readStringValue(TESTDATA_BINARYNAME); + do_throw("Reading a string from an Binary registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + +} + +function test_childkey_functions(testKey) +{ + strictEqual(testKey.childCount, 0); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false); + + let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + childKey.close(); + + strictEqual(testKey.childCount, 1); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), true); + strictEqual(testKey.getChildName(0), TESTDATA_CHILD_KEY); + + childKey = testKey.openChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + testKey.removeChild(TESTDATA_CHILD_KEY); + strictEqual(testKey.childCount, 0); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false); +} + +function test_watching_functions(testKey) +{ + strictEqual(testKey.isWatching(), false); + strictEqual(testKey.hasChanged(), false); + + testKey.startWatching(true); + strictEqual(testKey.isWatching(), true); + + testKey.stopWatching(); + strictEqual(testKey.isWatching(), false); + + // Create a child key, and update a value + let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + childKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE); + + // Start a recursive watch, and update the child's value + testKey.startWatching(true); + strictEqual(testKey.isWatching(), true); + + childKey.writeIntValue(TESTDATA_INTNAME, 0); + strictEqual(testKey.hasChanged(), true); + testKey.stopWatching(); + strictEqual(testKey.isWatching(), false); + + childKey.removeValue(TESTDATA_INTNAME); + childKey.close(); + testKey.removeChild(TESTDATA_CHILD_KEY); +} + +function cleanup_test_run(testKey, keyName) +{ + do_print("Cleaning up test."); + + for (var i = 0; i < testKey.childCount; i++) { + testKey.removeChild(testKey.getChildName(i)); + } + testKey.close(); + + let baseKey = regKeyComponent.createInstance(nsIWindowsRegKey); + baseKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, BASE_PATH, nsIWindowsRegKey.ACCESS_ALL); + baseKey.removeChild(TESTDATA_KEYNAME); + baseKey.close(); +} + +// Test data used above. +const BASE_PATH = "SOFTWARE"; +const TESTDATA_KEYNAME = "TestRegXPC"; +const TESTDATA_STRNAME = "AString"; +const TESTDATA_STRVALUE = "The quick brown fox jumps over the lazy dog."; +const TESTDATA_INTNAME = "AnInteger"; +const TESTDATA_INTVALUE = 65536; +const TESTDATA_INT64NAME = "AnInt64"; +const TESTDATA_INT64VALUE = 9223372036854775807; +const TESTDATA_BINARYNAME = "ABinary"; +const TESTDATA_BINARYVALUE = "She sells seashells by the seashore"; +const TESTDATA_CHILD_KEY = "TestChildKey"; diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini index bf1b2b7e4172..25f12ddbcaf0 100644 --- a/xpcom/tests/unit/xpcshell.ini +++ b/xpcom/tests/unit/xpcshell.ini @@ -75,3 +75,5 @@ skip-if = os == "win" fail-if = os == "android" [test_file_renameTo.js] [test_notxpcom_scriptable.js] +skip-if = os != "win" +[test_windows_registry.js] From ca377ad7dbcca3a459e18c036adc25e04dc6210e Mon Sep 17 00:00:00 2001 From: Stephanie Ouillon Date: Mon, 12 Oct 2015 14:20:00 +0200 Subject: [PATCH 05/79] Bug 1201626 - Remove reference to kind attribute to calls to isExplicitInPermissionsTable(). r=fabrice --- dom/apps/AppsUtils.jsm | 2 +- dom/apps/PermissionsTable.jsm | 2 +- dom/apps/Webapps.jsm | 6 ++---- dom/permission/PermissionSettings.js | 3 +-- dom/permission/PermissionSettings.jsm | 6 +++--- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dom/apps/AppsUtils.jsm b/dom/apps/AppsUtils.jsm index 8cd8bba7b8d6..f33ee633a60d 100644 --- a/dom/apps/AppsUtils.jsm +++ b/dom/apps/AppsUtils.jsm @@ -295,7 +295,7 @@ this.AppsUtils = { for (let id in aApps) { let app = aApps[id]; if (app.localId == aLocalId) { - // Use the app kind and the app status to choose the right default CSP. + // Use the app status to choose the right default CSP. try { switch (app.appStatus) { case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: diff --git a/dom/apps/PermissionsTable.jsm b/dom/apps/PermissionsTable.jsm index 94e68dc678a1..1e42aa9a7b86 100644 --- a/dom/apps/PermissionsTable.jsm +++ b/dom/apps/PermissionsTable.jsm @@ -646,7 +646,7 @@ this.AllPossiblePermissions = []; AllPossiblePermissions.concat(["indexedDB", "offline-app", "pin-app"]); })(); -this.isExplicitInPermissionsTable = function(aPermName, aIntStatus, aAppKind) { +this.isExplicitInPermissionsTable = function(aPermName, aIntStatus) { // Check to see if the 'webapp' is app/privileged/certified. let appStatus; diff --git a/dom/apps/Webapps.jsm b/dom/apps/Webapps.jsm index dc5a219fa404..b33a79bd70b5 100644 --- a/dom/apps/Webapps.jsm +++ b/dom/apps/Webapps.jsm @@ -1937,8 +1937,7 @@ this.DOMApplicationRegistry = { PermissionsInstaller.installPermissions( { manifest: newManifest, origin: app.origin, - manifestURL: app.manifestURL, - kind: app.kind }, + manifestURL: app.manifestURL }, true); } this.updateDataStore(this.webapps[id].localId, app.origin, @@ -2382,8 +2381,7 @@ this.DOMApplicationRegistry = { PermissionsInstaller.installPermissions({ manifest: aApp.manifest, origin: aApp.origin, - manifestURL: aData.manifestURL, - kind: aApp.kind + manifestURL: aData.manifestURL }, true); } diff --git a/dom/permission/PermissionSettings.js b/dom/permission/PermissionSettings.js index 6e8d3adb4d7f..51b16ef5323d 100644 --- a/dom/permission/PermissionSettings.js +++ b/dom/permission/PermissionSettings.js @@ -71,8 +71,7 @@ PermissionSettings.prototype = { .createCodebasePrincipal(uri, {appId: app.localId, inBrowser: aBrowserFlag}); return isExplicitInPermissionsTable(aPermName, - principal.appStatus, - app.kind); + principal.appStatus); }, set: function set(aPermName, aPermValue, aManifestURL, aOrigin, diff --git a/dom/permission/PermissionSettings.jsm b/dom/permission/PermissionSettings.jsm index ddd3a19c45d1..038b28a28b60 100644 --- a/dom/permission/PermissionSettings.jsm +++ b/dom/permission/PermissionSettings.jsm @@ -35,7 +35,7 @@ this.PermissionSettingsModule = { }, - _isChangeAllowed: function(aPrincipal, aPermName, aAction, aAppKind) { + _isChangeAllowed: function(aPrincipal, aPermName, aAction) { // Bug 812289: // Change is allowed from a child process when all of the following // conditions stand true: @@ -50,7 +50,7 @@ this.PermissionSettingsModule = { // on permissionManager also but we currently don't. let perm = Services.perms.testExactPermissionFromPrincipal(aPrincipal,aPermName); - let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus, aAppKind); + let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus); return (aAction === "unknown" && aPrincipal.appStatus === Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) || @@ -106,7 +106,7 @@ this.PermissionSettingsModule = { } if (aAllowAllChanges || - this._isChangeAllowed(principal, aData.type, aData.value, app.kind)) { + this._isChangeAllowed(principal, aData.type, aData.value)) { debug("add: " + aData.origin + " " + app.localId + " " + action); Services.perms.addFromPrincipal(principal, aData.type, action); return true; From 5a246716d19b2e23d31f6ce7b6a3f7d38f7edd4f Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Mon, 12 Oct 2015 09:56:00 +0200 Subject: [PATCH 06/79] Bug 1210249 - don't mess with toplevel widget when client side decorations are enabled. r=karlt --- widget/gtk/nsWindow.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 9574c07bfa0f..e9df1ffb1365 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3462,6 +3462,7 @@ nsWindow::Create(nsIWidget *aParent, GtkWindow *topLevelParent = nullptr; nsWindow *parentnsWindow = nullptr; GtkWidget *eventWidget = nullptr; + bool shellHasCSD = false; if (aParent) { parentnsWindow = static_cast(aParent); @@ -3614,9 +3615,7 @@ nsWindow::Create(nsIWidget *aParent, GtkWidget *container = moz_container_new(); mContainer = MOZ_CONTAINER(container); -#if (MOZ_WIDGET_GTK == 2) - bool containerHasWindow = false; -#else +#if (MOZ_WIDGET_GTK == 3) // "csd" style is set when widget is realized so we need to call // it explicitly now. gtk_widget_realize(mShell); @@ -3624,16 +3623,16 @@ nsWindow::Create(nsIWidget *aParent, // We can't draw directly to top-level window when client side // decorations are enabled. We use container with GdkWindow instead. GtkStyleContext* style = gtk_widget_get_style_context(mShell); - bool containerHasWindow = gtk_style_context_has_class(style, "csd"); + shellHasCSD = gtk_style_context_has_class(style, "csd"); #endif - if (!containerHasWindow) { + if (!shellHasCSD) { // Use mShell's window for drawing and events. gtk_widget_set_has_window(container, FALSE); // Prevent GtkWindow from painting a background to flicker. gtk_widget_set_app_paintable(mShell, TRUE); } // Set up event widget - eventWidget = containerHasWindow ? container : mShell; + eventWidget = shellHasCSD ? container : mShell; gtk_widget_add_events(eventWidget, kEvents); gtk_container_add(GTK_CONTAINER(mShell), container); @@ -3782,7 +3781,8 @@ nsWindow::Create(nsIWidget *aParent, g_signal_connect(mContainer, "drag_data_received", G_CALLBACK(drag_data_received_event_cb), nullptr); - GtkWidget *widgets[] = { GTK_WIDGET(mContainer), mShell }; + GtkWidget *widgets[] = { GTK_WIDGET(mContainer), + !shellHasCSD ? mShell : nullptr }; for (size_t i = 0; i < ArrayLength(widgets) && widgets[i]; ++i) { // Visibility events are sent to the owning widget of the relevant // window but do not propagate to parent widgets so connect on From a0d6fcda4b97c97c9fef0d7c6fa39afa3285d01d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Wed, 7 Oct 2015 02:14:00 +0200 Subject: [PATCH 07/79] Bug 1211858 - Add a hint for the Restyle label when the id is unavailable. r=roc,benwa --- layout/base/RestyleManager.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 108f57c2c55e..2647a061d717 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -4346,20 +4346,16 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame, aSwappedStructOwners) { nsIContent* content = aFrame->GetContent(); - nsAutoCString idStr; + nsAutoCString localDescriptor; if (profiler_is_active() && content) { - nsIAtom* id = content->GetID(); - if (id) { - id->ToUTF8String(idStr); - } else { - idStr.AssignLiteral("?"); - } + std::string elemDesc = ToString(*content); + localDescriptor.Assign(elemDesc.c_str()); } PROFILER_LABEL_PRINTF("ElementRestyler", "ComputeStyleChangeFor", js::ProfileEntry::Category::CSS, content ? "Element: %s" : "%s", - content ? idStr.get() : ""); + content ? localDescriptor.get() : ""); if (aMinChange) { aChangeList->AppendChange(aFrame, content, aMinChange); } From 370bdbf483a423f9bdce06a3ba050ec3e3ee0c03 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Mon, 12 Oct 2015 23:49:23 +0200 Subject: [PATCH 08/79] Bug 1211871 - Backout bug 1142083. r=mcmanus --- netwerk/protocol/http/nsHttpChannel.cpp | 16 --------- netwerk/test/mochitests/empty.html | 16 --------- netwerk/test/mochitests/mochitest.ini | 4 --- netwerk/test/mochitests/redirect_idn.html | 0 .../mochitests/redirect_idn.html^headers^ | 3 -- .../test/mochitests/test_idn_redirect.html | 36 ------------------- 6 files changed, 75 deletions(-) delete mode 100644 netwerk/test/mochitests/empty.html delete mode 100644 netwerk/test/mochitests/redirect_idn.html delete mode 100644 netwerk/test/mochitests/redirect_idn.html^headers^ delete mode 100644 netwerk/test/mochitests/test_idn_redirect.html diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index c2eec7b3a977..c83ba7a9e13e 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -4609,22 +4609,6 @@ nsHttpChannel::AsyncProcessRedirection(uint32_t redirectType) return NS_ERROR_CORRUPTED_CONTENT; } - nsAutoCString redirectHost; - mRedirectURI->GetHost(redirectHost); - nsAutoCString currentHost; - mURI->GetHost(currentHost); - if (redirectHost != currentHost) { - // When redirecting to another domain, the target domain should not be - // percent encoded, as the URL parser does not yet support that - nsAutoCString unescapedHost; - if (NS_UnescapeURL(redirectHost.BeginReading(), redirectHost.Length(), - 0, unescapedHost)) { - if (IsUTF8(unescapedHost)) { - mRedirectURI->SetHost(unescapedHost); - } - } - } - if (mApplicationCache) { // if we are redirected to a different origin check if there is a fallback // cache entry to fall back to. we don't care about file strict diff --git a/netwerk/test/mochitests/empty.html b/netwerk/test/mochitests/empty.html deleted file mode 100644 index e60f5abdf489..000000000000 --- a/netwerk/test/mochitests/empty.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - This page does nothing. If the loading page managed to load this, the test - probably succeeded. - - diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini index 80d057e9de42..375679aa1f6e 100644 --- a/netwerk/test/mochitests/mochitest.ini +++ b/netwerk/test/mochitests/mochitest.ini @@ -7,9 +7,6 @@ support-files = rel_preconnect.sjs user_agent.sjs user_agent_update.sjs - redirect_idn.html^headers^ - redirect_idn.html - empty.html web_packaged_app.sjs signed_web_packaged_app.sjs @@ -25,7 +22,6 @@ skip-if = e10s [test_user_agent_updates_reset.html] [test_xhr_method_case.html] skip-if = e10s -[test_idn_redirect.html] [test_signed_web_packaged_app.html] skip-if = e10s || buildapp != 'browser' [test_web_packaged_app.html] diff --git a/netwerk/test/mochitests/redirect_idn.html b/netwerk/test/mochitests/redirect_idn.html deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/netwerk/test/mochitests/redirect_idn.html^headers^ b/netwerk/test/mochitests/redirect_idn.html^headers^ deleted file mode 100644 index 753f65db87f4..000000000000 --- a/netwerk/test/mochitests/redirect_idn.html^headers^ +++ /dev/null @@ -1,3 +0,0 @@ -HTTP 301 Moved Permanently -Location: http://exämple.test/tests/netwerk/test/mochitests/empty.html -X-Comment: Bug 1142083 - This is a redirect to http://exämple.test diff --git a/netwerk/test/mochitests/test_idn_redirect.html b/netwerk/test/mochitests/test_idn_redirect.html deleted file mode 100644 index b9a594cc568f..000000000000 --- a/netwerk/test/mochitests/test_idn_redirect.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Test for URI Manipulation - - - - - -
-
-
-
-
-

From 171c1567f651eb155fb5252ff98577f2f5f14b88 Mon Sep 17 00:00:00 2001
From: Ting-Yu Chou 
Date: Mon, 12 Oct 2015 10:50:54 +0800
Subject: [PATCH 09/79] Bug 1213719 - Back out bug 1170314 for duplicate
 functionality. r=smaug

---
 dom/base/Console.cpp | 21 ---------------------
 dom/base/Console.h   |  4 ----
 2 files changed, 25 deletions(-)

diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp
index e245da77f801..244f641809ff 100644
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -41,10 +41,6 @@
 #include "nsIWebNavigation.h"
 #include "nsIXPConnect.h"
 
-#ifdef MOZ_ENABLE_PROFILER_SPS
-#include "nsIProfiler.h"
-#endif
-
 // The maximum allowed number of concurrent timers per page.
 #define MAX_PAGE_TIMERS 10000
 
@@ -827,23 +823,6 @@ Console::TimeStamp(JSContext* aCx, const JS::Handle aData)
     return;
   }
 
-#ifdef MOZ_ENABLE_PROFILER_SPS
-  if (aData.isString() && NS_IsMainThread()) {
-    if (!mProfiler) {
-      mProfiler = do_GetService("@mozilla.org/tools/profiler;1");
-    }
-    if (mProfiler) {
-      bool active = false;
-      if (NS_SUCCEEDED(mProfiler->IsActive(&active)) && active) {
-        nsAutoJSString stringValue;
-        if (stringValue.init(aCx, aData)) {
-          mProfiler->AddMarker(NS_ConvertUTF16toUTF8(stringValue).get());
-        }
-      }
-    }
-  }
-#endif
-
   Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
 }
 
diff --git a/dom/base/Console.h b/dom/base/Console.h
index 4ef5fdb1a116..834d62f56d36 100644
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -20,7 +20,6 @@
 
 class nsIConsoleAPIStorage;
 class nsIPrincipal;
-class nsIProfiler;
 
 namespace mozilla {
 namespace dom {
@@ -205,9 +204,6 @@ private:
   nsCOMPtr mWindow;
   nsCOMPtr mStorage;
   nsRefPtr mSandbox;
-#ifdef MOZ_ENABLE_PROFILER_SPS
-  nsCOMPtr mProfiler;
-#endif
 
   nsDataHashtable mTimerRegistry;
   nsDataHashtable mCounterRegistry;

From 6eb995ca1dc18222112b48ce2a2213e9498e3861 Mon Sep 17 00:00:00 2001
From: Andrew Comminos 
Date: Thu, 8 Oct 2015 12:57:57 -0700
Subject: [PATCH 10/79] Bug 1187385 - Use GTK style padding for entry widgets.
 r=karlt

---
 widget/gtk/gtk3drawing.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/widget/gtk/gtk3drawing.c b/widget/gtk/gtk3drawing.c
index df8347a997d9..067d33b5aa00 100644
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -2703,6 +2703,11 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
         {
             ensure_entry_widget();
             style = gtk_widget_get_style_context(gEntryWidget);
+
+            // XXX: Subtract 1 pixel from the padding to account for the default
+            // padding in forms.css. See bug 1187385.
+            *left = *top = *right = *bottom = -1;
+            moz_gtk_add_style_padding(style, left, top, right, bottom);
             moz_gtk_add_style_border(style, left, top, right, bottom);
 
             return MOZ_GTK_SUCCESS;

From b408fe99efd7271deb6d3e915f96a3bc59ab09b4 Mon Sep 17 00:00:00 2001
From: Andrew Comminos 
Date: Sat, 10 Oct 2015 13:48:41 -0700
Subject: [PATCH 11/79] Bug 1187385 - Use -moz-appearance: none to ignore
 widget style padding in test_caretPositionFromPoint. r=karlt

---
 dom/base/test/test_caretPositionFromPoint.html | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/dom/base/test/test_caretPositionFromPoint.html b/dom/base/test/test_caretPositionFromPoint.html
index 05d31ab50484..076dadadebce 100644
--- a/dom/base/test/test_caretPositionFromPoint.html
+++ b/dom/base/test/test_caretPositionFromPoint.html
@@ -25,6 +25,10 @@
     #test5 {
       height: 100px;
     }
+
+    textarea, input {
+      -moz-appearance: none;
+    }
   
 
+  
+
+
+  
+
+

From 4b6346f4e0eb8b363ae37feca6530d9f293e47fc Mon Sep 17 00:00:00 2001
From: Aryeh Gregor 
Date: Tue, 13 Oct 2015 14:08:30 +0300
Subject: [PATCH 18/79] Bug 1213842 - :lang() should not fall back to HTTP
 headers if empty lang attribute is specified; r=bz

---
 dom/base/nsIContent.h                                    | 9 +++++----
 layout/style/nsCSSRuleProcessor.cpp                      | 3 +--
 .../global-attributes/the-lang-attribute-009.html.ini    | 5 -----
 .../global-attributes/the-lang-attribute-010.html.ini    | 5 -----
 4 files changed, 6 insertions(+), 16 deletions(-)
 delete mode 100644 testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-009.html.ini
 delete mode 100644 testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-010.html.ini

diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index a569d74c1be4..f30de1f18ce0 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -911,11 +911,11 @@ public:
   mozilla::dom::Element* GetEditingHost();
 
   /**
-   * Determing language. Look at the nearest ancestor element that has a lang
+   * Determining language. Look at the nearest ancestor element that has a lang
    * attribute in the XML namespace or is an HTML/SVG element and has a lang in
-   * no namespace attribute.
+   * no namespace attribute.  Returns false if no language was specified.
    */
-  void GetLang(nsAString& aResult) const {
+  bool GetLang(nsAString& aResult) const {
     for (const nsIContent* content = this; content; content = content->GetParent()) {
       if (content->GetAttrCount() > 0) {
         // xml:lang has precedence over lang on HTML elements (see
@@ -930,10 +930,11 @@ public:
         NS_ASSERTION(hasAttr || aResult.IsEmpty(),
                      "GetAttr that returns false should not make string non-empty");
         if (hasAttr) {
-          return;
+          return true;
         }
       }
     }
+    return false;
   }
 
   // Overloaded from nsINode
diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp
index e65dde741eb7..e4afc2b58a16 100644
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1884,8 +1884,7 @@ static bool SelectorMatches(Element* aElement,
           // from the parent we have to be prepared to look at all parent
           // nodes.  The language itself is encoded in the LANG attribute.
           nsAutoString language;
-          aElement->GetLang(language);
-          if (!language.IsEmpty()) {
+          if (aElement->GetLang(language)) {
             if (!nsStyleUtil::DashMatchCompare(language,
                                                nsDependentString(pseudoClass->u.mString),
                                                nsASCIICaseInsensitiveStringComparator())) {
diff --git a/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-009.html.ini b/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-009.html.ini
deleted file mode 100644
index b11ab7419510..000000000000
--- a/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-009.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[the-lang-attribute-009.html]
-  type: testharness
-  [If the HTTP header contains a language declaration but the html element uses an empty lang value, the UA will not recognize the language declared in the HTTP header.]
-    expected: FAIL
-
diff --git a/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-010.html.ini b/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-010.html.ini
deleted file mode 100644
index 0089342a432f..000000000000
--- a/testing/web-platform/meta/html/dom/elements/global-attributes/the-lang-attribute-010.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[the-lang-attribute-010.html]
-  type: testharness
-  [If the meta Content-Language element contains a language declaration but the html element uses an empty lang value, the UA will not recognize the language declared in the meta Content-Language element.]
-    expected: FAIL
-

From bb2d3f9b642d906acca531f3c112a2de7e288a18 Mon Sep 17 00:00:00 2001
From: Jan de Mooij 
Date: Tue, 13 Oct 2015 13:20:37 +0200
Subject: [PATCH 19/79] Bug 1209118 part 11 - Fix and simplify condition in
 GetPropertyIC::maybeDisable. r=efaust

---
 js/src/jit/IonCaches.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp
index 91b8e472ab90..94ac32a18818 100644
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2225,7 +2225,7 @@ GetPropertyIC::maybeDisable(bool emitted)
         return;
     }
 
-    if (!canAttachStub() || (stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES)) {
+    if (++failedUpdates_ > MAX_FAILED_UPDATES) {
         JitSpew(JitSpew_IonIC, "Disable inline cache");
         disable();
     }

From 8dc69260427ebb15f0edd60db07541ae3ff77430 Mon Sep 17 00:00:00 2001
From: JW Wang 
Date: Tue, 13 Oct 2015 15:28:50 +0800
Subject: [PATCH 20/79] Bug 1212723. Part 1 - don't share mBufferedState per
 bug 1212723 comment 6. r=jya.

---
 dom/media/webm/WebMReader.cpp | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp
index f9845f38af4b..d57ed2f423ca 100644
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -170,12 +170,7 @@ WebMReader::Shutdown()
 
 nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor)
 {
-  if (aCloneDonor) {
-    mBufferedState = static_cast(aCloneDonor)->mBufferedState;
-  } else {
-    mBufferedState = new WebMBufferedState;
-  }
-
+  mBufferedState = new WebMBufferedState;
   return NS_OK;
 }
 

From d3c9b0b0dfea5833ca57f9ed77f6f1f199a69bd5 Mon Sep 17 00:00:00 2001
From: JW Wang 
Date: Tue, 13 Oct 2015 15:28:57 +0800
Subject: [PATCH 21/79] Bug 1212723. Part 2 - remove unused argument
 aCloneDonor from MediaDecoderReader::Init(). r=jya.

---
 dom/media/MediaDecoderReader.h            | 2 +-
 dom/media/MediaDecoderStateMachine.cpp    | 8 +-------
 dom/media/MediaFormatReader.cpp           | 2 +-
 dom/media/MediaFormatReader.h             | 2 +-
 dom/media/android/AndroidMediaReader.cpp  | 5 -----
 dom/media/android/AndroidMediaReader.h    | 3 +--
 dom/media/apple/AppleMP3Reader.cpp        | 2 +-
 dom/media/apple/AppleMP3Reader.h          | 2 +-
 dom/media/directshow/DirectShowReader.cpp | 7 -------
 dom/media/directshow/DirectShowReader.h   | 2 --
 dom/media/gstreamer/GStreamerReader.cpp   | 2 +-
 dom/media/gstreamer/GStreamerReader.h     | 2 +-
 dom/media/ogg/OggReader.cpp               | 2 +-
 dom/media/ogg/OggReader.h                 | 2 +-
 dom/media/omx/MediaCodecReader.cpp        | 6 ------
 dom/media/omx/MediaCodecReader.h          | 4 ----
 dom/media/omx/MediaOmxReader.cpp          | 5 -----
 dom/media/omx/MediaOmxReader.h            | 2 --
 dom/media/raw/RawReader.cpp               | 5 -----
 dom/media/raw/RawReader.h                 | 1 -
 dom/media/wave/WaveReader.cpp             | 5 -----
 dom/media/wave/WaveReader.h               | 1 -
 dom/media/webaudio/MediaBufferDecoder.cpp | 2 +-
 dom/media/webm/WebMReader.cpp             | 2 +-
 dom/media/webm/WebMReader.h               | 2 +-
 25 files changed, 14 insertions(+), 64 deletions(-)

diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h
index 3e7fece364bf..909390c7e80d 100644
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -92,7 +92,7 @@ public:
 
   // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
   // on failure.
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0;
+  virtual nsresult Init() { return NS_OK; }
 
   // Release media resources they should be released in dormant state
   // The reader can be made usable again by calling ReadMetadata().
diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp
index 0c39b6c69add..36b45e71b4d4 100644
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1033,13 +1033,7 @@ bool MediaDecoderStateMachine::IsPlaying() const
 nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  MediaDecoderReader* cloneReader = nullptr;
-  if (aCloneDonor) {
-    cloneReader = aCloneDonor->mReader;
-  }
-
-  nsresult rv = mReader->Init(cloneReader);
+  nsresult rv = mReader->Init();
   NS_ENSURE_SUCCESS(rv, rv);
   ScheduleStateMachineCrossThread();
   return NS_OK;
diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp
index c1c1bb449d71..5855a8e74558 100644
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -166,7 +166,7 @@ MediaFormatReader::InitLayersBackendType()
 static bool sIsEMEEnabled = false;
 
 nsresult
-MediaFormatReader::Init(MediaDecoderReader* aCloneDonor)
+MediaFormatReader::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   PDMFactory::Init();
diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h
index d7dcb44b76ea..4a0d0d868dad 100644
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -29,7 +29,7 @@ public:
 
   virtual ~MediaFormatReader();
 
-  nsresult Init(MediaDecoderReader* aCloneDonor) override;
+  nsresult Init() override;
 
   size_t SizeOfVideoQueueInFrames() override;
   size_t SizeOfAudioQueueInFrames() override;
diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp
index 715d35100236..91f521e83096 100644
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -35,11 +35,6 @@ AndroidMediaReader::AndroidMediaReader(AbstractMediaDecoder *aDecoder,
 {
 }
 
-nsresult AndroidMediaReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
 nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo,
                                           MetadataTags** aTags)
 {
diff --git a/dom/media/android/AndroidMediaReader.h b/dom/media/android/AndroidMediaReader.h
index 3d3c8591edad..65dcd0ce33ba 100644
--- a/dom/media/android/AndroidMediaReader.h
+++ b/dom/media/android/AndroidMediaReader.h
@@ -12,7 +12,7 @@
 #include "ImageContainer.h"
 #include "nsAutoPtr.h"
 #include "mozilla/layers/SharedRGBImage.h"
- 
+
 #include "MPAPI.h"
 
 class nsACString;
@@ -42,7 +42,6 @@ public:
   AndroidMediaReader(AbstractMediaDecoder* aDecoder,
                      const nsACString& aContentType);
 
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor);
   virtual nsresult ResetDecode();
 
   virtual bool DecodeAudioData();
diff --git a/dom/media/apple/AppleMP3Reader.cpp b/dom/media/apple/AppleMP3Reader.cpp
index 1b27b6ac3806..e6889978c4ae 100644
--- a/dom/media/apple/AppleMP3Reader.cpp
+++ b/dom/media/apple/AppleMP3Reader.cpp
@@ -103,7 +103,7 @@ AppleMP3Reader::Read(uint32_t *aNumBytes, char *aData)
 }
 
 nsresult
-AppleMP3Reader::Init(MediaDecoderReader* aCloneDonor)
+AppleMP3Reader::Init()
 {
   AudioFileTypeID fileType = kAudioFileMP3Type;
 
diff --git a/dom/media/apple/AppleMP3Reader.h b/dom/media/apple/AppleMP3Reader.h
index c5e704ac9c4a..5d3e559fc6d6 100644
--- a/dom/media/apple/AppleMP3Reader.h
+++ b/dom/media/apple/AppleMP3Reader.h
@@ -20,7 +20,7 @@ public:
   explicit AppleMP3Reader(AbstractMediaDecoder *aDecoder);
   virtual ~AppleMP3Reader() override;
 
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
+  virtual nsresult Init() override;
 
   nsresult PushDataToDemuxer();
 
diff --git a/dom/media/directshow/DirectShowReader.cpp b/dom/media/directshow/DirectShowReader.cpp
index 1270e92c6602..9756460183b1 100644
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -56,13 +56,6 @@ DirectShowReader::~DirectShowReader()
 #endif
 }
 
-nsresult
-DirectShowReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-  return NS_OK;
-}
-
 // Try to parse the MP3 stream to make sure this is indeed an MP3, get the
 // estimated duration of the stream, and find the offset of the actual MP3
 // frames in the stream, as DirectShow doesn't like large ID3 sections.
diff --git a/dom/media/directshow/DirectShowReader.h b/dom/media/directshow/DirectShowReader.h
index b95b029650f8..c9423f5856fd 100644
--- a/dom/media/directshow/DirectShowReader.h
+++ b/dom/media/directshow/DirectShowReader.h
@@ -43,8 +43,6 @@ public:
 
   virtual ~DirectShowReader();
 
-  nsresult Init(MediaDecoderReader* aCloneDonor) override;
-
   bool DecodeAudioData() override;
   bool DecodeVideoFrame(bool &aKeyframeSkip,
                         int64_t aTimeThreshold) override;
diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp
index 3514c97b7284..6ffe9ff4fe2e 100644
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -115,7 +115,7 @@ GStreamerReader::~GStreamerReader()
   NS_ASSERTION(!mPlayBin, "No Shutdown() after Init()");
 }
 
-nsresult GStreamerReader::Init(MediaDecoderReader* aCloneDonor)
+nsresult GStreamerReader::Init()
 {
   GStreamerFormatHelper::Instance();
 
diff --git a/dom/media/gstreamer/GStreamerReader.h b/dom/media/gstreamer/GStreamerReader.h
index 0bc606dfeca2..44f687972675 100644
--- a/dom/media/gstreamer/GStreamerReader.h
+++ b/dom/media/gstreamer/GStreamerReader.h
@@ -40,7 +40,7 @@ public:
   explicit GStreamerReader(AbstractMediaDecoder* aDecoder);
   virtual ~GStreamerReader();
 
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
+  virtual nsresult Init() override;
   virtual nsRefPtr Shutdown() override;
   virtual nsresult ResetDecode() override;
   virtual bool DecodeAudioData() override;
diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp
index 9265f3abaecf..9add93c9fd66 100644
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -152,7 +152,7 @@ OggReader::~OggReader()
   MOZ_COUNT_DTOR(OggReader);
 }
 
-nsresult OggReader::Init(MediaDecoderReader* aCloneDonor) {
+nsresult OggReader::Init() {
   int ret = ogg_sync_init(&mOggState);
   NS_ENSURE_TRUE(ret == 0, NS_ERROR_FAILURE);
   return NS_OK;
diff --git a/dom/media/ogg/OggReader.h b/dom/media/ogg/OggReader.h
index 2fa8564ed43a..e99a36a73d0a 100644
--- a/dom/media/ogg/OggReader.h
+++ b/dom/media/ogg/OggReader.h
@@ -50,7 +50,7 @@ protected:
   ~OggReader();
 
 public:
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
+  virtual nsresult Init() override;
   virtual nsresult ResetDecode() override;
   virtual bool DecodeAudioData() override;
 
diff --git a/dom/media/omx/MediaCodecReader.cpp b/dom/media/omx/MediaCodecReader.cpp
index 7a98a4e96d4a..42da43bcc61c 100644
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -283,12 +283,6 @@ MediaCodecReader::~MediaCodecReader()
 {
 }
 
-nsresult
-MediaCodecReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
 void
 MediaCodecReader::ReleaseMediaResources()
 {
diff --git a/dom/media/omx/MediaCodecReader.h b/dom/media/omx/MediaCodecReader.h
index 2199b96116e1..fb67cf1f0567 100644
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -60,10 +60,6 @@ public:
   MediaCodecReader(AbstractMediaDecoder* aDecoder);
   virtual ~MediaCodecReader();
 
-  // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
-  // on failure.
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor);
-
   // Release media resources they should be released in dormant state
   virtual void ReleaseMediaResources();
 
diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp
index 155309a3a2d9..202896342866 100644
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -135,11 +135,6 @@ MediaOmxReader::~MediaOmxReader()
 {
 }
 
-nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
 already_AddRefed
 MediaOmxReader::SafeGetDecoder() {
   nsRefPtr decoder;
diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h
index 6782b922947f..85b7d37403ac 100644
--- a/dom/media/omx/MediaOmxReader.h
+++ b/dom/media/omx/MediaOmxReader.h
@@ -70,8 +70,6 @@ public:
   MediaOmxReader(AbstractMediaDecoder* aDecoder);
   ~MediaOmxReader();
 
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor);
-
 protected:
   virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
 public:
diff --git a/dom/media/raw/RawReader.cpp b/dom/media/raw/RawReader.cpp
index c0f85f7b2e57..e932ce16e6de 100644
--- a/dom/media/raw/RawReader.cpp
+++ b/dom/media/raw/RawReader.cpp
@@ -26,11 +26,6 @@ RawReader::~RawReader()
   MOZ_COUNT_DTOR(RawReader);
 }
 
-nsresult RawReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
 nsresult RawReader::ResetDecode()
 {
   mCurrentFrame = 0;
diff --git a/dom/media/raw/RawReader.h b/dom/media/raw/RawReader.h
index 130412e1d4ff..cef642f549ee 100644
--- a/dom/media/raw/RawReader.h
+++ b/dom/media/raw/RawReader.h
@@ -20,7 +20,6 @@ protected:
   ~RawReader();
 
 public:
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
   virtual nsresult ResetDecode() override;
   virtual bool DecodeAudioData() override;
 
diff --git a/dom/media/wave/WaveReader.cpp b/dom/media/wave/WaveReader.cpp
index f3501beeef77..080c056c9b9f 100644
--- a/dom/media/wave/WaveReader.cpp
+++ b/dom/media/wave/WaveReader.cpp
@@ -116,11 +116,6 @@ WaveReader::~WaveReader()
   MOZ_COUNT_DTOR(WaveReader);
 }
 
-nsresult WaveReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
 nsresult WaveReader::ReadMetadata(MediaInfo* aInfo,
                                   MetadataTags** aTags)
 {
diff --git a/dom/media/wave/WaveReader.h b/dom/media/wave/WaveReader.h
index e390418234ad..4d5ac3db7ec9 100644
--- a/dom/media/wave/WaveReader.h
+++ b/dom/media/wave/WaveReader.h
@@ -22,7 +22,6 @@ protected:
   ~WaveReader();
 
 public:
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
   virtual bool DecodeAudioData() override;
   virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
                                   int64_t aTimeThreshold) override;
diff --git a/dom/media/webaudio/MediaBufferDecoder.cpp b/dom/media/webaudio/MediaBufferDecoder.cpp
index 3cabfc1186e5..a00437bed620 100644
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -206,7 +206,7 @@ MediaDecodeTask::CreateReader()
     return false;
   }
 
-  nsresult rv = mDecoderReader->Init(nullptr);
+  nsresult rv = mDecoderReader->Init();
   if (NS_FAILED(rv)) {
     return false;
   }
diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp
index d57ed2f423ca..cddf70074570 100644
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -168,7 +168,7 @@ WebMReader::Shutdown()
   return MediaDecoderReader::Shutdown();
 }
 
-nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor)
+nsresult WebMReader::Init()
 {
   mBufferedState = new WebMBufferedState;
   return NS_OK;
diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h
index 53369f71f964..ea3289bbeb7e 100644
--- a/dom/media/webm/WebMReader.h
+++ b/dom/media/webm/WebMReader.h
@@ -70,7 +70,7 @@ protected:
 
 public:
   virtual nsRefPtr Shutdown() override;
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
+  virtual nsresult Init() override;
   virtual nsresult ResetDecode() override;
   virtual bool DecodeAudioData() override;
 

From 0c40104171c377b082374fdbc341eb9b1701d455 Mon Sep 17 00:00:00 2001
From: Gian-Carlo Pascutto 
Date: Tue, 13 Oct 2015 13:58:44 +0200
Subject: [PATCH 22/79] Bug 1209987 - webrtc.org Engine creation and
 destruction should happen on the WebRTC threads. r=jesup

---
 dom/media/systemservices/CamerasParent.cpp | 386 +++++++++++----------
 dom/media/systemservices/CamerasParent.h   |  25 +-
 2 files changed, 219 insertions(+), 192 deletions(-)

diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp
index f77635f02273..a7584df9d22f 100644
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -14,6 +14,7 @@
 #include "mozilla/Logging.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "nsThreadUtils.h"
+#include "nsXPCOM.h"
 
 #undef LOG
 #undef LOG_ENABLED
@@ -142,6 +143,79 @@ private:
   int mResult;
 };
 
+NS_IMPL_ISUPPORTS(CamerasParent, nsIObserver)
+
+NS_IMETHODIMP
+CamerasParent::Observe(nsISupports *aSubject,
+                       const char *aTopic,
+                       const char16_t *aData)
+{
+  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
+  nsCOMPtr obs = services::GetObserverService();
+  MOZ_ASSERT(obs);
+  obs->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
+  StopVideoCapture();
+  return NS_OK;
+}
+
+nsresult
+CamerasParent::DispatchToVideoCaptureThread(nsRunnable *event)
+{
+  MonitorAutoLock lock(mThreadMonitor);
+
+  while(mChildIsAlive && mWebRTCAlive &&
+        (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning())) {
+    mThreadMonitor.Wait();
+  }
+  if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) {
+    return NS_ERROR_FAILURE;
+  }
+  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE,
+                                                new RunnableTask(event));
+  return NS_OK;
+}
+
+void
+CamerasParent::StopVideoCapture()
+{
+  // We are called from the main thread (xpcom-shutdown) or
+  // from PBackground (when the Actor shuts down).
+  // Shut down the WebRTC stack (on the capture thread)
+  nsRefPtr self(this);
+  nsRefPtr webrtc_runnable =
+    media::NewRunnableFrom([self]() -> nsresult {
+        MonitorAutoLock lock(self->mThreadMonitor);
+        self->CloseEngines();
+        self->mThreadMonitor.NotifyAll();
+        return NS_OK;
+      });
+  DispatchToVideoCaptureThread(webrtc_runnable);
+  // Hold here until the WebRTC thread is gone. We need to dispatch
+  // the thread deletion *now*, or there will be no more possibility
+  // to get to the main thread.
+  MonitorAutoLock lock(mThreadMonitor);
+  while (mWebRTCAlive) {
+    mThreadMonitor.Wait();
+  }
+  // After closing the WebRTC stack, clean up the
+  // VideoCapture thread.
+  if (self->mVideoCaptureThread) {
+    base::Thread *thread = self->mVideoCaptureThread;
+    self->mVideoCaptureThread = nullptr;
+    nsRefPtr threadShutdown =
+      media::NewRunnableFrom([thread]() -> nsresult {
+        if (thread->IsRunning()) {
+          thread->Stop();
+        }
+        delete thread;
+        return NS_OK;
+      });
+    if (NS_FAILED(NS_DispatchToMainThread(threadShutdown))) {
+      LOG(("Could not dispatch VideoCaptureThread destruction"));
+    }
+  }
+}
+
 int
 CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
                                    int cap_id,
@@ -235,6 +309,7 @@ CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) {
 bool
 CamerasParent::SetupEngine(CaptureEngine aCapEngine)
 {
+  MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
   EngineHelper *helper = &mEngines[aCapEngine];
 
   // Already initialized
@@ -308,51 +383,57 @@ CamerasParent::SetupEngine(CaptureEngine aCapEngine)
 void
 CamerasParent::CloseEngines()
 {
-  {
-    MutexAutoLock lock(mCallbackMutex);
-    // Stop the callers
-    while (mCallbacks.Length()) {
-      auto capEngine = mCallbacks[0]->mCapEngine;
-      auto capNum = mCallbacks[0]->mCapturerId;
-      LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum));
-      {
-        MutexAutoUnlock unlock(mCallbackMutex);
-        RecvStopCapture(capEngine, capNum);
-        RecvReleaseCaptureDevice(capEngine, capNum);
-      }
-      // The callbacks list might have changed while we released the lock,
-      // but note that due to the loop construct this will not break us.
+  if (!mWebRTCAlive) {
+    return;
+  }
+  MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
+
+  // Stop the callers
+  while (mCallbacks.Length()) {
+    auto capEngine = mCallbacks[0]->mCapEngine;
+    auto capNum = mCallbacks[0]->mCapturerId;
+    LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum));
+    RecvStopCapture(capEngine, capNum);
+    RecvReleaseCaptureDevice(capEngine, capNum);
+  }
+
+  for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
+    if (mEngines[i].mEngineIsRunning) {
+      LOG(("Being closed down while engine %d is running!", i));
+    }
+    if (mEngines[i].mPtrViERender) {
+      mEngines[i].mPtrViERender->Release();
+      mEngines[i].mPtrViERender = nullptr;
+    }
+    if (mEngines[i].mPtrViECapture) {
+      mEngines[i].mPtrViECapture->Release();
+        mEngines[i].mPtrViECapture = nullptr;
+    }
+    if(mEngines[i].mPtrViEBase) {
+      mEngines[i].mPtrViEBase->Release();
+      mEngines[i].mPtrViEBase = nullptr;
+    }
+    if (mEngines[i].mEngine) {
+      mEngines[i].mEngine->SetTraceCallback(nullptr);
+      webrtc::VideoEngine::Delete(mEngines[i].mEngine);
+      mEngines[i].mEngine = nullptr;
     }
   }
 
-  {
-    MutexAutoLock lock(mEngineMutex);
-    for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
-      if (mEngines[i].mEngineIsRunning) {
-        LOG(("Being closed down while engine %d is running!", i));
-      }
-      if (mEngines[i].mPtrViERender) {
-        mEngines[i].mPtrViERender->Release();
-        mEngines[i].mPtrViERender = nullptr;
-      }
-      if (mEngines[i].mPtrViECapture) {
-        mEngines[i].mPtrViECapture->Release();
-        mEngines[i].mPtrViECapture = nullptr;
-      }
-      if(mEngines[i].mPtrViEBase) {
-        mEngines[i].mPtrViEBase->Release();
-        mEngines[i].mPtrViEBase = nullptr;
-      }
-    }
-  }
+  mWebRTCAlive = false;
 }
 
 bool
 CamerasParent::EnsureInitialized(int aEngine)
 {
   LOG((__PRETTY_FUNCTION__));
+  // We're shutting down, don't try to do new WebRTC ops.
+  if (!mWebRTCAlive) {
+    return false;
+  }
   CaptureEngine capEngine = static_cast(aEngine);
   if (!SetupEngine(capEngine)) {
+    LOG(("CamerasParent failed to initialize engine"));
     return false;
   }
 
@@ -368,18 +449,12 @@ bool
 CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("RecvNumberOfCaptureDevices fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, aCapEngine]() -> nsresult {
-      MutexAutoLock lock(self->mEngineMutex);
       int num = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
+      if (self->EnsureInitialized(aCapEngine)) {
         num = self->mEngines[aCapEngine].mPtrViECapture->NumberOfCaptureDevices();
       }
       nsRefPtr ipc_runnable =
@@ -400,8 +475,7 @@ CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine)
         self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
-
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -410,19 +484,13 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine,
                                         const nsCString& unique_id)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("RecvNumberOfCapabilities fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
-
   LOG(("Getting caps for %s", unique_id.get()));
+
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult {
-      MutexAutoLock lock(self->mEngineMutex);
       int num = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
+      if (self->EnsureInitialized(aCapEngine)) {
         num =
           self->mEngines[aCapEngine].mPtrViECapture->NumberOfCapabilities(
             unique_id.get(),
@@ -446,7 +514,7 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -456,21 +524,14 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine,
                                         const int& num)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
-
   LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num));
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult {
       webrtc::CaptureCapability webrtcCaps;
-      MutexAutoLock lock(self->mEngineMutex);
       int error = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
+      if (self->EnsureInitialized(aCapEngine)) {
         error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureCapability(
           unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, num, webrtcCaps);
       }
@@ -503,7 +564,7 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -512,13 +573,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
                                     const int& aListNumber)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
 
-  LOG(("RecvGetCaptureDevice"));
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult {
@@ -526,20 +581,18 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
       char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
       nsCString name;
       nsCString uniqueId;
-      MutexAutoLock lock(self->mEngineMutex);
       int error = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
-        error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber,
-                                                                            deviceName,
-                                                                            sizeof(deviceName),
-                                                                            deviceUniqueId,
-                                                                            sizeof(deviceUniqueId));
+      if (self->EnsureInitialized(aCapEngine)) {
+          error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber,
+                                                                              deviceName,
+                                                                              sizeof(deviceName),
+                                                                              deviceUniqueId,
+                                                                              sizeof(deviceUniqueId));
       }
       if (!error) {
         name.Assign(deviceName);
         uniqueId.Assign(deviceUniqueId);
       }
-
       nsRefPtr ipc_runnable =
         media::NewRunnableFrom([self, error, name, uniqueId]() -> nsresult {
           if (self->IsShuttingDown()) {
@@ -558,7 +611,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -567,19 +620,13 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
                                          const nsCString& unique_id)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, aCapEngine, unique_id]() -> nsresult {
       int numdev = -1;
-      MutexAutoLock lock(self->mEngineMutex);
       int error = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
+      if (self->EnsureInitialized(aCapEngine)) {
         error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
           unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
       }
@@ -600,7 +647,7 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -609,19 +656,13 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine,
                                         const int& numdev)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Fails to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
+  LOG(("RecvReleaseCamera device nr %d", numdev));
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult {
-      LOG(("RecvReleaseCamera device nr %d", numdev));
-      MutexAutoLock lock(self->mEngineMutex);
       int error = -1;
-      if (self->mEngines[aCapEngine].mPtrViECapture) {
+      if (self->EnsureInitialized(aCapEngine)) {
         error = self->mEngines[aCapEngine].mPtrViECapture->ReleaseCaptureDevice(numdev);
       }
       nsRefPtr ipc_runnable =
@@ -641,12 +682,7 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-#ifndef XP_MACOSX
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
-#else
-  // Mac OS X hangs on shutdown if we don't do this on the main thread.
-  NS_DispatchToMainThread(webrtc_runnable);
-#endif
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -656,11 +692,6 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
                                 const CaptureCapability& ipcCaps)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Failure to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
@@ -668,23 +699,15 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
       CallbackHelper** cbh;
       webrtc::ExternalRenderer* render;
       EngineHelper* helper = nullptr;
-      int error;
-      {
-        MutexAutoLock lockCallback(self->mCallbackMutex);
+      int error = -1;
+      if (self->EnsureInitialized(aCapEngine)) {
         cbh = self->mCallbacks.AppendElement(
           new CallbackHelper(static_cast(aCapEngine), capnum, self));
         render = static_cast(*cbh);
-      }
-      {
-        MutexAutoLock lockEngine(self->mEngineMutex);
-        if (self->mEngines[aCapEngine].mPtrViECapture) {
-          helper = &self->mEngines[aCapEngine];
-          error =
-            helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render);
-        } else {
-          error = -1;
-        }
 
+        helper = &self->mEngines[aCapEngine];
+        error =
+          helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render);
         if (!error) {
           error = helper->mPtrViERender->StartRender(capnum);
         }
@@ -705,7 +728,6 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
           helper->mEngineIsRunning = true;
         }
       }
-
       nsRefPtr ipc_runnable =
         media::NewRunnableFrom([self, error]() -> nsresult {
           if (self->IsShuttingDown()) {
@@ -722,7 +744,7 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
+  DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
@@ -731,40 +753,32 @@ CamerasParent::RecvStopCapture(const int& aCapEngine,
                                const int& capnum)
 {
   LOG((__PRETTY_FUNCTION__));
-  if (!EnsureInitialized(aCapEngine)) {
-    LOG(("Failure to initialize"));
-    unused << SendReplyFailure();
-    return false;
-  }
 
   nsRefPtr self(this);
   nsRefPtr webrtc_runnable =
     media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult {
-      {
-        MutexAutoLock lock(self->mEngineMutex);
-        // We only need to check mPtrViECapture as all other engines are guaranteed
-        // to be nulled under the same lock.
-        if (self->mEngines[aCapEngine].mPtrViECapture) {
-          self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum);
-          self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum);
-          self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum);
-          self->mEngines[aCapEngine].mEngineIsRunning = false;
-        }
-      }
-      MutexAutoLock lock(self->mCallbackMutex);
-      for (unsigned int i = 0; i < self->mCallbacks.Length(); i++) {
-        if (self->mCallbacks[i]->mCapEngine == aCapEngine
-            && self->mCallbacks[i]->mCapturerId == capnum) {
-          delete self->mCallbacks[i];
-          self->mCallbacks.RemoveElementAt(i);
-          break;
+      if (self->EnsureInitialized(aCapEngine)) {
+        self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum);
+        self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum);
+        self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum);
+        self->mEngines[aCapEngine].mEngineIsRunning = false;
+
+        for (size_t i = 0; i < self->mCallbacks.Length(); i++) {
+          if (self->mCallbacks[i]->mCapEngine == aCapEngine
+              && self->mCallbacks[i]->mCapturerId == capnum) {
+            delete self->mCallbacks[i];
+            self->mCallbacks.RemoveElementAt(i);
+            break;
+          }
         }
       }
       return NS_OK;
     });
-
-  mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
-  return SendReplySuccess();
+  if (NS_SUCCEEDED(DispatchToVideoCaptureThread(webrtc_runnable))) {
+    return SendReplySuccess();
+  } else {
+    return SendReplyFailure();
+  }
 }
 
 void
@@ -788,49 +802,24 @@ CamerasParent::RecvAllDone()
   return Send__delete__(this);
 }
 
-void CamerasParent::DoShutdown()
-{
-  LOG((__PRETTY_FUNCTION__));
-  CloseEngines();
-
-  {
-    MutexAutoLock lock(mEngineMutex);
-    for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
-      if (mEngines[i].mEngine) {
-        mEngines[i].mEngine->SetTraceCallback(nullptr);
-        webrtc::VideoEngine::Delete(mEngines[i].mEngine);
-        mEngines[i].mEngine = nullptr;
-      }
-    }
-  }
-
-  mPBackgroundThread = nullptr;
-
-  if (mVideoCaptureThread) {
-    if (mVideoCaptureThread->IsRunning()) {
-      mVideoCaptureThread->Stop();
-    }
-    delete mVideoCaptureThread;
-    mVideoCaptureThread = nullptr;
-  }
-}
-
 void
 CamerasParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // No more IPC from here
   LOG((__PRETTY_FUNCTION__));
   StopIPC();
-  CloseEngines();
+  // Shut down WebRTC (if we're not in full shutdown, else this
+  // will already have happened)
+  StopVideoCapture();
 }
 
 CamerasParent::CamerasParent()
-  : mCallbackMutex("CamerasParent.mCallbackMutex"),
-    mEngineMutex("CamerasParent.mEngineMutex"),
-    mShmemPool(CaptureEngine::MaxEngine),
+  : mShmemPool(CaptureEngine::MaxEngine),
+    mThreadMonitor("CamerasParent::mThreadMonitor"),
     mVideoCaptureThread(nullptr),
     mChildIsAlive(true),
-    mDestroyed(false)
+    mDestroyed(false),
+    mWebRTCAlive(true)
 {
   if (!gCamerasParentLog) {
     gCamerasParentLog = PR_NewLogModule("CamerasParent");
@@ -841,16 +830,37 @@ CamerasParent::CamerasParent()
   MOZ_ASSERT(mPBackgroundThread != nullptr, "GetCurrentThread failed");
 
   LOG(("Spinning up WebRTC Cameras Thread"));
-  mVideoCaptureThread = new base::Thread("VideoCapture");
-  base::Thread::Options options;
+
+  nsRefPtr self(this);
+  nsRefPtr threadStart =
+    media::NewRunnableFrom([self]() -> nsresult {
+      // Register thread shutdown observer
+      nsCOMPtr obs = services::GetObserverService();
+      if (NS_WARN_IF(!obs)) {
+        return NS_ERROR_FAILURE;
+      }
+      nsresult rv =
+        obs->AddObserver(self, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      // Start the thread
+      MonitorAutoLock lock(self->mThreadMonitor);
+      self->mVideoCaptureThread = new base::Thread("VideoCapture");
+      base::Thread::Options options;
 #if defined(_WIN32)
-  options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
+      options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
 #else
-  options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
+
+      options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
 #endif
-  if (!mVideoCaptureThread->StartWithOptions(options)) {
-    MOZ_CRASH();
-  }
+      if (!self->mVideoCaptureThread->StartWithOptions(options)) {
+        MOZ_CRASH();
+      }
+      self->mThreadMonitor.NotifyAll();
+      return NS_OK;
+    });
+  NS_DispatchToMainThread(threadStart);
 
   MOZ_COUNT_CTOR(CamerasParent);
 }
@@ -860,7 +870,15 @@ CamerasParent::~CamerasParent()
   LOG(("~CamerasParent: %p", this));
 
   MOZ_COUNT_DTOR(CamerasParent);
-  DoShutdown();
+#ifdef DEBUG
+  // Verify we have shut down the webrtc engines, this is
+  // supposed to happen in ActorDestroy.
+  // That runnable takes a ref to us, so it must have finished
+  // by the time we get here.
+  for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
+    MOZ_ASSERT(!mEngines[i].mEngine);
+  }
+#endif
 }
 
 already_AddRefed
diff --git a/dom/media/systemservices/CamerasParent.h b/dom/media/systemservices/CamerasParent.h
index dfdd2d2d6abc..db08834fff0a 100644
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -7,10 +7,12 @@
 #ifndef mozilla_CamerasParent_h
 #define mozilla_CamerasParent_h
 
+#include "nsIObserver.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/camera/PCamerasParent.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ShmemPool.h"
+#include "mozilla/Atomics.h"
 
 // conflicts with #include of scoped_ptr.h
 #undef FF
@@ -73,9 +75,11 @@ public:
   bool mEngineIsRunning;
 };
 
-class CamerasParent :  public PCamerasParent
+class CamerasParent :  public PCamerasParent,
+                       public nsIObserver
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CamerasParent);
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOBSERVER
 
 public:
   static already_AddRefed Create();
@@ -94,7 +98,9 @@ public:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   nsIThread* GetBackgroundThread() { return mPBackgroundThread; };
-  bool IsShuttingDown() { return !mChildIsAlive || mDestroyed; };
+  bool IsShuttingDown() { return !mChildIsAlive
+                              ||  mDestroyed
+                              || !mWebRTCAlive; };
   ShmemBuffer GetBuffer(size_t aSize);
 
   // helper to forward to the PBackground thread
@@ -116,15 +122,12 @@ protected:
   bool SetupEngine(CaptureEngine aCapEngine);
   void CloseEngines();
   bool EnsureInitialized(int aEngine);
-  void DoShutdown();
   void StopIPC();
+  void StopVideoCapture();
+  nsresult DispatchToVideoCaptureThread(nsRunnable *event);
 
   EngineHelper mEngines[CaptureEngine::MaxEngine];
   nsTArray mCallbacks;
-  // Protects the callback arrays
-  Mutex mCallbackMutex;
-  // Protects the engines array
-  Mutex mEngineMutex;
 
   // image buffers
   mozilla::ShmemPool mShmemPool;
@@ -132,12 +135,18 @@ protected:
   // PBackground parent thread
   nsCOMPtr mPBackgroundThread;
 
+  // Monitors creation of the thread below
+  Monitor mThreadMonitor;
+
   // video processing thread - where webrtc.org capturer code runs
   base::Thread* mVideoCaptureThread;
 
   // Shutdown handling
   bool mChildIsAlive;
   bool mDestroyed;
+  // Above 2 are PBackground only, but this is potentially
+  // read cross-thread.
+  mozilla::Atomic mWebRTCAlive;
 };
 
 PCamerasParent* CreateCamerasParent();

From b21dc0c589cdb1002d65c8713a03a5caa470c711 Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Fri, 4 Sep 2015 11:23:21 +0100
Subject: [PATCH 23/79] Bug 1212114 - Stop using
 dom::Promise::MaybeRejectBrokenly() in various FileSystemTaskBase subclasses.
 r=baku

---
 dom/filesystem/CreateDirectoryTask.cpp    | 5 +----
 dom/filesystem/CreateFileTask.cpp         | 5 +----
 dom/filesystem/GetFileOrDirectoryTask.cpp | 5 +----
 dom/filesystem/RemoveTask.cpp             | 5 +----
 4 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/dom/filesystem/CreateDirectoryTask.cpp b/dom/filesystem/CreateDirectoryTask.cpp
index de3733ea1e49..941b5d1c9ac8 100644
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -6,7 +6,6 @@
 
 #include "CreateDirectoryTask.h"
 
-#include "DOMError.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
@@ -121,9 +120,7 @@ CreateDirectoryTask::HandlerCallback()
   }
 
   if (HasError()) {
-    nsRefPtr domError = new DOMError(mFileSystem->GetWindow(),
-      mErrorValue);
-    mPromise->MaybeRejectBrokenly(domError);
+    mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
diff --git a/dom/filesystem/CreateFileTask.cpp b/dom/filesystem/CreateFileTask.cpp
index 042e6d66e8e5..a215a6ec3b30 100644
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -8,7 +8,6 @@
 
 #include 
 
-#include "DOMError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
@@ -297,9 +296,7 @@ CreateFileTask::HandlerCallback()
   }
 
   if (HasError()) {
-    nsRefPtr domError = new DOMError(mFileSystem->GetWindow(),
-      mErrorValue);
-    mPromise->MaybeRejectBrokenly(domError);
+    mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
diff --git a/dom/filesystem/GetFileOrDirectoryTask.cpp b/dom/filesystem/GetFileOrDirectoryTask.cpp
index fcf96e9901eb..c99bda6a0036 100644
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -8,7 +8,6 @@
 
 #include "js/Value.h"
 #include "mozilla/dom/Directory.h"
-#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
@@ -199,9 +198,7 @@ GetFileOrDirectoryTask::HandlerCallback()
   }
 
   if (HasError()) {
-    nsRefPtr domError = new DOMError(mFileSystem->GetWindow(),
-      mErrorValue);
-    mPromise->MaybeRejectBrokenly(domError);
+    mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
diff --git a/dom/filesystem/RemoveTask.cpp b/dom/filesystem/RemoveTask.cpp
index 78a66ce2b581..84f66a8857b3 100644
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -6,7 +6,6 @@
 
 #include "RemoveTask.h"
 
-#include "DOMError.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
@@ -187,9 +186,7 @@ RemoveTask::HandlerCallback()
   }
 
   if (HasError()) {
-    nsRefPtr domError = new DOMError(mFileSystem->GetWindow(),
-      mErrorValue);
-    mPromise->MaybeRejectBrokenly(domError);
+    mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }

From daef6b660b68b8558273c81d9beb4fe1ff2611f7 Mon Sep 17 00:00:00 2001
From: Jon Coppeard 
Date: Thu, 8 Oct 2015 17:48:53 +0100
Subject: [PATCH 24/79] Bug 1212343 - Propagate OOM from SafepointWriter r=nbp

---
 .../jit-test/tests/gc/oomInArrayProtoTest.js  | 24 +++++++++++++++++++
 js/src/jit/CodeGenerator.cpp                  |  3 ++-
 js/src/jit/Safepoints.h                       |  3 +++
 js/src/jit/shared/CodeGenerator-shared.cpp    |  4 +++-
 js/src/jit/shared/CodeGenerator-shared.h      |  2 +-
 js/src/vm/TypeInference.cpp                   |  3 ++-
 6 files changed, 35 insertions(+), 4 deletions(-)
 create mode 100644 js/src/jit-test/tests/gc/oomInArrayProtoTest.js

diff --git a/js/src/jit-test/tests/gc/oomInArrayProtoTest.js b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js
new file mode 100644
index 000000000000..947101394013
--- /dev/null
+++ b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js
@@ -0,0 +1,24 @@
+load(libdir + 'oomTest.js');
+
+function arrayProtoOutOfRange() {
+    function f(obj) {
+        return typeof obj[15];
+    }
+
+    function test() {
+        var a = [1, 2];
+        a.__proto__ = {15: 1337};
+        var b = [1, 2, 3, 4];
+
+        for (var i = 0; i < 1000; i++) {
+            var r = f(i % 2 ? a : b);
+            assertEq(r, i % 2 ? "number" : "undefined");
+        }
+    }
+
+    test();
+    test();
+    test();
+}
+
+oomTest(arrayProtoOutOfRange);
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 19c15a81d020..3adb9d384fea 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8024,7 +8024,8 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
                            : FrameSizeClass::FromDepth(frameDepth_).frameSize();
 
     // We encode safepoints after the OSI-point offsets have been determined.
-    encodeSafepoints();
+    if (!encodeSafepoints())
+        return false;
 
     AutoDiscardIonCode discardIonCode(cx, &recompileInfo);
 
diff --git a/js/src/jit/Safepoints.h b/js/src/jit/Safepoints.h
index 783ad65e683c..714d2f72d63d 100644
--- a/js/src/jit/Safepoints.h
+++ b/js/src/jit/Safepoints.h
@@ -57,6 +57,9 @@ class SafepointWriter
     const uint8_t* buffer() const {
         return stream_.buffer();
     }
+    bool oom() const {
+        return stream_.oom();
+    }
 };
 
 class SafepointReader
diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp
index ad23f6002089..41ff56d33c10 100644
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -626,7 +626,7 @@ CodeGeneratorShared::assignBailoutId(LSnapshot* snapshot)
     return bailouts_.append(snapshot->snapshotOffset());
 }
 
-void
+bool
 CodeGeneratorShared::encodeSafepoints()
 {
     for (SafepointIndex& index : safepointIndices_) {
@@ -639,6 +639,8 @@ CodeGeneratorShared::encodeSafepoints()
 
         index.resolve();
     }
+
+    return !safepoints_.oom();
 }
 
 bool
diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h
index ab6279a37f8f..82d9d3bbc5fc 100644
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -303,7 +303,7 @@ class CodeGeneratorShared : public LElementVisitor
 
     // Encode all encountered safepoints in CG-order, and resolve |indices| for
     // safepoint offsets.
-    void encodeSafepoints();
+    bool encodeSafepoints();
 
     // Fixup offsets of native-to-bytecode map.
     bool createNativeToBytecodeScriptList(JSContext* cx);
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 0fc408bd5748..0a6e94bc739f 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4338,7 +4338,8 @@ TypeZone::beginSweep(FreeOp* fop, bool releaseTypes, AutoClearTypeInferenceState
             if (output.isValid()) {
                 JSScript* script = output.script();
                 if (IsAboutToBeFinalizedUnbarriered(&script)) {
-                    script->ionScript()->recompileInfoRef() = RecompileInfo();
+                    if (script->hasIonScript())
+                        script->ionScript()->recompileInfoRef() = RecompileInfo();
                     output.invalidate();
                 } else {
                     CompilerOutput newOutput(script);

From 0bba2d39d5e6e493360343690355e5db9bdbd910 Mon Sep 17 00:00:00 2001
From: Jon Coppeard 
Date: Tue, 13 Oct 2015 13:37:07 +0100
Subject: [PATCH 25/79] Bug 1212469 - Make oomTest() into a shell function
 r=nbp

---
 js/src/builtin/TestingFunctions.cpp           | 114 +++++++++++++++++-
 js/src/jit-test/lib/oomTest.js                |  39 ------
 js/src/jit-test/tests/gc/bug-1165966.js       |   4 +-
 js/src/jit-test/tests/gc/bug-1171909.js       |   4 +-
 js/src/jit-test/tests/gc/bug-1206677.js       |   4 +-
 js/src/jit-test/tests/gc/bug-1208994.js       |   4 +-
 js/src/jit-test/tests/gc/bug-1209001.js       |   4 +-
 js/src/jit-test/tests/gc/bug-978802.js        |   3 +-
 .../jit-test/tests/gc/oomInArrayProtoTest.js  |   3 +-
 js/src/jit-test/tests/gc/oomInDebugger.js     |   4 +-
 .../tests/gc/oomInExceptionHandlerBailout.js  |   3 +-
 .../jit-test/tests/gc/oomInFormatStackDump.js |   4 +-
 .../tests/gc/oomInGetJumpLabelForBranch.js    |   4 +-
 js/src/jit-test/tests/gc/oomInNewGlobal.js    |   4 +-
 js/src/jit-test/tests/gc/oomInParseAsmJS.js   |   4 +-
 .../jit-test/tests/gc/oomInParseFunction.js   |   4 +-
 js/src/jit-test/tests/gc/oomInRegExp.js       |   4 +-
 js/src/jit-test/tests/gc/oomInWeakMap.js      |   4 +-
 js/src/jit-test/tests/profiler/bug1211962.js  |   3 +-
 19 files changed, 158 insertions(+), 59 deletions(-)
 delete mode 100644 js/src/jit-test/lib/oomTest.js

diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index dbe3927c0424..fee5cc756b8a 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -53,6 +53,25 @@ static bool fuzzingSafe = false;
 // OOM conditions.
 static bool disableOOMFunctions = false;
 
+static bool
+EnvVarIsDefined(const char* name)
+{
+    const char* value = getenv(name);
+    return value && *value;
+}
+
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+static bool
+EnvVarAsInt(const char* name, int* valueOut)
+{
+    if (!EnvVarIsDefined(name))
+        return false;
+
+    *valueOut = atoi(getenv(name));
+    return true;
+}
+#endif
+
 static bool
 GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -1072,6 +1091,93 @@ ResetOOMFailure(JSContext* cx, unsigned argc, Value* vp)
     OOM_maxAllocations = UINT32_MAX;
     return true;
 }
+
+static bool
+OOMTest(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (args.length() != 1 || !args[0].isObject() || !args[0].toObject().is()) {
+        JS_ReportError(cx, "oomTest() takes a single function argument.");
+        return false;
+    }
+
+    if (disableOOMFunctions) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    RootedFunction function(cx, &args[0].toObject().as());
+
+    bool verbose = EnvVarIsDefined("OOM_VERBOSE");
+
+    unsigned threadStart = oom::THREAD_TYPE_MAIN;
+    unsigned threadEnd = oom::THREAD_TYPE_MAX;
+
+    // Test a single thread type if specified by the OOM_THREAD environment variable.
+    int threadOption = 0;
+    if (EnvVarAsInt("OOM_THREAD", &threadOption)) {
+        if (threadOption < oom::THREAD_TYPE_MAIN || threadOption > oom::THREAD_TYPE_MAX) {
+            JS_ReportError(cx, "OOM_THREAD value out of range.");
+            return false;
+        }
+
+        threadStart = threadOption;
+        threadEnd = threadOption + 1;
+    }
+
+    JS_SetGCZeal(cx, 0, JS_DEFAULT_ZEAL_FREQ);
+
+    for (unsigned thread = threadStart; thread < threadEnd; thread++) {
+        if (verbose)
+            fprintf(stderr, "thread %d\n", thread);
+
+        HelperThreadState().waitForAllThreads();
+        js::oom::targetThread = thread;
+
+        unsigned allocation = 1;
+        bool handledOOM;
+        do {
+            if (verbose)
+                fprintf(stderr, "  allocation %d\n", allocation);
+
+            MOZ_ASSERT(!cx->isExceptionPending());
+            MOZ_ASSERT(!cx->runtime()->hadOutOfMemory);
+
+            OOM_maxAllocations = OOM_counter + allocation;
+            OOM_failAlways = false;
+
+            RootedValue result(cx);
+            bool ok = JS_CallFunction(cx, cx->global(), function,
+                                      HandleValueArray::empty(), &result);
+
+            handledOOM = OOM_counter >= OOM_maxAllocations;
+            OOM_maxAllocations = UINT32_MAX;
+
+            MOZ_ASSERT_IF(ok, !cx->isExceptionPending());
+            MOZ_ASSERT_IF(!ok, cx->isExceptionPending());
+
+            // Note that it is possible that the function throws an exception
+            // unconnected to OOM, in which case we ignore it. More correct
+            // would be to have the caller pass some kind of exception
+            // specification and to check the exception against it.
+
+            cx->clearPendingException();
+            cx->runtime()->hadOutOfMemory = false;
+
+            allocation++;
+        } while (handledOOM);
+
+        if (verbose) {
+            fprintf(stderr, "  finished after %d allocations\n", allocation - 2);
+        }
+    }
+
+    js::oom::targetThread = js::oom::THREAD_TYPE_NONE;
+
+    args.rval().setUndefined();
+    return true;
+}
 #endif
 
 static const js::Class FakePromiseClass = {
@@ -3062,6 +3168,12 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
 "resetOOMFailure()",
 "  Remove the allocation failure scheduled by either oomAfterAllocations() or\n"
 "  oomAtAllocation() and return whether any allocation had been caused to fail."),
+
+    JS_FN_HELP("oomTest", OOMTest, 0, 0,
+"oomTest(function)",
+"  Test that the passed function behaves correctly under OOM conditions by\n"
+"  repeatedly executing it and simulating allocation failure at successive\n"
+"  allocations until the function completes without seeing a failure."),
 #endif
 
     JS_FN_HELP("makeFakePromise", MakeFakePromise, 0, 0,
@@ -3464,7 +3576,7 @@ js::DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe_,
                            bool disableOOMFunctions_)
 {
     fuzzingSafe = fuzzingSafe_;
-    if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0')
+    if (EnvVarIsDefined("MOZ_FUZZING_SAFE"))
         fuzzingSafe = true;
 
     disableOOMFunctions = disableOOMFunctions_;
diff --git a/js/src/jit-test/lib/oomTest.js b/js/src/jit-test/lib/oomTest.js
deleted file mode 100644
index 75e6d49219d1..000000000000
--- a/js/src/jit-test/lib/oomTest.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Function to test OOM handling by repeatedly calling a function and failing
-// successive allocations.
-
-if (!("oomAtAllocation" in this && "resetOOMFailure" in this && "oomThreadTypes" in this))
-    quit();
-
-if ("gczeal" in this)
-    gczeal(0);
-
-const verbose = ("os" in this) && os.getenv("OOM_VERBOSE");
-
-// Test out of memory handing by calling a function f() while causing successive
-// memory allocations to fail.  Repeat until f() finishes without reaching the
-// failing allocation.
-function oomTest(f) {
-    for (let thread = 1; thread < oomThreadTypes(); thread++) {
-        if (verbose)
-            print("testing thread " + thread);
-
-        var i = 1;
-        var more;
-        do {
-            if (verbose)
-                print("fail at " + i);
-            try {
-                oomAtAllocation(i, thread);
-                f();
-                more = resetOOMFailure();
-            } catch (e) {
-                // Ignore exceptions.
-                more = resetOOMFailure();
-            }
-            i++;
-        } while(more);
-
-        if (verbose)
-            print("finished after " + (i - 2) + " failures");
-    }
-}
diff --git a/js/src/jit-test/tests/gc/bug-1165966.js b/js/src/jit-test/tests/gc/bug-1165966.js
index 62c5b1a37264..bbcf4545e7ad 100644
--- a/js/src/jit-test/tests/gc/bug-1165966.js
+++ b/js/src/jit-test/tests/gc/bug-1165966.js
@@ -1,5 +1,7 @@
 // |jit-test| --no-ion
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 var g = newGlobal();
 oomTest(function() {
     Debugger(g);
diff --git a/js/src/jit-test/tests/gc/bug-1171909.js b/js/src/jit-test/tests/gc/bug-1171909.js
index 5a210fe051bd..16d4ff1bde69 100644
--- a/js/src/jit-test/tests/gc/bug-1171909.js
+++ b/js/src/jit-test/tests/gc/bug-1171909.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest((function(x) { assertEq(x + y + ex, 25); }));
diff --git a/js/src/jit-test/tests/gc/bug-1206677.js b/js/src/jit-test/tests/gc/bug-1206677.js
index 9ddfbf383a8f..c666b7aac892 100644
--- a/js/src/jit-test/tests/gc/bug-1206677.js
+++ b/js/src/jit-test/tests/gc/bug-1206677.js
@@ -1,6 +1,4 @@
-load(libdir + 'oomTest.js');
-
-if (helperThreadCount() === 0)
+if (!('oomTest' in this) || helperThreadCount() === 0)
   quit(0);
 
 var lfGlobal = newGlobal();
diff --git a/js/src/jit-test/tests/gc/bug-1208994.js b/js/src/jit-test/tests/gc/bug-1208994.js
index 4c69e49879a5..b2326cd628b1 100644
--- a/js/src/jit-test/tests/gc/bug-1208994.js
+++ b/js/src/jit-test/tests/gc/bug-1208994.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => getBacktrace({args: oomTest[load+1], locals: true, thisprops: true}));
diff --git a/js/src/jit-test/tests/gc/bug-1209001.js b/js/src/jit-test/tests/gc/bug-1209001.js
index c652307c66c6..dfbf54b31209 100644
--- a/js/src/jit-test/tests/gc/bug-1209001.js
+++ b/js/src/jit-test/tests/gc/bug-1209001.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => parseModule('import v from "mod";'));
diff --git a/js/src/jit-test/tests/gc/bug-978802.js b/js/src/jit-test/tests/gc/bug-978802.js
index 762f4dc365e0..33c2012ec102 100644
--- a/js/src/jit-test/tests/gc/bug-978802.js
+++ b/js/src/jit-test/tests/gc/bug-978802.js
@@ -1,4 +1,5 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
 
 oomTest(() => {
     try {
diff --git a/js/src/jit-test/tests/gc/oomInArrayProtoTest.js b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js
index 947101394013..c2712d8fd97b 100644
--- a/js/src/jit-test/tests/gc/oomInArrayProtoTest.js
+++ b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js
@@ -1,4 +1,5 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
 
 function arrayProtoOutOfRange() {
     function f(obj) {
diff --git a/js/src/jit-test/tests/gc/oomInDebugger.js b/js/src/jit-test/tests/gc/oomInDebugger.js
index 96f8174bcc81..adf7f64a7983 100644
--- a/js/src/jit-test/tests/gc/oomInDebugger.js
+++ b/js/src/jit-test/tests/gc/oomInDebugger.js
@@ -1,3 +1,5 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 var g = newGlobal();
 oomTest(() => Debugger(g));
diff --git a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js
index c00950e77e66..fd77c00c6e15 100644
--- a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js
+++ b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js
@@ -1,4 +1,5 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
 
 oomTest(() => {
     let x = 0;
diff --git a/js/src/jit-test/tests/gc/oomInFormatStackDump.js b/js/src/jit-test/tests/gc/oomInFormatStackDump.js
index c801a91f67e9..94a398b02534 100644
--- a/js/src/jit-test/tests/gc/oomInFormatStackDump.js
+++ b/js/src/jit-test/tests/gc/oomInFormatStackDump.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => getBacktrace({args: true, locals: true, thisprops: true}));
diff --git a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
index 501b71755d6c..e70155474040 100644
--- a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
+++ b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
@@ -1,3 +1,5 @@
 // |jit-test| allow-oom; allow-unhandlable-oom; --no-threads
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => getBacktrace({thisprops: gc() && delete addDebuggee.enabled}));
diff --git a/js/src/jit-test/tests/gc/oomInNewGlobal.js b/js/src/jit-test/tests/gc/oomInNewGlobal.js
index e371c72021fb..443c3c8e07c6 100644
--- a/js/src/jit-test/tests/gc/oomInNewGlobal.js
+++ b/js/src/jit-test/tests/gc/oomInNewGlobal.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(newGlobal);
diff --git a/js/src/jit-test/tests/gc/oomInParseAsmJS.js b/js/src/jit-test/tests/gc/oomInParseAsmJS.js
index 0ae3736a13ed..b5279a26a6c9 100644
--- a/js/src/jit-test/tests/gc/oomInParseAsmJS.js
+++ b/js/src/jit-test/tests/gc/oomInParseAsmJS.js
@@ -1,4 +1,6 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 function parseAsmJS() {
     eval(`function m(stdlib)
           {
diff --git a/js/src/jit-test/tests/gc/oomInParseFunction.js b/js/src/jit-test/tests/gc/oomInParseFunction.js
index 070e0e710396..9946bc2d0021 100644
--- a/js/src/jit-test/tests/gc/oomInParseFunction.js
+++ b/js/src/jit-test/tests/gc/oomInParseFunction.js
@@ -1,2 +1,4 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => eval("function f() {}"));
diff --git a/js/src/jit-test/tests/gc/oomInRegExp.js b/js/src/jit-test/tests/gc/oomInRegExp.js
index 01066cd997bb..a675f9b53c74 100644
--- a/js/src/jit-test/tests/gc/oomInRegExp.js
+++ b/js/src/jit-test/tests/gc/oomInRegExp.js
@@ -1,3 +1,5 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(() => assertEq("foobar\xff5baz\u1200".search(/bar\u0178\d/i), 3));
 oomTest(() => assertEq((/(?!(?!(?!6)[\Wc]))/i).test(), false));
diff --git a/js/src/jit-test/tests/gc/oomInWeakMap.js b/js/src/jit-test/tests/gc/oomInWeakMap.js
index e26fb5d5f3ed..157d72890734 100644
--- a/js/src/jit-test/tests/gc/oomInWeakMap.js
+++ b/js/src/jit-test/tests/gc/oomInWeakMap.js
@@ -1,4 +1,6 @@
-load(libdir + 'oomTest.js');
+if (!('oomTest' in this))
+    quit();
+
 oomTest(function () {
     eval(`var wm = new WeakMap();
          wm.set({}, 'FOO').get(false);`);
diff --git a/js/src/jit-test/tests/profiler/bug1211962.js b/js/src/jit-test/tests/profiler/bug1211962.js
index 532fa93fc605..01e819d502e8 100644
--- a/js/src/jit-test/tests/profiler/bug1211962.js
+++ b/js/src/jit-test/tests/profiler/bug1211962.js
@@ -1,5 +1,6 @@
 // |jit-test| slow;
-load(libdir + "oomTest.js");
+if (!('oomTest' in this))
+    quit();
 
 enableSPSProfiling();
 var lfGlobal = newGlobal();

From a48bd426550e8fc4a8f237171afe7d7118290607 Mon Sep 17 00:00:00 2001
From: Jon Coppeard 
Date: Tue, 13 Oct 2015 13:37:08 +0100
Subject: [PATCH 26/79] Bug 1212469 - Fix some OOM handling issues shown up by
 the previous patch r=jandem

---
 js/src/jit/Ion.cpp          |  9 ++++++---
 js/src/vm/TypeInference.cpp | 14 +++++++++++++-
 js/src/vm/TypeInference.h   |  4 ++++
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index ab7ae9862336..5a1f7498a4b2 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -605,6 +605,9 @@ jit::LazyLink(JSContext* cx, HandleScript calleeScript)
             // doesn't has code to handle it after linking happened. So it's
             // not OK to throw a catchable exception from there.
             cx->clearPendingException();
+
+            // Reset the TypeZone's compiler output for this script, if any.
+            InvalidateCompilerOutputsForScript(cx, calleeScript);
         }
     }
 
@@ -2207,9 +2210,6 @@ IonCompile(JSContext* cx, JSScript* script,
 
     // If possible, compile the script off thread.
     if (options.offThreadCompilationAvailable()) {
-        if (!recompile)
-            builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
-
         JitSpew(JitSpew_IonSyncLogs, "Can't log script %s:%" PRIuSIZE
                 ". (Compiled on background thread.)",
                 builderScript->filename(), builderScript->lineno());
@@ -2220,6 +2220,9 @@ IonCompile(JSContext* cx, JSScript* script,
             return AbortReason_Alloc;
         }
 
+        if (!recompile)
+            builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
+
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
         autoDelete.forget();
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 0a6e94bc739f..a507d3e877a7 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1368,7 +1368,7 @@ class TypeConstraintFreezeStack : public TypeConstraint
 
 bool
 js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
-                         RecompileInfo* precompileInfo)
+                      RecompileInfo* precompileInfo)
 {
     if (constraints->failed())
         return false;
@@ -1458,6 +1458,18 @@ js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList
     return true;
 }
 
+void
+js::InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script)
+{
+    TypeZone& types = cx->zone()->types;
+    if (types.compilerOutputs) {
+        for (auto& co : *types.compilerOutputs) {
+            if (co.script() == script)
+                co.invalidate();
+        }
+    }
+}
+
 static void
 CheckDefinitePropertiesTypeSet(JSContext* cx, TemporaryTypeSet* frozen, StackTypeSet* actual)
 {
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 5a76e251679d..ea00d5040db3 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1070,6 +1070,10 @@ bool
 FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
                   RecompileInfo* precompileInfo);
 
+// Reset any CompilerOutput present for a script.
+void
+InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
+
 // Update the actual types in any scripts queried by constraints with any
 // speculative types added during the definite properties analysis.
 void

From c617698d290f6b4e876e45463ac590f0f3d3eee0 Mon Sep 17 00:00:00 2001
From: Jon Coppeard 
Date: Tue, 13 Oct 2015 13:49:05 +0100
Subject: [PATCH 27/79] Bug 1212128 - Revert test code changes now issues with
 oomTest() have been fixed r=jandem

---
 js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
index e70155474040..e5df3de08de7 100644
--- a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
+++ b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js
@@ -1,4 +1,3 @@
-// |jit-test| allow-oom; allow-unhandlable-oom; --no-threads
 if (!('oomTest' in this))
     quit();
 

From b98d93ada9a55ac6cfc5b2c3893203d1ccfe7cf0 Mon Sep 17 00:00:00 2001
From: Mike Conley 
Date: Fri, 2 Oct 2015 19:44:48 -0400
Subject: [PATCH 28/79] Bug 1095236 - Simplify
 browser_test_new_window_from_content.js to use BrowserTestUtils. r=mrbkap

--HG--
extra : commitid : Ia8rS8t1WAn
extra : rebase_source : e5a9f99eb8c900dacb363658973050f78320be29
extra : histedit_source : 28435fa0ad3292ca096f79b53c91ef9ea6305ffd
---
 dom/tests/browser/browser.ini                 |   1 -
 .../browser_test_new_window_from_content.js   | 204 +++---------------
 .../test_new_window_from_content_child.html   |   9 +-
 .../test_new_window_from_content_child.js     |  19 --
 4 files changed, 36 insertions(+), 197 deletions(-)
 delete mode 100644 dom/tests/browser/test_new_window_from_content_child.js

diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini
index 3fc0938a8e0e..95767441d369 100644
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -26,7 +26,6 @@ skip-if= buildapp == 'mulet'
 skip-if = (toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet')
 support-files =
   test_new_window_from_content_child.html
-  test_new_window_from_content_child.js
 [browser_webapps_permissions.js]
 # TODO: Re-enable permissions tests on Mac, bug 795334
 skip-if = buildapp != "b2g"
diff --git a/dom/tests/browser/browser_test_new_window_from_content.js b/dom/tests/browser/browser_test_new_window_from_content.js
index 1514369321bd..3048818c2838 100644
--- a/dom/tests/browser/browser_test_new_window_from_content.js
+++ b/dom/tests/browser/browser_test_new_window_from_content.js
@@ -35,10 +35,7 @@
      each preference.
 */
 
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const kContentDoc = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html";
@@ -91,117 +88,8 @@ registerCleanupFunction(function() {
   Services.prefs.setIntPref(kNewWindowPrefKey, originalNewWindowPref);
   Services.prefs.setIntPref(kNewWindowRestrictionPrefKey,
                             originalNewWindowRestrictionPref);
-  // If there are any content tabs leftover, make sure they're not going to
-  // block exiting with onbeforeunload.
-  for (let tab of gBrowser.tabs) {
-    let browser = gBrowser.getBrowserForTab(tab);
-    if (browser.contentDocument.location == kContentDoc) {
-      closeTab(tab);
-    }
-  }
 });
 
-/**
- * WindowOpenListener is a very simple nsIWindowMediatorListener that
- * listens for a new window opening to aExpectedURI. It has two Promises
- * attached to it - openPromise and closePromise. As you'd expect,
- * openPromise resolves when the window is opened, and closePromise
- * resolves if and when a window with the same URI closes. There is
- * no attempt to make sure that it's the same window opening and
- * closing - we just use the URI.
- *
- * @param aExpectedURI the URI to watch for in a new window.
- * @return nsIWindowMediatorListener
- */
-function WindowOpenListener(aExpectedURI) {
-  this._openDeferred = Promise.defer();
-  this._closeDeferred = Promise.defer();
-  this._expectedURI = aExpectedURI;
-}
-
-WindowOpenListener.prototype = {
-  get openPromise() {
-    return this._openDeferred.promise;
-  },
-
-  get closePromise() {
-    return this._closeDeferred.promise;
-  },
-
-  onOpenWindow: function(aXULWindow) {
-    let domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindow);
-    let location = domWindow.document.location;
-    if (location == this._expectedURI) {
-      let deferred = this._openDeferred;
-      domWindow.addEventListener("load", function onWindowLoad() {
-        domWindow.removeEventListener("load", onWindowLoad);
-        deferred.resolve(domWindow);
-      })
-    }
-  },
-
-  onCloseWindow: function(aXULWindow) {
-    this._closeDeferred.resolve();
-  },
-  onWindowTitleChange: function(aXULWindow, aNewTitle) {},
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener])
-};
-
-/**
- * Adds the testing tab, and injects our frame script which
- * allows us to send click events to links and other things.
- *
- * @return a Promise that resolves once the tab is loaded and ready.
- */
-function loadAndSelectTestTab() {
-  let tab = gBrowser.addTab(kContentDoc);
-  gBrowser.selectedTab = tab;
-
-  let browser = gBrowser.getBrowserForTab(tab);
-  browser.messageManager.loadFrameScript(kContentScript, false);
-
-  let deferred = Promise.defer();
-  browser.addEventListener("DOMContentLoaded", function onBrowserLoad(aEvent) {
-    browser.removeEventListener("DOMContentLoaded", onBrowserLoad);
-    deferred.resolve(tab);
-  });
-
-  return deferred.promise;
-}
-
-/**
- * Clears the onbeforeunload event handler from the testing tab,
- * and then closes the tab.
- *
- * @param aTab the testing tab to close.
- * @param a Promise that resolves once the tab has been closed.
- */
-function closeTab(aTab) {
-  let deferred = Promise.defer();
-  let browserMM = gBrowser.getBrowserForTab(aTab).messageManager;
-  browserMM.sendAsyncMessage("TEST:allow-unload");
-  browserMM.addMessageListener("TEST:allow-unload:done", function(aMessage) {
-    gBrowser.removeTab(aTab);
-    deferred.resolve();
-  })
-  return deferred.promise;
-}
-
-/**
- * Sends a click event on some item into a tab.
- *
- * @param aTab the tab to send the click event to
- * @param aItemId the item within the tab content to click.
- */
-function clickInTab(aTab, aItemId) {
-  let browserMM = gBrowser.getBrowserForTab(aTab).messageManager;
-  browserMM.sendAsyncMessage("TEST:click-item", {
-    details: aItemId,
-  });
-}
-
 /**
  * For some expectation when a link is clicked, creates and
  * returns a Promise that resolves when that expectation is
@@ -213,62 +101,38 @@ function clickInTab(aTab, aItemId) {
  * occurred - for example, if a new window was opened, this function
  * closes it before resolving.
  *
- * @param aTab the tab with the test document
+ * @param aBrowser the  with the test document
  * @param aExpectation one of kSameTab, kNewWin, or kNewTab.
  * @return a Promise that resolves when the expectation is fulfilled,
  *         and cleaned up after.
  */
-function prepareForResult(aTab, aExpectation) {
-  let deferred = Promise.defer();
-  let browser = gBrowser.getBrowserForTab(aTab);
-
+function prepareForResult(aBrowser, aExpectation) {
   switch(aExpectation) {
     case kSameTab:
-      // We expect about:blank to be loaded in the current tab. In order
-      // to prevent us needing to reload the document and content script
-      // after browsing away, we'll detect the attempt by using onbeforeunload,
-      // and then cancel the unload. It's a hack, but it's also a pretty
-      // cheap way of detecting when we're browsing away in the test tab.
-      // The onbeforeunload event handler is set in the content script automatically.
-      browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() {
-        browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true);
-        executeSoon(() => {
-          let stack = browser.parentNode;
-          let dialogs = stack.getElementsByTagNameNS(kXULNS, "tabmodalprompt");
-          dialogs[0].ui.button1.click()
-          deferred.resolve();
-        })
-      }, true);
+      return Task.spawn(function*() {
+        yield BrowserTestUtils.browserLoaded(aBrowser);
+        is(aBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
+        // Now put the browser back where it came from
+        yield BrowserTestUtils.loadURI(aBrowser, kContentDoc);
+        yield BrowserTestUtils.browserLoaded(aBrowser);
+      });
       break;
     case kNewWin:
-      let listener = new WindowOpenListener("about:blank");
-      Services.wm.addListener(listener);
-
-      info("Waiting for a new about:blank window");
-      listener.openPromise.then(function(aWindow) {
-        info("Got the new about:blank window - closing it.");
-        executeSoon(() => {
-          aWindow.close();
-        });
-        listener.closePromise.then(() => {
-          info("New about:blank window closed!");
-          Services.wm.removeListener(listener);
-          deferred.resolve();
-        });
+      return Task.spawn(function*() {
+        let newWin = yield BrowserTestUtils.waitForNewWindow();
+        let newBrowser = newWin.gBrowser.selectedBrowser;
+        yield BrowserTestUtils.browserLoaded(newBrowser);
+        is(newBrowser.currentURI.spec, "about:robots", "Should be at about:robots");
+        yield BrowserTestUtils.closeWindow(newWin);
       });
       break;
     case kNewTab:
-      gBrowser.tabContainer.addEventListener("TabOpen", function onTabOpen(aEvent) {
-        let newTab = aEvent.target;
-        let newBrowser = gBrowser.getBrowserForTab(newTab);
-        if (newBrowser.contentDocument.location.href == "about:blank") {
-          gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
-          executeSoon(() => {
-            gBrowser.removeTab(newTab);
-            deferred.resolve();
-          })
-        }
-      })
+      return Task.spawn(function*() {
+        let newTab = yield BrowserTestUtils.waitForNewTab(gBrowser);
+        is(newTab.linkedBrowser.currentURI.spec, "about:robots",
+           "Should be at about:robots");
+        yield BrowserTestUtils.removeTab(newTab);
+      });
       break;
     default:
       ok(false, "prepareForResult can't handle an expectation of " + aExpectation)
@@ -283,14 +147,16 @@ function prepareForResult(aTab, aExpectation) {
  * perform as specified in the supplied aMatrix (kWinOpenDefault,
  * for example).
  *
- * @param aLinkId the id of the link within the testing page to test.
+ * @param aLinkSelector a selector for the link within the testing page to click.
  * @param aMatrix a testing matrix for the
  *        browser.link.open_newwindow and browser.link.open_newwindow.restriction
  *        prefs to test against. See kWinOpenDefault for an example.
  */
-function testLinkWithMatrix(aLinkId, aMatrix) {
-  return Task.spawn(function* () {
-    let tab = yield loadAndSelectTestTab();
+function testLinkWithMatrix(aLinkSelector, aMatrix) {
+  return BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: kContentDoc,
+  }, function*(browser) {
     // This nested for-loop is unravelling the matrix const
     // we set up, and gives us three things through each tick
     // of the inner loop:
@@ -298,7 +164,6 @@ function testLinkWithMatrix(aLinkId, aMatrix) {
     // 2) newWindowRestPref: a browser.link.open_newwindow.restriction pref to try
     // 3) expectation: what we expect the click outcome on this link to be,
     //                 which will either be kSameTab, kNewWin or kNewTab.
-
     for (let newWindowPref in aMatrix) {
       let expectations = aMatrix[newWindowPref];
       for (let i = 0; i < expectations.length; ++i) {
@@ -307,28 +172,27 @@ function testLinkWithMatrix(aLinkId, aMatrix) {
 
         Services.prefs.setIntPref("browser.link.open_newwindow", newWindowPref);
         Services.prefs.setIntPref("browser.link.open_newwindow.restriction", newWindowRestPref);
-        info("Clicking on " + aLinkId);
+        info("Clicking on " + aLinkSelector);
         info("Testing with browser.link.open_newwindow = " + newWindowPref + " and " +
              "browser.link.open_newwindow.restriction = " + newWindowRestPref);
         info("Expecting: " + expectation);
-        let resultPromise = prepareForResult(tab, expectation);
-        clickInTab(tab, aLinkId);
+        let resultPromise = prepareForResult(browser, expectation);
+        BrowserTestUtils.synthesizeMouseAtCenter(aLinkSelector, {}, browser);
         yield resultPromise;
-        ok(true, "Got expectation: " + expectation);
+        info("Got expectation: " + expectation);
       }
     }
-    yield closeTab(tab);
   });
 }
 
 add_task(function* test_window_open_with_defaults() {
-  yield testLinkWithMatrix("winOpenDefault", kWinOpenDefault);
+  yield testLinkWithMatrix("#winOpenDefault", kWinOpenDefault);
 });
 
 add_task(function* test_window_open_with_non_defaults() {
-  yield testLinkWithMatrix("winOpenNonDefault", kWinOpenNonDefault);
+  yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault);
 });
 
 add_task(function* test_target__blank() {
-  yield testLinkWithMatrix("targetBlank", kTargetBlank);
+  yield testLinkWithMatrix("#targetBlank", kTargetBlank);
 });
diff --git a/dom/tests/browser/test_new_window_from_content_child.html b/dom/tests/browser/test_new_window_from_content_child.html
index 0594919b3ac6..7609675b82ba 100644
--- a/dom/tests/browser/test_new_window_from_content_child.html
+++ b/dom/tests/browser/test_new_window_from_content_child.html
@@ -6,18 +6,13 @@
 
   

Open a new window via window.open with default features.

Open a new window via window.open with non-default features.

-

Open a new window via target="_blank".

+

Open a new window via target="_blank".

\ No newline at end of file diff --git a/dom/tests/browser/test_new_window_from_content_child.js b/dom/tests/browser/test_new_window_from_content_child.js deleted file mode 100644 index cd3f3ea9aa6a..000000000000 --- a/dom/tests/browser/test_new_window_from_content_child.js +++ /dev/null @@ -1,19 +0,0 @@ -// A hacky mechanism for catching and detecting that we're attempting -// to browse away is by setting the onbeforeunload event handler. We -// detect this dialog opening in the parent test script, and dismiss -// it. - -function handleClickItem(aMessage) { - let itemId = aMessage.data.details; - content.console.log("Getting item with ID: " + itemId); - let item = content.document.getElementById(itemId); - item.click(); -} - -function handleAllowUnload(aMessage) { - content.onbeforeunload = null; - sendSyncMessage("TEST:allow-unload:done"); -} - -addMessageListener("TEST:click-item", handleClickItem); -addMessageListener("TEST:allow-unload", handleAllowUnload); \ No newline at end of file From 722366ddf3d6d1baedd82be3146cce3fbf9a5fa3 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Fri, 2 Oct 2015 19:00:54 -0400 Subject: [PATCH 29/79] Bug 1095236 - Disable dialog=1 support for windows opened from content. r=mrbkap --HG-- extra : commitid : 4m7AvvB7uNQ extra : rebase_source : 071e0e0aad76a7f08899591cb2efcc04bd5f2223 extra : histedit_source : d4db8a83cd507d05be0c166542fbdeca0212c76d --- embedding/components/windowwatcher/nsWindowWatcher.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embedding/components/windowwatcher/nsWindowWatcher.cpp b/embedding/components/windowwatcher/nsWindowWatcher.cpp index 2f962dd48312..f481efda85bd 100644 --- a/embedding/components/windowwatcher/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp @@ -1651,9 +1651,9 @@ nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow* aParent, if (aParent) { aParent->GetFullScreen(&isFullScreen); } - if (isFullScreen && openedFromContentScript) { - // If the parent window is in fullscreen & the caller context is content, - // dialog feature is disabled. (see bug 803675) + if (openedFromContentScript) { + // If the caller context is content, we do not support the + // dialog feature. See bug 1095236. disableDialogFeature = true; } From 00646ae181352ddc05623cb5defa2bbf76e3fc95 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Fri, 2 Oct 2015 19:08:20 -0400 Subject: [PATCH 30/79] Bug 1095236 - Test that windows opened from content with dialog=1 still open. r=mrbkap. --HG-- extra : commitid : K0O9jLpNT8J extra : rebase_source : c2451a8d140b99435af9c754a5656648d6ab946f extra : histedit_source : 93dab434745a51088d77e5b33dbef0a9161ea51c --- dom/tests/browser/browser_test_new_window_from_content.js | 4 ++++ dom/tests/browser/test_new_window_from_content_child.html | 1 + 2 files changed, 5 insertions(+) diff --git a/dom/tests/browser/browser_test_new_window_from_content.js b/dom/tests/browser/browser_test_new_window_from_content.js index 3048818c2838..22a6bbb5f9ed 100644 --- a/dom/tests/browser/browser_test_new_window_from_content.js +++ b/dom/tests/browser/browser_test_new_window_from_content.js @@ -193,6 +193,10 @@ add_task(function* test_window_open_with_non_defaults() { yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault); }); +add_task(function* test_window_open_dialog() { + yield testLinkWithMatrix("#winOpenDialog", kWinOpenNonDefault); +}); + add_task(function* test_target__blank() { yield testLinkWithMatrix("#targetBlank", kTargetBlank); }); diff --git a/dom/tests/browser/test_new_window_from_content_child.html b/dom/tests/browser/test_new_window_from_content_child.html index 7609675b82ba..ab1bf6f4941d 100644 --- a/dom/tests/browser/test_new_window_from_content_child.html +++ b/dom/tests/browser/test_new_window_from_content_child.html @@ -6,6 +6,7 @@

Open a new window via window.open with default features.

Open a new window via window.open with non-default features.

+

Open a new window via window.open with dialog=1.

Open a new window via target="_blank".

From 0a799593e934e85c8a521235798d26f47480a217 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 12 Oct 2015 22:40:08 -0400 Subject: [PATCH 31/79] Bug 1207245 - part 5 - rename template parameters for nsRefPtrHashtable; r=ehsan Having a template parameter conflict with a global name is terribly inconvenient, so let's try to avoid that by renaming the 'RefPtr' template parameter to something else. --- xpcom/glue/nsRefPtrHashtable.h | 50 +++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/xpcom/glue/nsRefPtrHashtable.h b/xpcom/glue/nsRefPtrHashtable.h index e49274ae53c1..899dbfb68a9c 100644 --- a/xpcom/glue/nsRefPtrHashtable.h +++ b/xpcom/glue/nsRefPtrHashtable.h @@ -16,21 +16,21 @@ * See nsBaseHashtable for complete declaration. * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h * for a complete specification. - * @param RefPtr the reference-type being wrapped + * @param PtrType the reference-type being wrapped * @see nsDataHashtable, nsClassHashtable */ -template +template class nsRefPtrHashtable - : public nsBaseHashtable, RefPtr*> + : public nsBaseHashtable, PtrType*> { public: typedef typename KeyClass::KeyType KeyType; - typedef RefPtr* UserDataType; - typedef nsBaseHashtable, RefPtr*> base_type; + typedef PtrType* UserDataType; + typedef nsBaseHashtable, PtrType*> base_type; nsRefPtrHashtable() {} explicit nsRefPtrHashtable(uint32_t aInitLength) - : nsBaseHashtable, RefPtr*>(aInitLength) + : nsBaseHashtable, PtrType*>(aInitLength) { } @@ -47,14 +47,14 @@ public: * to false otherwise. * @return The entry, or nullptr if not found. Do not release this pointer! */ - RefPtr* GetWeak(KeyType aKey, bool* aFound = nullptr) const; + PtrType* GetWeak(KeyType aKey, bool* aFound = nullptr) const; // Overload Put, rather than overriding it. using base_type::Put; - void Put(KeyType aKey, already_AddRefed aData); + void Put(KeyType aKey, already_AddRefed aData); - MOZ_WARN_UNUSED_RESULT bool Put(KeyType aKey, already_AddRefed aData, + MOZ_WARN_UNUSED_RESULT bool Put(KeyType aKey, already_AddRefed aData, const mozilla::fallible_t&); // Overload Remove, rather than overriding it. @@ -93,10 +93,10 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, // nsRefPtrHashtable definitions // -template +template bool -nsRefPtrHashtable::Get(KeyType aKey, - UserDataType* aRefPtr) const +nsRefPtrHashtable::Get(KeyType aKey, + UserDataType* aRefPtr) const { typename base_type::EntryType* ent = this->GetEntry(aKey); @@ -119,9 +119,9 @@ nsRefPtrHashtable::Get(KeyType aKey, return false; } -template -RefPtr* -nsRefPtrHashtable::GetWeak(KeyType aKey, bool* aFound) const +template +PtrType* +nsRefPtrHashtable::GetWeak(KeyType aKey, bool* aFound) const { typename base_type::EntryType* ent = this->GetEntry(aKey); @@ -141,21 +141,21 @@ nsRefPtrHashtable::GetWeak(KeyType aKey, bool* aFound) const return nullptr; } -template +template void -nsRefPtrHashtable::Put(KeyType aKey, - already_AddRefed aData) +nsRefPtrHashtable::Put(KeyType aKey, + already_AddRefed aData) { if (!Put(aKey, mozilla::Move(aData), mozilla::fallible)) { NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount()); } } -template +template bool -nsRefPtrHashtable::Put(KeyType aKey, - already_AddRefed aData, - const mozilla::fallible_t&) +nsRefPtrHashtable::Put(KeyType aKey, + already_AddRefed aData, + const mozilla::fallible_t&) { typename base_type::EntryType* ent = this->PutEntry(aKey); @@ -168,10 +168,10 @@ nsRefPtrHashtable::Put(KeyType aKey, return true; } -template +template bool -nsRefPtrHashtable::Remove(KeyType aKey, - UserDataType* aRefPtr) +nsRefPtrHashtable::Remove(KeyType aKey, + UserDataType* aRefPtr) { MOZ_ASSERT(aRefPtr); typename base_type::EntryType* ent = this->GetEntry(aKey); From 208c875629cd857a1d6064c459f9613ddad45c4f Mon Sep 17 00:00:00 2001 From: Blake Winton Date: Mon, 28 Sep 2015 10:59:44 -0400 Subject: [PATCH 32/79] Bug 1207225 - Set the maximum width of a toolbarbutton-badge. ui-r=maritz r=gijs f=zer0 --HG-- extra : rebase_source : f0ceb3f78688302a51ac33d934e61f0194bf904f --- toolkit/themes/linux/global/toolbarbutton.css | 1 + toolkit/themes/osx/global/toolbarbutton.css | 1 + toolkit/themes/windows/global/toolbarbutton.css | 1 + 3 files changed, 3 insertions(+) diff --git a/toolkit/themes/linux/global/toolbarbutton.css b/toolkit/themes/linux/global/toolbarbutton.css index a62e173bb2f9..ffaf672bd426 100644 --- a/toolkit/themes/linux/global/toolbarbutton.css +++ b/toolkit/themes/linux/global/toolbarbutton.css @@ -122,6 +122,7 @@ toolbarbutton[type="menu-button"][disabled="true"]:hover:active { margin: -6px 0 0 !important; -moz-margin-end: -8px !important; min-width: 14px; + max-width: 28px; line-height: 10px; text-align: center; -moz-stack-sizing: ignore; diff --git a/toolkit/themes/osx/global/toolbarbutton.css b/toolkit/themes/osx/global/toolbarbutton.css index 77af0458063b..03a9352432a9 100644 --- a/toolkit/themes/osx/global/toolbarbutton.css +++ b/toolkit/themes/osx/global/toolbarbutton.css @@ -88,6 +88,7 @@ toolbarbutton[type="menu-button"][disabled="true"]:hover:active { margin: -6px 0 0 !important; -moz-margin-end: -6px !important; min-width: 14px; + max-width: 28px; line-height: 10px; text-align: center; -moz-stack-sizing: ignore; diff --git a/toolkit/themes/windows/global/toolbarbutton.css b/toolkit/themes/windows/global/toolbarbutton.css index 81cbde7b0030..be3a0146b956 100644 --- a/toolkit/themes/windows/global/toolbarbutton.css +++ b/toolkit/themes/windows/global/toolbarbutton.css @@ -163,6 +163,7 @@ toolbarbutton[type="menu-button"][disabled="true"]:hover:active { margin: -6px 0 0 !important; -moz-margin-end: -8px !important; min-width: 14px; + max-width: 28px; line-height: 10px; text-align: center; -moz-stack-sizing: ignore; From 3b7a3980fffd0b3d825baac4559432d238fdac9b Mon Sep 17 00:00:00 2001 From: Kilik Kuo Date: Tue, 13 Oct 2015 15:39:01 +0800 Subject: [PATCH 33/79] Bug 1213897 - Extract DelayedScheduler out of MDSM to a common class. r=jwwang --HG-- extra : rebase_source : 5408c282a678fe060d24138eccbe34cf99c8c929 --- dom/media/MediaDecoderStateMachine.cpp | 10 ++++- dom/media/MediaDecoderStateMachine.h | 47 +---------------------- dom/media/MediaTimer.h | 52 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 36b45e71b4d4..f29b82ddafe0 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -204,7 +204,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mProducerID(ImageContainer::AllocateProducerID()), mRealTime(aRealTime), mDispatchedStateMachine(false), - mDelayedScheduler(this), + mDelayedScheduler(mTaskQueue), mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"), mCurrentFrameID(0), mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"), @@ -2855,7 +2855,13 @@ MediaDecoderStateMachine::ScheduleStateMachineIn(int64_t aMicroseconds) TimeStamp target = now + TimeDuration::FromMicroseconds(aMicroseconds); SAMPLE_LOG("Scheduling state machine for %lf ms from now", (target - now).ToMilliseconds()); - mDelayedScheduler.Ensure(target); + + nsRefPtr self = this; + mDelayedScheduler.Ensure(target, [self] () { + self->OnDelayedSchedule(); + }, [self] () { + self->NotReached(); + }); } bool MediaDecoderStateMachine::OnTaskQueue() const diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index f27d96a73be8..a5846f4bfafc 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -679,51 +679,8 @@ private: // yet to run. bool mDispatchedStateMachine; - // Class for managing delayed dispatches of the state machine. - class DelayedScheduler { - public: - explicit DelayedScheduler(MediaDecoderStateMachine* aSelf) - : mSelf(aSelf), mMediaTimer(new MediaTimer()) {} - - bool IsScheduled() const { return !mTarget.IsNull(); } - - void Reset() - { - MOZ_ASSERT(mSelf->OnTaskQueue(), "Must be on state machine queue to disconnect"); - if (IsScheduled()) { - mRequest.Disconnect(); - mTarget = TimeStamp(); - } - } - - void Ensure(mozilla::TimeStamp& aTarget) - { - MOZ_ASSERT(mSelf->OnTaskQueue()); - if (IsScheduled() && mTarget <= aTarget) { - return; - } - Reset(); - mTarget = aTarget; - mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->Then( - mSelf->OwnerThread(), __func__, mSelf, - &MediaDecoderStateMachine::OnDelayedSchedule, - &MediaDecoderStateMachine::NotReached)); - } - - void CompleteRequest() - { - MOZ_ASSERT(mSelf->OnTaskQueue()); - mRequest.Complete(); - mTarget = TimeStamp(); - } - - private: - MediaDecoderStateMachine* mSelf; - nsRefPtr mMediaTimer; - MozPromiseRequestHolder mRequest; - TimeStamp mTarget; - - } mDelayedScheduler; + // Used to dispatch another round schedule with specific target time. + DelayedScheduler mDelayedScheduler; // StartTimeRendezvous is a helper class that quarantines the first sample // until it gets a sample from both channels, such that we can be guaranteed diff --git a/dom/media/MediaTimer.h b/dom/media/MediaTimer.h index d80066101de5..f7878a4fa54c 100644 --- a/dom/media/MediaTimer.h +++ b/dom/media/MediaTimer.h @@ -113,6 +113,58 @@ private: bool mUpdateScheduled; }; +// Class for managing delayed dispatches on target thread. +class DelayedScheduler { +public: + explicit DelayedScheduler(AbstractThread* aTargetThread) + : mTargetThread(aTargetThread), mMediaTimer(new MediaTimer()) + { + MOZ_ASSERT(mTargetThread); + } + + bool IsScheduled() const { return !mTarget.IsNull(); } + + void Reset() + { + MOZ_ASSERT(mTargetThread->IsCurrentThreadIn(), + "Must be on target thread to disconnect"); + if (IsScheduled()) { + mRequest.Disconnect(); + mTarget = TimeStamp(); + } + } + + template + void Ensure(mozilla::TimeStamp& aTarget, + ResolveFunc&& aResolver, + RejectFunc&& aRejector) + { + MOZ_ASSERT(mTargetThread->IsCurrentThreadIn()); + if (IsScheduled() && mTarget <= aTarget) { + return; + } + Reset(); + mTarget = aTarget; + mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->Then( + mTargetThread, __func__, + Forward(aResolver), + Forward(aRejector))); + } + + void CompleteRequest() + { + MOZ_ASSERT(mTargetThread->IsCurrentThreadIn()); + mRequest.Complete(); + mTarget = TimeStamp(); + } + +private: + nsRefPtr mTargetThread; + nsRefPtr mMediaTimer; + MozPromiseRequestHolder mRequest; + TimeStamp mTarget; +}; + } // namespace mozilla #endif From 591940732d1c23c77f6f86e2258cb946fa0d3093 Mon Sep 17 00:00:00 2001 From: Georg Fritzsche Date: Thu, 17 Sep 2015 14:07:45 +0700 Subject: [PATCH 34/79] Bug 1205564 - Add documentation for crash data in Telemetry. r=benjamin --- toolkit/components/telemetry/docs/crashes.rst | 23 +++++++++++++++++++ toolkit/components/telemetry/docs/index.rst | 1 + 2 files changed, 24 insertions(+) create mode 100644 toolkit/components/telemetry/docs/crashes.rst diff --git a/toolkit/components/telemetry/docs/crashes.rst b/toolkit/components/telemetry/docs/crashes.rst new file mode 100644 index 000000000000..e6f7e7c9f747 --- /dev/null +++ b/toolkit/components/telemetry/docs/crashes.rst @@ -0,0 +1,23 @@ +======= +Crashes +======= + +There are many different kinds of crashes for Firefox, there is not a single system used to record all of them. + +Main process crashes +==================== + +If the Firefox main process dies, that should be recorded as an aborted session. We would submit a :doc:`main ping ` with the reason ``aborted-session``. +If we have a crash dump for that crash, we should also submit a :doc:`crash ping `. + +The ``aborted-session`` information is first written to disk 60 seconds after startup, any earlier crashes will not trigger an ``aborted-session`` ping. +Also, the ``aborted-session`` is updated at least every 5 minutes, so it may lag behind the last session state. + +Crashes during startup should be recorded in the next sessions main ping in the ``STARTUP_CRASH_DETECTED`` histogram. + +Child process crashes +===================== + +If a Firefox plugin, content or gmplugin process dies unexpectedly, this is recorded in the main pings ``SUBPROCESS_ABNORMAL_ABORT`` keyed histogram. + +If we catch a crash report for this, then additionally the ``SUBPROCESS_CRASHES_WITH_DUMP`` keyed histogram is incremented. diff --git a/toolkit/components/telemetry/docs/index.rst b/toolkit/components/telemetry/docs/index.rst index 9bdae7d5a765..2f0fcc9cdf53 100644 --- a/toolkit/components/telemetry/docs/index.rst +++ b/toolkit/components/telemetry/docs/index.rst @@ -23,3 +23,4 @@ Client-side, this consists of: crash-ping uitour-ping preferences + crashes From 67f02040d693f3025d85dc6d0496c69c17482144 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 13 Oct 2015 18:14:43 +0300 Subject: [PATCH 35/79] Bug 1213818 - Align document.title for SVG documents with HTML spec; r=bz This allows setting, and for getting, pays attention to only children of the root element (instead of all descendants as in HTML). --- dom/base/nsDocument.cpp | 116 ++++++++++-------- dom/base/nsDocument.h | 16 +-- .../document.title-09.html.ini | 11 -- .../dom-tree-accessors/document.title-09.html | 47 ++++++- 4 files changed, 119 insertions(+), 71 deletions(-) delete mode 100644 testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-09.html.ini diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 283795d6fb48..fc378131c167 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -7014,8 +7014,8 @@ nsIDocument::GetHtmlChildElement(nsIAtom* aTag) return nullptr; } -nsIContent* -nsDocument::GetTitleContent(uint32_t aNamespace) +Element* +nsDocument::GetTitleElement() { // mMayHaveTitleElement will have been set to true if any HTML or SVG // element has been bound to this document. So if it's false, @@ -7025,19 +7025,26 @@ nsDocument::GetTitleContent(uint32_t aNamespace) if (!mMayHaveTitleElement) return nullptr; + Element* root = GetRootElement(); + if (root && root->IsSVGElement(nsGkAtoms::svg)) { + // In SVG, the document's title must be a child + for (nsIContent* child = root->GetFirstChild(); + child; child = child->GetNextSibling()) { + if (child->IsSVGElement(nsGkAtoms::title)) { + return child->AsElement(); + } + } + return nullptr; + } + + // We check the HTML namespace even for non-HTML documents, except SVG. This + // matches the spec and the behavior of all tested browsers. nsRefPtr<nsContentList> list = - NS_GetContentList(this, aNamespace, NS_LITERAL_STRING("title")); + NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("title")); - return list->Item(0, false); -} + nsIContent* first = list->Item(0, false); -void -nsDocument::GetTitleFromElement(uint32_t aNamespace, nsAString& aTitle) -{ - nsIContent* title = GetTitleContent(aNamespace); - if (!title) - return; - nsContentUtils::GetNodeTextContent(title, false, aTitle); + return first ? first->AsElement() : nullptr; } NS_IMETHODIMP @@ -7054,26 +7061,24 @@ nsDocument::GetTitle(nsString& aTitle) { aTitle.Truncate(); - nsIContent *rootElement = GetRootElement(); - if (!rootElement) + Element* rootElement = GetRootElement(); + if (!rootElement) { return; + } nsAutoString tmp; - switch (rootElement->GetNameSpaceID()) { #ifdef MOZ_XUL - case kNameSpaceID_XUL: - rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp); - break; + if (rootElement->IsXULElement()) { + rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp); + } else #endif - case kNameSpaceID_SVG: - if (rootElement->IsSVGElement(nsGkAtoms::svg)) { - GetTitleFromElement(kNameSpaceID_SVG, tmp); - break; - } // else fall through - default: - GetTitleFromElement(kNameSpaceID_XHTML, tmp); - break; + { + Element* title = GetTitleElement(); + if (!title) { + return; + } + nsContentUtils::GetNodeTextContent(title, false, tmp); } tmp.CompressWhitespace(); @@ -7083,41 +7088,56 @@ nsDocument::GetTitle(nsString& aTitle) NS_IMETHODIMP nsDocument::SetTitle(const nsAString& aTitle) { - Element *rootElement = GetRootElement(); - if (!rootElement) + Element* rootElement = GetRootElement(); + if (!rootElement) { return NS_OK; - - switch (rootElement->GetNameSpaceID()) { - case kNameSpaceID_SVG: - return NS_OK; // SVG doesn't support setting a title -#ifdef MOZ_XUL - case kNameSpaceID_XUL: - return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title, - aTitle, true); -#endif } +#ifdef MOZ_XUL + if (rootElement->IsXULElement()) { + return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title, + aTitle, true); + } +#endif + // Batch updates so that mutation events don't change "the title // element" under us mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, true); - nsIContent* title = GetTitleContent(kNameSpaceID_XHTML); - if (!title) { - Element *head = GetHeadElement(); - if (!head) - return NS_OK; + nsCOMPtr<Element> title = GetTitleElement(); + if (rootElement->IsSVGElement(nsGkAtoms::svg)) { + if (!title) { + nsRefPtr<mozilla::dom::NodeInfo> titleInfo = + mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr, + kNameSpaceID_SVG, + nsIDOMNode::ELEMENT_NODE); + NS_NewSVGElement(getter_AddRefs(title), titleInfo.forget(), + NOT_FROM_PARSER); + if (!title) { + return NS_OK; + } + rootElement->InsertChildAt(title, 0, true); + } + } else if (rootElement->IsHTMLElement()) { + if (!title) { + Element* head = GetHeadElement(); + if (!head) { + return NS_OK; + } - { nsRefPtr<mozilla::dom::NodeInfo> titleInfo; titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr, - kNameSpaceID_XHTML, - nsIDOMNode::ELEMENT_NODE); + kNameSpaceID_XHTML, + nsIDOMNode::ELEMENT_NODE); title = NS_NewHTMLTitleElement(titleInfo.forget()); - if (!title) + if (!title) { return NS_OK; - } + } - head->AppendChildTo(title, true); + head->AppendChildTo(title, true); + } + } else { + return NS_OK; } return nsContentUtils::SetNodeTextContent(title, aTitle, false); diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index b1afd3575f3c..e0afa0057e7c 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -1474,13 +1474,15 @@ protected: nsIContent* GetFirstBaseNodeWithHref(); nsresult SetFirstBaseNodeWithHref(nsIContent *node); - // Get the first <title> element with the given IsNodeOfType type, or - // return null if there isn't one - nsIContent* GetTitleContent(uint32_t aNodeType); - // Find the first "title" element in the given IsNodeOfType type and - // append the concatenation of its text node children to aTitle. Do - // nothing if there is no such element. - void GetTitleFromElement(uint32_t aNodeType, nsAString& aTitle); + /** + * Returns the title element of the document as defined by the HTML + * specification, or null if there isn't one. For documents whose root + * element is an <svg:svg>, this is the first <svg:title> element that's a + * child of the root. For other documents, it's the first HTML title element + * in the document. + */ + Element* GetTitleElement(); + public: // Get our title virtual void GetTitle(nsString& aTitle) override; diff --git a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-09.html.ini b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-09.html.ini deleted file mode 100644 index 617f8d14bacc..000000000000 --- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/document.title-09.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[document.title-09.html] - type: testharness - [No title element in SVG document] - expected: FAIL - - [Title element in SVG document] - expected: FAIL - - [Title element not child of SVG root] - expected: FAIL - diff --git a/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.title-09.html b/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.title-09.html index 731d78cc14f3..1527d006cbb7 100644 --- a/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.title-09.html +++ b/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.title-09.html @@ -5,21 +5,25 @@ <div id="log"></div> <script> var SVG_NAMESPACE = "http://www.w3.org/2000/svg"; +var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; function newSVGDocument() { return document.implementation.createDocument(SVG_NAMESPACE, "svg"); } +function assertIsSVGTitle(element, expectedText) { + assert_equals(element.namespaceURI, SVG_NAMESPACE); + assert_equals(element.localName, "title"); + assert_equals(element.textContent, expectedText); +} + test(function() { var doc = newSVGDocument(); assert_equals(doc.title, ""); var child = doc.createElementNS(SVG_NAMESPACE, "x-child"); doc.documentElement.appendChild(child); doc.title = "foo"; - var lastChild = doc.documentElement.lastChild; - assert_equals(lastChild.namespaceURI, SVG_NAMESPACE); - assert_equals(lastChild.localName, "title"); - assert_equals(lastChild.textContent, "foo"); + assertIsSVGTitle(doc.documentElement.firstChild, "foo"); assert_equals(doc.title, "foo"); }, "No title element in SVG document"); @@ -48,13 +52,46 @@ test(function() { child.appendChild(title); doc.documentElement.appendChild(child); assert_equals(doc.title, ""); + + // Now test that on setting, we create a new element and don't change the + // existing one + doc.title = "bar"; + assert_equals(title.textContent, "foo"); + assertIsSVGTitle(doc.documentElement.firstChild, "bar"); + assert_equals(doc.title, "bar"); }, "Title element not child of SVG root"); test(function() { var doc = newSVGDocument(); - var title = doc.createElement("title"); + var title = doc.createElementNS(HTML_NAMESPACE, "title"); title.textContent = "foo"; doc.documentElement.appendChild(title); assert_equals(doc.title, ""); }, "Title element not in SVG namespace"); + +test(function() { + // "SVG" != "svg" + var doc = document.implementation.createDocument(SVG_NAMESPACE, "SVG", null); + + // Per spec, this does nothing + doc.title = "foo"; + assert_equals(doc.documentElement.childNodes.length, 0); + assert_equals(doc.title, ""); + + // An SVG title is ignored by .title + doc.documentElement.appendChild(doc.createElementNS(SVG_NAMESPACE, "title")); + doc.documentElement.lastChild.textContent = "foo"; + assert_equals(doc.title, ""); + + // But an HTML title is respected + doc.documentElement.appendChild(doc.createElementNS(HTML_NAMESPACE, "title")); + doc.documentElement.lastChild.textContent = "bar"; + assert_equals(doc.title, "bar"); + + // Even if it's not a child of the root + var div = doc.createElementNS(HTML_NAMESPACE, "div"); + div.appendChild(doc.documentElement.lastChild); + doc.documentElement.appendChild(div); + assert_equals(doc.title, "bar"); +}, 'Root element not named "svg"'); </script> From bc130fa093457b804382a9dff97b47f7413df8e6 Mon Sep 17 00:00:00 2001 From: Terrence Cole <terrence@mozilla.com> Date: Tue, 13 Oct 2015 09:23:17 -0700 Subject: [PATCH 36/79] Bug 1206987 - Only disable the GPF dialog during testing; r=sfink --HG-- extra : rebase_source : 24779b325030ac836b4b11ff4f0577cc02dd2178 --- js/src/shell/js.cpp | 22 ++++++++-------------- js/src/tests/lib/tests.py | 2 ++ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 7701f7295d10..ef7f581e1de9 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -6352,11 +6352,14 @@ static void PreInit() { #ifdef XP_WIN - // Disable the segfault dialog. We want to fail the tests immediately - // instead of hanging automation. - UINT prevMode = SetErrorMode(0); - UINT newMode = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX; - SetErrorMode(prevMode | newMode); + const char* crash_option = getenv("XRE_NO_WINDOWS_CRASH_DIALOG"); + if (crash_option && strncmp(crash_option, "1", 1)) { + // Disable the segfault dialog. We want to fail the tests immediately + // instead of hanging automation. + UINT newMode = SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX; + UINT prevMode = SetErrorMode(newMode); + SetErrorMode(prevMode | newMode); + } #endif } @@ -6371,15 +6374,6 @@ main(int argc, char** argv, char** envp) JSRuntime* rt; JSContext* cx; int result; -#ifdef XP_WIN - { - const char* crash_option = getenv("XRE_NO_WINDOWS_CRASH_DIALOG"); - if (crash_option && strncmp(crash_option, "1", 1)) { - DWORD oldmode = SetErrorMode(SEM_NOGPFAULTERRORBOX); - SetErrorMode(oldmode | SEM_NOGPFAULTERRORBOX); - } - } -#endif #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); diff --git a/js/src/tests/lib/tests.py b/js/src/tests/lib/tests.py index f11514ab260f..3b40abd87fb3 100644 --- a/js/src/tests/lib/tests.py +++ b/js/src/tests/lib/tests.py @@ -57,6 +57,8 @@ def get_environment_overlay(js_shell): 'TZ': 'PST8PDT', # Force date strings to English. 'LC_TIME': 'en_US.UTF-8', + # Tell the shell to disable crash dialogs on windows. + 'XRE_NO_WINDOWS_CRASH_DIALOG': '1', } # Add the binary's directory to the library search path so that we find the # nspr and icu we built, instead of the platform supplied ones (or none at From 040e2d5aab954a3ba3a595448aad5c8117a68bd5 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald <fitzgen@gmail.com> Date: Tue, 13 Oct 2015 09:42:39 -0700 Subject: [PATCH 37/79] Bug 1211006 - Add Debugger.Source.prototype.canonicalId; r=ejpbruel --- js/public/Value.h | 11 ++++++- js/src/doc/Debugger/Debugger.Source.md | 11 +++++++ .../tests/debug/Source-canonicalId.js | 32 +++++++++++++++++++ js/src/vm/Debugger.cpp | 27 ++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/debug/Source-canonicalId.js diff --git a/js/public/Value.h b/js/public/Value.h index 0bbaf3d11c82..4fc2afb85c57 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1010,6 +1010,15 @@ class Value Value(const Value& v) = default; #endif + /** + * Returns false if creating a NumberValue containing the given type would + * be lossy, true otherwise. + */ + template <typename T> + static bool isNumberRepresentable(const T t) { + return T(double(t)) == t; + } + /*** Mutators ***/ void setNull() { @@ -1611,7 +1620,7 @@ template <typename T> static inline Value NumberValue(const T t) { - MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy"); + MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t); } diff --git a/js/src/doc/Debugger/Debugger.Source.md b/js/src/doc/Debugger/Debugger.Source.md index 7b89c2edc519..d9946a543c00 100644 --- a/js/src/doc/Debugger/Debugger.Source.md +++ b/js/src/doc/Debugger/Debugger.Source.md @@ -40,6 +40,17 @@ to store metadata about particular pieces of source code. A `Debugger.Source` instance inherits the following accessor properties from its prototype: +`canonicalId` +: A stable, unique identifier for the source referent. This identifier is + suitable for checking if two `Debugger.Source` instances originating from + different `Debugger` instances refer to the same source that was compiled by + SpiderMonkey. The `canonicalId` is reliable even when the source does not + have a URL, or shares the same URL as another source but has different + source text. It is more efficient to compare `canonicalId`s than to compare + source text character-by-character. The `canonicalId` is not suitable for + ordering comparisons such as "greater than" or "less than". It is not + suitable for checking the equality of sources across worker threads. + `text` : The JavaScript source code, as a string. The value satisfies the `Program`, `FunctionDeclaration`, or `FunctionExpression` productions in diff --git a/js/src/jit-test/tests/debug/Source-canonicalId.js b/js/src/jit-test/tests/debug/Source-canonicalId.js new file mode 100644 index 000000000000..2d9b46bf96c7 --- /dev/null +++ b/js/src/jit-test/tests/debug/Source-canonicalId.js @@ -0,0 +1,32 @@ +// Test Debugger.Source.prototype.canonicalId + +const g = newGlobal(); + +const dbg1 = new Debugger; +const dbg2 = new Debugger; + +const gw1 = dbg1.addDebuggee(g); +const gw2 = dbg2.addDebuggee(g); + +g.eval("function f(x) { return 2*x; }"); +g.eval("function g(x) { return 2+x; }"); + +const fw1 = gw1.getOwnPropertyDescriptor('f').value; +const fw2 = gw2.getOwnPropertyDescriptor('f').value; +const hw1 = gw1.getOwnPropertyDescriptor('g').value; +const hw2 = gw2.getOwnPropertyDescriptor('g').value; + +const fs1 = fw1.script.source; +const fs2 = fw2.script.source; +const gs1 = hw1.script.source; +const gs2 = hw2.script.source; + +assertEq(!!fs1, true); +assertEq(!!fs2, true); +assertEq(fs1.canonicalId, fs2.canonicalId); + +assertEq(!!gs1, true); +assertEq(!!gs2, true); +assertEq(gs1.canonicalId, gs2.canonicalId); + +assertEq(fs1.canonicalId !== gs1.canonicalId, true); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 81089dc4dd3d..d74fffac25fb 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -8,6 +8,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/ScopeExit.h" +#include "mozilla/TypeTraits.h" #include "jscntxt.h" #include "jscompartment.h" @@ -5953,6 +5954,31 @@ DebuggerSource_getSourceMapUrl(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +DebuggerSource_getCanonicalId(JSContext* cx, unsigned argc, Value* vp) +{ + THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get sourceMapURL)", args, obj, sourceObject); + + ScriptSource* ss = sourceObject->source(); + MOZ_ASSERT(ss); + + static_assert(!mozilla::IsBaseOf<gc::Cell, ScriptSource>::value, + "We rely on ScriptSource* pointers to be stable, and not move in memory. " + "Currently, this holds true because ScriptSource is not managed by the GC. If " + "that changes, it doesn't necessarily mean that it will start moving, but we " + "will need a new assertion here. If we do start moving ScriptSources in memory, " + "then DebuggerSource_getCanonicalId will need to be reworked!"); + auto id = uintptr_t(ss); + + // IEEE 754 doubles can precisely store integers of up 53 bits. On 32 bit + // platforms, pointers trivially fit. On 64 bit platforms, pointers only use + // 48 bits so we are still good. + MOZ_ASSERT(Value::isNumberRepresentable(id)); + + args.rval().set(NumberValue(id)); + return true; +} + static const JSPropertySpec DebuggerSource_properties[] = { JS_PSG("text", DebuggerSource_getText, 0), JS_PSG("url", DebuggerSource_getUrl, 0), @@ -5963,6 +5989,7 @@ static const JSPropertySpec DebuggerSource_properties[] = { JS_PSG("introductionType", DebuggerSource_getIntroductionType, 0), JS_PSG("elementAttributeName", DebuggerSource_getElementProperty, 0), JS_PSGS("sourceMapURL", DebuggerSource_getSourceMapUrl, DebuggerSource_setSourceMapUrl, 0), + JS_PSG("canonicalId", DebuggerSource_getCanonicalId, 0), JS_PS_END }; From 73e113381fdadb6c5350c3390d8d507bb7daf98b Mon Sep 17 00:00:00 2001 From: Wes Kocher <wkocher@mozilla.com> Date: Tue, 13 Oct 2015 10:08:11 -0700 Subject: [PATCH 38/79] Backed out 3 changesets (bug 1095236) for possibly spiking the frequency of VP(b-m) failures CLOSED TREE Backed out changeset 11cb6379251a (bug 1095236) Backed out changeset 856b7b90184f (bug 1095236) Backed out changeset a179310161fb (bug 1095236) --- dom/tests/browser/browser.ini | 1 + .../browser_test_new_window_from_content.js | 208 ++++++++++++++---- .../test_new_window_from_content_child.html | 10 +- .../test_new_window_from_content_child.js | 19 ++ .../windowwatcher/nsWindowWatcher.cpp | 6 +- 5 files changed, 200 insertions(+), 44 deletions(-) create mode 100644 dom/tests/browser/test_new_window_from_content_child.js diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index 95767441d369..3fc0938a8e0e 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -26,6 +26,7 @@ skip-if= buildapp == 'mulet' skip-if = (toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet') support-files = test_new_window_from_content_child.html + test_new_window_from_content_child.js [browser_webapps_permissions.js] # TODO: Re-enable permissions tests on Mac, bug 795334 skip-if = buildapp != "b2g" diff --git a/dom/tests/browser/browser_test_new_window_from_content.js b/dom/tests/browser/browser_test_new_window_from_content.js index 22a6bbb5f9ed..1514369321bd 100644 --- a/dom/tests/browser/browser_test_new_window_from_content.js +++ b/dom/tests/browser/browser_test_new_window_from_content.js @@ -35,7 +35,10 @@ each preference. */ +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const kContentDoc = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html"; @@ -88,8 +91,117 @@ registerCleanupFunction(function() { Services.prefs.setIntPref(kNewWindowPrefKey, originalNewWindowPref); Services.prefs.setIntPref(kNewWindowRestrictionPrefKey, originalNewWindowRestrictionPref); + // If there are any content tabs leftover, make sure they're not going to + // block exiting with onbeforeunload. + for (let tab of gBrowser.tabs) { + let browser = gBrowser.getBrowserForTab(tab); + if (browser.contentDocument.location == kContentDoc) { + closeTab(tab); + } + } }); +/** + * WindowOpenListener is a very simple nsIWindowMediatorListener that + * listens for a new window opening to aExpectedURI. It has two Promises + * attached to it - openPromise and closePromise. As you'd expect, + * openPromise resolves when the window is opened, and closePromise + * resolves if and when a window with the same URI closes. There is + * no attempt to make sure that it's the same window opening and + * closing - we just use the URI. + * + * @param aExpectedURI the URI to watch for in a new window. + * @return nsIWindowMediatorListener + */ +function WindowOpenListener(aExpectedURI) { + this._openDeferred = Promise.defer(); + this._closeDeferred = Promise.defer(); + this._expectedURI = aExpectedURI; +} + +WindowOpenListener.prototype = { + get openPromise() { + return this._openDeferred.promise; + }, + + get closePromise() { + return this._closeDeferred.promise; + }, + + onOpenWindow: function(aXULWindow) { + let domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + let location = domWindow.document.location; + if (location == this._expectedURI) { + let deferred = this._openDeferred; + domWindow.addEventListener("load", function onWindowLoad() { + domWindow.removeEventListener("load", onWindowLoad); + deferred.resolve(domWindow); + }) + } + }, + + onCloseWindow: function(aXULWindow) { + this._closeDeferred.resolve(); + }, + onWindowTitleChange: function(aXULWindow, aNewTitle) {}, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener]) +}; + +/** + * Adds the testing tab, and injects our frame script which + * allows us to send click events to links and other things. + * + * @return a Promise that resolves once the tab is loaded and ready. + */ +function loadAndSelectTestTab() { + let tab = gBrowser.addTab(kContentDoc); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + browser.messageManager.loadFrameScript(kContentScript, false); + + let deferred = Promise.defer(); + browser.addEventListener("DOMContentLoaded", function onBrowserLoad(aEvent) { + browser.removeEventListener("DOMContentLoaded", onBrowserLoad); + deferred.resolve(tab); + }); + + return deferred.promise; +} + +/** + * Clears the onbeforeunload event handler from the testing tab, + * and then closes the tab. + * + * @param aTab the testing tab to close. + * @param a Promise that resolves once the tab has been closed. + */ +function closeTab(aTab) { + let deferred = Promise.defer(); + let browserMM = gBrowser.getBrowserForTab(aTab).messageManager; + browserMM.sendAsyncMessage("TEST:allow-unload"); + browserMM.addMessageListener("TEST:allow-unload:done", function(aMessage) { + gBrowser.removeTab(aTab); + deferred.resolve(); + }) + return deferred.promise; +} + +/** + * Sends a click event on some item into a tab. + * + * @param aTab the tab to send the click event to + * @param aItemId the item within the tab content to click. + */ +function clickInTab(aTab, aItemId) { + let browserMM = gBrowser.getBrowserForTab(aTab).messageManager; + browserMM.sendAsyncMessage("TEST:click-item", { + details: aItemId, + }); +} + /** * For some expectation when a link is clicked, creates and * returns a Promise that resolves when that expectation is @@ -101,38 +213,62 @@ registerCleanupFunction(function() { * occurred - for example, if a new window was opened, this function * closes it before resolving. * - * @param aBrowser the <xul:browser> with the test document + * @param aTab the tab with the test document * @param aExpectation one of kSameTab, kNewWin, or kNewTab. * @return a Promise that resolves when the expectation is fulfilled, * and cleaned up after. */ -function prepareForResult(aBrowser, aExpectation) { +function prepareForResult(aTab, aExpectation) { + let deferred = Promise.defer(); + let browser = gBrowser.getBrowserForTab(aTab); + switch(aExpectation) { case kSameTab: - return Task.spawn(function*() { - yield BrowserTestUtils.browserLoaded(aBrowser); - is(aBrowser.currentURI.spec, "about:robots", "Should be at about:robots"); - // Now put the browser back where it came from - yield BrowserTestUtils.loadURI(aBrowser, kContentDoc); - yield BrowserTestUtils.browserLoaded(aBrowser); - }); + // We expect about:blank to be loaded in the current tab. In order + // to prevent us needing to reload the document and content script + // after browsing away, we'll detect the attempt by using onbeforeunload, + // and then cancel the unload. It's a hack, but it's also a pretty + // cheap way of detecting when we're browsing away in the test tab. + // The onbeforeunload event handler is set in the content script automatically. + browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() { + browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true); + executeSoon(() => { + let stack = browser.parentNode; + let dialogs = stack.getElementsByTagNameNS(kXULNS, "tabmodalprompt"); + dialogs[0].ui.button1.click() + deferred.resolve(); + }) + }, true); break; case kNewWin: - return Task.spawn(function*() { - let newWin = yield BrowserTestUtils.waitForNewWindow(); - let newBrowser = newWin.gBrowser.selectedBrowser; - yield BrowserTestUtils.browserLoaded(newBrowser); - is(newBrowser.currentURI.spec, "about:robots", "Should be at about:robots"); - yield BrowserTestUtils.closeWindow(newWin); + let listener = new WindowOpenListener("about:blank"); + Services.wm.addListener(listener); + + info("Waiting for a new about:blank window"); + listener.openPromise.then(function(aWindow) { + info("Got the new about:blank window - closing it."); + executeSoon(() => { + aWindow.close(); + }); + listener.closePromise.then(() => { + info("New about:blank window closed!"); + Services.wm.removeListener(listener); + deferred.resolve(); + }); }); break; case kNewTab: - return Task.spawn(function*() { - let newTab = yield BrowserTestUtils.waitForNewTab(gBrowser); - is(newTab.linkedBrowser.currentURI.spec, "about:robots", - "Should be at about:robots"); - yield BrowserTestUtils.removeTab(newTab); - }); + gBrowser.tabContainer.addEventListener("TabOpen", function onTabOpen(aEvent) { + let newTab = aEvent.target; + let newBrowser = gBrowser.getBrowserForTab(newTab); + if (newBrowser.contentDocument.location.href == "about:blank") { + gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); + executeSoon(() => { + gBrowser.removeTab(newTab); + deferred.resolve(); + }) + } + }) break; default: ok(false, "prepareForResult can't handle an expectation of " + aExpectation) @@ -147,16 +283,14 @@ function prepareForResult(aBrowser, aExpectation) { * perform as specified in the supplied aMatrix (kWinOpenDefault, * for example). * - * @param aLinkSelector a selector for the link within the testing page to click. + * @param aLinkId the id of the link within the testing page to test. * @param aMatrix a testing matrix for the * browser.link.open_newwindow and browser.link.open_newwindow.restriction * prefs to test against. See kWinOpenDefault for an example. */ -function testLinkWithMatrix(aLinkSelector, aMatrix) { - return BrowserTestUtils.withNewTab({ - gBrowser, - url: kContentDoc, - }, function*(browser) { +function testLinkWithMatrix(aLinkId, aMatrix) { + return Task.spawn(function* () { + let tab = yield loadAndSelectTestTab(); // This nested for-loop is unravelling the matrix const // we set up, and gives us three things through each tick // of the inner loop: @@ -164,6 +298,7 @@ function testLinkWithMatrix(aLinkSelector, aMatrix) { // 2) newWindowRestPref: a browser.link.open_newwindow.restriction pref to try // 3) expectation: what we expect the click outcome on this link to be, // which will either be kSameTab, kNewWin or kNewTab. + for (let newWindowPref in aMatrix) { let expectations = aMatrix[newWindowPref]; for (let i = 0; i < expectations.length; ++i) { @@ -172,31 +307,28 @@ function testLinkWithMatrix(aLinkSelector, aMatrix) { Services.prefs.setIntPref("browser.link.open_newwindow", newWindowPref); Services.prefs.setIntPref("browser.link.open_newwindow.restriction", newWindowRestPref); - info("Clicking on " + aLinkSelector); + info("Clicking on " + aLinkId); info("Testing with browser.link.open_newwindow = " + newWindowPref + " and " + "browser.link.open_newwindow.restriction = " + newWindowRestPref); info("Expecting: " + expectation); - let resultPromise = prepareForResult(browser, expectation); - BrowserTestUtils.synthesizeMouseAtCenter(aLinkSelector, {}, browser); + let resultPromise = prepareForResult(tab, expectation); + clickInTab(tab, aLinkId); yield resultPromise; - info("Got expectation: " + expectation); + ok(true, "Got expectation: " + expectation); } } + yield closeTab(tab); }); } add_task(function* test_window_open_with_defaults() { - yield testLinkWithMatrix("#winOpenDefault", kWinOpenDefault); + yield testLinkWithMatrix("winOpenDefault", kWinOpenDefault); }); add_task(function* test_window_open_with_non_defaults() { - yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault); -}); - -add_task(function* test_window_open_dialog() { - yield testLinkWithMatrix("#winOpenDialog", kWinOpenNonDefault); + yield testLinkWithMatrix("winOpenNonDefault", kWinOpenNonDefault); }); add_task(function* test_target__blank() { - yield testLinkWithMatrix("#targetBlank", kTargetBlank); + yield testLinkWithMatrix("targetBlank", kTargetBlank); }); diff --git a/dom/tests/browser/test_new_window_from_content_child.html b/dom/tests/browser/test_new_window_from_content_child.html index ab1bf6f4941d..0594919b3ac6 100644 --- a/dom/tests/browser/test_new_window_from_content_child.html +++ b/dom/tests/browser/test_new_window_from_content_child.html @@ -6,14 +6,18 @@ <body> <p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p> <p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p> - <p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p> - <p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p> + <p><a id="targetBlank" href="about:blank" target="_blank">Open a new window via target="_blank".</a></p> </body> </html> <script> function openWindow(aFeatures="") { - window.open("about:robots", "_blank", aFeatures); + window.open("about:blank", "_blank", aFeatures); return false; } + +window.onbeforeunload = function(aEvent) { + return "We should not browse away from this document."; +} + </script> \ No newline at end of file diff --git a/dom/tests/browser/test_new_window_from_content_child.js b/dom/tests/browser/test_new_window_from_content_child.js new file mode 100644 index 000000000000..cd3f3ea9aa6a --- /dev/null +++ b/dom/tests/browser/test_new_window_from_content_child.js @@ -0,0 +1,19 @@ +// A hacky mechanism for catching and detecting that we're attempting +// to browse away is by setting the onbeforeunload event handler. We +// detect this dialog opening in the parent test script, and dismiss +// it. + +function handleClickItem(aMessage) { + let itemId = aMessage.data.details; + content.console.log("Getting item with ID: " + itemId); + let item = content.document.getElementById(itemId); + item.click(); +} + +function handleAllowUnload(aMessage) { + content.onbeforeunload = null; + sendSyncMessage("TEST:allow-unload:done"); +} + +addMessageListener("TEST:click-item", handleClickItem); +addMessageListener("TEST:allow-unload", handleAllowUnload); \ No newline at end of file diff --git a/embedding/components/windowwatcher/nsWindowWatcher.cpp b/embedding/components/windowwatcher/nsWindowWatcher.cpp index f481efda85bd..2f962dd48312 100644 --- a/embedding/components/windowwatcher/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp @@ -1651,9 +1651,9 @@ nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow* aParent, if (aParent) { aParent->GetFullScreen(&isFullScreen); } - if (openedFromContentScript) { - // If the caller context is content, we do not support the - // dialog feature. See bug 1095236. + if (isFullScreen && openedFromContentScript) { + // If the parent window is in fullscreen & the caller context is content, + // dialog feature is disabled. (see bug 803675) disableDialogFeature = true; } From d8c70c1560ac5753a3db5df55a2c2cfe036d9fa5 Mon Sep 17 00:00:00 2001 From: Mike Conley <mconley@mozilla.com> Date: Fri, 2 Oct 2015 19:44:48 -0400 Subject: [PATCH 39/79] Bug 1095236 - Simplify browser_test_new_window_from_content.js to use BrowserTestUtils. r=mrbkap --HG-- extra : source : a179310161fb9240245995f86a31ef45cace38f6 --- dom/tests/browser/browser.ini | 1 - .../browser_test_new_window_from_content.js | 204 +++--------------- .../test_new_window_from_content_child.html | 9 +- .../test_new_window_from_content_child.js | 19 -- 4 files changed, 36 insertions(+), 197 deletions(-) delete mode 100644 dom/tests/browser/test_new_window_from_content_child.js diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index 3fc0938a8e0e..95767441d369 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -26,7 +26,6 @@ skip-if= buildapp == 'mulet' skip-if = (toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet') support-files = test_new_window_from_content_child.html - test_new_window_from_content_child.js [browser_webapps_permissions.js] # TODO: Re-enable permissions tests on Mac, bug 795334 skip-if = buildapp != "b2g" diff --git a/dom/tests/browser/browser_test_new_window_from_content.js b/dom/tests/browser/browser_test_new_window_from_content.js index 1514369321bd..3048818c2838 100644 --- a/dom/tests/browser/browser_test_new_window_from_content.js +++ b/dom/tests/browser/browser_test_new_window_from_content.js @@ -35,10 +35,7 @@ each preference. */ -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const kContentDoc = "http://www.example.com/browser/dom/tests/browser/test_new_window_from_content_child.html"; @@ -91,117 +88,8 @@ registerCleanupFunction(function() { Services.prefs.setIntPref(kNewWindowPrefKey, originalNewWindowPref); Services.prefs.setIntPref(kNewWindowRestrictionPrefKey, originalNewWindowRestrictionPref); - // If there are any content tabs leftover, make sure they're not going to - // block exiting with onbeforeunload. - for (let tab of gBrowser.tabs) { - let browser = gBrowser.getBrowserForTab(tab); - if (browser.contentDocument.location == kContentDoc) { - closeTab(tab); - } - } }); -/** - * WindowOpenListener is a very simple nsIWindowMediatorListener that - * listens for a new window opening to aExpectedURI. It has two Promises - * attached to it - openPromise and closePromise. As you'd expect, - * openPromise resolves when the window is opened, and closePromise - * resolves if and when a window with the same URI closes. There is - * no attempt to make sure that it's the same window opening and - * closing - we just use the URI. - * - * @param aExpectedURI the URI to watch for in a new window. - * @return nsIWindowMediatorListener - */ -function WindowOpenListener(aExpectedURI) { - this._openDeferred = Promise.defer(); - this._closeDeferred = Promise.defer(); - this._expectedURI = aExpectedURI; -} - -WindowOpenListener.prototype = { - get openPromise() { - return this._openDeferred.promise; - }, - - get closePromise() { - return this._closeDeferred.promise; - }, - - onOpenWindow: function(aXULWindow) { - let domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - let location = domWindow.document.location; - if (location == this._expectedURI) { - let deferred = this._openDeferred; - domWindow.addEventListener("load", function onWindowLoad() { - domWindow.removeEventListener("load", onWindowLoad); - deferred.resolve(domWindow); - }) - } - }, - - onCloseWindow: function(aXULWindow) { - this._closeDeferred.resolve(); - }, - onWindowTitleChange: function(aXULWindow, aNewTitle) {}, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener]) -}; - -/** - * Adds the testing tab, and injects our frame script which - * allows us to send click events to links and other things. - * - * @return a Promise that resolves once the tab is loaded and ready. - */ -function loadAndSelectTestTab() { - let tab = gBrowser.addTab(kContentDoc); - gBrowser.selectedTab = tab; - - let browser = gBrowser.getBrowserForTab(tab); - browser.messageManager.loadFrameScript(kContentScript, false); - - let deferred = Promise.defer(); - browser.addEventListener("DOMContentLoaded", function onBrowserLoad(aEvent) { - browser.removeEventListener("DOMContentLoaded", onBrowserLoad); - deferred.resolve(tab); - }); - - return deferred.promise; -} - -/** - * Clears the onbeforeunload event handler from the testing tab, - * and then closes the tab. - * - * @param aTab the testing tab to close. - * @param a Promise that resolves once the tab has been closed. - */ -function closeTab(aTab) { - let deferred = Promise.defer(); - let browserMM = gBrowser.getBrowserForTab(aTab).messageManager; - browserMM.sendAsyncMessage("TEST:allow-unload"); - browserMM.addMessageListener("TEST:allow-unload:done", function(aMessage) { - gBrowser.removeTab(aTab); - deferred.resolve(); - }) - return deferred.promise; -} - -/** - * Sends a click event on some item into a tab. - * - * @param aTab the tab to send the click event to - * @param aItemId the item within the tab content to click. - */ -function clickInTab(aTab, aItemId) { - let browserMM = gBrowser.getBrowserForTab(aTab).messageManager; - browserMM.sendAsyncMessage("TEST:click-item", { - details: aItemId, - }); -} - /** * For some expectation when a link is clicked, creates and * returns a Promise that resolves when that expectation is @@ -213,62 +101,38 @@ function clickInTab(aTab, aItemId) { * occurred - for example, if a new window was opened, this function * closes it before resolving. * - * @param aTab the tab with the test document + * @param aBrowser the <xul:browser> with the test document * @param aExpectation one of kSameTab, kNewWin, or kNewTab. * @return a Promise that resolves when the expectation is fulfilled, * and cleaned up after. */ -function prepareForResult(aTab, aExpectation) { - let deferred = Promise.defer(); - let browser = gBrowser.getBrowserForTab(aTab); - +function prepareForResult(aBrowser, aExpectation) { switch(aExpectation) { case kSameTab: - // We expect about:blank to be loaded in the current tab. In order - // to prevent us needing to reload the document and content script - // after browsing away, we'll detect the attempt by using onbeforeunload, - // and then cancel the unload. It's a hack, but it's also a pretty - // cheap way of detecting when we're browsing away in the test tab. - // The onbeforeunload event handler is set in the content script automatically. - browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() { - browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true); - executeSoon(() => { - let stack = browser.parentNode; - let dialogs = stack.getElementsByTagNameNS(kXULNS, "tabmodalprompt"); - dialogs[0].ui.button1.click() - deferred.resolve(); - }) - }, true); + return Task.spawn(function*() { + yield BrowserTestUtils.browserLoaded(aBrowser); + is(aBrowser.currentURI.spec, "about:robots", "Should be at about:robots"); + // Now put the browser back where it came from + yield BrowserTestUtils.loadURI(aBrowser, kContentDoc); + yield BrowserTestUtils.browserLoaded(aBrowser); + }); break; case kNewWin: - let listener = new WindowOpenListener("about:blank"); - Services.wm.addListener(listener); - - info("Waiting for a new about:blank window"); - listener.openPromise.then(function(aWindow) { - info("Got the new about:blank window - closing it."); - executeSoon(() => { - aWindow.close(); - }); - listener.closePromise.then(() => { - info("New about:blank window closed!"); - Services.wm.removeListener(listener); - deferred.resolve(); - }); + return Task.spawn(function*() { + let newWin = yield BrowserTestUtils.waitForNewWindow(); + let newBrowser = newWin.gBrowser.selectedBrowser; + yield BrowserTestUtils.browserLoaded(newBrowser); + is(newBrowser.currentURI.spec, "about:robots", "Should be at about:robots"); + yield BrowserTestUtils.closeWindow(newWin); }); break; case kNewTab: - gBrowser.tabContainer.addEventListener("TabOpen", function onTabOpen(aEvent) { - let newTab = aEvent.target; - let newBrowser = gBrowser.getBrowserForTab(newTab); - if (newBrowser.contentDocument.location.href == "about:blank") { - gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); - executeSoon(() => { - gBrowser.removeTab(newTab); - deferred.resolve(); - }) - } - }) + return Task.spawn(function*() { + let newTab = yield BrowserTestUtils.waitForNewTab(gBrowser); + is(newTab.linkedBrowser.currentURI.spec, "about:robots", + "Should be at about:robots"); + yield BrowserTestUtils.removeTab(newTab); + }); break; default: ok(false, "prepareForResult can't handle an expectation of " + aExpectation) @@ -283,14 +147,16 @@ function prepareForResult(aTab, aExpectation) { * perform as specified in the supplied aMatrix (kWinOpenDefault, * for example). * - * @param aLinkId the id of the link within the testing page to test. + * @param aLinkSelector a selector for the link within the testing page to click. * @param aMatrix a testing matrix for the * browser.link.open_newwindow and browser.link.open_newwindow.restriction * prefs to test against. See kWinOpenDefault for an example. */ -function testLinkWithMatrix(aLinkId, aMatrix) { - return Task.spawn(function* () { - let tab = yield loadAndSelectTestTab(); +function testLinkWithMatrix(aLinkSelector, aMatrix) { + return BrowserTestUtils.withNewTab({ + gBrowser, + url: kContentDoc, + }, function*(browser) { // This nested for-loop is unravelling the matrix const // we set up, and gives us three things through each tick // of the inner loop: @@ -298,7 +164,6 @@ function testLinkWithMatrix(aLinkId, aMatrix) { // 2) newWindowRestPref: a browser.link.open_newwindow.restriction pref to try // 3) expectation: what we expect the click outcome on this link to be, // which will either be kSameTab, kNewWin or kNewTab. - for (let newWindowPref in aMatrix) { let expectations = aMatrix[newWindowPref]; for (let i = 0; i < expectations.length; ++i) { @@ -307,28 +172,27 @@ function testLinkWithMatrix(aLinkId, aMatrix) { Services.prefs.setIntPref("browser.link.open_newwindow", newWindowPref); Services.prefs.setIntPref("browser.link.open_newwindow.restriction", newWindowRestPref); - info("Clicking on " + aLinkId); + info("Clicking on " + aLinkSelector); info("Testing with browser.link.open_newwindow = " + newWindowPref + " and " + "browser.link.open_newwindow.restriction = " + newWindowRestPref); info("Expecting: " + expectation); - let resultPromise = prepareForResult(tab, expectation); - clickInTab(tab, aLinkId); + let resultPromise = prepareForResult(browser, expectation); + BrowserTestUtils.synthesizeMouseAtCenter(aLinkSelector, {}, browser); yield resultPromise; - ok(true, "Got expectation: " + expectation); + info("Got expectation: " + expectation); } } - yield closeTab(tab); }); } add_task(function* test_window_open_with_defaults() { - yield testLinkWithMatrix("winOpenDefault", kWinOpenDefault); + yield testLinkWithMatrix("#winOpenDefault", kWinOpenDefault); }); add_task(function* test_window_open_with_non_defaults() { - yield testLinkWithMatrix("winOpenNonDefault", kWinOpenNonDefault); + yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault); }); add_task(function* test_target__blank() { - yield testLinkWithMatrix("targetBlank", kTargetBlank); + yield testLinkWithMatrix("#targetBlank", kTargetBlank); }); diff --git a/dom/tests/browser/test_new_window_from_content_child.html b/dom/tests/browser/test_new_window_from_content_child.html index 0594919b3ac6..7609675b82ba 100644 --- a/dom/tests/browser/test_new_window_from_content_child.html +++ b/dom/tests/browser/test_new_window_from_content_child.html @@ -6,18 +6,13 @@ <body> <p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p> <p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p> - <p><a id="targetBlank" href="about:blank" target="_blank">Open a new window via target="_blank".</a></p> + <p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p> </body> </html> <script> function openWindow(aFeatures="") { - window.open("about:blank", "_blank", aFeatures); + window.open("about:robots", "_blank", aFeatures); return false; } - -window.onbeforeunload = function(aEvent) { - return "We should not browse away from this document."; -} - </script> \ No newline at end of file diff --git a/dom/tests/browser/test_new_window_from_content_child.js b/dom/tests/browser/test_new_window_from_content_child.js deleted file mode 100644 index cd3f3ea9aa6a..000000000000 --- a/dom/tests/browser/test_new_window_from_content_child.js +++ /dev/null @@ -1,19 +0,0 @@ -// A hacky mechanism for catching and detecting that we're attempting -// to browse away is by setting the onbeforeunload event handler. We -// detect this dialog opening in the parent test script, and dismiss -// it. - -function handleClickItem(aMessage) { - let itemId = aMessage.data.details; - content.console.log("Getting item with ID: " + itemId); - let item = content.document.getElementById(itemId); - item.click(); -} - -function handleAllowUnload(aMessage) { - content.onbeforeunload = null; - sendSyncMessage("TEST:allow-unload:done"); -} - -addMessageListener("TEST:click-item", handleClickItem); -addMessageListener("TEST:allow-unload", handleAllowUnload); \ No newline at end of file From 30c59e510c54f9c97a2c31bca8622eea721f6c9b Mon Sep 17 00:00:00 2001 From: Mike Conley <mconley@mozilla.com> Date: Fri, 2 Oct 2015 19:00:54 -0400 Subject: [PATCH 40/79] Bug 1095236 - Disable dialog=1 support for windows opened from content. r=mrbkap --HG-- extra : source : 856b7b90184f29a64093970e540193731b963f61 --- embedding/components/windowwatcher/nsWindowWatcher.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embedding/components/windowwatcher/nsWindowWatcher.cpp b/embedding/components/windowwatcher/nsWindowWatcher.cpp index 2f962dd48312..f481efda85bd 100644 --- a/embedding/components/windowwatcher/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp @@ -1651,9 +1651,9 @@ nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow* aParent, if (aParent) { aParent->GetFullScreen(&isFullScreen); } - if (isFullScreen && openedFromContentScript) { - // If the parent window is in fullscreen & the caller context is content, - // dialog feature is disabled. (see bug 803675) + if (openedFromContentScript) { + // If the caller context is content, we do not support the + // dialog feature. See bug 1095236. disableDialogFeature = true; } From c569672024c01b2e73724faf72ee45ba15524d2b Mon Sep 17 00:00:00 2001 From: Mike Conley <mconley@mozilla.com> Date: Fri, 2 Oct 2015 19:08:20 -0400 Subject: [PATCH 41/79] Bug 1095236 - Test that windows opened from content with dialog=1 still open. r=mrbkap. Relanding CLOSED TREE --HG-- extra : source : 11cb6379251ae9efd70bf3bc1f8fab9b66b3d964 extra : amend_source : 6a585ebc1cb80896b598a76cb4275b4ee9f1cee8 --- dom/tests/browser/browser_test_new_window_from_content.js | 4 ++++ dom/tests/browser/test_new_window_from_content_child.html | 1 + 2 files changed, 5 insertions(+) diff --git a/dom/tests/browser/browser_test_new_window_from_content.js b/dom/tests/browser/browser_test_new_window_from_content.js index 3048818c2838..22a6bbb5f9ed 100644 --- a/dom/tests/browser/browser_test_new_window_from_content.js +++ b/dom/tests/browser/browser_test_new_window_from_content.js @@ -193,6 +193,10 @@ add_task(function* test_window_open_with_non_defaults() { yield testLinkWithMatrix("#winOpenNonDefault", kWinOpenNonDefault); }); +add_task(function* test_window_open_dialog() { + yield testLinkWithMatrix("#winOpenDialog", kWinOpenNonDefault); +}); + add_task(function* test_target__blank() { yield testLinkWithMatrix("#targetBlank", kTargetBlank); }); diff --git a/dom/tests/browser/test_new_window_from_content_child.html b/dom/tests/browser/test_new_window_from_content_child.html index 7609675b82ba..ab1bf6f4941d 100644 --- a/dom/tests/browser/test_new_window_from_content_child.html +++ b/dom/tests/browser/test_new_window_from_content_child.html @@ -6,6 +6,7 @@ <body> <p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p> <p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p> + <p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p> <p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p> </body> </html> From 07ed05b04743786407055e7a385fb4df8d3aef34 Mon Sep 17 00:00:00 2001 From: Wes Kocher <wkocher@mozilla.com> Date: Tue, 13 Oct 2015 12:21:02 -0700 Subject: [PATCH 42/79] Backed out changeset fc7d1acf804f (bug 1209987) for m-e10s(2) leaks CLOSED TREE --- dom/media/systemservices/CamerasParent.cpp | 382 ++++++++++----------- dom/media/systemservices/CamerasParent.h | 25 +- 2 files changed, 190 insertions(+), 217 deletions(-) diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp index a7584df9d22f..f77635f02273 100644 --- a/dom/media/systemservices/CamerasParent.cpp +++ b/dom/media/systemservices/CamerasParent.cpp @@ -14,7 +14,6 @@ #include "mozilla/Logging.h" #include "mozilla/ipc/BackgroundParent.h" #include "nsThreadUtils.h" -#include "nsXPCOM.h" #undef LOG #undef LOG_ENABLED @@ -143,79 +142,6 @@ private: int mResult; }; -NS_IMPL_ISUPPORTS(CamerasParent, nsIObserver) - -NS_IMETHODIMP -CamerasParent::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)); - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - MOZ_ASSERT(obs); - obs->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID); - StopVideoCapture(); - return NS_OK; -} - -nsresult -CamerasParent::DispatchToVideoCaptureThread(nsRunnable *event) -{ - MonitorAutoLock lock(mThreadMonitor); - - while(mChildIsAlive && mWebRTCAlive && - (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning())) { - mThreadMonitor.Wait(); - } - if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) { - return NS_ERROR_FAILURE; - } - mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, - new RunnableTask(event)); - return NS_OK; -} - -void -CamerasParent::StopVideoCapture() -{ - // We are called from the main thread (xpcom-shutdown) or - // from PBackground (when the Actor shuts down). - // Shut down the WebRTC stack (on the capture thread) - nsRefPtr<CamerasParent> self(this); - nsRefPtr<nsRunnable> webrtc_runnable = - media::NewRunnableFrom([self]() -> nsresult { - MonitorAutoLock lock(self->mThreadMonitor); - self->CloseEngines(); - self->mThreadMonitor.NotifyAll(); - return NS_OK; - }); - DispatchToVideoCaptureThread(webrtc_runnable); - // Hold here until the WebRTC thread is gone. We need to dispatch - // the thread deletion *now*, or there will be no more possibility - // to get to the main thread. - MonitorAutoLock lock(mThreadMonitor); - while (mWebRTCAlive) { - mThreadMonitor.Wait(); - } - // After closing the WebRTC stack, clean up the - // VideoCapture thread. - if (self->mVideoCaptureThread) { - base::Thread *thread = self->mVideoCaptureThread; - self->mVideoCaptureThread = nullptr; - nsRefPtr<nsRunnable> threadShutdown = - media::NewRunnableFrom([thread]() -> nsresult { - if (thread->IsRunning()) { - thread->Stop(); - } - delete thread; - return NS_OK; - }); - if (NS_FAILED(NS_DispatchToMainThread(threadShutdown))) { - LOG(("Could not dispatch VideoCaptureThread destruction")); - } - } -} - int CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine, int cap_id, @@ -309,7 +235,6 @@ CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) { bool CamerasParent::SetupEngine(CaptureEngine aCapEngine) { - MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId()); EngineHelper *helper = &mEngines[aCapEngine]; // Already initialized @@ -383,57 +308,51 @@ CamerasParent::SetupEngine(CaptureEngine aCapEngine) void CamerasParent::CloseEngines() { - if (!mWebRTCAlive) { - return; - } - MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId()); - - // Stop the callers - while (mCallbacks.Length()) { - auto capEngine = mCallbacks[0]->mCapEngine; - auto capNum = mCallbacks[0]->mCapturerId; - LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum)); - RecvStopCapture(capEngine, capNum); - RecvReleaseCaptureDevice(capEngine, capNum); + { + MutexAutoLock lock(mCallbackMutex); + // Stop the callers + while (mCallbacks.Length()) { + auto capEngine = mCallbacks[0]->mCapEngine; + auto capNum = mCallbacks[0]->mCapturerId; + LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum)); + { + MutexAutoUnlock unlock(mCallbackMutex); + RecvStopCapture(capEngine, capNum); + RecvReleaseCaptureDevice(capEngine, capNum); + } + // The callbacks list might have changed while we released the lock, + // but note that due to the loop construct this will not break us. + } } - for (int i = 0; i < CaptureEngine::MaxEngine; i++) { - if (mEngines[i].mEngineIsRunning) { - LOG(("Being closed down while engine %d is running!", i)); - } - if (mEngines[i].mPtrViERender) { - mEngines[i].mPtrViERender->Release(); - mEngines[i].mPtrViERender = nullptr; - } - if (mEngines[i].mPtrViECapture) { - mEngines[i].mPtrViECapture->Release(); + { + MutexAutoLock lock(mEngineMutex); + for (int i = 0; i < CaptureEngine::MaxEngine; i++) { + if (mEngines[i].mEngineIsRunning) { + LOG(("Being closed down while engine %d is running!", i)); + } + if (mEngines[i].mPtrViERender) { + mEngines[i].mPtrViERender->Release(); + mEngines[i].mPtrViERender = nullptr; + } + if (mEngines[i].mPtrViECapture) { + mEngines[i].mPtrViECapture->Release(); mEngines[i].mPtrViECapture = nullptr; - } - if(mEngines[i].mPtrViEBase) { - mEngines[i].mPtrViEBase->Release(); - mEngines[i].mPtrViEBase = nullptr; - } - if (mEngines[i].mEngine) { - mEngines[i].mEngine->SetTraceCallback(nullptr); - webrtc::VideoEngine::Delete(mEngines[i].mEngine); - mEngines[i].mEngine = nullptr; + } + if(mEngines[i].mPtrViEBase) { + mEngines[i].mPtrViEBase->Release(); + mEngines[i].mPtrViEBase = nullptr; + } } } - - mWebRTCAlive = false; } bool CamerasParent::EnsureInitialized(int aEngine) { LOG((__PRETTY_FUNCTION__)); - // We're shutting down, don't try to do new WebRTC ops. - if (!mWebRTCAlive) { - return false; - } CaptureEngine capEngine = static_cast<CaptureEngine>(aEngine); if (!SetupEngine(capEngine)) { - LOG(("CamerasParent failed to initialize engine")); return false; } @@ -449,12 +368,18 @@ bool CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("RecvNumberOfCaptureDevices fails to initialize")); + unused << SendReplyFailure(); + return false; + } nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine]() -> nsresult { + MutexAutoLock lock(self->mEngineMutex); int num = -1; - if (self->EnsureInitialized(aCapEngine)) { + if (self->mEngines[aCapEngine].mPtrViECapture) { num = self->mEngines[aCapEngine].mPtrViECapture->NumberOfCaptureDevices(); } nsRefPtr<nsIRunnable> ipc_runnable = @@ -475,7 +400,8 @@ CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine) self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); + return true; } @@ -484,13 +410,19 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine, const nsCString& unique_id) { LOG((__PRETTY_FUNCTION__)); - LOG(("Getting caps for %s", unique_id.get())); + if (!EnsureInitialized(aCapEngine)) { + LOG(("RecvNumberOfCapabilities fails to initialize")); + unused << SendReplyFailure(); + return false; + } + LOG(("Getting caps for %s", unique_id.get())); nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult { + MutexAutoLock lock(self->mEngineMutex); int num = -1; - if (self->EnsureInitialized(aCapEngine)) { + if (self->mEngines[aCapEngine].mPtrViECapture) { num = self->mEngines[aCapEngine].mPtrViECapture->NumberOfCapabilities( unique_id.get(), @@ -514,7 +446,7 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); return true; } @@ -524,14 +456,21 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine, const int& num) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Fails to initialize")); + unused << SendReplyFailure(); + return false; + } + LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num)); nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult { webrtc::CaptureCapability webrtcCaps; + MutexAutoLock lock(self->mEngineMutex); int error = -1; - if (self->EnsureInitialized(aCapEngine)) { + if (self->mEngines[aCapEngine].mPtrViECapture) { error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureCapability( unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, num, webrtcCaps); } @@ -564,7 +503,7 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); return true; } @@ -573,7 +512,13 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine, const int& aListNumber) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Fails to initialize")); + unused << SendReplyFailure(); + return false; + } + LOG(("RecvGetCaptureDevice")); nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult { @@ -581,18 +526,20 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine, char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength]; nsCString name; nsCString uniqueId; + MutexAutoLock lock(self->mEngineMutex); int error = -1; - if (self->EnsureInitialized(aCapEngine)) { - error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber, - deviceName, - sizeof(deviceName), - deviceUniqueId, - sizeof(deviceUniqueId)); + if (self->mEngines[aCapEngine].mPtrViECapture) { + error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber, + deviceName, + sizeof(deviceName), + deviceUniqueId, + sizeof(deviceUniqueId)); } if (!error) { name.Assign(deviceName); uniqueId.Assign(deviceUniqueId); } + nsRefPtr<nsIRunnable> ipc_runnable = media::NewRunnableFrom([self, error, name, uniqueId]() -> nsresult { if (self->IsShuttingDown()) { @@ -611,7 +558,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); return true; } @@ -620,13 +567,19 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine, const nsCString& unique_id) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Fails to initialize")); + unused << SendReplyFailure(); + return false; + } nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, unique_id]() -> nsresult { int numdev = -1; + MutexAutoLock lock(self->mEngineMutex); int error = -1; - if (self->EnsureInitialized(aCapEngine)) { + if (self->mEngines[aCapEngine].mPtrViECapture) { error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice( unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev); } @@ -647,7 +600,7 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); return true; } @@ -656,13 +609,19 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine, const int& numdev) { LOG((__PRETTY_FUNCTION__)); - LOG(("RecvReleaseCamera device nr %d", numdev)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Fails to initialize")); + unused << SendReplyFailure(); + return false; + } nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult { + LOG(("RecvReleaseCamera device nr %d", numdev)); + MutexAutoLock lock(self->mEngineMutex); int error = -1; - if (self->EnsureInitialized(aCapEngine)) { + if (self->mEngines[aCapEngine].mPtrViECapture) { error = self->mEngines[aCapEngine].mPtrViECapture->ReleaseCaptureDevice(numdev); } nsRefPtr<nsIRunnable> ipc_runnable = @@ -682,7 +641,12 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); +#ifndef XP_MACOSX + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); +#else + // Mac OS X hangs on shutdown if we don't do this on the main thread. + NS_DispatchToMainThread(webrtc_runnable); +#endif return true; } @@ -692,6 +656,11 @@ CamerasParent::RecvStartCapture(const int& aCapEngine, const CaptureCapability& ipcCaps) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Failure to initialize")); + unused << SendReplyFailure(); + return false; + } nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = @@ -699,15 +668,23 @@ CamerasParent::RecvStartCapture(const int& aCapEngine, CallbackHelper** cbh; webrtc::ExternalRenderer* render; EngineHelper* helper = nullptr; - int error = -1; - if (self->EnsureInitialized(aCapEngine)) { + int error; + { + MutexAutoLock lockCallback(self->mCallbackMutex); cbh = self->mCallbacks.AppendElement( new CallbackHelper(static_cast<CaptureEngine>(aCapEngine), capnum, self)); render = static_cast<webrtc::ExternalRenderer*>(*cbh); + } + { + MutexAutoLock lockEngine(self->mEngineMutex); + if (self->mEngines[aCapEngine].mPtrViECapture) { + helper = &self->mEngines[aCapEngine]; + error = + helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render); + } else { + error = -1; + } - helper = &self->mEngines[aCapEngine]; - error = - helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render); if (!error) { error = helper->mPtrViERender->StartRender(capnum); } @@ -728,6 +705,7 @@ CamerasParent::RecvStartCapture(const int& aCapEngine, helper->mEngineIsRunning = true; } } + nsRefPtr<nsIRunnable> ipc_runnable = media::NewRunnableFrom([self, error]() -> nsresult { if (self->IsShuttingDown()) { @@ -744,7 +722,7 @@ CamerasParent::RecvStartCapture(const int& aCapEngine, self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); - DispatchToVideoCaptureThread(webrtc_runnable); + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); return true; } @@ -753,32 +731,40 @@ CamerasParent::RecvStopCapture(const int& aCapEngine, const int& capnum) { LOG((__PRETTY_FUNCTION__)); + if (!EnsureInitialized(aCapEngine)) { + LOG(("Failure to initialize")); + unused << SendReplyFailure(); + return false; + } nsRefPtr<CamerasParent> self(this); nsRefPtr<nsRunnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult { - if (self->EnsureInitialized(aCapEngine)) { - self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum); - self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum); - self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum); - self->mEngines[aCapEngine].mEngineIsRunning = false; - - for (size_t i = 0; i < self->mCallbacks.Length(); i++) { - if (self->mCallbacks[i]->mCapEngine == aCapEngine - && self->mCallbacks[i]->mCapturerId == capnum) { - delete self->mCallbacks[i]; - self->mCallbacks.RemoveElementAt(i); - break; - } + { + MutexAutoLock lock(self->mEngineMutex); + // We only need to check mPtrViECapture as all other engines are guaranteed + // to be nulled under the same lock. + if (self->mEngines[aCapEngine].mPtrViECapture) { + self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum); + self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum); + self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum); + self->mEngines[aCapEngine].mEngineIsRunning = false; + } + } + MutexAutoLock lock(self->mCallbackMutex); + for (unsigned int i = 0; i < self->mCallbacks.Length(); i++) { + if (self->mCallbacks[i]->mCapEngine == aCapEngine + && self->mCallbacks[i]->mCapturerId == capnum) { + delete self->mCallbacks[i]; + self->mCallbacks.RemoveElementAt(i); + break; } } return NS_OK; }); - if (NS_SUCCEEDED(DispatchToVideoCaptureThread(webrtc_runnable))) { - return SendReplySuccess(); - } else { - return SendReplyFailure(); - } + + mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable)); + return SendReplySuccess(); } void @@ -802,24 +788,49 @@ CamerasParent::RecvAllDone() return Send__delete__(this); } +void CamerasParent::DoShutdown() +{ + LOG((__PRETTY_FUNCTION__)); + CloseEngines(); + + { + MutexAutoLock lock(mEngineMutex); + for (int i = 0; i < CaptureEngine::MaxEngine; i++) { + if (mEngines[i].mEngine) { + mEngines[i].mEngine->SetTraceCallback(nullptr); + webrtc::VideoEngine::Delete(mEngines[i].mEngine); + mEngines[i].mEngine = nullptr; + } + } + } + + mPBackgroundThread = nullptr; + + if (mVideoCaptureThread) { + if (mVideoCaptureThread->IsRunning()) { + mVideoCaptureThread->Stop(); + } + delete mVideoCaptureThread; + mVideoCaptureThread = nullptr; + } +} + void CamerasParent::ActorDestroy(ActorDestroyReason aWhy) { // No more IPC from here LOG((__PRETTY_FUNCTION__)); StopIPC(); - // Shut down WebRTC (if we're not in full shutdown, else this - // will already have happened) - StopVideoCapture(); + CloseEngines(); } CamerasParent::CamerasParent() - : mShmemPool(CaptureEngine::MaxEngine), - mThreadMonitor("CamerasParent::mThreadMonitor"), + : mCallbackMutex("CamerasParent.mCallbackMutex"), + mEngineMutex("CamerasParent.mEngineMutex"), + mShmemPool(CaptureEngine::MaxEngine), mVideoCaptureThread(nullptr), mChildIsAlive(true), - mDestroyed(false), - mWebRTCAlive(true) + mDestroyed(false) { if (!gCamerasParentLog) { gCamerasParentLog = PR_NewLogModule("CamerasParent"); @@ -830,37 +841,16 @@ CamerasParent::CamerasParent() MOZ_ASSERT(mPBackgroundThread != nullptr, "GetCurrentThread failed"); LOG(("Spinning up WebRTC Cameras Thread")); - - nsRefPtr<CamerasParent> self(this); - nsRefPtr<nsRunnable> threadStart = - media::NewRunnableFrom([self]() -> nsresult { - // Register thread shutdown observer - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (NS_WARN_IF(!obs)) { - return NS_ERROR_FAILURE; - } - nsresult rv = - obs->AddObserver(self, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - // Start the thread - MonitorAutoLock lock(self->mThreadMonitor); - self->mVideoCaptureThread = new base::Thread("VideoCapture"); - base::Thread::Options options; + mVideoCaptureThread = new base::Thread("VideoCapture"); + base::Thread::Options options; #if defined(_WIN32) - options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD; + options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD; #else - - options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD; + options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD; #endif - if (!self->mVideoCaptureThread->StartWithOptions(options)) { - MOZ_CRASH(); - } - self->mThreadMonitor.NotifyAll(); - return NS_OK; - }); - NS_DispatchToMainThread(threadStart); + if (!mVideoCaptureThread->StartWithOptions(options)) { + MOZ_CRASH(); + } MOZ_COUNT_CTOR(CamerasParent); } @@ -870,15 +860,7 @@ CamerasParent::~CamerasParent() LOG(("~CamerasParent: %p", this)); MOZ_COUNT_DTOR(CamerasParent); -#ifdef DEBUG - // Verify we have shut down the webrtc engines, this is - // supposed to happen in ActorDestroy. - // That runnable takes a ref to us, so it must have finished - // by the time we get here. - for (int i = 0; i < CaptureEngine::MaxEngine; i++) { - MOZ_ASSERT(!mEngines[i].mEngine); - } -#endif + DoShutdown(); } already_AddRefed<CamerasParent> diff --git a/dom/media/systemservices/CamerasParent.h b/dom/media/systemservices/CamerasParent.h index db08834fff0a..dfdd2d2d6abc 100644 --- a/dom/media/systemservices/CamerasParent.h +++ b/dom/media/systemservices/CamerasParent.h @@ -7,12 +7,10 @@ #ifndef mozilla_CamerasParent_h #define mozilla_CamerasParent_h -#include "nsIObserver.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/camera/PCamerasParent.h" #include "mozilla/ipc/Shmem.h" #include "mozilla/ShmemPool.h" -#include "mozilla/Atomics.h" // conflicts with #include of scoped_ptr.h #undef FF @@ -75,11 +73,9 @@ public: bool mEngineIsRunning; }; -class CamerasParent : public PCamerasParent, - public nsIObserver +class CamerasParent : public PCamerasParent { - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIOBSERVER + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CamerasParent); public: static already_AddRefed<CamerasParent> Create(); @@ -98,9 +94,7 @@ public: virtual void ActorDestroy(ActorDestroyReason aWhy) override; nsIThread* GetBackgroundThread() { return mPBackgroundThread; }; - bool IsShuttingDown() { return !mChildIsAlive - || mDestroyed - || !mWebRTCAlive; }; + bool IsShuttingDown() { return !mChildIsAlive || mDestroyed; }; ShmemBuffer GetBuffer(size_t aSize); // helper to forward to the PBackground thread @@ -122,12 +116,15 @@ protected: bool SetupEngine(CaptureEngine aCapEngine); void CloseEngines(); bool EnsureInitialized(int aEngine); + void DoShutdown(); void StopIPC(); - void StopVideoCapture(); - nsresult DispatchToVideoCaptureThread(nsRunnable *event); EngineHelper mEngines[CaptureEngine::MaxEngine]; nsTArray<CallbackHelper*> mCallbacks; + // Protects the callback arrays + Mutex mCallbackMutex; + // Protects the engines array + Mutex mEngineMutex; // image buffers mozilla::ShmemPool mShmemPool; @@ -135,18 +132,12 @@ protected: // PBackground parent thread nsCOMPtr<nsIThread> mPBackgroundThread; - // Monitors creation of the thread below - Monitor mThreadMonitor; - // video processing thread - where webrtc.org capturer code runs base::Thread* mVideoCaptureThread; // Shutdown handling bool mChildIsAlive; bool mDestroyed; - // Above 2 are PBackground only, but this is potentially - // read cross-thread. - mozilla::Atomic<bool> mWebRTCAlive; }; PCamerasParent* CreateCamerasParent(); From 4ea84cc59041ed90503bbc651b353b7289de3ac7 Mon Sep 17 00:00:00 2001 From: philipp <madperson@gmx.at> Date: Tue, 13 Oct 2015 13:03:12 -0700 Subject: [PATCH 43/79] Bug 1205987 - Add freecorder dll to Windows blocklist. r=dmajor CLOSED TREE --- mozglue/build/WindowsDllBlocklist.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 319edb99bfe1..1d6410171756 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -182,6 +182,9 @@ static DllBlockInfo sWindowsDllBlocklist[] = { // NetOp School, discontinued product, bug 763395 { "nlsp.dll", MAKE_VERSION(6, 23, 2012, 19) }, + + // Startup crashes with Freecorder dll, bug 1205987 + { "flvsrvlib.dll", MAKE_VERSION(1, 0, 0, 0) }, { nullptr, 0 } }; From a7dbfbd7dfcc2dcea490b45041569b84a8e8897c Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari <ehsan@mozilla.com> Date: Tue, 13 Oct 2015 14:20:39 -0400 Subject: [PATCH 44/79] Bug 1182727 - Part 19: Fix another stupid mistake in build_tar_package() DONTBUILD --- build/unix/build-clang/build-clang.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/unix/build-clang/build-clang.py b/build/unix/build-clang/build-clang.py index a502fb03677d..471f03063998 100755 --- a/build/unix/build-clang/build-clang.py +++ b/build/unix/build-clang/build-clang.py @@ -64,7 +64,9 @@ def updated_env(env): def build_tar_package(tar, name, base, directory): name = os.path.realpath(name) run_in(base, [tar, - "-c -%s -f" % ("J" if ".xz" in name else "j"), + "-c", + "-%s" % ("J" if ".xz" in name else "j"), + "-f", name, directory]) From 49f91fb31f6464ac0c8652a4ddc5c65d8d440c01 Mon Sep 17 00:00:00 2001 From: David Keeler <dkeeler@mozilla.com> Date: Tue, 29 Sep 2015 13:24:19 -0700 Subject: [PATCH 45/79] bug 1209695 - fold mochitest test_bug413909.html into xpcshell test_cert_overrides.js r=mgoodwin test_bug413909.html doesn't need to be a mochitest. Furthermore, test_cert_overrides.js tests a lot of the same functionality. This just moves the unique parts from the old test to a new home in the xpcshell test (to be specific, some IDN handling and that "port" -1 is the same as port 443). --- .../ssl/tests/mochitest/bugs/chrome.ini | 6 - .../ssl/tests/mochitest/bugs/moz.build | 7 - .../tests/mochitest/bugs/test_bug413909.html | 127 ------------------ .../manager/ssl/tests/mochitest/moz.build | 2 - .../bad_certs/idn-certificate.pem.certspec | 3 + .../ssl/tests/unit/bad_certs/moz.build | 1 + .../ssl/tests/unit/test_cert_overrides.js | 57 +++++++- .../unit/tlsserver/cmd/BadCertServer.cpp | 1 + 8 files changed, 59 insertions(+), 145 deletions(-) delete mode 100644 security/manager/ssl/tests/mochitest/bugs/chrome.ini delete mode 100644 security/manager/ssl/tests/mochitest/bugs/moz.build delete mode 100644 security/manager/ssl/tests/mochitest/bugs/test_bug413909.html create mode 100644 security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec diff --git a/security/manager/ssl/tests/mochitest/bugs/chrome.ini b/security/manager/ssl/tests/mochitest/bugs/chrome.ini deleted file mode 100644 index 07ba0b46a0ba..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/chrome.ini +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] -tags = psm -skip-if = buildapp == 'b2g' || os == 'android' - -[test_bug413909.html] -skip-if = buildapp == 'mulet' diff --git a/security/manager/ssl/tests/mochitest/bugs/moz.build b/security/manager/ssl/tests/mochitest/bugs/moz.build deleted file mode 100644 index 4b299d0ec79b..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] diff --git a/security/manager/ssl/tests/mochitest/bugs/test_bug413909.html b/security/manager/ssl/tests/mochitest/bugs/test_bug413909.html deleted file mode 100644 index d2f2663965b3..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/test_bug413909.html +++ /dev/null @@ -1,127 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test bug 413909 - - - - - - - - - diff --git a/security/manager/ssl/tests/mochitest/moz.build b/security/manager/ssl/tests/mochitest/moz.build index 74dd0b5f37ac..56e335476659 100644 --- a/security/manager/ssl/tests/mochitest/moz.build +++ b/security/manager/ssl/tests/mochitest/moz.build @@ -6,8 +6,6 @@ TEST_DIRS += [ 'browser', - 'bugs', 'mixedcontent', 'stricttransportsecurity', ] - diff --git a/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec new file mode 100644 index 000000000000..b3d840fbd3c1 --- /dev/null +++ b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec @@ -0,0 +1,3 @@ +issuer:Unknown Issuer +subject:IDN Certificate +extension:subjectAlternativeName:bug413909.xn--hxajbheg2az3al.xn--jxalpdlp diff --git a/security/manager/ssl/tests/unit/bad_certs/moz.build b/security/manager/ssl/tests/unit/bad_certs/moz.build index 15aa27c43332..e01778f5b894 100644 --- a/security/manager/ssl/tests/unit/bad_certs/moz.build +++ b/security/manager/ssl/tests/unit/bad_certs/moz.build @@ -16,6 +16,7 @@ test_certificates = ( 'expired-ee.pem', 'expiredINT.pem', 'expiredissuer.pem', + 'idn-certificate.pem', 'inadequateKeySizeEE.pem', 'inadequatekeyusage-ee.pem', 'ipAddressAsDNSNameInSAN.pem', diff --git a/security/manager/ssl/tests/unit/test_cert_overrides.js b/security/manager/ssl/tests/unit/test_cert_overrides.js index b2e1d45d5ad5..59b0583c4ac6 100644 --- a/security/manager/ssl/tests/unit/test_cert_overrides.js +++ b/security/manager/ssl/tests/unit/test_cert_overrides.js @@ -19,7 +19,7 @@ function check_telemetry() { .getHistogramById("SSL_CERT_ERROR_OVERRIDES") .snapshot(); equal(histogram.counts[ 0], 0, "Should have 0 unclassified counts"); - equal(histogram.counts[ 2], 7, + equal(histogram.counts[ 2], 8, "Actual and expected SEC_ERROR_UNKNOWN_ISSUER counts should match"); equal(histogram.counts[ 3], 1, "Actual and expected SEC_ERROR_CA_CERT_INVALID counts should match"); @@ -60,13 +60,47 @@ function check_telemetry() { "Actual and expected successful verifications of 2048-bit keys should match"); equal(keySizeHistogram.counts[2], 0, "Actual and expected successful verifications of 1024-bit keys should match"); - equal(keySizeHistogram.counts[3], 54, - "Actual and expected key size verification failures should match"); + equal(keySizeHistogram.counts[3], 56, + "Actual and expected verification failures unrelated to key size should match"); run_next_test(); } +// Internally, specifying "port" -1 is the same as port 443. This tests that. +function run_port_equivalency_test(inPort, outPort) { + Assert.ok((inPort == 443 && outPort == -1) || (inPort == -1 && outPort == 443), + "The two specified ports must be -1 and 443 (in any order)"); + let certOverrideService = Cc["@mozilla.org/security/certoverride;1"] + .getService(Ci.nsICertOverrideService); + let cert = constructCertFromFile("bad_certs/default-ee.pem"); + let expectedBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED + let expectedTemporary = true; + certOverrideService.rememberValidityOverride("example.com", inPort, cert, + expectedBits, expectedTemporary); + let actualBits = {}; + let actualTemporary = {}; + Assert.ok(certOverrideService.hasMatchingOverride("example.com", outPort, + cert, actualBits, + actualTemporary), + `override set on port ${inPort} should match port ${outPort}`); + equal(actualBits.value, expectedBits, + "input override bits should match output bits"); + equal(actualTemporary.value, expectedTemporary, + "input override temporary value should match output temporary value"); + Assert.ok(!certOverrideService.hasMatchingOverride("example.com", 563, + cert, {}, {}), + `override set on port ${inPort} should not match port 563`); + certOverrideService.clearValidityOverride("example.com", inPort); + Assert.ok(!certOverrideService.hasMatchingOverride("example.com", outPort, + cert, actualBits, {}), + `override cleared on port ${inPort} should match port ${outPort}`); + equal(actualBits.value, 0, "should have no bits set if there is no override"); +} + function run_test() { + run_port_equivalency_test(-1, 443); + run_port_equivalency_test(443, -1); + Services.prefs.setIntPref("security.OCSP.enabled", 1); add_tls_server_setup("BadCertServer", "bad_certs"); @@ -211,6 +245,23 @@ function add_simple_tests() { add_cert_override_test("badSubjectAltNames.example.com", Ci.nsICertOverrideService.ERROR_MISMATCH, SSL_ERROR_BAD_CERT_DOMAIN); + + add_cert_override_test("bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", + Ci.nsICertOverrideService.ERROR_UNTRUSTED, + SEC_ERROR_UNKNOWN_ISSUER); + add_test(function() { + // At this point, the override for bug413909.xn--hxajbheg2az3al.xn--jxalpdlp + // is still valid. Do some additional tests relating to IDN handling. + let certOverrideService = Cc["@mozilla.org/security/certoverride;1"] + .getService(Ci.nsICertOverrideService); + let uri = Services.io.newURI("https://bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", null, null); + let cert = constructCertFromFile("bad_certs/idn-certificate.pem"); + Assert.ok(certOverrideService.hasMatchingOverride(uri.asciiHost, 8443, cert, {}, {}), + "IDN certificate should have matching override using ascii host"); + Assert.ok(!certOverrideService.hasMatchingOverride(uri.host, 8443, cert, {}, {}), + "IDN certificate should not have matching override using (non-ascii) host"); + run_next_test(); + }); } function add_combo_tests() { diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp index adcfa2461b46..ee4a3a4636f1 100644 --- a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp @@ -74,6 +74,7 @@ const BadCertHost sBadCertHosts[] = { "badSubjectAltNames.example.com", "badSubjectAltNames" }, { "ipAddressAsDNSNameInSAN.example.com", "ipAddressAsDNSNameInSAN" }, { "noValidNames.example.com", "noValidNames" }, + { "bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", "idn-certificate" }, { nullptr, nullptr } }; From bbbdfb102ec009b10c61746e6a9984692879da2a Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 10 Oct 2015 21:47:13 -0400 Subject: [PATCH 46/79] Bug 1213627 - Add ninja to the desktop-build image to support building clang 3.7; r=dustin --- testing/docker/centos6-build-upd/VERSION | 2 +- testing/docker/centos6-build/VERSION | 2 +- testing/docker/centos6-build/system-setup.sh | 19 +++++++++++++++++++ testing/docker/desktop-build/VERSION | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/testing/docker/centos6-build-upd/VERSION b/testing/docker/centos6-build-upd/VERSION index 1f999886f186..e39ff5df9fa1 100644 --- a/testing/docker/centos6-build-upd/VERSION +++ b/testing/docker/centos6-build-upd/VERSION @@ -1 +1 @@ -20150930093701 +20151013094100 diff --git a/testing/docker/centos6-build/VERSION b/testing/docker/centos6-build/VERSION index 17e51c385ea3..d917d3e26adc 100644 --- a/testing/docker/centos6-build/VERSION +++ b/testing/docker/centos6-build/VERSION @@ -1 +1 @@ -0.1.1 +0.1.2 diff --git a/testing/docker/centos6-build/system-setup.sh b/testing/docker/centos6-build/system-setup.sh index 04ca0e30d916..5cbfb4a1854a 100644 --- a/testing/docker/centos6-build/system-setup.sh +++ b/testing/docker/centos6-build/system-setup.sh @@ -425,6 +425,25 @@ peep install -r requirements.txt # TC-VCS npm install -g taskcluster-vcs@2.3.12 +# Ninja +cd $BUILD +tooltool_fetch <<'EOF' +[ +{ + "size": 174501, + "digest": "551a9e14b95c2d2ddad6bee0f939a45614cce86719748dc580192dd122f3671e3d95fd6a6fb3facb2d314ba100d61a004af4df77f59df119b1b95c6fe8c38875", + "algorithm": "sha512", + "filename": "ninja-1.6.0.tar.gz", + "unpack": true +} +] +EOF +cd ninja-1.6.0 +./configure.py --bootstrap +cp ninja /usr/local/bin/ninja +# Old versions of Cmake can only find ninja in this location! +ln -s /usr/local/bin/ninja /usr/local/bin/ninja-build + # note that TC will replace workspace with a cache mount; there's no sense # creating anything inside there mkdir -p /home/worker/workspace diff --git a/testing/docker/desktop-build/VERSION b/testing/docker/desktop-build/VERSION index 9767cc98e703..20f49513e15f 100644 --- a/testing/docker/desktop-build/VERSION +++ b/testing/docker/desktop-build/VERSION @@ -1 +1 @@ -0.1.10 +0.1.11 From b1d9d9136de3fecff0357788c5766ad8655a07a5 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 13 Oct 2015 12:20:25 -0600 Subject: [PATCH 47/79] Bug 1211262: Ensure that STORED entries in ZIP are considered corrupt if compressed and uncompressed sizes differ; r=mwu --HG-- extra : rebase_source : 515c582e158620057f0eab4d46d462cec5eb4cc3 --- modules/libjar/nsZipArchive.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 3c8f3fb960b6..6eef8120ed62 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -841,8 +841,10 @@ MOZ_WIN_MEM_TRY_BEGIN // -- check if there is enough source data in the file if (!offset || mFd->mLen < aItem->Size() || - offset > mFd->mLen - aItem->Size()) + offset > mFd->mLen - aItem->Size() || + aItem->Compression() == STORED && aItem->Size() != aItem->RealSize()) { return nullptr; + } return mFd->mFileData + offset; MOZ_WIN_MEM_TRY_CATCH(return nullptr) From 1c47713120e719f73d15a683c47a61fb25241255 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 13 Oct 2015 13:59:15 -0700 Subject: [PATCH 48/79] Backed out changeset 6d7a8e19086c (bug 1211262) for wError build bustage CLOSED TREE --- modules/libjar/nsZipArchive.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 6eef8120ed62..3c8f3fb960b6 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -841,10 +841,8 @@ MOZ_WIN_MEM_TRY_BEGIN // -- check if there is enough source data in the file if (!offset || mFd->mLen < aItem->Size() || - offset > mFd->mLen - aItem->Size() || - aItem->Compression() == STORED && aItem->Size() != aItem->RealSize()) { + offset > mFd->mLen - aItem->Size()) return nullptr; - } return mFd->mFileData + offset; MOZ_WIN_MEM_TRY_CATCH(return nullptr) From 9ef65516f43f19e6ae4434551f1ca74fc30b5ff2 Mon Sep 17 00:00:00 2001 From: Chris Manchester Date: Tue, 13 Oct 2015 14:10:10 -0700 Subject: [PATCH 49/79] Bug 1077670 - Package tests in parallel. r=gps --HG-- extra : commitid : LPmnxGneA65 --- build/moz-automation.mk | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build/moz-automation.mk b/build/moz-automation.mk index a4e7d718d114..ec63233a1345 100644 --- a/build/moz-automation.mk +++ b/build/moz-automation.mk @@ -101,17 +101,13 @@ automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS)) AUTOMATION_EXTRA_CMDLINE-l10n-check = -j1 AUTOMATION_EXTRA_CMDLINE-pretty-l10n-check = -j1 -# And force -j1 here until bug 1077670 is fixed. -AUTOMATION_EXTRA_CMDLINE-package-tests = -j1 -AUTOMATION_EXTRA_CMDLINE-pretty-package-tests = -j1 - # The commands only run if the corresponding MOZ_AUTOMATION_* variable is # enabled. This means, for example, if we enable MOZ_AUTOMATION_UPLOAD, then # 'buildsymbols' will only run if MOZ_AUTOMATION_BUILD_SYMBOLS is also set. # However, the target automation/buildsymbols will still be executed in this # case because it is a prerequisite of automation/upload. define automation_commands -@$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1) +@+$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1) $(call BUILDSTATUS,TIER_FINISH $1) endef From c3c790dd8788ba56cf083fdfa1a4a4851e5ef096 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 13 Oct 2015 16:58:40 +0100 Subject: [PATCH 50/79] Bug 1213800: More exhaustive Marionette screen capture tests The screen capture tests were not testing that the screenshots are of what they're meant to be of. In order to confidently fix bug 1202663, these new tests will ensure we do not have any regressions. r=jgriffin r=dburns --HG-- extra : commitid : AulnylZMj6Y extra : rebase_source : c2604e0e3bf1a975b1f35a149ef7f2bdb08840de --- .../marionette/tests/unit/test_screenshot.py | 197 ++++++++++++++---- 1 file changed, 153 insertions(+), 44 deletions(-) diff --git a/testing/marionette/client/marionette/tests/unit/test_screenshot.py b/testing/marionette/client/marionette/tests/unit/test_screenshot.py index 3a0f3ce0904d..43ee4bb3ef98 100644 --- a/testing/marionette/client/marionette/tests/unit/test_screenshot.py +++ b/testing/marionette/client/marionette/tests/unit/test_screenshot.py @@ -1,59 +1,168 @@ +# 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/. + import base64 import imghdr +import struct +import urllib + +from unittest import skip from marionette import MarionetteTestCase -RED_ELEMENT_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVUlEQVRoge3PsQ0AIAzAsI78fzBwBhHykD2ePev80LweAAGJB1ILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdQCqQVSC6QWSC2QWiC1QGp9A7ma+7nyXgOpzQAAAABJRU5ErkJggg==' -GREEN_ELEMENT_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAV0lEQVRoge3PQRGAQAwAsWINvXgsNnI3+4iAzM7sDWZn9vneoxXRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNHcF7nBD/Ha5Ye4BbsYAAAAAElFTkSuQmCC' +def inline(doc, mime="text/html;charset=utf-8"): + return "data:%s,%s" % (mime, urllib.quote(doc)) -class ScreenshotTests(MarionetteTestCase): - def testWeCanTakeAScreenShotOfEntireViewport(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - content = self.marionette.screenshot() - self.marionette.set_context(self.marionette.CONTEXT_CHROME) +ELEMENT = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVklEQVRoge3PMQ0AMAzAsPJHVWYbjEWTj/zx7O75oXk9AAISD6QWSC2QWiC1QGqB1AKpBVILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdT6BnIBMKa1DtYxhPkAAAAASUVORK5CYII=" +HIGHLIGHTED_ELEMENT = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVklEQVRoge3PQRHAQAgAMfyrwhm1sb3JIwIyN3MvmJu53f01kRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRmvciL/gAQgW/OxTpMPwAAAAASUVORK5CYII=" + + +box = inline( + "
") +long = inline("

foo") +short = inline("") +svg = inline(""" + +""", mime="image/svg+xml") + + +class ScreenCaptureTestCase(MarionetteTestCase): + def assert_png(self, string): + """Test that string is a Base64 encoded PNG file.""" + image = base64.decodestring(string) + self.assertEqual(imghdr.what("", image), "png") + + def get_image_dimensions(self, string): + self.assert_png(string) + image = base64.decodestring(string) + width, height = struct.unpack(">LL", image[16:24]) + return int(width), int(height) + + +class Chrome(ScreenCaptureTestCase): + @property + def primary_window_dimensions(self): + return tuple(self.marionette.execute_script(""" + let win = document.getElementsByTagName("window")[0]; + let rect = win.getBoundingClientRect(); + return [rect.width, rect.height];""")) + + def setUp(self): + ScreenCaptureTestCase.setUp(self) + self.marionette.set_context("chrome") + + # A full chrome window screenshot is not the outer dimensions of + # the window, but instead the bounding box of the inside + # . + def test_window(self): + string = self.marionette.screenshot() + self.assert_png(string) + self.assertEqual(self.primary_window_dimensions, + self.get_image_dimensions(string)) + + + def test_chrome_delegation(self): + with self.marionette.using_context("content"): + content = self.marionette.screenshot() chrome = self.marionette.screenshot() - # Check the base64 decoded string is a PNG file. - image = base64.decodestring(chrome) - self.assertEqual(imghdr.what('', image), 'png') self.assertNotEqual(content, chrome) - def testWeCanTakeAScreenShotOfAnElement(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - el = self.marionette.find_element('id', 'red') - self.assertEqual(RED_ELEMENT_BASE64, - self.marionette.screenshot(element=el)) - def testWeCanTakeAScreenShotWithHighlightOfAnElement(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - el = self.marionette.find_element('id', 'green') - self.assertEqual(GREEN_ELEMENT_BASE64, - self.marionette.screenshot(element=el, highlights=[el])) +class Content(ScreenCaptureTestCase): + @property + def body_scroll_dimensions(self): + return tuple(self.marionette.execute_script( + "return [document.body.scrollWidth, document.body.scrollHeight]")) - def testWeCanTakeAScreenShotOfEntireCanvas(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - # Check the base64 decoded string is a PNG file. - image = base64.decodestring(self.marionette.screenshot()) - self.assertEqual(imghdr.what('', image), 'png') + @property + def viewport_dimensions(self): + return tuple(self.marionette.execute_script(""" + let docEl = document.documentElement; + return [docEl.clientWidth, docEl.clientHeight];""")) - def testWeCanTakeABinaryScreenShotOfAnElement(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - el = self.marionette.find_element('id', 'red') - binary_data = self.marionette.screenshot(element=el, format="binary") - self.assertEqual(RED_ELEMENT_BASE64, - base64.b64encode(binary_data)) + @property + def document_element(self): + return self.marionette.execute_script("return document.documentElement") - def testNotAllowedScreenshotFormatRaiseValueError(self): - test_url = self.marionette.absolute_url('html5Page.html') - self.marionette.navigate(test_url) - el = self.marionette.find_element('id', 'red') - self.assertRaises(ValueError, - self.marionette.screenshot, - element=el, - format="unknowformat") + @property + def page_y_offset(self): + return self.marionette.execute_script("return window.pageYOffset") + + def setUp(self): + ScreenCaptureTestCase.setUp(self) + self.marionette.set_context("content") + + def test_html_document_element(self): + self.marionette.navigate(long) + string = self.marionette.screenshot() + self.assert_png(string) + self.assertEqual( + self.body_scroll_dimensions, self.get_image_dimensions(string)) + + @skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213797") + def test_svg_document_element(self): + self.marionette.navigate(svg) + doc_el = self.document_element + string = self.marionette.screenshot() + self.assert_png(string) + self.assertEqual((doc_el.rect["width"], doc_el.rect["height"]), + self.get_image_dimensions(string)) + + def test_viewport(self): + self.marionette.navigate(short) + string = self.marionette.screenshot(full=False) + self.assert_png(string) + self.assertEqual( + self.viewport_dimensions, self.get_image_dimensions(string)) + + def test_viewport_after_scroll(self): + self.marionette.navigate(long) + before = self.marionette.screenshot() + el = self.marionette.find_element("tag name", "p") + self.marionette.execute_script( + "arguments[0].scrollIntoView()", script_args=[el]) + after = self.marionette.screenshot(full=False) + self.assertNotEqual(before, after) + self.assertGreater(self.page_y_offset, 0) + + def test_element(self): + self.marionette.navigate(box) + el = self.marionette.find_element("tag name", "div") + string = self.marionette.screenshot(element=el) + self.assert_png(string) + self.assertEqual( + (el.rect["width"], el.rect["height"]), self.get_image_dimensions(string)) + self.assertEqual(ELEMENT, string) + + @skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213875") + def test_element_scrolled_into_view(self): + self.marionette.navigate(long) + el = self.marionette.find_element("tag name", "p") + string = self.marionette.screenshot(element=el) + self.assert_png(string) + self.assertEqual( + (el.rect["width"], el.rect["height"]), self.get_image_dimensions(string)) + self.assertGreater(self.page_y_offset, 0) + + def test_element_with_highlight(self): + self.marionette.navigate(box) + el = self.marionette.find_element("tag name", "div") + string = self.marionette.screenshot(element=el, highlights=[el]) + self.assert_png(string) + self.assertEqual( + (el.rect["width"], el.rect["height"]), self.get_image_dimensions(string)) + self.assertEqual(HIGHLIGHTED_ELEMENT, string) + + def test_binary_element(self): + self.marionette.navigate(box) + el = self.marionette.find_element("tag name", "div") + bin = self.marionette.screenshot(element=el, format="binary") + enc = base64.b64encode(bin) + self.assertEqual(ELEMENT, enc) + + def test_unknown_format(self): + with self.assertRaises(ValueError): + self.marionette.screenshot(format="cheese") From 4e5128c472119c7d2fd5ca96d5293d6ba4ab75a5 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Fri, 9 Oct 2015 12:02:42 +0100 Subject: [PATCH 51/79] Bug 1202663: Use dispatcher for screen capture command in listener r=dburns r=jgriffin --HG-- extra : commitid : 8Hc32mr6EX extra : rebase_source : 5036cfc0eb6a9acb5a8f91548414448365162751 --- testing/marionette/driver.js | 7 ++-- testing/marionette/listener.js | 72 ++++++++++++++++------------------ 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index 81bae312f65c..22895ad1983e 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -2535,6 +2535,8 @@ GeckoDriver.prototype.clearImportedScripts = function(cmd, resp) { * PNG image encoded as base64 encoded string. */ GeckoDriver.prototype.takeScreenshot = function(cmd, resp) { + let {id, highlights, full} = cmd.parameters; + switch (this.context) { case Context.CHROME: let win = this.getCurrentWindow(); @@ -2577,10 +2579,7 @@ GeckoDriver.prototype.takeScreenshot = function(cmd, resp) { break; case Context.CONTENT: - resp.body.value = yield this.listener.takeScreenshot({ - id: cmd.parameters.id, - highlights: cmd.parameters.highlights, - full: cmd.parameters.full}); + return this.listener.takeScreenshot(id, highlights, full); break; } }; diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index 14cf200d0991..8119c4fe2a86 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -216,6 +216,7 @@ var getElementValueOfCssPropertyFn = dispatch(getElementValueOfCssProperty); var switchToShadowRootFn = dispatch(switchToShadowRoot); var getCookiesFn = dispatch(getCookies); var singleTapFn = dispatch(singleTap); +var takeScreenshotFn = dispatch(takeScreenshot); /** * Start all message listeners @@ -260,7 +261,7 @@ function startListeners() { addMessageListenerId("Marionette:importScript", importScript); addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus); addMessageListenerId("Marionette:setTestName", setTestName); - addMessageListenerId("Marionette:takeScreenshot", takeScreenshot); + addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn); addMessageListenerId("Marionette:addCookie", addCookie); addMessageListenerId("Marionette:getCookies", getCookiesFn); addMessageListenerId("Marionette:deleteAllCookies", deleteAllCookies); @@ -364,7 +365,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:importScript", importScript); removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus); removeMessageListenerId("Marionette:setTestName", setTestName); - removeMessageListenerId("Marionette:takeScreenshot", takeScreenshot); + removeMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn); removeMessageListenerId("Marionette:addCookie", addCookie); removeMessageListenerId("Marionette:getCookies", getCookiesFn); removeMessageListenerId("Marionette:deleteAllCookies", deleteAllCookies); @@ -2004,44 +2005,35 @@ function importScript(msg) { * msg.json.highlights, a red box will be painted around * them to highlight their position. */ -function takeScreenshot(msg) { +function takeScreenshot(id, highlights, full) { let node = null; - if (msg.json.id) { - try { - node = elementManager.getKnownElement(msg.json.id, curContainer) - } - catch (e) { - sendResponse(e.message, e.code, e.stack, msg.json.command_id); - return; - } - } - else { + if (id) { + node = elementManager.getKnownElement(id, curContainer) + } else { node = curContainer.frame; } - let highlights = msg.json.highlights; - var document = curContainer.frame.document; - var rect, win, width, height, left, top; + let document = curContainer.frame.document; + let rect, win, width, height, left, top; + // node can be either a window or an arbitrary DOM node if (node == curContainer.frame) { // node is a window win = node; - if (msg.json.full) { + if (full) { // the full window width = document.body.scrollWidth; height = document.body.scrollHeight; top = 0; left = 0; - } - else { + } else { // only the viewport width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; left = curContainer.frame.pageXOffset; top = curContainer.frame.pageYOffset; } - } - else { + } else { // node is an arbitrary DOM node win = node.ownerDocument.defaultView; rect = node.getBoundingClientRect(); @@ -2051,15 +2043,16 @@ function takeScreenshot(msg) { left = rect.left; } - var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", - "canvas"); + let canvas = document.createElementNS( + "http://www.w3.org/1999/xhtml", "canvas"); canvas.width = width; canvas.height = height; - var ctx = canvas.getContext("2d"); - // Draws the DOM contents of the window to the canvas + let ctx = canvas.getContext("2d"); + + // draws the DOM contents of the window to the canvas ctx.drawWindow(win, left, top, width, height, "rgb(255,255,255)"); - // This section is for drawing a red rectangle around each element + // this section is for drawing a red rectangle around each element // passed in via the highlights array if (highlights) { ctx.lineWidth = "2"; @@ -2067,25 +2060,26 @@ function takeScreenshot(msg) { ctx.save(); for (var i = 0; i < highlights.length; ++i) { - var elem = elementManager.getKnownElement(highlights[i], curContainer); + let elem = elementManager.getKnownElement(highlights[i], curContainer); rect = elem.getBoundingClientRect(); - var offsetY = -top; - var offsetX = -left; + let offsetY = -top; + let offsetX = -left; - // Draw the rectangle - ctx.strokeRect(rect.left + offsetX, - rect.top + offsetY, - rect.width, - rect.height); + // draw the rectangle + ctx.strokeRect( + rect.left + offsetX, + rect.top + offsetY, + rect.width, + rect.height); } } - // Return the Base64 encoded string back to the client so that it - // can save the file to disk if it is required - var dataUrl = canvas.toDataURL("image/png", ""); - var data = dataUrl.substring(dataUrl.indexOf(",") + 1); - sendResponse({value: data}, msg.json.command_id); + // return the Base64 encoded string back to the client + // so that it can save the file to disk if it is required + let dataUrl = canvas.toDataURL("image/png", ""); + let encoded = dataUrl.substring(dataUrl.indexOf(",") + 1); + return encoded; } // Call register self when we get loaded From 30ee512caa92c6e498fb6c0a7fcab8214e0ea03e Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 13 Oct 2015 16:52:26 +0100 Subject: [PATCH 52/79] Bug 1213797: Refactor screen capture and SVG document support Errors thrown by takeScreenshot used to be silently ignored. When the command started using the new dispatching technique in bug 1202663, it was surfaced we do not support taking screen captures of SVG documents. Since this is a requirement for Web Platform Tests, this patch corrects the wrong assumptions about document body and document element. This patch also significantly refactors the screen capture code, but only uses the new implementation in contnent space, since some further modifications are required to use it in chrome. r=dburns r=jgriffin --HG-- extra : commitid : DdCIEpd5PEJ extra : rebase_source : 7357010f992d7f995765c685000892cc59d9ec9a --- testing/marionette/capture.js | 142 ++++++++++++++++++ .../marionette/tests/unit/test_screenshot.py | 1 - testing/marionette/driver.js | 3 +- testing/marionette/jar.mn | 1 + testing/marionette/listener.js | 107 ++++--------- 5 files changed, 178 insertions(+), 76 deletions(-) create mode 100644 testing/marionette/capture.js diff --git a/testing/marionette/capture.js b/testing/marionette/capture.js new file mode 100644 index 000000000000..c9117655aaa0 --- /dev/null +++ b/testing/marionette/capture.js @@ -0,0 +1,142 @@ +/* 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 = ["capture"]; + +const CONTEXT_2D = "2d"; +const BG_COLOUR = "rgb(255,255,255)"; +const PNG_MIME = "image/png"; +const XHTML_NS = "http://www.w3.org/1999/xhtml"; + +/** Provides primitives to capture screenshots. */ +this.capture = {}; + +/** + * Take a screenshot of a single element. + * + * @param {Node} node + * The node to take a screenshot of. + * @param {Array.=} highlights + * Optional array of nodes, around which a border will be marked to + * highlight them in the screenshot. + * + * @return {HTMLCanvasElement} + * The canvas element where the element has been painted on. + */ +capture.element = function(node, highlights=[]) { + let doc = node.ownerDocument; + let win = doc.defaultView; + let rect = node.getBoundingClientRect(); + + return capture.canvas( + doc, + rect.left, + rect.top, + rect.width, + rect.height, + highlights); +}; + +/** + * Take a screenshot of the document's viewport, taking into account + * the current window's offset. + * + * @param {Document} document + * The DOM document providing the document element to capture, + * and a window for determining the offset of the viewport. + * @param {Array.=} highlights + * Optional array of nodes, around which a border will be marked to + * highlight them in the screenshot. + * + * @return {HTMLCanvasElement} + * The canvas element where the viewport has been painted on. + */ +capture.viewport = function(document, highlights=[]) { + let win = document.defaultView; + let docEl = document.documentElement; + + return capture.canvas( + document, + win.pageXOffset, + win.pageYOffset, + docEl.clientWidth, + docEl.clientHeight, + highlights); +}; + +/** + * Low-level interface to draw a rectangle off the framebuffer. + * + * @param {Document} document + * A DOM document providing the window used to the framebuffer, + * and interfaces for creating an HTMLCanvasElement. + * @param {number} left + * The left, X axis offset of the rectangle. + * @param {number} top + * The top, Y axis offset of the rectangle. + * @param {number} width + * The width dimension of the rectangle to paint. + * @param {number} height + * The height dimension of the rectangle to paint. + * @param {Array.=} highlights + * Optional array of nodes, around which a border will be marked to + * highlight them in the screenshot. + * + * @return {HTMLCanvasElement} + * The canvas on which the selection from the window's framebuffer + * has been painted on. + */ +capture.canvas = function(document, left, top, width, height, highlights=[]) { + let win = document.defaultView; + + let canvas = document.createElementNS(XHTML_NS, "canvas"); + canvas.width = width; + canvas.height = height; + + let ctx = canvas.getContext(CONTEXT_2D); + ctx.drawWindow(win, left, top, width, height, BG_COLOUR); + ctx = capture.highlight_(ctx, highlights, top, left); + + return canvas; +}; + +capture.highlight_ = function(context, highlights, top=0, left=0) { + if (!highlights) { + return; + } + + context.lineWidth = "2"; + context.strokeStyle = "red"; + context.save(); + + for (let el of highlights) { + let rect = el.getBoundingClientRect(); + let oy = -top; + let ox = -left; + + context.strokeRect( + rect.left + ox, + rect.top + oy, + rect.width, + rect.height); + } + + return context; +}; + +/** + * Encode the contents of an HTMLCanvasElement to a Base64 encoded string. + * + * @param {HTMLCanvasElement} canvas + * The canvas to encode. + * + * @return {string} + * A Base64 encoded string. + */ +capture.toBase64 = function(canvas) { + let u = canvas.toDataURL(PNG_MIME); + return u.substring(u.indexOf(",") + 1); +}; diff --git a/testing/marionette/client/marionette/tests/unit/test_screenshot.py b/testing/marionette/client/marionette/tests/unit/test_screenshot.py index 43ee4bb3ef98..181831c65339 100644 --- a/testing/marionette/client/marionette/tests/unit/test_screenshot.py +++ b/testing/marionette/client/marionette/tests/unit/test_screenshot.py @@ -102,7 +102,6 @@ class Content(ScreenCaptureTestCase): self.assertEqual( self.body_scroll_dimensions, self.get_image_dimensions(string)) - @skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213797") def test_svg_document_element(self): self.marionette.navigate(svg) doc_el = self.document_element diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index 22895ad1983e..ae07db704c76 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -2536,6 +2536,7 @@ GeckoDriver.prototype.clearImportedScripts = function(cmd, resp) { */ GeckoDriver.prototype.takeScreenshot = function(cmd, resp) { let {id, highlights, full} = cmd.parameters; + highlights = highlights || []; switch (this.context) { case Context.CHROME: @@ -2579,7 +2580,7 @@ GeckoDriver.prototype.takeScreenshot = function(cmd, resp) { break; case Context.CONTENT: - return this.listener.takeScreenshot(id, highlights, full); + return this.listener.takeScreenshot(id, full, highlights); break; } }; diff --git a/testing/marionette/jar.mn b/testing/marionette/jar.mn index 111caf729abd..634a4b29b04d 100644 --- a/testing/marionette/jar.mn +++ b/testing/marionette/jar.mn @@ -21,6 +21,7 @@ marionette.jar: content/emulator.js (emulator.js) content/modal.js (modal.js) content/proxy.js (proxy.js) + content/capture.js (capture.js) #ifdef ENABLE_TESTS content/test.xul (client/marionette/chrome/test.xul) content/test2.xul (client/marionette/chrome/test2.xul) diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index 8119c4fe2a86..12be6ac15b31 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -13,6 +13,7 @@ var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] loader.loadSubScript("chrome://marionette/content/simpletest.js"); loader.loadSubScript("chrome://marionette/content/common.js"); loader.loadSubScript("chrome://marionette/content/actions.js"); +Cu.import("chrome://marionette/content/capture.js"); Cu.import("chrome://marionette/content/elements.js"); Cu.import("chrome://marionette/content/error.js"); Cu.import("resource://gre/modules/FileUtils.jsm"); @@ -1997,89 +1998,47 @@ function importScript(msg) { } /** - * Takes a screen capture of the given web element if id - * property exists in the message's JSON object, or if null captures - * the bounding box of the current frame. + * Perform a screen capture in content context. * - * If given an array of web element references in - * msg.json.highlights, a red box will be painted around - * them to highlight their position. + * @param {UUID=} id + * Optional web element reference of an element to take a screenshot + * of. + * @param {boolean=} full + * True to take a screenshot of the entire document element. Is not + * considered if {@code id} is not defined. Defaults to true. + * @param {Array.=} highlights + * Draw a border around the elements found by their web element + * references. + * + * @return {string} + * Base64 encoded string of an image/png type. */ -function takeScreenshot(id, highlights, full) { - let node = null; - if (id) { - node = elementManager.getKnownElement(id, curContainer) - } else { - node = curContainer.frame; +function takeScreenshot(id, full=true, highlights=[]) { + let canvas; + + let highlightEls = []; + for (let h of highlights) { + let el = elementManager.getKnownElement(h, curContainer); + highlightEls.push(el); } - let document = curContainer.frame.document; - let rect, win, width, height, left, top; + // viewport + if (!id && !full) { + canvas = capture.viewport(curContainer.frame.document, highlightEls); - // node can be either a window or an arbitrary DOM node - if (node == curContainer.frame) { - // node is a window - win = node; - if (full) { - // the full window - width = document.body.scrollWidth; - height = document.body.scrollHeight; - top = 0; - left = 0; + // element or full document element + } else { + let node; + if (id) { + node = elementManager.getKnownElement(id, curContainer); } else { - // only the viewport - width = document.documentElement.clientWidth; - height = document.documentElement.clientHeight; - left = curContainer.frame.pageXOffset; - top = curContainer.frame.pageYOffset; + node = curContainer.frame.document.documentElement; } - } else { - // node is an arbitrary DOM node - win = node.ownerDocument.defaultView; - rect = node.getBoundingClientRect(); - width = rect.width; - height = rect.height; - top = rect.top; - left = rect.left; + + canvas = capture.element(node, highlightEls); } - let canvas = document.createElementNS( - "http://www.w3.org/1999/xhtml", "canvas"); - canvas.width = width; - canvas.height = height; - let ctx = canvas.getContext("2d"); - - // draws the DOM contents of the window to the canvas - ctx.drawWindow(win, left, top, width, height, "rgb(255,255,255)"); - - // this section is for drawing a red rectangle around each element - // passed in via the highlights array - if (highlights) { - ctx.lineWidth = "2"; - ctx.strokeStyle = "red"; - ctx.save(); - - for (var i = 0; i < highlights.length; ++i) { - let elem = elementManager.getKnownElement(highlights[i], curContainer); - rect = elem.getBoundingClientRect(); - - let offsetY = -top; - let offsetX = -left; - - // draw the rectangle - ctx.strokeRect( - rect.left + offsetX, - rect.top + offsetY, - rect.width, - rect.height); - } - } - - // return the Base64 encoded string back to the client - // so that it can save the file to disk if it is required - let dataUrl = canvas.toDataURL("image/png", ""); - let encoded = dataUrl.substring(dataUrl.indexOf(",") + 1); - return encoded; + return capture.toBase64(canvas); } // Call register self when we get loaded From f6dde272fbd0f2d29b23e4f6e27c19e30fdac5cc Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 13 Oct 2015 12:20:25 -0600 Subject: [PATCH 53/79] Bug 1211262: Ensure that STORED entries in ZIP are considered corrupt if compressed and uncompressed sizes differ; r=mwu --HG-- extra : amend_source : d37546a886106b1858d28c2e4c28021970462850 --- modules/libjar/nsZipArchive.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 3c8f3fb960b6..a97e1c7d3880 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -841,8 +841,10 @@ MOZ_WIN_MEM_TRY_BEGIN // -- check if there is enough source data in the file if (!offset || mFd->mLen < aItem->Size() || - offset > mFd->mLen - aItem->Size()) + offset > mFd->mLen - aItem->Size() || + (aItem->Compression() == STORED && aItem->Size() != aItem->RealSize())) { return nullptr; + } return mFd->mFileData + offset; MOZ_WIN_MEM_TRY_CATCH(return nullptr) From 7de30b64ba5a38be5701af9c407b07b2153d1027 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 13 Oct 2015 23:43:14 +0200 Subject: [PATCH 54/79] Bug 1212794 - Remove decompile-body functionality. r=till --- .../jit-test/tests/auto-regress/bug776484.js | 4 -- .../basic/function-tosource-constructor.js | 2 - .../tests/basic/function-tosource-exprbody.js | 1 - .../tests/basic/function-tosource-genexpr.js | 2 +- .../tests/basic/function-tosource-lambda.js | 3 - .../basic/function-tosource-statement.js | 2 - js/src/jsapi.cpp | 12 +--- js/src/jsapi.h | 4 +- js/src/jsfun.cpp | 64 +++++++++---------- js/src/jsfun.h | 2 +- js/src/shell/js.cpp | 21 +----- .../extensions/strict-function-toSource.js | 4 +- 12 files changed, 37 insertions(+), 84 deletions(-) delete mode 100644 js/src/jit-test/tests/auto-regress/bug776484.js diff --git a/js/src/jit-test/tests/auto-regress/bug776484.js b/js/src/jit-test/tests/auto-regress/bug776484.js deleted file mode 100644 index 971cea966f1e..000000000000 --- a/js/src/jit-test/tests/auto-regress/bug776484.js +++ /dev/null @@ -1,4 +0,0 @@ -// Binary: cache/js-dbg-64-462106f027af-linux -// Flags: -// -decompileBody(function () { }); diff --git a/js/src/jit-test/tests/basic/function-tosource-constructor.js b/js/src/jit-test/tests/basic/function-tosource-constructor.js index 5ee9ff6db445..e1d1443640a2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-constructor.js +++ b/js/src/jit-test/tests/basic/function-tosource-constructor.js @@ -2,12 +2,10 @@ var f = Function("a", "b", "return a + b;"); assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}"); assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})"); assertEq(decompileFunction(f), f.toString()); -assertEq(decompileBody(f), "return a + b;"); f = Function("a", "...rest", "return rest[42] + b;"); assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}"); assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})") assertEq(decompileFunction(f), f.toString()); -assertEq(decompileBody(f), "return rest[42] + b;"); f = Function(""); assertEq(f.toString(), "function anonymous() {\n\n}"); f = Function("", "(abc)"); diff --git a/js/src/jit-test/tests/basic/function-tosource-exprbody.js b/js/src/jit-test/tests/basic/function-tosource-exprbody.js index ebd608b4b9d4..b78e06e0490d 100644 --- a/js/src/jit-test/tests/basic/function-tosource-exprbody.js +++ b/js/src/jit-test/tests/basic/function-tosource-exprbody.js @@ -2,7 +2,6 @@ function f1(foo, bar) foo + bar; assertEq(f1.toString(), "function f1(foo, bar) foo + bar"); assertEq(f1.toString(), f1.toSource()); assertEq(decompileFunction(f1), f1.toString()); -assertEq(decompileBody(f1), "foo + bar;"); // No semicolon on purpose function f2(foo, bar) foo + bar assertEq(f2.toString(), "function f2(foo, bar) foo + bar"); diff --git a/js/src/jit-test/tests/basic/function-tosource-genexpr.js b/js/src/jit-test/tests/basic/function-tosource-genexpr.js index 684de81db85c..b98f8767dcd5 100644 --- a/js/src/jit-test/tests/basic/function-tosource-genexpr.js +++ b/js/src/jit-test/tests/basic/function-tosource-genexpr.js @@ -4,4 +4,4 @@ function getgen() { var gen; (getgen() for (x of [1])).next(); assertEq(gen.toSource(), "function genexp() {\n [generator expression]\n}"); -assertEq(decompileBody(gen), "\n [generator expression]\n"); +assertEq(gen.toString(), gen.toSource()); diff --git a/js/src/jit-test/tests/basic/function-tosource-lambda.js b/js/src/jit-test/tests/basic/function-tosource-lambda.js index b2571411fbd1..5c013fcba7a2 100644 --- a/js/src/jit-test/tests/basic/function-tosource-lambda.js +++ b/js/src/jit-test/tests/basic/function-tosource-lambda.js @@ -2,14 +2,11 @@ var f1 = function f0(a, b) { return a + b; } assertEq(f1.toSource(), "(function f0(a, b) { return a + b; })"); assertEq(f1.toString(), "function f0(a, b) { return a + b; }"); assertEq(decompileFunction(f1), f1.toString()); -assertEq(decompileBody(f1), " return a + b; "); var f2 = function (a, b) { return a + b; }; assertEq(f2.toSource(), "(function (a, b) { return a + b; })"); assertEq(f2.toString(), "function (a, b) { return a + b; }"); assertEq(decompileFunction(f2), f2.toString()); -assertEq(decompileBody(f2), " return a + b; "); var f3 = (function (a, b) { return a + b; }); assertEq(f3.toSource(), "(function (a, b) { return a + b; })"); assertEq(f3.toString(), "function (a, b) { return a + b; }"); assertEq(decompileFunction(f3), f3.toString()); -assertEq(decompileBody(f3), " return a + b; "); diff --git a/js/src/jit-test/tests/basic/function-tosource-statement.js b/js/src/jit-test/tests/basic/function-tosource-statement.js index df8b9a57331d..c0c990e4f112 100644 --- a/js/src/jit-test/tests/basic/function-tosource-statement.js +++ b/js/src/jit-test/tests/basic/function-tosource-statement.js @@ -7,7 +7,5 @@ function f2(a, /* ))))pernicious comment */ b, c, // another comment(( d) {} assertEq(f2.toString(), "function f2(a, /* ))))pernicious comment */ b,\n c, // another comment((\n d) {}"); -assertEq(decompileBody(f2), ""); function f3() { } assertEq(f3.toString(), "function f3() { }"); -assertEq(decompileBody(f3), " "); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 152364d064c7..5b1f394236b1 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4583,17 +4583,7 @@ JS_DecompileFunction(JSContext* cx, HandleFunction fun, unsigned indent) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, fun); - return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT)); -} - -JS_PUBLIC_API(JSString*) -JS_DecompileFunctionBody(JSContext* cx, HandleFunction fun, unsigned indent) -{ - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, fun); - return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT)); + return FunctionToString(cx, fun, !(indent & JS_DONT_PRETTY_PRINT)); } MOZ_NEVER_INLINE static bool diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 2d8f93a72f5e..9959c4626f7f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4047,15 +4047,13 @@ JS_DecompileScript(JSContext* cx, JS::Handle script, const char* name /* * API extension: OR this into indent to avoid pretty-printing the decompiled - * source resulting from JS_DecompileFunction{,Body}. + * source resulting from JS_DecompileFunction. */ #define JS_DONT_PRETTY_PRINT ((unsigned)0x8000) extern JS_PUBLIC_API(JSString*) JS_DecompileFunction(JSContext* cx, JS::Handle fun, unsigned indent); -extern JS_PUBLIC_API(JSString*) -JS_DecompileFunctionBody(JSContext* cx, JS::Handle fun, unsigned indent); /* * NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 433c6a2dd5f4..86f3589259a1 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -909,7 +909,7 @@ js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* } JSString* -js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lambdaParen) +js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen) { if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) return nullptr; @@ -925,9 +925,9 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb if (fun->hasScript()) { script = fun->nonLazyScript(); if (script->isGeneratorExp()) { - if ((!bodyOnly && !out.append("function genexp() {")) || + if (!out.append("function genexp() {") || !out.append("\n [generator expression]\n") || - (!bodyOnly && !out.append("}"))) + !out.append("}")) { return nullptr; } @@ -937,21 +937,21 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() || fun->isGetter() || fun->isSetter(); - if (!bodyOnly) { - // If we're not in pretty mode, put parentheses around lambda functions and methods. - if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda) { - if (!out.append("(")) - return nullptr; - } - if (!fun->isArrow()) { - if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) - return nullptr; - } - if (fun->atom()) { - if (!out.append(fun->atom())) - return nullptr; - } + + // If we're not in pretty mode, put parentheses around lambda functions and methods. + if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda) { + if (!out.append("(")) + return nullptr; } + if (!fun->isArrow()) { + if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) + return nullptr; + } + if (fun->atom()) { + if (!out.append(fun->atom())) + return nullptr; + } + bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); if (haveSource && !script->scriptSource()->hasSourceData() && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) @@ -987,7 +987,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb // resulting function will have the same semantics. bool addUseStrict = script->strict() && !script->explicitUseStrict() && !fun->isArrow(); - bool buildBody = funCon && !bodyOnly; + bool buildBody = funCon; if (buildBody) { // This function was created with the Function constructor. We don't // have source for the arguments, so we have to generate that. Part @@ -1012,7 +1012,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb if (!out.append(") {\n")) return nullptr; } - if ((bodyOnly && !funCon) || addUseStrict) { + if (addUseStrict) { // We need to get at the body either because we're only supposed to // return the body or we need to insert "use strict" into the body. size_t bodyStart = 0, bodyEnd; @@ -1043,10 +1043,8 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb } } - // Output just the body (for bodyOnly) or the body and possibly - // closing braces (for addUseStrict). - size_t dependentEnd = bodyOnly ? bodyEnd : src->length(); - if (!out.appendSubstring(src, bodyStart, dependentEnd - bodyStart)) + // Output the body and possibly closing braces (for addUseStrict). + if (!out.appendSubstring(src, bodyStart, src->length() - bodyStart)) return nullptr; } else { if (!out.append(src)) @@ -1056,32 +1054,30 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb if (!out.append("\n}")) return nullptr; } - if (bodyOnly) { - // Slap a semicolon on the end of functions with an expression body. - if (exprBody && !out.append(";")) - return nullptr; - } else if (!lambdaParen && funIsMethodOrNonArrowLambda) { + if (!lambdaParen && funIsMethodOrNonArrowLambda) { if (!out.append(")")) return nullptr; } } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { - if ((!bodyOnly && !out.append("() {\n ")) || + if (!out.append("() {\n ") || !out.append("[sourceless code]") || - (!bodyOnly && !out.append("\n}"))) + !out.append("\n}")) + { return nullptr; + } if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")")) return nullptr; } else { MOZ_ASSERT(!fun->isExprBody()); if (fun->isNative() && fun->native() == js::DefaultDerivedClassConstructor) { - if ((!bodyOnly && !out.append("(...args) {\n ")) || + if (!out.append("(...args) {\n ") || !out.append("super(...args);\n}")) { return nullptr; } } else { - if (!bodyOnly && !out.append("() {\n ")) + if (!out.append("() {\n ")) return nullptr; if (!fun->isNative() || fun->native() != js::DefaultClassConstructor) { @@ -1089,7 +1085,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb return nullptr; } - if (!bodyOnly && !out.append("\n}")) + if (!out.append("\n}")) return nullptr; } } @@ -1110,7 +1106,7 @@ fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent) } RootedFunction fun(cx, &obj->as()); - return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT); + return FunctionToString(cx, fun, indent != JS_DONT_PRETTY_PRINT); } bool diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 6433fda0454e..3f21a99c039a 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -761,7 +761,7 @@ JSFunction::getExtendedSlot(size_t which) const namespace js { -JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lambdaParen); +JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen); template bool diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index ef7f581e1de9..66da6e3591fb 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3698,8 +3698,7 @@ NestedShell(JSContext* cx, unsigned argc, Value* vp) } static bool -DecompileFunctionSomehow(JSContext* cx, unsigned argc, Value* vp, - JSString* (*decompiler)(JSContext*, HandleFunction, unsigned)) +DecompileFunction(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() < 1 || !args[0].isObject() || !args[0].toObject().is()) { @@ -3707,25 +3706,13 @@ DecompileFunctionSomehow(JSContext* cx, unsigned argc, Value* vp, return true; } RootedFunction fun(cx, &args[0].toObject().as()); - JSString* result = decompiler(cx, fun, 0); + JSString* result = JS_DecompileFunction(cx, fun, 0); if (!result) return false; args.rval().setString(result); return true; } -static bool -DecompileBody(JSContext* cx, unsigned argc, Value* vp) -{ - return DecompileFunctionSomehow(cx, argc, vp, JS_DecompileFunctionBody); -} - -static bool -DecompileFunction(JSContext* cx, unsigned argc, Value* vp) -{ - return DecompileFunctionSomehow(cx, argc, vp, JS_DecompileFunction); -} - static bool DecompileThisScript(JSContext* cx, unsigned argc, Value* vp) { @@ -4866,10 +4853,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "decompileFunction(func)", " Decompile a function."), - JS_FN_HELP("decompileBody", DecompileBody, 1, 0, -"decompileBody(func)", -" Decompile a function's body."), - JS_FN_HELP("decompileThis", DecompileThisScript, 0, 0, "decompileThis()", " Decompile the currently executing script."), diff --git a/js/src/tests/ecma_5/extensions/strict-function-toSource.js b/js/src/tests/ecma_5/extensions/strict-function-toSource.js index 9f366cddf6dd..c144500dda3a 100644 --- a/js/src/tests/ecma_5/extensions/strict-function-toSource.js +++ b/js/src/tests/ecma_5/extensions/strict-function-toSource.js @@ -10,8 +10,6 @@ function testRunOptionStrictMode(str, arg, result) { } assertEq(eval(uneval(testRunOptionStrictMode()))(), true); -if (typeof decompileBody !== "undefined") { - assertEq(decompileBody(new Function('x', 'return x*2;')).includes('\n"use strict"'), true); -} +assertEq((new Function('x', 'return x*2;')).toSource().includes('\n"use strict"'), true); reportCompare(true, true); From 9b82cb15843923ae2cd6ad8f3bff0da8240f17b6 Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Tue, 13 Oct 2015 17:43:16 -0400 Subject: [PATCH 55/79] Bug 1035091 part 1: change CSS parser and loader APIs to distinguish UA, user, and author sheets instead of just UA vs everyone else. r=heycam --HG-- extra : rebase_source : a8a5a27db01306d1de58974ebb4d06d29d4b72b0 --- dom/base/nsDocument.cpp | 32 ++++++++++--- dom/base/nsTreeSanitizer.cpp | 3 +- dom/svg/SVGDocument.cpp | 4 +- editor/libeditor/nsHTMLEditor.cpp | 3 +- layout/base/nsStyleSheetService.cpp | 55 +++++++++++++++++------ layout/style/CSSStyleSheet.cpp | 9 ++-- layout/style/Loader.cpp | 57 +++++++++++++++--------- layout/style/Loader.h | 49 +++++++++++++++----- layout/style/nsCSSParser.cpp | 44 ++++++++++++------ layout/style/nsCSSParser.h | 8 ++-- layout/style/nsLayoutStylesheetCache.cpp | 49 ++++++++++---------- layout/style/nsLayoutStylesheetCache.h | 11 +++-- 12 files changed, 221 insertions(+), 103 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index fc378131c167..1ae96d223c71 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -4405,7 +4405,8 @@ FindSheet(const nsCOMArray& aSheets, nsIURI* aSheetURI) } nsresult -nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) +nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, + nsIURI* aSheetURI) { NS_PRECONDITION(aSheetURI, "null arg"); @@ -4414,11 +4415,29 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetUR return NS_ERROR_INVALID_ARG; // Loading the sheet sync. - nsRefPtr loader = new mozilla::css::Loader(); + nsRefPtr loader = new css::Loader(); + + css::SheetParsingMode parsingMode; + switch (aType) { + case nsIDocument::eAgentSheet: + parsingMode = css::eAgentSheetFeatures; + break; + + case nsIDocument::eUserSheet: + parsingMode = css::eUserSheetFeatures; + break; + + case nsIDocument::eAuthorSheet: + parsingMode = css::eAuthorSheetFeatures; + break; + + default: + MOZ_CRASH("impossible value for aType"); + } nsRefPtr sheet; - nsresult rv = loader->LoadSheetSync(aSheetURI, aType == eAgentSheet, - true, getter_AddRefs(sheet)); + nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, + getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); sheet->SetOwningDocument(this); @@ -9905,7 +9924,10 @@ nsresult nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet, CSSStyleSheet** sheet) { - return CSSLoader()->LoadSheetSync(uri, isAgentSheet, isAgentSheet, sheet); + css::SheetParsingMode mode = + isAgentSheet ? css::eAgentSheetFeatures + : css::eAuthorSheetFeatures; + return CSSLoader()->LoadSheetSync(uri, mode, isAgentSheet, sheet); } class nsDelayedEventDispatcher : public nsRunnable diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index e9502bdd2566..7164a3e08210 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -1098,7 +1098,8 @@ nsTreeSanitizer::SanitizeStyleSheet(const nsAString& aOriginal, // Create the CSS parser, and parse the CSS text. nsCSSParser parser(nullptr, sheet); rv = parser.ParseSheet(aOriginal, aDocument->GetDocumentURI(), aBaseURI, - aDocument->NodePrincipal(), 0, false); + aDocument->NodePrincipal(), 0, + mozilla::css::eAuthorSheetFeatures); NS_ENSURE_SUCCESS(rv, true); // Mark the sheet as complete. MOZ_ASSERT(!sheet->IsModified(), diff --git a/dom/svg/SVGDocument.cpp b/dom/svg/SVGDocument.cpp index 913f90338270..7270ca183a6f 100644 --- a/dom/svg/SVGDocument.cpp +++ b/dom/svg/SVGDocument.cpp @@ -148,7 +148,9 @@ SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded() NS_NewURI(getter_AddRefs(uri), spec); if (uri) { nsRefPtr cssSheet; - cssLoader->LoadSheetSync(uri, true, true, getter_AddRefs(cssSheet)); + cssLoader->LoadSheetSync(uri, + mozilla::css::eAgentSheetFeatures, + true, getter_AddRefs(cssSheet)); if (cssSheet) { EnsureOnDemandBuiltInUASheet(cssSheet); } diff --git a/editor/libeditor/nsHTMLEditor.cpp b/editor/libeditor/nsHTMLEditor.cpp index c169c38f6cc2..1afb7f7b6509 100644 --- a/editor/libeditor/nsHTMLEditor.cpp +++ b/editor/libeditor/nsHTMLEditor.cpp @@ -2843,7 +2843,8 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL) nsRefPtr sheet; // Editor override style sheets may want to style Gecko anonymous boxes rv = ps->GetDocument()->CSSLoader()-> - LoadSheetSync(uaURI, true, true, getter_AddRefs(sheet)); + LoadSheetSync(uaURI, mozilla::css::eAgentSheetFeatures, true, + getter_AddRefs(sheet)); // Synchronous loads should ALWAYS return completed NS_ENSURE_TRUE(sheet, NS_ERROR_NULL_POINTER); diff --git a/layout/base/nsStyleSheetService.cpp b/layout/base/nsStyleSheetService.cpp index f85227ee9298..36d50bde609a 100644 --- a/layout/base/nsStyleSheetService.cpp +++ b/layout/base/nsStyleSheetService.cpp @@ -180,17 +180,32 @@ nsresult nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI, uint32_t aSheetType) { - NS_ENSURE_ARG(aSheetType == AGENT_SHEET || - aSheetType == USER_SHEET || - aSheetType == AUTHOR_SHEET); NS_ENSURE_ARG_POINTER(aSheetURI); + css::SheetParsingMode parsingMode; + switch (aSheetType) { + case AGENT_SHEET: + parsingMode = css::eAgentSheetFeatures; + break; + + case USER_SHEET: + parsingMode = css::eUserSheetFeatures; + break; + + case AUTHOR_SHEET: + parsingMode = css::eAuthorSheetFeatures; + break; + + default: + NS_WARNING("invalid sheet type argument"); + return NS_ERROR_INVALID_ARG; + } + nsRefPtr loader = new css::Loader(); nsRefPtr sheet; - // Allow UA sheets, but not user sheets, to use unsafe rules - nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET, - true, getter_AddRefs(sheet)); + nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, + getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); if (!mSheets[aSheetType].AppendObject(sheet)) { @@ -219,18 +234,32 @@ NS_IMETHODIMP nsStyleSheetService::PreloadSheet(nsIURI *aSheetURI, uint32_t aSheetType, nsIDOMStyleSheet **aSheet) { - NS_ENSURE_ARG(aSheetType == AGENT_SHEET || - aSheetType == USER_SHEET || - aSheetType == AUTHOR_SHEET); - NS_ENSURE_ARG_POINTER(aSheetURI); NS_PRECONDITION(aSheet, "Null out param"); + NS_ENSURE_ARG_POINTER(aSheetURI); + css::SheetParsingMode parsingMode; + switch (aSheetType) { + case AGENT_SHEET: + parsingMode = css::eAgentSheetFeatures; + break; + + case USER_SHEET: + parsingMode = css::eUserSheetFeatures; + break; + + case AUTHOR_SHEET: + parsingMode = css::eAuthorSheetFeatures; + break; + + default: + NS_WARNING("invalid sheet type argument"); + return NS_ERROR_INVALID_ARG; + } nsRefPtr loader = new css::Loader(); - // Allow UA sheets, but not user sheets, to use unsafe rules nsRefPtr sheet; - nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET, - true, getter_AddRefs(sheet)); + nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, + getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); sheet.forget(aSheet); return NS_OK; diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index 36db0ff3b8f4..c556ea1de6f8 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -2331,8 +2331,11 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput) mInner->mFirstChild = nullptr; mInner->mNameSpaceMap = nullptr; - // allow unsafe rules if the style sheet's principal is the system principal - bool allowUnsafeRules = nsContentUtils::IsSystemPrincipal(mInner->mPrincipal); + // allow agent features if the style sheet's principal is the system principal + css::SheetParsingMode parsingMode = + nsContentUtils::IsSystemPrincipal(mInner->mPrincipal) + ? css::eAgentSheetFeatures + : css::eAuthorSheetFeatures; uint32_t lineNumber = 1; if (mOwningNode) { @@ -2345,7 +2348,7 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput) nsCSSParser parser(loader, this); nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI, mInner->mPrincipal, lineNumber, - allowUnsafeRules, &reusableSheets); + parsingMode, &reusableSheets); DidDirty(); // we are always 'dirty' here since we always remove rules first NS_ENSURE_SUCCESS(rv, rv); diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 488b07b9aa34..53b49c3d1769 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -104,6 +104,12 @@ namespace css { * Data needed to properly load a stylesheet * *********************************************/ +static_assert(eAuthorSheetFeatures == 0 && + eUserSheetFeatures == 1 && + eAgentSheetFeatures == 2, + "sheet parsing mode constants won't fit " + "in SheetLoadData::mParsingMode"); + class SheetLoadData final : public nsIRunnable, public nsIUnicharStreamLoaderObserver, public nsIThreadObserver @@ -137,7 +143,7 @@ public: nsIURI* aURI, CSSStyleSheet* aSheet, bool aSyncLoad, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, const nsCString& aCharset, nsICSSLoaderObserver* aObserver, @@ -215,9 +221,12 @@ public: // created. bool mWasAlternate : 1; - // mAllowUnsafeRules is true if we should allow unsafe rules to be parsed - // in the loaded sheet. - bool mAllowUnsafeRules : 1; + // mParsingMode controls access to nonstandard style constructs that + // are not safe for use on the public Web but necessary in UA sheets + // and/or useful in user sheets. The only values stored in this + // field are 0, 1, and 2; three bits are allocated to avoid issues + // should the enum type be signed. + SheetParsingMode mParsingMode : 3; // mUseSystemPrincipal is true if the system principal should be used for // this sheet, no matter what the channel principal is. Only true for sync @@ -333,7 +342,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, mIsCancelled(false), mMustNotify(false), mWasAlternate(aIsAlternate), - mAllowUnsafeRules(false), + mParsingMode(eAuthorSheetFeatures), mUseSystemPrincipal(false), mSheetAlreadyComplete(false), mOwningElement(aOwningElement), @@ -364,7 +373,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, mIsCancelled(false), mMustNotify(false), mWasAlternate(false), - mAllowUnsafeRules(false), + mParsingMode(eAuthorSheetFeatures), mUseSystemPrincipal(false), mSheetAlreadyComplete(false), mOwningElement(nullptr), @@ -376,7 +385,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, if (mParentData) { mSyncLoad = mParentData->mSyncLoad; mIsNonDocumentSheet = mParentData->mIsNonDocumentSheet; - mAllowUnsafeRules = mParentData->mAllowUnsafeRules; + mParsingMode = mParentData->mParsingMode; mUseSystemPrincipal = mParentData->mUseSystemPrincipal; ++(mParentData->mPendingChildren); } @@ -389,7 +398,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, nsIURI* aURI, CSSStyleSheet* aSheet, bool aSyncLoad, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, const nsCString& aCharset, nsICSSLoaderObserver* aObserver, @@ -407,7 +416,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, mIsCancelled(false), mMustNotify(false), mWasAlternate(false), - mAllowUnsafeRules(aAllowUnsafeRules), + mParsingMode(aParsingMode), mUseSystemPrincipal(aUseSystemPrincipal), mSheetAlreadyComplete(false), mOwningElement(nullptr), @@ -417,6 +426,10 @@ SheetLoadData::SheetLoadData(Loader* aLoader, mCharsetHint(aCharset) { NS_PRECONDITION(mLoader, "Must have a loader!"); + NS_PRECONDITION(aParsingMode == eAuthorSheetFeatures || + aParsingMode == eUserSheetFeatures || + aParsingMode == eAgentSheetFeatures, + "Unrecognized sheet parsing mode"); NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad, "Shouldn't use system principal for async loads"); @@ -1779,7 +1792,7 @@ Loader::ParseSheet(const nsAString& aInput, nsresult rv = parser.ParseSheet(aInput, sheetURI, baseURI, aLoadData->mSheet->Principal(), aLoadData->mLineNumber, - aLoadData->mAllowUnsafeRules); + aLoadData->mParsingMode); mParsingDatas.RemoveElementAt(mParsingDatas.Length() - 1); if (NS_FAILED(rv)) { @@ -2293,14 +2306,16 @@ Loader::LoadChildSheet(CSSStyleSheet* aParentSheet, } nsresult -Loader::LoadSheetSync(nsIURI* aURL, bool aAllowUnsafeRules, +Loader::LoadSheetSync(nsIURI* aURL, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, CSSStyleSheet** aSheet) { LOG(("css::Loader::LoadSheetSync")); - return InternalLoadNonDocumentSheet(aURL, false, aAllowUnsafeRules, - aUseSystemPrincipal, nullptr, - EmptyCString(), aSheet, nullptr); + return InternalLoadNonDocumentSheet(aURL, + false, aParsingMode, aUseSystemPrincipal, + nullptr, EmptyCString(), + aSheet, nullptr); } nsresult @@ -2312,7 +2327,8 @@ Loader::LoadSheet(nsIURI* aURL, { LOG(("css::Loader::LoadSheet(aURL, aObserver, aSheet) api call")); NS_PRECONDITION(aSheet, "aSheet is null"); - return InternalLoadNonDocumentSheet(aURL, false, false, false, + return InternalLoadNonDocumentSheet(aURL, + false, eAuthorSheetFeatures, false, aOriginPrincipal, aCharset, aSheet, aObserver); } @@ -2328,16 +2344,17 @@ Loader::LoadSheet(nsIURI* aURL, const nsAString& aIntegrity) { LOG(("css::Loader::LoadSheet(aURL, aObserver) api call")); - return InternalLoadNonDocumentSheet(aURL, aIsPreload, false, false, + return InternalLoadNonDocumentSheet(aURL, + aIsPreload, eAuthorSheetFeatures, false, aOriginPrincipal, aCharset, - nullptr, aObserver, aCORSMode, - aReferrerPolicy, aIntegrity); + nullptr, aObserver, + aCORSMode, aReferrerPolicy, aIntegrity); } nsresult Loader::InternalLoadNonDocumentSheet(nsIURI* aURL, bool aIsPreload, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, nsIPrincipal* aOriginPrincipal, const nsCString& aCharset, @@ -2394,7 +2411,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL, } SheetLoadData* data = - new SheetLoadData(this, aURL, sheet, syncLoad, aAllowUnsafeRules, + new SheetLoadData(this, aURL, sheet, syncLoad, aParsingMode, aUseSystemPrincipal, aCharset, aObserver, aOriginPrincipal, mDocument); diff --git a/layout/style/Loader.h b/layout/style/Loader.h index 6da5285e8157..0e81d4ccc6f8 100644 --- a/layout/style/Loader.h +++ b/layout/style/Loader.h @@ -183,6 +183,33 @@ enum StyleSheetState { eSheetComplete }; +/** + * Enum defining the mode in which a sheet is to be parsed. This is + * usually, but not always, the same as the cascade level at which the + * sheet will apply (see nsStyleSet.h). Most of the Loader APIs only + * support loading of author sheets. + * + * Author sheets are the normal case: styles embedded in or linked + * from HTML pages. They are also the most restricted. + * + * User sheets can do anything author sheets can do, and also get + * access to a few CSS extensions that are not yet suitable for + * exposure on the public Web, but are very useful for expressing + * user style overrides, such as @-moz-document rules. + * + * Agent sheets have access to all author- and user-sheet features + * plus more extensions that are necessary for internal use but, + * again, not yet suitable for exposure on the public Web. Some of + * these are outright unsafe to expose; in particular, incorrect + * styling of anonymous box pseudo-elements can violate layout + * invariants. + */ +enum SheetParsingMode { + eAuthorSheetFeatures = 0, + eUserSheetFeatures, + eAgentSheetFeatures +}; + class Loader final { typedef mozilla::net::ReferrerPolicy ReferrerPolicy; @@ -300,13 +327,8 @@ public: * method can be used to load sheets not associated with a document. * * @param aURL the URL of the sheet to load - * @param aEnableUnsafeRules whether unsafe rules are enabled for this - * sheet load - * Unsafe rules are rules that can violate key Gecko invariants if misused. - * In particular, most anonymous box pseudoelements must be very carefully - * styled or we will have severe problems. Therefore unsafe rules should - * never be enabled for stylesheets controlled by untrusted sites; preferably - * unsafe rules should only be enabled for agent sheets. + * @param aParsingMode the mode in which to parse the sheet + * (see comments at enum SheetParsingMode, above). * @param aUseSystemPrincipal if true, give the resulting sheet the system * principal no matter where it's being loaded from. * @param [out] aSheet the loaded, complete sheet. @@ -319,22 +341,25 @@ public: * whether the data could be parsed as CSS and doesn't indicate anything * about the status of child sheets of the returned sheet. */ - nsresult LoadSheetSync(nsIURI* aURL, bool aEnableUnsafeRules, + nsresult LoadSheetSync(nsIURI* aURL, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, CSSStyleSheet** aSheet); /** - * As above, but aUseSystemPrincipal and aEnableUnsafeRules are assumed false. + * As above, but defaults aParsingMode to eAuthorSheetFeatures and + * aUseSystemPrincipal to false. */ nsresult LoadSheetSync(nsIURI* aURL, CSSStyleSheet** aSheet) { - return LoadSheetSync(aURL, false, false, aSheet); + return LoadSheetSync(aURL, eAuthorSheetFeatures, false, aSheet); } /** * Asynchronously load the stylesheet at aURL. If a successful result is * returned, aObserver is guaranteed to be notified asynchronously once the * sheet is loaded and marked complete. This method can be used to load - * sheets not associated with a document. + * sheets not associated with a document. This method cannot be used to + * load user or agent sheets. * * @param aURL the URL of the sheet to load * @param aOriginPrincipal the principal to use for security checks. This @@ -495,7 +520,7 @@ private: nsresult InternalLoadNonDocumentSheet(nsIURI* aURL, bool aIsPreload, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, bool aUseSystemPrincipal, nsIPrincipal* aOriginPrincipal, const nsCString& aCharset, diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index b460e73c56b5..826b6951caf0 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -107,6 +107,12 @@ struct CSSParserInputState { bool mHavePushBack; }; +static_assert(eAuthorSheetFeatures == 0 && + eUserSheetFeatures == 1 && + eAgentSheetFeatures == 2, + "sheet parsing mode constants won't fit " + "in CSSParserImpl::mParsingMode"); + // Your basic top-down recursive descent style parser // The exposed methods and members of this class are precisely those // needed by nsCSSParser, far below. @@ -131,7 +137,7 @@ public: nsIURI* aBaseURI, nsIPrincipal* aSheetPrincipal, uint32_t aLineNumber, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, LoaderReusableStyleSheets* aReusableSheets); nsresult ParseStyleAttribute(const nsAString& aAttributeValue, @@ -316,12 +322,20 @@ public: uint32_t aLineNumber, uint32_t aLineOffset); + bool AgentRulesEnabled() const { + return mParsingMode == eAgentSheetFeatures; + } + bool UserRulesEnabled() const { + return mParsingMode == eAgentSheetFeatures || + mParsingMode == eUserSheetFeatures; + } + nsCSSProps::EnabledState PropertyEnabledState() const { static_assert(nsCSSProps::eEnabledForAllContent == 0, "nsCSSProps::eEnabledForAllContent should be zero for " "this bitfield to work"); nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent; - if (mUnsafeRulesEnabled) { + if (AgentRulesEnabled()) { enabledState |= nsCSSProps::eEnabledInUASheets; } if (mIsChrome) { @@ -1215,8 +1229,12 @@ protected: // True when the unitless length quirk applies. bool mUnitlessLengthQuirk : 1; - // True if unsafe rules should be allowed - bool mUnsafeRulesEnabled : 1; + // Controls access to nonstandard style constructs that are not safe + // for use on the public Web but necessary in UA sheets and/or + // useful in user sheets. The only values stored in this field are + // 0, 1, and 2; three bits are allocated to avoid issues should the + // enum type be signed. + SheetParsingMode mParsingMode : 3; // True if we are in parsing rules for the chrome. bool mIsChrome : 1; @@ -1346,7 +1364,7 @@ CSSParserImpl::CSSParserImpl() mNavQuirkMode(false), mHashlessColorQuirk(false), mUnitlessLengthQuirk(false), - mUnsafeRulesEnabled(false), + mParsingMode(eAuthorSheetFeatures), mIsChrome(false), mViewportUnitsEnabled(true), mHTMLMediaMode(false), @@ -1453,7 +1471,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput, nsIURI* aBaseURI, nsIPrincipal* aSheetPrincipal, uint32_t aLineNumber, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, LoaderReusableStyleSheets* aReusableSheets) { NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); @@ -1499,7 +1517,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput, mSection = eCSSSection_Charset; // sheet is empty, any rules are fair } - mUnsafeRulesEnabled = aAllowUnsafeRules; + mParsingMode = aParsingMode; mIsChrome = nsContentUtils::IsSystemPrincipal(aSheetPrincipal); mReusableSheets = aReusableSheets; @@ -1524,7 +1542,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput, } ReleaseScanner(); - mUnsafeRulesEnabled = false; + mParsingMode = eAuthorSheetFeatures; mIsChrome = false; mReusableSheets = nullptr; @@ -5604,7 +5622,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, bool pseudoClassIsUserAction = nsCSSPseudoClasses::IsUserActionPseudoClass(pseudoClassType); - if (!mUnsafeRulesEnabled && + if (!AgentRulesEnabled() && ((pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount && nsCSSPseudoElements::PseudoElementIsUASheetOnly(pseudoElementType)) || (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass && @@ -5640,10 +5658,10 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, bool isPseudoElement = (pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount); // anonymous boxes are only allowed if they're the tree boxes or we have - // enabled unsafe rules + // enabled agent rules bool isAnonBox = isTreePseudo || (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox && - mUnsafeRulesEnabled); + AgentRulesEnabled()); bool isPseudoClass = (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass); @@ -15820,12 +15838,12 @@ nsCSSParser::ParseSheet(const nsAString& aInput, nsIURI* aBaseURI, nsIPrincipal* aSheetPrincipal, uint32_t aLineNumber, - bool aAllowUnsafeRules, + SheetParsingMode aParsingMode, LoaderReusableStyleSheets* aReusableSheets) { return static_cast(mImpl)-> ParseSheet(aInput, aSheetURI, aBaseURI, aSheetPrincipal, aLineNumber, - aAllowUnsafeRules, aReusableSheets); + aParsingMode, aReusableSheets); } nsresult diff --git a/layout/style/nsCSSParser.h b/layout/style/nsCSSParser.h index a4e18a2de88e..f23958100fd5 100644 --- a/layout/style/nsCSSParser.h +++ b/layout/style/nsCSSParser.h @@ -9,6 +9,7 @@ #define nsCSSParser_h___ #include "mozilla/Attributes.h" +#include "mozilla/css/Loader.h" #include "nsCSSProperty.h" #include "nsCSSScanner.h" @@ -32,8 +33,6 @@ class CSSVariableValues; namespace css { class Rule; class Declaration; -class Loader; -class LoaderReusableStyleSheets; class StyleRule; } // namespace css } // namespace mozilla @@ -78,8 +77,7 @@ public: * @param aSheetPrincipal the principal of the stylesheet. This must match * the principal of the sheet passed to SetStyleSheet. * @param aLineNumber the line number of the first line of the sheet. - * @param aAllowUnsafeRules see aEnableUnsafeRules in - * mozilla::css::Loader::LoadSheetSync + * @param aParsingMode see SheetParsingMode in css/Loader.h * @param aReusableSheets style sheets that can be reused by an @import. * This can be nullptr. */ @@ -88,7 +86,7 @@ public: nsIURI* aBaseURI, nsIPrincipal* aSheetPrincipal, uint32_t aLineNumber, - bool aAllowUnsafeRules, + mozilla::css::SheetParsingMode aParsingMode, mozilla::css::LoaderReusableStyleSheets* aReusableSheets = nullptr); diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index fdf054eb5c79..2692a3a84ade 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -30,6 +30,7 @@ #endif using namespace mozilla; +using namespace mozilla::css; static bool sNumberControlEnabled; @@ -70,7 +71,7 @@ nsLayoutStylesheetCache::ScrollbarsSheet() if (!gStyleCache->mScrollbarsSheet) { // Scrollbars don't need access to unsafe rules LoadSheetURL("chrome://global/skin/scrollbars.css", - gStyleCache->mScrollbarsSheet, false); + gStyleCache->mScrollbarsSheet, eAuthorSheetFeatures); } return gStyleCache->mScrollbarsSheet; @@ -84,7 +85,7 @@ nsLayoutStylesheetCache::FormsSheet() if (!gStyleCache->mFormsSheet) { // forms.css needs access to unsafe rules LoadSheetURL("resource://gre-resources/forms.css", - gStyleCache->mFormsSheet, true); + gStyleCache->mFormsSheet, eAgentSheetFeatures); } return gStyleCache->mFormsSheet; @@ -101,7 +102,7 @@ nsLayoutStylesheetCache::NumberControlSheet() if (!gStyleCache->mNumberControlSheet) { LoadSheetURL("resource://gre-resources/number-control.css", - gStyleCache->mNumberControlSheet, true); + gStyleCache->mNumberControlSheet, eAgentSheetFeatures); } return gStyleCache->mNumberControlSheet; @@ -128,7 +129,7 @@ nsLayoutStylesheetCache::UASheet() if (!gStyleCache->mUASheet) { LoadSheetURL("resource://gre-resources/ua.css", - gStyleCache->mUASheet, true); + gStyleCache->mUASheet, eAgentSheetFeatures); } return gStyleCache->mUASheet; @@ -141,7 +142,7 @@ nsLayoutStylesheetCache::HTMLSheet() if (!gStyleCache->mHTMLSheet) { LoadSheetURL("resource://gre-resources/html.css", - gStyleCache->mHTMLSheet, true); + gStyleCache->mHTMLSheet, eAgentSheetFeatures); } return gStyleCache->mHTMLSheet; @@ -182,7 +183,7 @@ nsLayoutStylesheetCache::MathMLSheet() if (!gStyleCache->mMathMLSheet) { LoadSheetURL("resource://gre-resources/mathml.css", - gStyleCache->mMathMLSheet, true); + gStyleCache->mMathMLSheet, eAgentSheetFeatures); } return gStyleCache->mMathMLSheet; @@ -209,7 +210,7 @@ nsLayoutStylesheetCache::NoScriptSheet() #else "resource://gre-resources/noscript.css", #endif - gStyleCache->mNoScriptSheet, true); + gStyleCache->mNoScriptSheet, eAgentSheetFeatures); } return gStyleCache->mNoScriptSheet; @@ -229,7 +230,7 @@ nsLayoutStylesheetCache::NoFramesSheet() #else "resource://gre-resources/noframes.css", #endif - gStyleCache->mNoFramesSheet, true); + gStyleCache->mNoFramesSheet, eAgentSheetFeatures); } return gStyleCache->mNoFramesSheet; @@ -268,7 +269,7 @@ nsLayoutStylesheetCache::ContentEditableSheet() if (!gStyleCache->mContentEditableSheet) { LoadSheetURL("resource://gre/res/contenteditable.css", - gStyleCache->mContentEditableSheet, true); + gStyleCache->mContentEditableSheet, eAgentSheetFeatures); } return gStyleCache->mContentEditableSheet; @@ -281,7 +282,7 @@ nsLayoutStylesheetCache::DesignModeSheet() if (!gStyleCache->mDesignModeSheet) { LoadSheetURL("resource://gre/res/designmode.css", - gStyleCache->mDesignModeSheet, true); + gStyleCache->mDesignModeSheet, eAgentSheetFeatures); } return gStyleCache->mDesignModeSheet; @@ -359,15 +360,15 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache() // And make sure that we load our UA sheets. No need to do this // per-profile, since they're profile-invariant. LoadSheetURL("resource://gre-resources/counterstyles.css", - mCounterStylesSheet, true); + mCounterStylesSheet, eAgentSheetFeatures); LoadSheetURL("chrome://global/content/minimal-xul.css", - mMinimalXULSheet, true); + mMinimalXULSheet, eAgentSheetFeatures); LoadSheetURL("resource://gre-resources/quirk.css", - mQuirkSheet, true); + mQuirkSheet, eAgentSheetFeatures); LoadSheetURL("resource://gre/res/svg.css", - mSVGSheet, true); + mSVGSheet, eAgentSheetFeatures); LoadSheetURL("chrome://global/content/xul.css", - mXULSheet, true); + mXULSheet, eAgentSheetFeatures); // The remaining sheets are created on-demand do to their use being rarer // (which helps save memory for Firefox OS apps) or because they need to @@ -434,25 +435,27 @@ nsLayoutStylesheetCache::InitFromProfile() contentFile->Append(NS_LITERAL_STRING("userContent.css")); chromeFile->Append(NS_LITERAL_STRING("userChrome.css")); - LoadSheetFile(contentFile, mUserContentSheet); - LoadSheetFile(chromeFile, mUserChromeSheet); + LoadSheetFile(contentFile, mUserContentSheet, eUserSheetFeatures); + LoadSheetFile(chromeFile, mUserChromeSheet, eUserSheetFeatures); } /* static */ void nsLayoutStylesheetCache::LoadSheetURL(const char* aURL, nsRefPtr& aSheet, - bool aEnableUnsafeRules) + SheetParsingMode aParsingMode) { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), aURL); - LoadSheet(uri, aSheet, aEnableUnsafeRules); + LoadSheet(uri, aSheet, aParsingMode); if (!aSheet) { NS_ERROR(nsPrintfCString("Could not load %s", aURL).get()); } } void -nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr& aSheet) +nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, + nsRefPtr& aSheet, + SheetParsingMode aParsingMode) { bool exists = false; aFile->Exists(&exists); @@ -462,7 +465,7 @@ nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr& nsCOMPtr uri; NS_NewFileURI(getter_AddRefs(uri), aFile); - LoadSheet(uri, aSheet, false); + LoadSheet(uri, aSheet, aParsingMode); } #ifdef MOZ_CRASHREPORTER @@ -719,7 +722,7 @@ ErrorLoadingBuiltinSheet(nsIURI* aURI, const char* aMsg) void nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, nsRefPtr& aSheet, - bool aEnableUnsafeRules) + SheetParsingMode aParsingMode) { if (!aURI) { ErrorLoadingBuiltinSheet(aURI, "null URI"); @@ -736,7 +739,7 @@ nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, } - nsresult rv = gCSSLoader->LoadSheetSync(aURI, aEnableUnsafeRules, true, + nsresult rv = gCSSLoader->LoadSheetSync(aURI, aParsingMode, true, getter_AddRefs(aSheet)); if (NS_FAILED(rv)) { ErrorLoadingBuiltinSheet(aURI, diff --git a/layout/style/nsLayoutStylesheetCache.h b/layout/style/nsLayoutStylesheetCache.h index 5d9beb8f90c8..f18271b3860d 100644 --- a/layout/style/nsLayoutStylesheetCache.h +++ b/layout/style/nsLayoutStylesheetCache.h @@ -13,15 +13,13 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/StaticPtr.h" +#include "mozilla/css/Loader.h" class nsIFile; class nsIURI; namespace mozilla { class CSSStyleSheet; -namespace css { -class Loader; -} // namespace css } // namespace mozilla class nsLayoutStylesheetCache final @@ -69,11 +67,12 @@ private: void InitMemoryReporter(); static void LoadSheetURL(const char* aURL, nsRefPtr& aSheet, - bool aEnableUnsafeRules); + mozilla::css::SheetParsingMode aParsingMode); static void LoadSheetFile(nsIFile* aFile, - nsRefPtr& aSheet); + nsRefPtr& aSheet, + mozilla::css::SheetParsingMode aParsingMode); static void LoadSheet(nsIURI* aURI, nsRefPtr& aSheet, - bool aEnableUnsafeRules); + mozilla::css::SheetParsingMode aParsingMode); static void InvalidateSheet(nsRefPtr& aSheet); static void DependentPrefChanged(const char* aPref, void* aData); void BuildPreferenceSheet(nsRefPtr& aSheet, From dd53187aac796fa8601d004b0a4ccb3d11d5a646 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Wed, 14 Oct 2015 08:57:06 +1100 Subject: [PATCH 56/79] Bug 1196379 - Fix incorrect assertion checking for sorted arrays in nsDocumentRuleResultCacheKey::Matches. r=dbaron --- layout/style/CSSStyleSheet.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index c556ea1de6f8..224ffa91af08 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -351,12 +351,34 @@ nsDocumentRuleResultCacheKey::Finalize() #endif } +#ifdef DEBUG +static bool +ArrayIsSorted(const nsTArray& aRules) +{ + for (size_t i = 1; i < aRules.Length(); i++) { + if (aRules[i - 1] > aRules[i]) { + return false; + } + } + return true; +} +#endif + bool nsDocumentRuleResultCacheKey::Matches( nsPresContext* aPresContext, const nsTArray& aRules) const { MOZ_ASSERT(mFinalized); + MOZ_ASSERT(ArrayIsSorted(mMatchingRules)); + MOZ_ASSERT(ArrayIsSorted(aRules)); + +#ifdef DEBUG + for (css::DocumentRule* rule : mMatchingRules) { + MOZ_ASSERT(aRules.BinaryIndexOf(rule) != aRules.NoIndex, + "aRules must contain all rules in mMatchingRules"); + } +#endif // First check that aPresContext matches all the rules listed in // mMatchingRules. @@ -382,8 +404,6 @@ nsDocumentRuleResultCacheKey::Matches( while (pr < pr_end) { while (pm < pm_end && *pm < *pr) { ++pm; - MOZ_ASSERT(pm >= pm_end || *pm == *pr, - "shouldn't find rule in mMatchingRules that is not in aRules"); } if (pm >= pm_end || *pm != *pr) { if ((*pr)->UseForPresentation(aPresContext)) { From 96219d6d087bb7498ab7eb0bf0aff4afc9210723 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 13 Oct 2015 10:56:24 -0700 Subject: [PATCH 57/79] Bug 1214295 - Fix up entry points for ClickWithInputSource. r=bz --- dom/xul/nsXULElement.cpp | 16 +++++++--------- dom/xul/nsXULElement.h | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index c3bff9befd59..55c7f430ad80 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -687,7 +687,7 @@ nsXULElement::PerformAccesskey(bool aKeyCausesActivation, } if (aKeyCausesActivation && !content->IsAnyOfXULElements(nsGkAtoms::textbox, nsGkAtoms::menulist)) { - elm->ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD); + elm->ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD, aIsTrustedEvent); } } else { return content->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent); @@ -1726,17 +1726,17 @@ nsXULElement::Blur(ErrorResult& rv) NS_IMETHODIMP nsXULElement::Click() { - return ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN); + return ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN, /* aIsTrusted = */ true); } void nsXULElement::Click(ErrorResult& rv) { - rv = Click(); + rv = ClickWithInputSource(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN, nsContentUtils::IsCallerChrome()); } nsresult -nsXULElement::ClickWithInputSource(uint16_t aInputSource) +nsXULElement::ClickWithInputSource(uint16_t aInputSource, bool aIsTrustedEvent) { if (BoolAttrIsTrue(nsGkAtoms::disabled)) return NS_OK; @@ -1748,13 +1748,11 @@ nsXULElement::ClickWithInputSource(uint16_t aInputSource) // strong ref to PresContext so events don't destroy it nsRefPtr context = shell->GetPresContext(); - bool isCallerChrome = nsContentUtils::IsCallerChrome(); - - WidgetMouseEvent eventDown(isCallerChrome, eMouseDown, + WidgetMouseEvent eventDown(aIsTrustedEvent, eMouseDown, nullptr, WidgetMouseEvent::eReal); - WidgetMouseEvent eventUp(isCallerChrome, eMouseUp, + WidgetMouseEvent eventUp(aIsTrustedEvent, eMouseUp, nullptr, WidgetMouseEvent::eReal); - WidgetMouseEvent eventClick(isCallerChrome, eMouseClick, nullptr, + WidgetMouseEvent eventClick(aIsTrustedEvent, eMouseClick, nullptr, WidgetMouseEvent::eReal); eventDown.inputSource = eventUp.inputSource = eventClick.inputSource = aInputSource; diff --git a/dom/xul/nsXULElement.h b/dom/xul/nsXULElement.h index e3fc7b9a50da..ecc5bac281e2 100644 --- a/dom/xul/nsXULElement.h +++ b/dom/xul/nsXULElement.h @@ -401,7 +401,7 @@ public: virtual bool PerformAccesskey(bool aKeyCausesActivation, bool aIsTrustedEvent) override; - nsresult ClickWithInputSource(uint16_t aInputSource); + nsresult ClickWithInputSource(uint16_t aInputSource, bool aIsTrustedEvent); virtual nsIContent *GetBindingParent() const override; virtual bool IsNodeOfType(uint32_t aFlags) const override; From 9af046b5b476abe09fb65c270ac3c7cf3e652f4e Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 6 Oct 2015 12:13:33 +0900 Subject: [PATCH 58/79] Bug 1211765 - Remove remnants from --with-libxul-sdk. r=bsmedberg The configure option has explicitly thrown an error for more than a year now, and it happens that the remaining way to still forcefully use it has been broken for more than 8 months. --- Makefile.in | 4 -- b2g/app.mozbuild | 6 +-- b2g/app/Makefile.in | 10 ---- b2g/app/moz.build | 35 ++++++------ b2g/confvars.sh | 4 -- b2g/dev/app.mozbuild | 3 +- b2g/graphene/app.mozbuild | 5 +- b2g/locales/Makefile.in | 8 --- browser/app.mozbuild | 3 +- browser/app/Makefile.in | 12 ----- browser/app/moz.build | 8 --- browser/app/nsBrowserApp.cpp | 53 ++----------------- browser/installer/Makefile.in | 6 --- browser/installer/package-manifest.in | 5 -- build/Makefile.in | 4 -- build/autoconf/nspr-build.m4 | 13 ++--- config/config.mk | 6 --- config/external/nspr/Makefile.in | 3 -- config/makefiles/xpidl/Makefile.in | 4 -- config/rules.mk | 2 +- configure.in | 28 ++-------- mobile/android/app.mozbuild | 6 +-- mobile/android/b2gdroid/app.mozbuild | 6 +-- mobile/android/b2gdroid/confvars.sh | 4 -- mobile/android/confvars.sh | 4 -- mobile/android/locales/Makefile.in | 8 --- mobile/android/moz.build | 3 +- moz.build | 19 ++++--- .../mozbuild/mozbuild/backend/fastermake.py | 4 +- toolkit/mozapps/installer/packager.mk | 2 - toolkit/mozapps/installer/packager.py | 6 +-- toolkit/mozapps/installer/upload-files.mk | 2 - toolkit/toolkit.mozbuild | 3 -- xpcom/xpidl/Makefile.in | 2 - 34 files changed, 48 insertions(+), 243 deletions(-) diff --git a/Makefile.in b/Makefile.in index 9360b1978117..95395677181d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -39,13 +39,11 @@ ifndef MOZ_PROFILE_USE # otherwise the rule in rules.mk doesn't run early enough. $(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend ifndef JS_STANDALONE -ifndef LIBXUL_SDK ifdef COMPILE_ENVIRONMENT $(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status endif endif endif -endif ifdef JS_STANDALONE .PHONY: CLOBBER @@ -106,7 +104,6 @@ install_manifest_depends = \ $(NULL) ifndef JS_STANDALONE -ifndef LIBXUL_SDK ifdef COMPILE_ENVIRONMENT install_manifest_depends += \ $(topsrcdir)/js/src/configure \ @@ -114,7 +111,6 @@ install_manifest_depends += \ $(NULL) endif endif -endif .PHONY: install-manifests install-manifests: $(addprefix install-,$(install_manifests)) diff --git a/b2g/app.mozbuild b/b2g/app.mozbuild index 65f046ef728f..4587438d5f5b 100644 --- a/b2g/app.mozbuild +++ b/b2g/app.mozbuild @@ -3,10 +3,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') -elif CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/mochitest'] + +include('/toolkit/toolkit.mozbuild') if CONFIG['MOZ_EXTENSIONS']: DIRS += ['/extensions'] diff --git a/b2g/app/Makefile.in b/b2g/app/Makefile.in index 12068016e5bb..92d1e05a1918 100644 --- a/b2g/app/Makefile.in +++ b/b2g/app/Makefile.in @@ -52,24 +52,14 @@ tools repackage:: $(libs-preqs) sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/$(LPROJ)/InfoPlist.strings rsync -a --exclude 'mangle' --exclude 'shlibsign' --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/Resources rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/MacOS -ifdef LIBXUL_SDK - cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY) - rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks -else $(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM) rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS -endif cp -RL $(DIST)/branding/app.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns printf APPLMOZB > $(DIST)/$(APP_NAME).app/Contents/PkgInfo else # MOZ_WIDGET_TOOLKIT != cocoa libs:: -ifdef LIBXUL_SDK - cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY) - $(NSINSTALL) -D $(DIST)/bin/xulrunner - (cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -) -endif $(NSINSTALL) -D $(DIST)/bin/chrome/icons/default # Copy the app icon for b2g-desktop diff --git a/b2g/app/moz.build b/b2g/app/moz.build index 8222635fd0b5..8e9815e4146b 100644 --- a/b2g/app/moz.build +++ b/b2g/app/moz.build @@ -4,27 +4,26 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - if CONFIG['GAIADIR']: - GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin") - else: - GeckoProgram(CONFIG['MOZ_APP_NAME']) - if CONFIG['MOZ_B2G_LOADER']: - SOURCES += [ - 'B2GLoader.cpp', - ] - +if CONFIG['GAIADIR']: + GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin") +else: + GeckoProgram(CONFIG['MOZ_APP_NAME']) +if CONFIG['MOZ_B2G_LOADER']: SOURCES += [ - 'nsBrowserApp.cpp', + 'B2GLoader.cpp', ] - if CONFIG['_MSC_VER']: - # Always enter a Windows program through wmain, whether or not we're - # a console application. - WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] - USE_LIBS += [ - 'zlib', - ] +SOURCES += [ + 'nsBrowserApp.cpp', +] +if CONFIG['_MSC_VER']: + # Always enter a Windows program through wmain, whether or not we're + # a console application. + WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] + +USE_LIBS += [ + 'zlib', +] for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'): DEFINES[var] = CONFIG[var] diff --git a/b2g/confvars.sh b/b2g/confvars.sh index 5631d223a777..07b12e326560 100644 --- a/b2g/confvars.sh +++ b/b2g/confvars.sh @@ -44,11 +44,7 @@ fi # use custom widget for html:select MOZ_USE_NATIVE_POPUP_WINDOWS=1 -if test "$LIBXUL_SDK"; then -MOZ_XULRUNNER=1 -else MOZ_XULRUNNER= -fi MOZ_MEDIA_NAVIGATOR=1 diff --git a/b2g/dev/app.mozbuild b/b2g/dev/app.mozbuild index ff4990a88adf..cf3d74824c99 100644 --- a/b2g/dev/app.mozbuild +++ b/b2g/dev/app.mozbuild @@ -3,8 +3,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') +include('/toolkit/toolkit.mozbuild') if CONFIG['MOZ_EXTENSIONS']: DIRS += ['/extensions'] diff --git a/b2g/graphene/app.mozbuild b/b2g/graphene/app.mozbuild index b891cac42a42..0985b613c73d 100644 --- a/b2g/graphene/app.mozbuild +++ b/b2g/graphene/app.mozbuild @@ -3,10 +3,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') -elif CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/mochitest'] +include('/toolkit/toolkit.mozbuild') if CONFIG['MOZ_EXTENSIONS']: DIRS += ['/extensions'] diff --git a/b2g/locales/Makefile.in b/b2g/locales/Makefile.in index 2381053bb4af..dd8df0382805 100644 --- a/b2g/locales/Makefile.in +++ b/b2g/locales/Makefile.in @@ -117,18 +117,10 @@ installers-%: clobber-% langpack-% repackage-win32-installer-% repackage-zip-% # When we unpack b2g on MacOS X the platform.ini and application.ini are in slightly # different locations that on all other platforms ifeq (Darwin, $(OS_ARCH)) -ifdef LIBXUL_SDK -GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/../Frameworks/XUL.framework/Versions/$(MOZILLA_VERSION)/platform.ini' -else GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini' -endif B2G_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini' else -ifdef LIBXUL_SDK -GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/xulrunner/platform.ini' -else GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini' -endif B2G_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini' endif diff --git a/browser/app.mozbuild b/browser/app.mozbuild index d7c1b0f8298b..ceef37f7dd72 100644 --- a/browser/app.mozbuild +++ b/browser/app.mozbuild @@ -3,8 +3,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') +include('/toolkit/toolkit.mozbuild') if CONFIG['MOZ_EXTENSIONS']: DIRS += ['/extensions'] diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in index a4f2b048b0c7..d9d0b432f042 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in @@ -62,12 +62,10 @@ libs:: $(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png $(FINAL_TARGET)/chrome/icons/default endif -ifndef LIBXUL_SDK # channel-prefs.js is handled separate from other prefs due to bug 756325 libs:: $(srcdir)/profile/channel-prefs.js $(NSINSTALL) -D $(DIST)/bin/defaults/pref $(call py_action,preprocessor,-Fsubstitution $(PREF_PPFLAGS) $(ACDEFINES) $^ -o $(DIST)/bin/defaults/pref/channel-prefs.js) -endif ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) @@ -107,13 +105,3 @@ tools repackage:: $(PROGRAM) cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns printf APPLMOZB > $(dist_dest)/Contents/PkgInfo endif - -ifdef LIBXUL_SDK #{ -libs:: -ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{ - rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(dist_dest)/Contents/Frameworks -else - $(NSINSTALL) -D $(DIST)/bin/xulrunner - (cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -) -endif #} cocoa -endif #} LIBXUL_SDK diff --git a/browser/app/moz.build b/browser/app/moz.build index 2ed385809717..be76aa2ed278 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -15,11 +15,6 @@ JS_PREFERENCE_FILES += [ 'profile/firefox.js', ] -if CONFIG['LIBXUL_SDK']: - PREF_JS_EXPORTS += [ - 'profile/channel-prefs.js', - ] - SOURCES += [ 'nsBrowserApp.cpp', ] @@ -29,9 +24,6 @@ FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js'] DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -if CONFIG['LIBXUL_SDK']: - DEFINES['LIBXUL_SDK'] = True - GENERATED_INCLUDES += [ '/build', ] diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index b6753d30f62c..fc65ce5201ac 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -225,11 +225,6 @@ FileExists(const char *path) #endif } -#ifdef LIBXUL_SDK -# define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL -#else -# define XPCOM_PATH XPCOM_DLL -#endif static nsresult InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) { @@ -242,55 +237,13 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) } char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); - if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1)) + if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - +sizeof(XPCOM_DLL) - 1)) return NS_ERROR_FAILURE; - strcpy(lastSlash + 1, XPCOM_PATH); - lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL); + strcpy(lastSlash + 1, XPCOM_DLL); if (!FileExists(exePath)) { -#if defined(LIBXUL_SDK) && defined(XP_MACOSX) - // Check for /Contents/Frameworks/XUL.framework/libxpcom.dylib - bool greFound = false; - CFBundleRef appBundle = CFBundleGetMainBundle(); - if (!appBundle) - return NS_ERROR_FAILURE; - CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle); - CFURLRef absfwurl = nullptr; - if (fwurl) { - absfwurl = CFURLCopyAbsoluteURL(fwurl); - CFRelease(fwurl); - } - if (absfwurl) { - CFURLRef xulurl = - CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl, - CFSTR("XUL.framework"), - true); - - if (xulurl) { - CFURLRef xpcomurl = - CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, - CFSTR("libxpcom.dylib"), - false); - - if (xpcomurl) { - if (CFURLGetFileSystemRepresentation(xpcomurl, true, - (UInt8*) exePath, - sizeof(exePath)) && - access(tbuffer, R_OK | X_OK) == 0) { - if (realpath(tbuffer, exePath)) { - greFound = true; - } - } - CFRelease(xpcomurl); - } - CFRelease(xulurl); - } - CFRelease(absfwurl); - } - } - if (!greFound) { -#endif Output("Could not find the Mozilla runtime.\n"); return NS_ERROR_FAILURE; } diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in index 568186abe158..691b5dcf528e 100644 --- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -20,10 +20,6 @@ endif DEFINES += -DMOZ_APP_NAME=$(MOZ_APP_NAME) -DPREF_DIR=$(PREF_DIR) -ifdef LIBXUL_SDK -DEFINES += -DLIBXUL_SDK=1 -endif - ifdef MOZ_DEBUG DEFINES += -DMOZ_DEBUG=1 endif @@ -103,9 +99,7 @@ MOZ_PKG_MAC_ICON=branding/disk.icns MOZ_PKG_MAC_EXTRA=--symlink '/Applications:/ ' endif -ifndef LIBXUL_SDK INSTALL_SDK = 1 -endif include $(topsrcdir)/toolkit/mozapps/installer/signing.mk include $(topsrcdir)/toolkit/mozapps/installer/packager.mk diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index f68595c74a95..83381b4dc9a8 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -709,15 +709,10 @@ @RESPATH@/defaults/autoconfig/prefcalls.js @RESPATH@/browser/defaults/profile/prefs.js -#ifndef LIBXUL_SDK ; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325) ; Technically this is an app pref file, but we are keeping it in the original ; gre location for now. @RESPATH@/defaults/pref/channel-prefs.js -#else -; For Fx-on-xr, channel-prefs lives with the app preferences. (Bug 762588) -@RESPATH@/@PREF_DIR@/channel-prefs.js -#endif ; Services (gre) prefs #ifdef MOZ_SERVICES_NOTIFICATIONS diff --git a/build/Makefile.in b/build/Makefile.in index 86d09ee9b6cc..2d82093b882b 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -7,11 +7,7 @@ USE_RCS_MK := 1 include $(topsrcdir)/config/makefiles/makeutils.mk ifdef MOZ_APP_BASENAME -ifdef LIBXUL_SDK -APP_INI_DEPS = $(LIBXUL_DIST)/bin/platform.ini -else APP_INI_DEPS = $(topsrcdir)/config/milestone.txt -endif MOZ_APP_BUILDID := $(shell cat $(DEPTH)/config/buildid) APP_INI_DEPS += $(DEPTH)/config/buildid diff --git a/build/autoconf/nspr-build.m4 b/build/autoconf/nspr-build.m4 index 4a6f09dd796d..c097f90043bc 100644 --- a/build/autoconf/nspr-build.m4 +++ b/build/autoconf/nspr-build.m4 @@ -157,16 +157,11 @@ if test -n "$MOZ_NATIVE_NSPR" -o -n "$NSPR_CFLAGS" -o -n "$NSPR_LIBS"; then AC_MSG_ERROR([system NSPR does not support PR_UINT64 or including prtypes.h does not provide it])) CFLAGS=$_SAVE_CFLAGS elif test -z "$JS_POSIX_NSPR"; then - if test -z "$LIBXUL_SDK"; then - NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr" - if test -n "$GNU_CC"; then - NSPR_LIBS="-L${LIBXUL_DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}" - else - NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib " - fi + NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr" + if test -n "$GNU_CC"; then + NSPR_LIBS="-L${LIBXUL_DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}" else - NSPR_CFLAGS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --includedir="${LIBXUL_DIST}/include/nspr" --cflags` - NSPR_LIBS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --libdir="${LIBXUL_DIST}"/lib --libs` + NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib " fi fi diff --git a/config/config.mk b/config/config.mk index 0920bf37e02f..f5d79a2acc23 100644 --- a/config/config.mk +++ b/config/config.mk @@ -301,7 +301,6 @@ ifndef IS_GYP_DIR # NSPR_CFLAGS and NSS_CFLAGS must appear ahead of the other flags to avoid Linux # builds wrongly picking up system NSPR/NSS header files. OS_INCLUDES := \ - $(if $(LIBXUL_SDK),-I$(LIBXUL_SDK)/include) \ $(NSPR_CFLAGS) $(NSS_CFLAGS) \ $(MOZ_JPEG_CFLAGS) \ $(MOZ_PNG_CFLAGS) \ @@ -432,13 +431,8 @@ HOST_CXXFLAGS += $(HOST_DEFINES) $(MOZBUILD_HOST_CXXFLAGS) # Override defaults # Default location of include files -ifndef LIBXUL_SDK IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser IDL_PARSER_CACHE_DIR = $(DEPTH)/xpcom/idl-parser -else -IDL_PARSER_DIR = $(LIBXUL_SDK)/sdk/bin -IDL_PARSER_CACHE_DIR = $(LIBXUL_SDK)/sdk/bin -endif SDK_LIB_DIR = $(DIST)/sdk/lib SDK_BIN_DIR = $(DIST)/sdk/bin diff --git a/config/external/nspr/Makefile.in b/config/external/nspr/Makefile.in index e945065600c6..c4349f35b6ea 100644 --- a/config/external/nspr/Makefile.in +++ b/config/external/nspr/Makefile.in @@ -5,9 +5,6 @@ include $(topsrcdir)/config/rules.mk -ifdef LIBXUL_SDK -$(error config/external/nspr/Makefile.in is not compatible with --enable-libxul-sdk=) -endif ifdef MOZ_BUILD_NSPR # Copy NSPR to the SDK diff --git a/config/makefiles/xpidl/Makefile.in b/config/makefiles/xpidl/Makefile.in index a952fdfd210c..1375e0bd5f76 100644 --- a/config/makefiles/xpidl/Makefile.in +++ b/config/makefiles/xpidl/Makefile.in @@ -30,10 +30,6 @@ dist_idl_dir := $(DIST)/idl dist_include_dir := $(DIST)/include process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py -ifdef LIBXUL_SDK -libxul_sdk_includes := -I$(LIBXUL_SDK)/idl -endif - # TODO we should use py_action, but that would require extra directories to be # in the virtualenv. %.xpt: diff --git a/config/rules.mk b/config/rules.mk index 844787c9be27..63a0b62453c3 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1148,7 +1148,7 @@ PREF_DIR = defaults/pref # If DIST_SUBDIR is defined it indicates that app and gre dirs are # different and that we are building app related resources. Hence, # PREF_DIR should point to the app prefs location. -ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXUL_SDK)) +ifneq (,$(DIST_SUBDIR)$(XPI_NAME)) PREF_DIR = defaults/preferences endif diff --git a/configure.in b/configure.in index 6ecdc119e6f2..a10cadd10b59 100644 --- a/configure.in +++ b/configure.in @@ -3344,11 +3344,7 @@ MOZ_CONFIG_NSPR() dnl set GRE_MILESTONE dnl ======================================================== -if test -n "$LIBXUL_SDK"; then - GRE_MILESTONE=`$PYTHON "$_topsrcdir"/config/printconfigsetting.py "$LIBXUL_DIST"/bin/platform.ini Build Milestone` -else - GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt` -fi +GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt` AC_SUBST(GRE_MILESTONE) # set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in @@ -3989,15 +3985,6 @@ if test -n "$WITH_APP_BASENAME" ; then MOZ_APP_BASENAME="$WITH_APP_BASENAME" fi -# Now is a good time to test for logic errors, define mismatches, etc. -case "$MOZ_BUILD_APP" in -xulrunner) - if test "$LIBXUL_SDK"; then - AC_MSG_ERROR([Building XULRunner --with-libxul-sdk doesn't make sense; XULRunner provides the libxul SDK.]) - fi - ;; -esac - # Special cases where we need to AC_DEFINE something. Also a holdover for apps # that haven't made a confvars.sh yet. Don't add new stuff here, use # MOZ_BUILD_APP. @@ -6276,11 +6263,6 @@ if test -z "$MOZ_ENABLE_GIO" -a `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; th MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'` fi -dnl Do not build gio with libxul based apps -if test -n "$LIBXUL_SDK_DIR" -a `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then - MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'` -fi - if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then MOZ_GIO_COMPONENT=1 MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'` @@ -9139,8 +9121,7 @@ AC_SUBST(JS_SHARED_LIBRARY) MOZ_CREATE_CONFIG_STATUS() -# No need to run subconfigures when building with LIBXUL_SDK_DIR -if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then +if test "$COMPILE_ENVIRONMENT"; then MOZ_SUBCONFIGURE_ICU() MOZ_SUBCONFIGURE_FFI() MOZ_SUBCONFIGURE_JEMALLOC() @@ -9208,8 +9189,7 @@ if test -n "$_subconfigure_subdir"; then srcdir="$_save_srcdir" fi -# No need to run subconfigures when building with LIBXUL_SDK_DIR -if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then +if test "$COMPILE_ENVIRONMENT"; then export WRAP_LDFLAGS @@ -9288,7 +9268,7 @@ fi AC_OUTPUT_SUBDIRS(js/src,$cache_file) ac_configure_args="$_SUBDIR_CONFIG_ARGS" -fi # COMPILE_ENVIRONMENT && !LIBXUL_SDK_DIR +fi # COMPILE_ENVIRONMENT export WRITE_MOZINFO=1 dnl we need to run config.status after js/src subconfigure because we're diff --git a/mobile/android/app.mozbuild b/mobile/android/app.mozbuild index f19efa891d7f..b29d15c0774d 100644 --- a/mobile/android/app.mozbuild +++ b/mobile/android/app.mozbuild @@ -3,11 +3,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') - -elif CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/mochitest'] +include('/toolkit/toolkit.mozbuild') if CONFIG['ENABLE_TESTS']: DIRS += ['/testing/instrumentation'] diff --git a/mobile/android/b2gdroid/app.mozbuild b/mobile/android/b2gdroid/app.mozbuild index 01554b03f1b9..12d933bda00b 100644 --- a/mobile/android/b2gdroid/app.mozbuild +++ b/mobile/android/b2gdroid/app.mozbuild @@ -3,11 +3,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not CONFIG['LIBXUL_SDK']: - include('/toolkit/toolkit.mozbuild') - -elif CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/mochitest'] +include('/toolkit/toolkit.mozbuild') if CONFIG['ENABLE_TESTS']: DIRS += ['/testing/instrumentation'] diff --git a/mobile/android/b2gdroid/confvars.sh b/mobile/android/b2gdroid/confvars.sh index a2f0e733726e..6482c7af546b 100644 --- a/mobile/android/b2gdroid/confvars.sh +++ b/mobile/android/b2gdroid/confvars.sh @@ -40,11 +40,7 @@ MOZ_MEDIA_NAVIGATOR=1 # Enable NFC permission MOZ_ANDROID_BEAM=1 -if test "$LIBXUL_SDK"; then -MOZ_XULRUNNER=1 -else MOZ_XULRUNNER= -fi MOZ_CAPTURE=1 MOZ_RAW=1 diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index 6d2f124c9d8c..477c158a30c0 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -33,11 +33,7 @@ MOZ_MEDIA_NAVIGATOR=1 # Enable NFC permission MOZ_ANDROID_BEAM=1 -if test "$LIBXUL_SDK"; then -MOZ_XULRUNNER=1 -else MOZ_XULRUNNER= -fi MOZ_CAPTURE=1 MOZ_RAW=1 diff --git a/mobile/android/locales/Makefile.in b/mobile/android/locales/Makefile.in index bcd7c783d3da..ebd054dbdd51 100644 --- a/mobile/android/locales/Makefile.in +++ b/mobile/android/locales/Makefile.in @@ -64,18 +64,10 @@ installers-%: clobber-stage repackage-zip-% # When we unpack fennec on MacOS X the platform.ini and application.ini are in slightly # different locations that on all other platforms ifeq (Darwin, $(OS_ARCH)) -ifdef LIBXUL_SDK -GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/../Frameworks/XUL.framework/Versions/$(MOZILLA_VERSION)/platform.ini' -else GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini' -endif FENNEC_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini' else -ifdef LIBXUL_SDK -GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/xulrunner/platform.ini' -else GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini' -endif FENNEC_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini' endif diff --git a/mobile/android/moz.build b/mobile/android/moz.build index 3ed21211310b..10317b1906ab 100644 --- a/mobile/android/moz.build +++ b/mobile/android/moz.build @@ -27,8 +27,7 @@ DIRS += [ 'extensions', ] -if not CONFIG['LIBXUL_SDK']: - DIRS += ['../../xulrunner/tools/redit'] +DIRS += ['../../xulrunner/tools/redit'] TEST_DIRS += [ 'tests', diff --git a/moz.build b/moz.build index 983d3afa5369..485ef5f5d512 100644 --- a/moz.build +++ b/moz.build @@ -32,21 +32,20 @@ if not CONFIG['JS_STANDALONE']: 'probes', ] -if not CONFIG['LIBXUL_SDK']: - DIRS += [ - 'config/external/zlib', - 'memory', - 'mfbt', - 'mozglue', - ] +DIRS += [ + 'config/external/zlib', + 'memory', + 'mfbt', + 'mozglue', +] - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android' and int(CONFIG['MOZ_ANDROID_MIN_SDK_VERSION']) < 11: - DIRS += ['other-licenses/android'] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android' and int(CONFIG['MOZ_ANDROID_MIN_SDK_VERSION']) < 11: + DIRS += ['other-licenses/android'] if not CONFIG['JS_STANDALONE']: DIRS += ['xpcom/xpidl'] -if CONFIG['COMPILE_ENVIRONMENT'] and not CONFIG['LIBXUL_SDK']: +if CONFIG['COMPILE_ENVIRONMENT']: DIRS += ['config/external/nspr'] if not CONFIG['JS_STANDALONE']: diff --git a/python/mozbuild/mozbuild/backend/fastermake.py b/python/mozbuild/mozbuild/backend/fastermake.py index 0cc3b7ab5757..50f41b7bc015 100644 --- a/python/mozbuild/mozbuild/backend/fastermake.py +++ b/python/mozbuild/mozbuild/backend/fastermake.py @@ -127,9 +127,7 @@ class FasterMakeBackend(CommonBackend): elif isinstance(obj, JsPreferenceFile) and \ obj.install_target.startswith('dist/bin'): # The condition for the directory value in config/rules.mk is: - # ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXUL_SDK)) - # - LIBXUL_SDK is not supported (it likely doesn't work in the - # recursive backend anyways + # ifneq (,$(DIST_SUBDIR)$(XPI_NAME)) # - when XPI_NAME is set, obj.install_target will start with # dist/xpi-stage # - when DIST_SUBDIR is set, obj.install_target will start with diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 1e80689706e4..465d6f76a2d7 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -58,14 +58,12 @@ stage-package: $(MOZ_PKG_MANIFEST) $(MOZ_PKG_MANIFEST_DEPS) $(call py_action,test_archive, \ mozharness \ $(abspath $(DIST))/$(PKG_PATH)$(MOZHARNESS_PACKAGE)) -ifndef LIBXUL_SDK ifdef MOZ_PACKAGE_JSSHELL # Package JavaScript Shell @echo 'Packaging JavaScript Shell...' $(RM) $(PKG_JSSHELL) $(MAKE_JSSHELL) endif # MOZ_PACKAGE_JSSHELL -endif # LIBXUL_SDK ifdef MOZ_CODE_COVERAGE # Package code coverage gcno tree @echo 'Packaging code coverage data...' diff --git a/toolkit/mozapps/installer/packager.py b/toolkit/mozapps/installer/packager.py index dc48e5e7b98d..7555e397189b 100644 --- a/toolkit/mozapps/installer/packager.py +++ b/toolkit/mozapps/installer/packager.py @@ -381,11 +381,7 @@ def main(): # Fill startup cache if isinstance(formatter, OmniJarFormatter) and launcher.can_launch() \ and buildconfig.substs['MOZ_DISABLE_STARTUPCACHE'] != '1': - if buildconfig.substs.get('LIBXUL_SDK'): - gre_path = mozpath.join(buildconfig.substs['LIBXUL_DIST'], - 'bin') - else: - gre_path = None + gre_path = None def get_bases(): for b in sink.packager.get_bases(addons=False): for p in (mozpath.join('bin', b), b): diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 822161112a79..9a08171a3b82 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -64,7 +64,6 @@ SDK = $(SDK_PATH)$(PKG_BASENAME)-$(TARGET_CPU).sdk$(SDK_SUFFIX) endif # JavaScript Shell packaging -ifndef LIBXUL_SDK JSSHELL_BINS = \ js$(BIN_SUFFIX) \ $(DLL_PREFIX)mozglue$(DLL_SUFFIX) \ @@ -116,7 +115,6 @@ endif # Darwin endif # WINNT endif # MOZ_STATIC_JS MAKE_JSSHELL = $(call py_action,zip,-C $(DIST)/bin $(abspath $(PKG_JSSHELL)) $(JSSHELL_BINS)) -endif # LIBXUL_SDK _ABS_DIST = $(abspath $(DIST)) JARLOG_DIR = $(abspath $(DEPTH)/jarlog/) diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index 74311a2470da..494c8c4ae89c 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -3,9 +3,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -if CONFIG['LIBXUL_SDK']: - error('toolkit.mozbuild is not compatible with --enable-libxul-sdk=') - if CONFIG['MOZ_SANDBOX']: DIRS += ['/security/sandbox'] diff --git a/xpcom/xpidl/Makefile.in b/xpcom/xpidl/Makefile.in index ec43f7c27dcc..917d6c8cb411 100644 --- a/xpcom/xpidl/Makefile.in +++ b/xpcom/xpidl/Makefile.in @@ -3,9 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. export:: -ifndef LIBXUL_SDK $(call SUBMAKE,xpidl-parser,$(DEPTH)/xpcom/idl-parser/xpidl) -endif $(call py_action,process_install_manifest,$(DIST)/idl $(DEPTH)/_build_manifests/install/dist_idl) $(call SUBMAKE,xpidl,$(DEPTH)/config/makefiles/xpidl) From 544e62ef89c5f38726f15e8daf6977868ed0159d Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Wed, 14 Oct 2015 12:18:06 +1300 Subject: [PATCH 59/79] Bug 121442 - Add platform to GMP storage base dir. r=gerald --- dom/media/gmp/GMPChild.cpp | 7 -- dom/media/gmp/GMPServiceParent.cpp | 118 +++++++++++++++++++++++++++++ dom/media/gmp/GMPUtils.cpp | 7 ++ dom/media/gmp/GMPUtils.h | 3 + 4 files changed, 128 insertions(+), 7 deletions(-) diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp index f01cd8f41963..8226396b2bf5 100644 --- a/dom/media/gmp/GMPChild.cpp +++ b/dom/media/gmp/GMPChild.cpp @@ -49,13 +49,6 @@ extern PRLogModuleInfo* GetGMPLog(); namespace gmp { -static bool -FileExists(nsIFile* aFile) -{ - bool exists = false; - return aFile && NS_SUCCEEDED(aFile->Exists(&exists)) && exists; -} - GMPChild::GMPChild() : mAsyncShutdown(nullptr) , mGMPMessageLoop(MessageLoop::current()) diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 4a1abe974abe..68c354199a4c 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -41,6 +41,7 @@ #include "nsExceptionHandler.h" #include "nsPrintfCString.h" #endif +#include "nsIXULRuntime.h" #include namespace mozilla { @@ -148,6 +149,96 @@ GeckoMediaPluginServiceParent::Init() return GetThread(getter_AddRefs(thread)); } +already_AddRefed +CloneAndAppend(nsIFile* aFile, const nsAString& aDir) +{ + nsCOMPtr f; + nsresult rv = aFile->Clone(getter_AddRefs(f)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + rv = f->Append(aDir); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + return f.forget(); +} + +static void +MoveAndOverwrite(nsIFile* aOldStorageDir, + nsIFile* aNewStorageDir, + const nsAString& aSubDir) +{ + nsresult rv; + + nsCOMPtr srcDir(CloneAndAppend(aOldStorageDir, aSubDir)); + if (NS_WARN_IF(!srcDir)) { + return; + } + + if (!FileExists(srcDir)) { + // No sub-directory to be migrated. + return; + } + + nsCOMPtr dstDir(CloneAndAppend(aNewStorageDir, aSubDir)); + if (FileExists(dstDir)) { + // We must have migrated before already, and then ran an old version + // of Gecko again which created storage at the old location. Overwrite + // the previously migrated storage. + rv = dstDir->Remove(true); + if (NS_WARN_IF(NS_FAILED(rv))) { + // MoveTo will fail. + return; + } + } + + rv = srcDir->MoveTo(aNewStorageDir, EmptyString()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } +} + +static void +MigratePreGecko42StorageDir(nsIFile* aOldStorageDir, + nsIFile* aNewStorageDir) +{ + MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("id")); + MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("storage")); +} + +static nsresult +GMPPlatformString(nsAString& aOutPlatform) +{ + // Append the OS and arch so that we don't reuse the storage if the profile is + // copied or used under a different bit-ness, or copied to another platform. + nsCOMPtr runtime = do_GetService("@mozilla.org/xre/runtime;1"); + if (!runtime) { + return NS_ERROR_FAILURE; + } + + nsAutoCString OS; + nsresult rv = runtime->GetOS(OS); + if (NS_FAILED(rv)) { + return rv; + } + + nsAutoCString arch; + rv = runtime->GetXPCOMABI(arch); + if (NS_FAILED(rv)) { + return rv; + } + + nsCString platform; + platform.Append(OS); + platform.AppendLiteral("_"); + platform.Append(arch); + + aOutPlatform = NS_ConvertUTF8toUTF16(platform); + + return NS_OK; +} nsresult GeckoMediaPluginServiceParent::InitStorage() @@ -181,6 +272,33 @@ GeckoMediaPluginServiceParent::InitStorage() return rv; } + nsCOMPtr gmpDirWithoutPlatform; + rv = mStorageBaseDir->Clone(getter_AddRefs(gmpDirWithoutPlatform)); + if (NS_FAILED(rv)) { + return rv; + } + + nsAutoString platform; + rv = GMPPlatformString(platform); + if (NS_FAILED(rv)) { + return rv; + } + + rv = mStorageBaseDir->Append(platform); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = mStorageBaseDir->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) { + return rv; + } + + // Prior to 42, GMP storage was stored in $profile/gmp/. After 42, it's + // stored in $profile/gmp/$platform/. So we must migrate any old records + // from the old location to the new location, for forwards compatibility. + MigratePreGecko42StorageDir(gmpDirWithoutPlatform, mStorageBaseDir); + return GeckoMediaPluginService::Init(); } diff --git a/dom/media/gmp/GMPUtils.cpp b/dom/media/gmp/GMPUtils.cpp index 44732d05076f..ec503a65b92d 100644 --- a/dom/media/gmp/GMPUtils.cpp +++ b/dom/media/gmp/GMPUtils.cpp @@ -64,4 +64,11 @@ ToBase64(const nsTArray& aBytes) return base64; } +bool +FileExists(nsIFile* aFile) +{ + bool exists = false; + return aFile && NS_SUCCEEDED(aFile->Exists(&exists)) && exists; +} + } // namespace mozilla diff --git a/dom/media/gmp/GMPUtils.h b/dom/media/gmp/GMPUtils.h index 8d688325dcab..d9071b5e4d36 100644 --- a/dom/media/gmp/GMPUtils.h +++ b/dom/media/gmp/GMPUtils.h @@ -43,6 +43,9 @@ enum GMPCrashReason { kInvalid, }; +bool +FileExists(nsIFile* aFile); + } // namespace mozilla #endif From 2fa470c47b85ba150ee9c09e1e369aca0a077a8d Mon Sep 17 00:00:00 2001 From: James Graham Date: Wed, 14 Oct 2015 00:35:55 +0100 Subject: [PATCH 60/79] Bug 1202663,1213797 - Add missing wpt metadata update for marionette screenshot changes, a=testonly --- .../meta/html/editing/the-hidden-attribute/hidden-2.svg.ini | 3 --- .../text-level-semantics/the-bdo-element/bdo-override.html.ini | 3 +++ .../text-level-semantics/the-br-element/br-bidi.html.ini | 3 +++ .../untriaged/shadow-trees/text-decoration-001.html.ini | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) delete mode 100644 testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-2.svg.ini create mode 100644 testing/web-platform/meta/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini create mode 100644 testing/web-platform/meta/html/semantics/text-level-semantics/the-br-element/br-bidi.html.ini create mode 100644 testing/web-platform/meta/shadow-dom/untriaged/shadow-trees/text-decoration-001.html.ini diff --git a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-2.svg.ini b/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-2.svg.ini deleted file mode 100644 index 2b2fe4564d50..000000000000 --- a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-2.svg.ini +++ /dev/null @@ -1,3 +0,0 @@ -[hidden-2.svg] - type: reftest - expected: TIMEOUT diff --git a/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini b/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini new file mode 100644 index 000000000000..1093b89f0c64 --- /dev/null +++ b/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini @@ -0,0 +1,3 @@ +[bdo-override.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/text-level-semantics/the-br-element/br-bidi.html.ini b/testing/web-platform/meta/html/semantics/text-level-semantics/the-br-element/br-bidi.html.ini new file mode 100644 index 000000000000..795c8f230b6a --- /dev/null +++ b/testing/web-platform/meta/html/semantics/text-level-semantics/the-br-element/br-bidi.html.ini @@ -0,0 +1,3 @@ +[br-bidi.html] + type: reftest + expected: FAIL diff --git a/testing/web-platform/meta/shadow-dom/untriaged/shadow-trees/text-decoration-001.html.ini b/testing/web-platform/meta/shadow-dom/untriaged/shadow-trees/text-decoration-001.html.ini new file mode 100644 index 000000000000..3be2dc1fbb1f --- /dev/null +++ b/testing/web-platform/meta/shadow-dom/untriaged/shadow-trees/text-decoration-001.html.ini @@ -0,0 +1,3 @@ +[text-decoration-001.html] + type: reftest + expected: FAIL From ac5a8fd81960bb12892b9eb5665850c0dd96e397 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 Oct 2015 16:45:40 -0700 Subject: [PATCH 61/79] Block some Radeon drivers that crash on D3D9. (bug 1213107, r=jrmuizel) --- widget/windows/GfxInfo.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 5e2366b2c9f3..7c520d094a0f 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -1086,6 +1086,16 @@ GfxInfo::GetGfxDriverInfo() nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_EQUAL, V(15,200,1006,0)); + /* Bug 1213107: D3D9 crashes with ATI cards on Windows 7. */ + APPEND_TO_DRIVER_BLOCKLIST_RANGE(DRIVER_OS_WINDOWS_7, + (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BETWEEN_INCLUSIVE, V(8,861,0,0), V(8,862,6,5000), "Radeon driver > 8.862.6.5000"); + APPEND_TO_DRIVER_BLOCKLIST_RANGE(DRIVER_OS_WINDOWS_7, + (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_ANGLE, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BETWEEN_INCLUSIVE, V(8,861,0,0), V(8,862,6,5000), "Radeon driver > 8.862.6.5000"); + APPEND_TO_DRIVER_BLOCKLIST2(DRIVER_OS_WINDOWS_7, (nsAString&)GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(Bug1155608), nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, From 1bfe7be8a103d95a0dcbbdd1492fc4244f2ba5b2 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 13 Oct 2015 14:40:26 -0400 Subject: [PATCH 62/79] Bug 1207288. Enable the ANGLE shader validator for WebGL 2. r=jgilbert ANGLE's shader parser has much better support for ES3 now. Let's no longer disable it by default. --HG-- extra : rebase_source : 1292347863eb3ea960d9a8f470bbceb6601d0ce1 --- dom/canvas/WebGL2Context.cpp | 2 -- dom/canvas/WebGLShaderValidator.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dom/canvas/WebGL2Context.cpp b/dom/canvas/WebGL2Context.cpp index 0a0b0edf34a5..346d7a096ed0 100644 --- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -180,8 +180,6 @@ WebGLContext::InitWebGL2() mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0); mBoundTransformFeedback = mDefaultTransformFeedback; - mBypassShaderValidation = true; - return true; } diff --git a/dom/canvas/WebGLShaderValidator.cpp b/dom/canvas/WebGLShaderValidator.cpp index 5553ad8f72ec..9933026ea1e8 100644 --- a/dom/canvas/WebGLShaderValidator.cpp +++ b/dom/canvas/WebGLShaderValidator.cpp @@ -99,7 +99,7 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const if (mBypassShaderValidation) return nullptr; - ShShaderSpec spec = SH_WEBGL_SPEC; + ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC; ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; From 56c94bef12d5fd40053faf1e1cdb994e4456c4b7 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 13 Oct 2015 17:00:55 -0700 Subject: [PATCH 63/79] Bug 1165558 - Return valid dispositions even if there wasn't a header. r=bz --- browser/extensions/pdfjs/test/browser.ini | 5 ++++- uriloader/exthandler/ExternalHelperAppParent.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index 0bc7bfe8dca0..1856a0472a75 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -1,9 +1,12 @@ [DEFAULT] -skip-if = e10s # Bug 1159385 support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_navigation.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_zoom.js] +skip-if = e10s # Bug 1159385 diff --git a/uriloader/exthandler/ExternalHelperAppParent.cpp b/uriloader/exthandler/ExternalHelperAppParent.cpp index cd5b41d80d97..352c05bbffbd 100644 --- a/uriloader/exthandler/ExternalHelperAppParent.cpp +++ b/uriloader/exthandler/ExternalHelperAppParent.cpp @@ -396,7 +396,9 @@ ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset) NS_IMETHODIMP ExternalHelperAppParent::GetContentDisposition(uint32_t *aContentDisposition) { - if (mContentDispositionHeader.IsEmpty()) + // NB: mContentDisposition may or may not be set to a non UINT32_MAX value in + // nsExternalHelperAppService::DoContentContentProcessHelper + if (mContentDispositionHeader.IsEmpty() && mContentDisposition == UINT32_MAX) return NS_ERROR_NOT_AVAILABLE; *aContentDisposition = mContentDisposition; From de600168e06be26f9acc33f7e89911afdcf6e63d Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 13 Oct 2015 17:01:05 -0700 Subject: [PATCH 64/79] Bug 1159385 - Make browser_pdfjs_main.js e10s compatible. r=mconley --- browser/extensions/pdfjs/test/browser.ini | 1 - .../pdfjs/test/browser_pdfjs_main.js | 110 +++++++++--------- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index 1856a0472a75..c82f5ac91d1e 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -2,7 +2,6 @@ support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] -skip-if = e10s # Bug 1159385 [browser_pdfjs_navigation.js] skip-if = e10s # Bug 1159385 [browser_pdfjs_savedialog.js] diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_main.js b/browser/extensions/pdfjs/test/browser_pdfjs_main.js index 9dd1e7a68e6e..5de890aaee2f 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_main.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_main.js @@ -4,9 +4,7 @@ const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; -function test() { - var tab; - +add_task(function* test() { let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -17,70 +15,68 @@ function test() { info('Pref action: ' + handlerInfo.preferredAction); - waitForExplicitFinish(); - registerCleanupFunction(function() { - gBrowser.removeTab(tab); - }); + yield BrowserTestUtils.withNewTab({ gBrowser: gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, + function* (newTabBrowser) { + ok(gBrowser.isFindBarInitialized(), "Browser FindBar initialized!"); - tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); - var newTabBrowser = gBrowser.getBrowserForTab(tab); - newTabBrowser.addEventListener("load", function eventHandler() { - newTabBrowser.removeEventListener("load", eventHandler, true); + // + // Overall sanity tests + // + let [ viewer, PDFJS ] = yield ContentTask.spawn(newTabBrowser, null, function() { + return [ content.document.querySelector('div#viewer') !== null, + 'PDFJS' in content.wrappedJSObject ]; + }); - var document = newTabBrowser.contentDocument, - window = newTabBrowser.contentWindow; + ok(viewer, "document content has viewer UI"); + ok(PDFJS, "window content has PDFJS object"); - // Runs tests after all 'load' event handlers have fired off - window.addEventListener("documentload", function() { - runTests(document, window, tab, finish); - }, false, true); - }, true); -} + // + // Sidebar: open + // + let contains = yield ContentTask.spawn(newTabBrowser, null, function() { + var sidebar = content.document.querySelector('button#sidebarToggle'), + outerContainer = content.document.querySelector('div#outerContainer'); + sidebar.click(); + return outerContainer.classList.contains('sidebarOpen'); + }); -function runTests(document, window, tab, callback) { + ok(contains, "sidebar opens on click"); - // - // Overall sanity tests - // - ok(document.querySelector('div#viewer'), "document content has viewer UI"); - ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); + // + // Sidebar: close + // + contains = yield ContentTask.spawn(newTabBrowser, null, function() { + var sidebar = content.document.querySelector('button#sidebarToggle'), + outerContainer = content.document.querySelector('div#outerContainer'); - // - // Browser Find - // - ok(gBrowser.isFindBarInitialized(tab), "Browser FindBar initialized!"); + sidebar.click(); + return outerContainer.classList.contains('sidebarOpen'); + }); - // - // Sidebar: open - // - var sidebar = document.querySelector('button#sidebarToggle'), - outerContainer = document.querySelector('div#outerContainer'); + ok(!contains, "sidebar closes on click"); - sidebar.click(); - ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click'); + // + // Page change from prev/next buttons + // + let pageNumber = yield ContentTask.spawn(newTabBrowser, null, function() { + var prevPage = content.document.querySelector('button#previous'), + nextPage = content.document.querySelector('button#next'); - // - // Sidebar: close - // - sidebar.click(); - ok(!outerContainer.classList.contains('sidebarOpen'), 'sidebar closes on click'); + return content.document.querySelector('input#pageNumber').value; + }); - // - // Page change from prev/next buttons - // - var prevPage = document.querySelector('button#previous'), - nextPage = document.querySelector('button#next'); + is(parseInt(pageNumber), 1, 'initial page is 1'); - var pageNumber = document.querySelector('input#pageNumber'); - is(parseInt(pageNumber.value), 1, 'initial page is 1'); + // + // Bookmark button + // + let numBookmarks = yield ContentTask.spawn(newTabBrowser, null, function() { + var viewBookmark = content.document.querySelector('a#viewBookmark'); + viewBookmark.click(); + return viewBookmark.href.length; + }); - // - // Bookmark button - // - var viewBookmark = document.querySelector('a#viewBookmark'); - viewBookmark.click(); - ok(viewBookmark.href.length > 0, 'viewBookmark button has href'); - - callback(); -} + ok(numBookmarks > 0, "viewBookmark button has href"); + }); +}); From 985d27c98a6e1e4ff4e9454eef9860dff834fbd6 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 13 Oct 2015 17:01:05 -0700 Subject: [PATCH 65/79] Bug 1159385 - Make browser_pdfjs_navigation.js e10s-compatible. r=yury --- browser/extensions/pdfjs/test/browser.ini | 1 - .../pdfjs/test/browser_pdfjs_navigation.js | 250 +++++++++--------- 2 files changed, 118 insertions(+), 133 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index c82f5ac91d1e..7699e913cead 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -3,7 +3,6 @@ support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] [browser_pdfjs_navigation.js] -skip-if = e10s # Bug 1159385 [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] skip-if = e10s # Bug 1159385 diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js b/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js index a1a501a023f2..5ba6a2a541ba 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js @@ -139,9 +139,7 @@ const TESTS = [ } ]; -function test() { - var tab; - +add_task(function* test() { let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -151,51 +149,85 @@ function test() { info('Pref action: ' + handlerInfo.preferredAction); - waitForExplicitFinish(); - registerCleanupFunction(function() { - gBrowser.removeTab(tab); - }); - - tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); - gBrowser.selectedTab = tab; - - var newTabBrowser = gBrowser.getBrowserForTab(tab); - newTabBrowser.addEventListener("load", function eventHandler() { - newTabBrowser.removeEventListener("load", eventHandler, true); - - var document = newTabBrowser.contentDocument, - window = newTabBrowser.contentWindow; - - // Runs tests after all 'load' event handlers have fired off - window.addEventListener("documentload", function() { - runTests(document, window, function () { - var pageNumber = document.querySelector('input#pageNumber'); - is(pageNumber.value, pageNumber.max, "Document is left on the last page"); - finish(); + yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, + function* (newTabBrowser) { + // Runs tests after all 'load' event handlers have fired off + yield ContentTask.spawn(newTabBrowser, null, function* () { + yield new Promise((resolve) => { + content.addEventListener("documentload", function() { + resolve(); + }, false, true); + }); }); - }, false, true); - }, true); -} -function runTests(document, window, finish) { - // Check if PDF is opened with internal viewer - ok(document.querySelector('div#viewer'), "document content has viewer UI"); - ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); + let [ viewer, pdfjs ] = yield ContentTask.spawn(newTabBrowser, null, function* () { + // Check if PDF is opened with internal viewer + return [ content.document.querySelector('div#viewer') !== null, + 'PDFJS' in content.wrappedJSObject ]; + }); - // Wait for outline items, the start the navigation actions - waitForOutlineItems(document).then(function () { - // The key navigation has to happen in page-fit, otherwise it won't scroll - // trough a complete page - setZoomToPageFit(document).then(function () { - runNextTest(document, window, finish); - }, function () { - ok(false, "Current scale has been set to 'page-fit'"); - finish(); + ok(viewer, "document content has viewer UI"); + ok(pdfjs, "window content has PDFJS object"); + + yield ContentTask.spawn(newTabBrowser, null, contentSetUp); + + yield Task.spawn(runTests(newTabBrowser)); + + let [ pageNumberValue, pageNumberMax ] = yield ContentTask.spawn(newTabBrowser, null, + function*() { + let pageNumber = content.document.querySelector('input#pageNumber'); + return [ pageNumber.value, pageNumber.max ]; + }); + is(pageNumberValue, pageNumberMax, "Document is left on the last page"); }); - }, function () { - ok(false, "Outline items have been found"); - finish(); - }); +}); + +function* contentSetUp() { + /** + * Outline Items gets appended to the document later on we have to + * wait for them before we start to navigate though document + * + * @param document + * @returns {deferred.promise|*} + */ + function waitForOutlineItems(document) { + return new Promise((resolve, reject) => { + document.addEventListener("outlineloaded", function outlineLoaded(evt) { + document.removeEventListener("outlineloaded", outlineLoaded); + var outlineCount = evt.detail.outlineCount; + + if (document.querySelectorAll(".outlineItem").length === outlineCount) { + resolve(); + } else { + reject(); + } + }); + }); + } + + /** + * The key navigation has to happen in page-fit, otherwise it won't scroll + * through a complete page + * + * @param document + * @returns {deferred.promise|*} + */ + function setZoomToPageFit(document) { + return new Promise((resolve) => { + document.addEventListener("pagerendered", function onZoom(e) { + document.removeEventListener("pagerendered", onZoom); + document.querySelector("#viewer").click(); + resolve(); + }); + + var select = document.querySelector("select#scaleSelect"); + select.selectedIndex = 2; + select.dispatchEvent(new Event("change")); + }); + } + + yield waitForOutlineItems(content.document); + yield setZoomToPageFit(content.document); } /** @@ -207,99 +239,53 @@ function runTests(document, window, finish) { * @param test * @param callback */ -function runNextTest(document, window, endCallback) { - var test = TESTS.shift(), - deferred = Promise.defer(), - pageNumber = document.querySelector('input#pageNumber'); +function* runTests(browser) { + for (let test of TESTS) { + let pgNumber = yield ContentTask.spawn(browser, test, function* (test) { + let window = content; + let document = window.document; - // Add an event-listener to wait for page to change, afterwards resolve the promise - var timeout = window.setTimeout(() => deferred.reject(), 5000); - window.addEventListener('pagechange', function pageChange() { - if (pageNumber.value == test.expectedPage) { - window.removeEventListener('pagechange', pageChange); - window.clearTimeout(timeout); - deferred.resolve(pageNumber.value); - } - }); + let deferred = {}; + deferred.promise = new Promise((resolve, reject) => { + deferred.resolve = resolve; + deferred.reject = reject; + }); - // Get the element and trigger the action for changing the page - var el = document.querySelector(test.action.selector); - ok(el, "Element '" + test.action.selector + "' has been found"); + let pageNumber = document.querySelector('input#pageNumber'); - // The value option is for input case - if (test.action.value) - el.value = test.action.value; + // Add an event-listener to wait for page to change, afterwards resolve the promise + let timeout = window.setTimeout(() => deferred.reject(), 5000); + window.addEventListener('pagechange', function pageChange() { + if (pageNumber.value == test.expectedPage) { + window.removeEventListener('pagechange', pageChange); + window.clearTimeout(timeout); + deferred.resolve(pageNumber.value); + } + }); - // Dispatch the event for changing the page - if (test.action.event == "keydown") { - var ev = document.createEvent("KeyboardEvent"); - ev.initKeyEvent("keydown", true, true, null, false, false, false, false, - test.action.keyCode, 0); - el.dispatchEvent(ev); - } - else { - var ev = new Event(test.action.event); - } - el.dispatchEvent(ev); + // Get the element and trigger the action for changing the page + var el = document.querySelector(test.action.selector); + // The value option is for input case + if (test.action.value) + el.value = test.action.value; - // When the promise gets resolved we call the next test if there are any left - // or else we call the final callback which will end the test - deferred.promise.then(function (pgNumber) { + // Dispatch the event for changing the page + if (test.action.event == "keydown") { + var ev = document.createEvent("KeyboardEvent"); + ev.initKeyEvent("keydown", true, true, null, false, false, false, false, + test.action.keyCode, 0); + el.dispatchEvent(ev); + } + else { + var ev = new Event(test.action.event); + } + el.dispatchEvent(ev); + + return yield deferred.promise; + }); + + info("Element '" + test.action.selector + "' has been found"); is(pgNumber, test.expectedPage, test.message); - - if (TESTS.length) - runNextTest(document, window, endCallback); - else - endCallback(); - }, function () { - ok(false, "Test '" + test.message + "' failed with timeout."); - endCallback(); - }); + } } - -/** - * Outline Items gets appended to the document latter on we have to - * wait for them before we start to navigate though document - * - * @param document - * @returns {deferred.promise|*} - */ -function waitForOutlineItems(document) { - var deferred = Promise.defer(); - document.addEventListener("outlineloaded", function outlineLoaded(evt) { - document.removeEventListener("outlineloaded", outlineLoaded); - var outlineCount = evt.detail.outlineCount; - - if (document.querySelectorAll(".outlineItem").length === outlineCount) { - deferred.resolve(); - } else { - deferred.reject(); - } - }); - - return deferred.promise; -} - -/** - * The key navigation has to happen in page-fit, otherwise it won't scroll - * trough a complete page - * - * @param document - * @returns {deferred.promise|*} - */ -function setZoomToPageFit(document) { - var deferred = Promise.defer(); - document.addEventListener("pagerendered", function onZoom(e) { - document.removeEventListener("pagerendered", onZoom); - document.querySelector("#viewer").click(); - deferred.resolve(); - }); - - var select = document.querySelector("select#scaleSelect"); - select.selectedIndex = 2; - select.dispatchEvent(new Event("change")); - - return deferred.promise; -} - From 5d8a54c39baae0f1c65ce8455357b38df77239b4 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 13 Oct 2015 17:01:05 -0700 Subject: [PATCH 66/79] Bug 1159385 - Make browser_pdfjs_views.js e10s-compatible. r=yury --- browser/extensions/pdfjs/test/browser.ini | 1 - .../pdfjs/test/browser_pdfjs_views.js | 109 ++++++++++-------- .../BrowserTestUtils/BrowserTestUtils.jsm | 2 +- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index 7699e913cead..3883ac79dc17 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -5,6 +5,5 @@ support-files = file_pdfjs_test.pdf [browser_pdfjs_navigation.js] [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] -skip-if = e10s # Bug 1159385 [browser_pdfjs_zoom.js] skip-if = e10s # Bug 1159385 diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_views.js b/browser/extensions/pdfjs/test/browser_pdfjs_views.js index 6a5da3fad5ec..c8e6fd2aa208 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_views.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_views.js @@ -4,9 +4,7 @@ const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; -function test() { - var tab; - +add_task(function* test() { let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -17,60 +15,79 @@ function test() { info('Pref action: ' + handlerInfo.preferredAction); - waitForExplicitFinish(); - registerCleanupFunction(function() { - gBrowser.removeTab(tab); - }); + yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, + function* (browser) { + // check that PDF is opened with internal viewer + let [ viewer, pdfjs ] = yield ContentTask.spawn(browser, null, function* () { + yield new Promise((resolve) => { + content.addEventListener("documentload", function documentload() { + content.removeEventListener("documentload", documentload); + resolve(); + }); + }); + return [ content.document.querySelector('div#viewer') !== null, + 'PDFJS' in content.wrappedJSObject ] + }); - tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); - var newTabBrowser = gBrowser.getBrowserForTab(tab); - newTabBrowser.addEventListener("load", function eventHandler() { - newTabBrowser.removeEventListener("load", eventHandler, true); + ok(viewer, "document content has viewer UI"); + ok(pdfjs, "window content has PDFJS object"); - var document = newTabBrowser.contentDocument, - window = newTabBrowser.contentWindow; + //open sidebar + let sidebarOpen = yield ContentTask.spawn(browser, null, function* () { + var sidebar = content.document.querySelector('button#sidebarToggle'); + var outerContainer = content.document.querySelector('div#outerContainer'); - // Runs tests after all 'load' event handlers have fired off - window.addEventListener("documentload", function() { - runTests(document, window, finish); - }, false, true); - }, true); -} + sidebar.click(); + return outerContainer.classList.contains('sidebarOpen'); + }); -function runTests(document, window, callback) { - // check that PDF is opened with internal viewer - ok(document.querySelector('div#viewer'), "document content has viewer UI"); - ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); + ok(sidebarOpen, 'sidebar opens on click'); - //open sidebar - var sidebar = document.querySelector('button#sidebarToggle'); - var outerContainer = document.querySelector('div#outerContainer'); + // check that thumbnail view is open + let [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { + var thumbnailView = content.document.querySelector('div#thumbnailView'); + var outlineView = content.document.querySelector('div#outlineView'); - sidebar.click(); - ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click'); + return [ thumbnailView.getAttribute('class'), + outlineView.getAttribute('class') ] + }); - // check that thumbnail view is open - var thumbnailView = document.querySelector('div#thumbnailView'); - var outlineView = document.querySelector('div#outlineView'); + is(thumbnailClass, null, 'Initial view is thumbnail view'); + is(outlineClass, 'hidden', 'Outline view is hidden initially'); - is(thumbnailView.getAttribute('class'), null, 'Initial view is thumbnail view'); - is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden initially'); + //switch to outline view + [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { + var viewOutlineButton = content.document.querySelector('button#viewOutline'); + viewOutlineButton.click(); - //switch to outline view - var viewOutlineButton = document.querySelector('button#viewOutline'); - viewOutlineButton.click(); + var thumbnailView = content.document.querySelector('div#thumbnailView'); + var outlineView = content.document.querySelector('div#outlineView'); - is(outlineView.getAttribute('class'), '', 'Outline view is visible when selected'); - is(thumbnailView.getAttribute('class'), 'hidden', 'Thumbnail view is hidden when outline is selected'); + return [ thumbnailView.getAttribute('class'), + outlineView.getAttribute('class') ]; + }); - //switch back to thumbnail view - var viewThumbnailButton = document.querySelector('button#viewThumbnail'); - viewThumbnailButton.click(); + is(thumbnailClass, 'hidden', 'Thumbnail view is hidden when outline is selected'); + is(outlineClass, '', 'Outline view is visible when selected'); - is(thumbnailView.getAttribute('class'), '', 'Thumbnail view is visible when selected'); - is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden when thumbnail is selected'); + //switch back to thumbnail view + [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { + var viewThumbnailButton = content.document.querySelector('button#viewThumbnail'); + viewThumbnailButton.click(); - sidebar.click(); + var thumbnailView = content.document.querySelector('div#thumbnailView'); + var outlineView = content.document.querySelector('div#outlineView'); - callback(); -} + let rval = [ thumbnailView.getAttribute('class'), + outlineView.getAttribute('class') ]; + + var sidebar = content.document.querySelector('button#sidebarToggle'); + sidebar.click(); + + return rval; + }); + + is(thumbnailClass, '', 'Thumbnail view is visible when selected'); + is(outlineClass, 'hidden', 'Outline view is hidden when thumbnail is selected'); + }); +}); diff --git a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm index 2dcf60ad88f1..7533ffa637a8 100644 --- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm +++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm @@ -321,7 +321,7 @@ this.BrowserTestUtils = { * Waits for an event to be fired on a specified element. * * Usage: - * let promiseEvent = BrowserTestUtil.waitForEvent(element, "eventName"); + * let promiseEvent = BrowserTestUtils.waitForEvent(element, "eventName"); * // Do some processing here that will cause the event to be fired * // ... * // Now yield until the Promise is fulfilled From fa7a5b34b260018c00cbaa373e356989538895e3 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 13 Oct 2015 17:01:05 -0700 Subject: [PATCH 67/79] Bug 1159385 - Make browser_pdfjs_zoom.js e10s-compatible. r=yury --- browser/extensions/pdfjs/test/browser.ini | 1 - .../pdfjs/test/browser_pdfjs_zoom.js | 171 +++++++++--------- 2 files changed, 83 insertions(+), 89 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index 3883ac79dc17..5f70a8596a4c 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -6,4 +6,3 @@ support-files = file_pdfjs_test.pdf [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] [browser_pdfjs_zoom.js] -skip-if = e10s # Bug 1159385 diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js b/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js index af555e0147ea..e8a79abfd60f 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js @@ -28,6 +28,7 @@ const TESTS = [ { action: { keyboard: true, + keyCode: 61, event: "+" }, expectedZoom: 1, // 1 - zoom in @@ -37,6 +38,7 @@ const TESTS = [ { action: { keyboard: true, + keyCode: 109, event: "-" }, expectedZoom: -1, // -1 - zoom out @@ -54,11 +56,7 @@ const TESTS = [ } ]; -var initialWidth; // the initial width of the PDF document -var previousWidth; // the width of the PDF document at previous step/test - -function test() { - var tab; +add_task(function* test() { let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"] .getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); @@ -72,104 +70,101 @@ function test() { info('Pref action: ' + handlerInfo.preferredAction); - waitForExplicitFinish(); - registerCleanupFunction(function() { - gBrowser.removeTab(tab); - }); + yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, + function* (newTabBrowser) { + let initialWidth = 0; // the initial width of the PDF document + let previousWidth = 0; // the width of the PDF document at previous step/test - tab = gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); - var newTabBrowser = gBrowser.getBrowserForTab(tab); + initialWidth = previousWidth = + yield ContentTask.spawn(newTabBrowser, null, function* () { + // Runs tests after all 'load' event handlers have fired off + return yield new Promise((resolve) => { + content.addEventListener("documentload", function loaded() { + content.removeEventListener("documentload", loaded); + resolve(parseInt(content.document.querySelector("div#pageContainer1").style.width)); + }, false, true); + }); + }); - newTabBrowser.addEventListener("load", function eventHandler() { - newTabBrowser.removeEventListener("load", eventHandler, true); + // Basic tests. + let [ viewer, pdfjs ] = yield ContentTask.spawn(newTabBrowser, null, function* () { + // check that PDF is opened with internal viewer + return [ content.document.querySelector('div#viewer') !== null, + 'PDFJS' in content.wrappedJSObject ]; + }); - var document = newTabBrowser.contentDocument, - window = newTabBrowser.contentWindow; + ok(viewer, "document content has viewer UI"); + ok(pdfjs, "window content has PDFJS object"); - // Runs tests after all 'load' event handlers have fired off - window.addEventListener("documentload", function() { - initialWidth = parseInt(document.querySelector("div#pageContainer1").style.width); - previousWidth = initialWidth; - runTests(document, window, finish); - }, false, true); - }, true); -} + for (let test of TESTS) { + yield ContentTask.spawn(newTabBrowser, test, function* (test) { + let document = content.document; -function runTests(document, window, callback) { - // check that PDF is opened with internal viewer - ok(document.querySelector('div#viewer'), "document content has viewer UI"); - ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); + function waitForRender() { + return new Promise((resolve) => { + document.addEventListener("pagerendered", function onPageRendered(e) { + if(e.detail.pageNumber !== 1) { + return; + } - // Start the zooming tests after the document is loaded - waitForDocumentLoad(document).then(function () { - zoomPDF(document, window, TESTS.shift(), finish); - }); -} + document.removeEventListener("pagerendered", onPageRendered, true); + resolve(); + }, true); + }); + } -function waitForDocumentLoad(document) { - var deferred = Promise.defer(); - var interval = setInterval(function () { - if (document.querySelector("div#pageContainer1") != null){ - clearInterval(interval); - deferred.resolve(); - } - }, 500); + // We zoom using an UI element + var ev; + if (test.action.selector) { + // Get the element and trigger the action for changing the zoom + var el = document.querySelector(test.action.selector); - return deferred.promise; -} + if (test.action.index){ + el.selectedIndex = test.action.index; + } -function zoomPDF(document, window, test, endCallback) { - var renderedPage; + // Dispatch the event for changing the zoom + ev = new Event(test.action.event); + } + // We zoom using keyboard + else { + // Simulate key press + ev = new content.KeyboardEvent("keydown", + { key: test.action.event, + keyCode: test.action.keyCode, + ctrlKey: true }); + el = content; + } - document.addEventListener("pagerendered", function onPageRendered(e) { - if(e.detail.pageNumber !== 1) { - return; - } + el.dispatchEvent(ev); + yield waitForRender(); + }); - document.removeEventListener("pagerendered", onPageRendered, true); + if (test.action.selector) { + info("Element '" + test.action.selector + "' has been found"); + } - var pageZoomScale = document.querySelector('select#scaleSelect'); + let { actualWidth, zoomValue } = yield ContentTask.spawn(newTabBrowser, null, function* () { + var pageZoomScale = content.document.querySelector('select#scaleSelect'); - // The zoom value displayed in the zoom select - var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML; + // The zoom value displayed in the zoom select + var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML; - let pageContainer = document.querySelector('div#pageContainer1'); - let actualWidth = parseInt(pageContainer.style.width); + let pageContainer = content.document.querySelector('div#pageContainer1'); + let actualWidth = parseInt(pageContainer.style.width); - // the actual zoom of the PDF document - let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%"; - is(computedZoomValue, zoomValue, "Content has correct zoom"); + return { actualWidth, zoomValue }; + }); - // Check that document zooms in the expected way (in/out) - let zoom = (actualWidth - previousWidth) * test.expectedZoom; - ok(zoom > 0, test.message); + // the actual zoom of the PDF document + let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%"; + is(computedZoomValue, zoomValue, "Content has correct zoom"); - // Go to next test (if there is any) or finish - var nextTest = TESTS.shift(); - if (nextTest) { - previousWidth = actualWidth; - zoomPDF(document, window, nextTest, endCallback); - } - else - endCallback(); - }, true); + // Check that document zooms in the expected way (in/out) + let zoom = (actualWidth - previousWidth) * test.expectedZoom; + ok(zoom > 0, test.message); - // We zoom using an UI element - if (test.action.selector) { - // Get the element and trigger the action for changing the zoom - var el = document.querySelector(test.action.selector); - ok(el, "Element '" + test.action.selector + "' has been found"); - - if (test.action.index){ - el.selectedIndex = test.action.index; - } - - // Dispatch the event for changing the zoom - el.dispatchEvent(new Event(test.action.event)); - } - // We zoom using keyboard - else { - // Simulate key press - EventUtils.synthesizeKey(test.action.event, { ctrlKey: true }); - } -} + previousWidth = actualWidth; + } + }); +}); From 225fa78d5ce0e45e89ac82fe53d57ea2abc4ba70 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 13 Oct 2015 17:19:06 -0700 Subject: [PATCH 68/79] Bug 1181313: Remove some unnecessary logging statements for success conditions, in nsPermissionManager.cpp. r=bsmedberg --- extensions/cookie/nsPermissionManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp index 3fed53ffdb57..1f50cfdc099a 100644 --- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -891,7 +891,6 @@ nsPermissionManager::InitDB(bool aRemoveFile) return NS_ERROR_UNEXPECTED; } - LogToConsole(NS_LITERAL_STRING("Get a connection to permissions.sqlite.")); bool tableExists = false; mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &tableExists); @@ -901,7 +900,6 @@ nsPermissionManager::InitDB(bool aRemoveFile) if (!tableExists) { rv = CreateTable(); NS_ENSURE_SUCCESS(rv, rv); - LogToConsole(NS_LITERAL_STRING("DB table(moz_perms) is created!")); } else { // table already exists; check the schema version before reading int32_t dbSchemaVersion; From 5a14010e95cc5500f2ba5f10168a5639df6663cb Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sat, 10 Oct 2015 18:27:48 -0700 Subject: [PATCH 69/79] Bug 1052139 - Adjust sandbox code to create the sandbox with an (observably) immutable [[Prototype]], once the flag's flipped. r=bz --- js/xpconnect/src/Sandbox.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 76828e417afa..07aa2f16ddeb 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -1046,6 +1046,24 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin // Pass on ownership of sbp to |sandbox|. JS_SetPrivate(sandbox, sbp.forget().take()); + { + // Don't try to mirror standard class properties, if we're using a + // mirroring sandbox. (This is meaningless for non-mirroring + // sandboxes.) + AutoSkipPropertyMirroring askip(CompartmentPrivate::Get(sandbox)); + + // Ensure |Object.prototype| is instantiated before prototype- + // splicing below. For write-to-global-prototype behavior, extend + // this to all builtin properties. + if (options.writeToGlobalPrototype) { + if (!JS_EnumerateStandardClasses(cx, sandbox)) + return NS_ERROR_XPC_UNEXPECTED; + } else { + if (!JS_GetObjectPrototype(cx, sandbox)) + return NS_ERROR_XPC_UNEXPECTED; + } + } + if (options.proto) { bool ok = JS_WrapObject(cx, &options.proto); if (!ok) @@ -1114,10 +1132,6 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin // every global. if (!dom::PromiseBinding::GetConstructorObject(cx, sandbox)) return NS_ERROR_XPC_UNEXPECTED; - - // Resolve standard classes eagerly to avoid triggering mirroring hooks for them. - if (options.writeToGlobalPrototype && !JS_EnumerateStandardClasses(cx, sandbox)) - return NS_ERROR_XPC_UNEXPECTED; } // We handle the case where the context isn't in a compartment for the From c9a85da898ade22180a3cf60c8e115158ff3ae94 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 9 Oct 2015 13:21:39 -0700 Subject: [PATCH 70/79] Bug 1052139 - Make prototype-setting first create Object.prototype so that subsequent prototype chain-splicing will work correctly. r=bz --- js/src/jsobj.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index d8b03541fb97..9f265867f1e8 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2467,6 +2467,15 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object if (!extensible) return result.fail(JSMSG_CANT_SET_PROTO); + // If this is a global object, resolve the Object class so that its + // [[Prototype]] chain is always properly immutable, even in the presence + // of lazy standard classes. + if (obj->is()) { + Rooted global(cx, &obj->as()); + if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object)) + return false; + } + /* * ES6 9.1.2 step 6 forbids generating cyclical prototype chains. But we * have to do this comparison on the observable outer objects, not on the From 57c195d47770c4ba5aa2f6a8e02ffb072f765c6e Mon Sep 17 00:00:00 2001 From: Andrew Sutherland Date: Tue, 13 Oct 2015 20:48:49 -0400 Subject: [PATCH 71/79] Bug 1210330 - TCPSocket data event should be an ArrayBuffer in non-e10s case too. r=jdm The conversion to WebIDL introduced a minor regression where the "data" event carried a Uint8Array payload instead of an ArrayBuffer. This patch corrects the type and introduces a fix. --- dom/network/TCPSocket.cpp | 2 +- dom/network/tests/test_tcpsocket_client_and_server_basics.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index 73e0e1b2fa79..c522ff21d799 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -1040,7 +1040,7 @@ TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInput JSContext* cx = api.cx(); JS::Rooted value(cx); - if (!ToJSValue(cx, TypedArrayCreator(buffer), &value)) { + if (!ToJSValue(cx, TypedArrayCreator(buffer), &value)) { return NS_ERROR_FAILURE; } FireDataEvent(cx, NS_LITERAL_STRING("data"), value); diff --git a/dom/network/tests/test_tcpsocket_client_and_server_basics.js b/dom/network/tests/test_tcpsocket_client_and_server_basics.js index 69854276b0e1..796dedb38737 100644 --- a/dom/network/tests/test_tcpsocket_client_and_server_basics.js +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.js @@ -55,6 +55,7 @@ function listenForEventsOnSocket(socket, socketType) { socket.ondata = function(event) { dump('(' + socketType + ' event: ' + event.type + ' length: ' + event.data.byteLength + ')\n'); + ok(event.data instanceof ArrayBuffer, 'payload is ArrayBuffer'); var arr = new Uint8Array(event.data); if (receivedData === null) { receivedData = arr; From c335f06a809d34609c625803b9c9224a5adcc74f Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 13 Oct 2015 18:33:27 -0700 Subject: [PATCH 72/79] Backed out changeset e28dde22ac26 (bug 1211344) --- xpfe/appshell/nsXULWindow.cpp | 54 ++++++++++++++--------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index 741f06af5e38..571ae4b5a0e7 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -1473,9 +1473,6 @@ void nsXULWindow::SaveAttributes() return; } - nsAutoString persistString; - docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString); - // get our size, position and mode to persist nsIntRect rect; bool gotRestoredBounds = NS_SUCCEEDED(mWindow->GetRestoredBounds(rect)); @@ -1498,29 +1495,23 @@ void nsXULWindow::SaveAttributes() ErrorResult rv; // (only for size elements which are persisted) if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) { - if (persistString.Find("screenX") >= 0) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); - } - if (persistString.Find("screenY") >= 0) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); - } + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); + + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); } if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) { - if (persistString.Find("width") >= 0) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); - } - if (persistString.Find("height") >= 0) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); - } + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); + + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); } if (mPersistentAttributesDirty & PAD_MISC) { @@ -1535,15 +1526,14 @@ void nsXULWindow::SaveAttributes() sizeString.Assign(SIZEMODE_NORMAL); docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); } - if (persistString.Find("zlevel") >= 0) { - uint32_t zLevel; - nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); - if (mediator) { - mediator->GetZLevel(this, &zLevel); - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); - } + + uint32_t zLevel; + nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); + if (mediator) { + mediator->GetZLevel(this, &zLevel); + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); } } From a195766b709126f7dd61529b53a7e7176c1c8ec3 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 13 Oct 2015 18:33:51 -0700 Subject: [PATCH 73/79] Backed out 2 changesets (bug 1137009) Backed out changeset 2c77e4edc2a5 (bug 1137009) Backed out changeset 7a5322e5fa07 (bug 1137009) --- dom/xul/XULDocument.cpp | 40 +++-------- xpfe/appshell/nsWebShellWindow.cpp | 10 +-- xpfe/appshell/nsXULWindow.cpp | 106 +++++++++++++++++++---------- xpfe/appshell/nsXULWindow.h | 4 +- 4 files changed, 87 insertions(+), 73 deletions(-) diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index f307d294fd2e..b7d023a28e45 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -916,23 +916,6 @@ XULDocument::AttributeWillChange(nsIDocument* aDocument, } } -static bool -ShouldPersistAttribute(nsIDocument* aDocument, Element* aElement) -{ - if (aElement->IsXULElement(nsGkAtoms::window)) { - if (nsCOMPtr window = aDocument->GetWindow()) { - bool isFullscreen; - window->GetFullScreen(&isFullscreen); - if (isFullscreen) { - // Don't persist attributes if it is window element and - // we are in fullscreen state. - return false; - } - } - } - return true; -} - void XULDocument::AttributeChanged(nsIDocument* aDocument, Element* aElement, int32_t aNameSpaceID, @@ -1007,19 +990,18 @@ XULDocument::AttributeChanged(nsIDocument* aDocument, bool listener, resolved; CheckBroadcasterHookup(aElement, &listener, &resolved); - if (ShouldPersistAttribute(aDocument, aElement)) { - // See if there is anything we need to persist in the localstore. - // - // XXX Namespace handling broken :-( - nsString persist; - aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist); - if (!persist.IsEmpty() && - // XXXldb This should check that it's a token, not just a substring. - persist.Find(nsDependentAtomString(aAttribute)) >= 0) { + // See if there is anything we need to persist in the localstore. + // + // XXX Namespace handling broken :-( + nsAutoString persist; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist); + if (!persist.IsEmpty()) { + // XXXldb This should check that it's a token, not just a substring. + if (persist.Find(nsDependentAtomString(aAttribute)) >= 0) { nsContentUtils::AddScriptRunner(NS_NewRunnableMethodWithArgs - - (this, &XULDocument::DoPersist, aElement, - kNameSpaceID_None, aAttribute)); + + (this, &XULDocument::DoPersist, aElement, kNameSpaceID_None, + aAttribute)); } } } diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index e04eb825ead1..6041c5570e41 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -419,8 +419,8 @@ nsWebShellWindow::WindowActivated() fm->WindowRaised(window); if (mChromeLoaded) { - SetAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); - SaveAttributes(); + PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); + SavePersistentAttributes(); } } @@ -512,14 +512,14 @@ nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags) mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, nsITimer::TYPE_ONE_SHOT); - SetAttributesDirty(aDirtyFlags); + PersistentAttributesDirty(aDirtyFlags); } void nsWebShellWindow::FirePersistenceTimer() { MutexAutoLock lock(mSPTimerLock); - SaveAttributes(); + SavePersistentAttributes(); } @@ -772,7 +772,7 @@ NS_IMETHODIMP nsWebShellWindow::Destroy() MutexAutoLock lock(mSPTimerLock); if (mSPTimer) { mSPTimer->Cancel(); - SaveAttributes(); + SavePersistentAttributes(); mSPTimer = nullptr; } } diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index 571ae4b5a0e7..cf6836221011 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -222,8 +222,8 @@ NS_IMETHODIMP nsXULWindow::SetZLevel(uint32_t aLevel) // do it mediator->SetZLevel(this, aLevel); - SetAttributesDirty(PAD_MISC); - SaveAttributes(); + PersistentAttributesDirty(PAD_MISC); + SavePersistentAttributes(); nsCOMPtr cv; mDocShell->GetContentViewer(getter_AddRefs(cv)); @@ -577,8 +577,8 @@ NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) mIgnoreXULPosition = true; return NS_OK; } - SetAttributesDirty(PAD_POSITION); - SaveAttributes(); + PersistentAttributesDirty(PAD_POSITION); + SavePersistentAttributes(); return NS_OK; } @@ -609,8 +609,8 @@ NS_IMETHODIMP nsXULWindow::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) mIgnoreXULSizeMode = true; return NS_OK; } - SetAttributesDirty(PAD_SIZE); - SaveAttributes(); + PersistentAttributesDirty(PAD_SIZE); + SavePersistentAttributes(); return NS_OK; } @@ -643,8 +643,8 @@ NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY, mIgnoreXULSizeMode = true; return NS_OK; } - SetAttributesDirty(PAD_POSITION | PAD_SIZE); - SaveAttributes(); + PersistentAttributesDirty(PAD_POSITION | PAD_SIZE); + SavePersistentAttributes(); return NS_OK; } @@ -1460,17 +1460,22 @@ void nsXULWindow::SyncAttributesToWidget() } } -void nsXULWindow::SaveAttributes() +NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() { // can happen when the persistence timer fires at an inopportune time // during window shutdown - if (!mDocShell) { - return; - } + if (!mDocShell) + return NS_ERROR_FAILURE; nsCOMPtr docShellElement = GetWindowDOMElement(); - if (!docShellElement) { - return; + if (!docShellElement) + return NS_ERROR_FAILURE; + + nsAutoString persistString; + docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString); + if (persistString.IsEmpty()) { // quick check which sometimes helps + mPersistentAttributesDirty = 0; + return NS_OK; } // get our size, position and mode to persist @@ -1491,27 +1496,49 @@ void nsXULWindow::SaveAttributes() char sizeBuf[10]; nsAutoString sizeString; + nsAutoString windowElementId; + nsCOMPtr ownerXULDoc; + + // fetch docShellElement's ID and XUL owner document + ownerXULDoc = do_QueryInterface(docShellElement->OwnerDoc()); + if (docShellElement->IsXULElement()) { + docShellElement->GetId(windowElementId); + } ErrorResult rv; // (only for size elements which are persisted) if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); - - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); + if (persistString.Find("screenX") >= 0) { + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); + if (ownerXULDoc) // force persistence in case the value didn't change + ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE); + } + if (persistString.Find("screenY") >= 0) { + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); + if (ownerXULDoc) + ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE); + } } if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) { - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); - - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale)); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); + if (persistString.Find("width") >= 0) { + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); + if (ownerXULDoc) + ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE); + } + if (persistString.Find("height") >= 0) { + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale)); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); + if (ownerXULDoc) + ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE); + } } if (mPersistentAttributesDirty & PAD_MISC) { @@ -1525,19 +1552,24 @@ void nsXULWindow::SaveAttributes() else sizeString.Assign(SIZEMODE_NORMAL); docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); + if (ownerXULDoc && persistString.Find("sizemode") >= 0) + ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE); } - - uint32_t zLevel; - nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); - if (mediator) { - mediator->GetZLevel(this, &zLevel); - PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); - sizeString.AssignWithConversion(sizeBuf); - docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); + if (persistString.Find("zlevel") >= 0) { + uint32_t zLevel; + nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); + if (mediator) { + mediator->GetZLevel(this, &zLevel); + PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); + sizeString.AssignWithConversion(sizeBuf); + docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); + ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE); + } } } mPersistentAttributesDirty = 0; + return NS_OK; } NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow) @@ -2008,7 +2040,7 @@ bool nsXULWindow::GetContentScrollbarVisibility() } // during spinup, attributes that haven't been loaded yet can't be dirty -void nsXULWindow::SetAttributesDirty(uint32_t aDirtyFlags) +void nsXULWindow::PersistentAttributesDirty(uint32_t aDirtyFlags) { mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask; } diff --git a/xpfe/appshell/nsXULWindow.h b/xpfe/appshell/nsXULWindow.h index 064d4c3a4e9b..4cacfd051afb 100644 --- a/xpfe/appshell/nsXULWindow.h +++ b/xpfe/appshell/nsXULWindow.h @@ -96,7 +96,7 @@ protected: bool LoadSizeFromXUL(); bool LoadMiscPersistentAttributesFromXUL(); void SyncAttributesToWidget(); - void SaveAttributes(); + NS_IMETHOD SavePersistentAttributes(); NS_IMETHOD GetWindowDOMWindow(nsIDOMWindow** aDOMWindow); mozilla::dom::Element* GetWindowDOMElement() const; @@ -119,7 +119,7 @@ protected: nsIXULWindow *aBehind); void SetContentScrollbarVisibility(bool aVisible); bool GetContentScrollbarVisibility(); - void SetAttributesDirty(uint32_t aDirtyFlags); + void PersistentAttributesDirty(uint32_t aDirtyFlags); nsChromeTreeOwner* mChromeTreeOwner; nsContentTreeOwner* mContentTreeOwner; From ffd56892f220742d1cb718a433eb7aa8a7a6651d Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Tue, 13 Oct 2015 12:09:40 -0700 Subject: [PATCH 74/79] Bug 1209774 - Transform from GDK coords to layout device pixels before calling DispatchEvent. r=karlt --- widget/gtk/nsWindow.cpp | 43 ++++++++++++++++++----------------------- widget/gtk/nsWindow.h | 1 + 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index e9df1ffb1365..43d135058fe4 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -531,10 +531,6 @@ nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) debug_DumpEvent(stdout, aEvent->widget, aEvent, nsAutoCString("something"), 0); #endif - // Translate the mouse event into device pixels. - aEvent->refPoint.x = GdkCoordToDevicePixels(aEvent->refPoint.x); - aEvent->refPoint.y = GdkCoordToDevicePixels(aEvent->refPoint.y); - aStatus = nsEventStatus_eIgnore; nsIWidgetListener* listener = mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; @@ -2462,9 +2458,7 @@ nsWindow::OnEnterNotifyEvent(GdkEventCrossing *aEvent) WidgetMouseEvent event(true, eMouseEnterIntoWidget, this, WidgetMouseEvent::eReal); - event.refPoint.x = nscoord(aEvent->x); - event.refPoint.y = nscoord(aEvent->y); - + event.refPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); event.time = aEvent->time; event.timeStamp = GetEventTimeStamp(aEvent->time); @@ -2505,9 +2499,7 @@ nsWindow::OnLeaveNotifyEvent(GdkEventCrossing *aEvent) WidgetMouseEvent event(true, eMouseExitFromWidget, this, WidgetMouseEvent::eReal); - event.refPoint.x = nscoord(aEvent->x); - event.refPoint.y = nscoord(aEvent->y); - + event.refPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); event.time = aEvent->time; event.timeStamp = GetEventTimeStamp(aEvent->time); @@ -2572,8 +2564,7 @@ nsWindow::OnMotionNotifyEvent(GdkEventMotion *aEvent) event.time = xevent.xmotion.time; event.timeStamp = GetEventTimeStamp(xevent.xmotion.time); #else - event.refPoint.x = nscoord(aEvent->x); - event.refPoint.y = nscoord(aEvent->y); + event.refPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); modifierState = aEvent->state; @@ -2584,11 +2575,10 @@ nsWindow::OnMotionNotifyEvent(GdkEventMotion *aEvent) else { // XXX see OnScrollEvent() if (aEvent->window == mGdkWindow) { - event.refPoint.x = nscoord(aEvent->x); - event.refPoint.y = nscoord(aEvent->y); + event.refPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); } else { - LayoutDeviceIntPoint point(NSToIntFloor(aEvent->x_root), - NSToIntFloor(aEvent->y_root)); + LayoutDeviceIntPoint point = GdkEventCoordsToDevicePixels( + aEvent->x_root, aEvent->y_root); event.refPoint = point - WidgetToScreenOffset(); } @@ -2661,11 +2651,10 @@ nsWindow::InitButtonEvent(WidgetMouseEvent& aEvent, { // XXX see OnScrollEvent() if (aGdkEvent->window == mGdkWindow) { - aEvent.refPoint.x = nscoord(aGdkEvent->x); - aEvent.refPoint.y = nscoord(aGdkEvent->y); + aEvent.refPoint = GdkEventCoordsToDevicePixels(aGdkEvent->x, aGdkEvent->y); } else { - LayoutDeviceIntPoint point(NSToIntFloor(aGdkEvent->x_root), - NSToIntFloor(aGdkEvent->y_root)); + LayoutDeviceIntPoint point = GdkEventCoordsToDevicePixels( + aGdkEvent->x_root, aGdkEvent->y_root); aEvent.refPoint = point - WidgetToScreenOffset(); } @@ -3184,14 +3173,13 @@ nsWindow::OnScrollEvent(GdkEventScroll *aEvent) if (aEvent->window == mGdkWindow) { // we are the window that the event happened on so no need for expensive WidgetToScreenOffset - wheelEvent.refPoint.x = nscoord(aEvent->x); - wheelEvent.refPoint.y = nscoord(aEvent->y); + wheelEvent.refPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); } else { // XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling // in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into // coordinates relative to this widget. - LayoutDeviceIntPoint point(NSToIntFloor(aEvent->x_root), - NSToIntFloor(aEvent->y_root)); + LayoutDeviceIntPoint point = GdkEventCoordsToDevicePixels( + aEvent->x_root, aEvent->y_root); wheelEvent.refPoint = point - WidgetToScreenOffset(); } @@ -6603,6 +6591,13 @@ nsWindow::GdkCoordToDevicePixels(gint coord) { return coord * GdkScaleFactor(); } +LayoutDeviceIntPoint +nsWindow::GdkEventCoordsToDevicePixels(gdouble x, gdouble y) +{ + gint scale = GdkScaleFactor(); + return LayoutDeviceIntPoint(floor(x * scale + 0.5), floor(y * scale + 0.5)); +} + LayoutDeviceIntPoint nsWindow::GdkPointToDevicePixels(GdkPoint point) { gint scale = GdkScaleFactor(); diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index df2c2ccad002..b1af84ec0047 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -527,6 +527,7 @@ private: // From GDK int GdkCoordToDevicePixels(gint coord); mozilla::LayoutDeviceIntPoint GdkPointToDevicePixels(GdkPoint point); + mozilla::LayoutDeviceIntPoint GdkEventCoordsToDevicePixels(gdouble x, gdouble y); nsIntRect GdkRectToDevicePixels(GdkRectangle rect); }; From 39d48b3bb056e4a09246442f84c705efa54ad7a9 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 13 Oct 2015 19:40:20 -0700 Subject: [PATCH 75/79] Back out changeset 81b6dbef4fb1 (bug 1210330) for Android and b2g mochitest-chrome failures in test_tcpsocket_jsm.html CLOSED TREE --- dom/network/TCPSocket.cpp | 2 +- dom/network/tests/test_tcpsocket_client_and_server_basics.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index c522ff21d799..73e0e1b2fa79 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -1040,7 +1040,7 @@ TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInput JSContext* cx = api.cx(); JS::Rooted value(cx); - if (!ToJSValue(cx, TypedArrayCreator(buffer), &value)) { + if (!ToJSValue(cx, TypedArrayCreator(buffer), &value)) { return NS_ERROR_FAILURE; } FireDataEvent(cx, NS_LITERAL_STRING("data"), value); diff --git a/dom/network/tests/test_tcpsocket_client_and_server_basics.js b/dom/network/tests/test_tcpsocket_client_and_server_basics.js index 796dedb38737..69854276b0e1 100644 --- a/dom/network/tests/test_tcpsocket_client_and_server_basics.js +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.js @@ -55,7 +55,6 @@ function listenForEventsOnSocket(socket, socketType) { socket.ondata = function(event) { dump('(' + socketType + ' event: ' + event.type + ' length: ' + event.data.byteLength + ')\n'); - ok(event.data instanceof ArrayBuffer, 'payload is ArrayBuffer'); var arr = new Uint8Array(event.data); if (receivedData === null) { receivedData = arr; From 228ec2a1e49c1333caef92134d9acf9d6785f297 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 13 Oct 2015 20:00:38 -0700 Subject: [PATCH 76/79] Back out changeset d34a1af95066 (bug 1207288) for Windows mochitest-gl not being that into being validated CLOSED TREE --- dom/canvas/WebGL2Context.cpp | 2 ++ dom/canvas/WebGLShaderValidator.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/canvas/WebGL2Context.cpp b/dom/canvas/WebGL2Context.cpp index 346d7a096ed0..0a0b0edf34a5 100644 --- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -180,6 +180,8 @@ WebGLContext::InitWebGL2() mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0); mBoundTransformFeedback = mDefaultTransformFeedback; + mBypassShaderValidation = true; + return true; } diff --git a/dom/canvas/WebGLShaderValidator.cpp b/dom/canvas/WebGLShaderValidator.cpp index 9933026ea1e8..5553ad8f72ec 100644 --- a/dom/canvas/WebGLShaderValidator.cpp +++ b/dom/canvas/WebGLShaderValidator.cpp @@ -99,7 +99,7 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const if (mBypassShaderValidation) return nullptr; - ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC; + ShShaderSpec spec = SH_WEBGL_SPEC; ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; From 122a5a517664113edc39fb4141c0fde206d5cf07 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 13 Oct 2015 20:39:00 -0700 Subject: [PATCH 77/79] Bug 1202663, bug 1213797 followup followup, fix more missing metadata update CLOSED TREE --- .../the-bdi-element/bdi-neutral-wrapped.html.ini | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 testing/web-platform/meta/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html.ini diff --git a/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html.ini b/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html.ini deleted file mode 100644 index b5cded75b352..000000000000 --- a/testing/web-platform/meta/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[bdi-neutral-wrapped.html] - type: reftest - expected: - if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL From bad48ad6fa040db2d2b26102e910545bcdd61080 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 13 Oct 2015 21:36:10 -0700 Subject: [PATCH 78/79] Back out 5 changesets (bug 1159385, bug 1165558) for making browser_pdfjs_zoom.js frequently leak on Windows CLOSED TREE Backed out changeset 9c0a6b934c7a (bug 1159385) Backed out changeset 1dcf1d5a95ce (bug 1159385) Backed out changeset 50b20aa3fd46 (bug 1159385) Backed out changeset 863379c3fe31 (bug 1159385) Backed out changeset 8decc8f8fcb1 (bug 1165558) --- browser/extensions/pdfjs/test/browser.ini | 1 + .../pdfjs/test/browser_pdfjs_main.js | 110 ++++---- .../pdfjs/test/browser_pdfjs_navigation.js | 254 +++++++++--------- .../pdfjs/test/browser_pdfjs_views.js | 109 ++++---- .../pdfjs/test/browser_pdfjs_zoom.js | 171 ++++++------ .../BrowserTestUtils/BrowserTestUtils.jsm | 2 +- .../exthandler/ExternalHelperAppParent.cpp | 4 +- 7 files changed, 328 insertions(+), 323 deletions(-) diff --git a/browser/extensions/pdfjs/test/browser.ini b/browser/extensions/pdfjs/test/browser.ini index 5f70a8596a4c..0bc7bfe8dca0 100644 --- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -1,4 +1,5 @@ [DEFAULT] +skip-if = e10s # Bug 1159385 support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_main.js b/browser/extensions/pdfjs/test/browser_pdfjs_main.js index 5de890aaee2f..9dd1e7a68e6e 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_main.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_main.js @@ -4,7 +4,9 @@ const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; -add_task(function* test() { +function test() { + var tab; + let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -15,68 +17,70 @@ add_task(function* test() { info('Pref action: ' + handlerInfo.preferredAction); - yield BrowserTestUtils.withNewTab({ gBrowser: gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, - function* (newTabBrowser) { - ok(gBrowser.isFindBarInitialized(), "Browser FindBar initialized!"); + waitForExplicitFinish(); + registerCleanupFunction(function() { + gBrowser.removeTab(tab); + }); - // - // Overall sanity tests - // - let [ viewer, PDFJS ] = yield ContentTask.spawn(newTabBrowser, null, function() { - return [ content.document.querySelector('div#viewer') !== null, - 'PDFJS' in content.wrappedJSObject ]; - }); + tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + var newTabBrowser = gBrowser.getBrowserForTab(tab); + newTabBrowser.addEventListener("load", function eventHandler() { + newTabBrowser.removeEventListener("load", eventHandler, true); - ok(viewer, "document content has viewer UI"); - ok(PDFJS, "window content has PDFJS object"); + var document = newTabBrowser.contentDocument, + window = newTabBrowser.contentWindow; - // - // Sidebar: open - // - let contains = yield ContentTask.spawn(newTabBrowser, null, function() { - var sidebar = content.document.querySelector('button#sidebarToggle'), - outerContainer = content.document.querySelector('div#outerContainer'); + // Runs tests after all 'load' event handlers have fired off + window.addEventListener("documentload", function() { + runTests(document, window, tab, finish); + }, false, true); + }, true); +} - sidebar.click(); - return outerContainer.classList.contains('sidebarOpen'); - }); - ok(contains, "sidebar opens on click"); +function runTests(document, window, tab, callback) { - // - // Sidebar: close - // - contains = yield ContentTask.spawn(newTabBrowser, null, function() { - var sidebar = content.document.querySelector('button#sidebarToggle'), - outerContainer = content.document.querySelector('div#outerContainer'); + // + // Overall sanity tests + // + ok(document.querySelector('div#viewer'), "document content has viewer UI"); + ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); - sidebar.click(); - return outerContainer.classList.contains('sidebarOpen'); - }); + // + // Browser Find + // + ok(gBrowser.isFindBarInitialized(tab), "Browser FindBar initialized!"); - ok(!contains, "sidebar closes on click"); + // + // Sidebar: open + // + var sidebar = document.querySelector('button#sidebarToggle'), + outerContainer = document.querySelector('div#outerContainer'); - // - // Page change from prev/next buttons - // - let pageNumber = yield ContentTask.spawn(newTabBrowser, null, function() { - var prevPage = content.document.querySelector('button#previous'), - nextPage = content.document.querySelector('button#next'); + sidebar.click(); + ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click'); - return content.document.querySelector('input#pageNumber').value; - }); + // + // Sidebar: close + // + sidebar.click(); + ok(!outerContainer.classList.contains('sidebarOpen'), 'sidebar closes on click'); - is(parseInt(pageNumber), 1, 'initial page is 1'); + // + // Page change from prev/next buttons + // + var prevPage = document.querySelector('button#previous'), + nextPage = document.querySelector('button#next'); - // - // Bookmark button - // - let numBookmarks = yield ContentTask.spawn(newTabBrowser, null, function() { - var viewBookmark = content.document.querySelector('a#viewBookmark'); - viewBookmark.click(); - return viewBookmark.href.length; - }); + var pageNumber = document.querySelector('input#pageNumber'); + is(parseInt(pageNumber.value), 1, 'initial page is 1'); - ok(numBookmarks > 0, "viewBookmark button has href"); - }); -}); + // + // Bookmark button + // + var viewBookmark = document.querySelector('a#viewBookmark'); + viewBookmark.click(); + ok(viewBookmark.href.length > 0, 'viewBookmark button has href'); + + callback(); +} diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js b/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js index 5ba6a2a541ba..a1a501a023f2 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_navigation.js @@ -139,7 +139,9 @@ const TESTS = [ } ]; -add_task(function* test() { +function test() { + var tab; + let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -149,85 +151,51 @@ add_task(function* test() { info('Pref action: ' + handlerInfo.preferredAction); - yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, - function* (newTabBrowser) { - // Runs tests after all 'load' event handlers have fired off - yield ContentTask.spawn(newTabBrowser, null, function* () { - yield new Promise((resolve) => { - content.addEventListener("documentload", function() { - resolve(); - }, false, true); - }); + waitForExplicitFinish(); + registerCleanupFunction(function() { + gBrowser.removeTab(tab); + }); + + tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + gBrowser.selectedTab = tab; + + var newTabBrowser = gBrowser.getBrowserForTab(tab); + newTabBrowser.addEventListener("load", function eventHandler() { + newTabBrowser.removeEventListener("load", eventHandler, true); + + var document = newTabBrowser.contentDocument, + window = newTabBrowser.contentWindow; + + // Runs tests after all 'load' event handlers have fired off + window.addEventListener("documentload", function() { + runTests(document, window, function () { + var pageNumber = document.querySelector('input#pageNumber'); + is(pageNumber.value, pageNumber.max, "Document is left on the last page"); + finish(); }); + }, false, true); + }, true); +} - let [ viewer, pdfjs ] = yield ContentTask.spawn(newTabBrowser, null, function* () { - // Check if PDF is opened with internal viewer - return [ content.document.querySelector('div#viewer') !== null, - 'PDFJS' in content.wrappedJSObject ]; - }); +function runTests(document, window, finish) { + // Check if PDF is opened with internal viewer + ok(document.querySelector('div#viewer'), "document content has viewer UI"); + ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); - ok(viewer, "document content has viewer UI"); - ok(pdfjs, "window content has PDFJS object"); - - yield ContentTask.spawn(newTabBrowser, null, contentSetUp); - - yield Task.spawn(runTests(newTabBrowser)); - - let [ pageNumberValue, pageNumberMax ] = yield ContentTask.spawn(newTabBrowser, null, - function*() { - let pageNumber = content.document.querySelector('input#pageNumber'); - return [ pageNumber.value, pageNumber.max ]; - }); - is(pageNumberValue, pageNumberMax, "Document is left on the last page"); + // Wait for outline items, the start the navigation actions + waitForOutlineItems(document).then(function () { + // The key navigation has to happen in page-fit, otherwise it won't scroll + // trough a complete page + setZoomToPageFit(document).then(function () { + runNextTest(document, window, finish); + }, function () { + ok(false, "Current scale has been set to 'page-fit'"); + finish(); }); -}); - -function* contentSetUp() { - /** - * Outline Items gets appended to the document later on we have to - * wait for them before we start to navigate though document - * - * @param document - * @returns {deferred.promise|*} - */ - function waitForOutlineItems(document) { - return new Promise((resolve, reject) => { - document.addEventListener("outlineloaded", function outlineLoaded(evt) { - document.removeEventListener("outlineloaded", outlineLoaded); - var outlineCount = evt.detail.outlineCount; - - if (document.querySelectorAll(".outlineItem").length === outlineCount) { - resolve(); - } else { - reject(); - } - }); - }); - } - - /** - * The key navigation has to happen in page-fit, otherwise it won't scroll - * through a complete page - * - * @param document - * @returns {deferred.promise|*} - */ - function setZoomToPageFit(document) { - return new Promise((resolve) => { - document.addEventListener("pagerendered", function onZoom(e) { - document.removeEventListener("pagerendered", onZoom); - document.querySelector("#viewer").click(); - resolve(); - }); - - var select = document.querySelector("select#scaleSelect"); - select.selectedIndex = 2; - select.dispatchEvent(new Event("change")); - }); - } - - yield waitForOutlineItems(content.document); - yield setZoomToPageFit(content.document); + }, function () { + ok(false, "Outline items have been found"); + finish(); + }); } /** @@ -239,53 +207,99 @@ function* contentSetUp() { * @param test * @param callback */ -function* runTests(browser) { - for (let test of TESTS) { - let pgNumber = yield ContentTask.spawn(browser, test, function* (test) { - let window = content; - let document = window.document; +function runNextTest(document, window, endCallback) { + var test = TESTS.shift(), + deferred = Promise.defer(), + pageNumber = document.querySelector('input#pageNumber'); - let deferred = {}; - deferred.promise = new Promise((resolve, reject) => { - deferred.resolve = resolve; - deferred.reject = reject; - }); + // Add an event-listener to wait for page to change, afterwards resolve the promise + var timeout = window.setTimeout(() => deferred.reject(), 5000); + window.addEventListener('pagechange', function pageChange() { + if (pageNumber.value == test.expectedPage) { + window.removeEventListener('pagechange', pageChange); + window.clearTimeout(timeout); + deferred.resolve(pageNumber.value); + } + }); - let pageNumber = document.querySelector('input#pageNumber'); + // Get the element and trigger the action for changing the page + var el = document.querySelector(test.action.selector); + ok(el, "Element '" + test.action.selector + "' has been found"); - // Add an event-listener to wait for page to change, afterwards resolve the promise - let timeout = window.setTimeout(() => deferred.reject(), 5000); - window.addEventListener('pagechange', function pageChange() { - if (pageNumber.value == test.expectedPage) { - window.removeEventListener('pagechange', pageChange); - window.clearTimeout(timeout); - deferred.resolve(pageNumber.value); - } - }); + // The value option is for input case + if (test.action.value) + el.value = test.action.value; - // Get the element and trigger the action for changing the page - var el = document.querySelector(test.action.selector); - - // The value option is for input case - if (test.action.value) - el.value = test.action.value; - - // Dispatch the event for changing the page - if (test.action.event == "keydown") { - var ev = document.createEvent("KeyboardEvent"); - ev.initKeyEvent("keydown", true, true, null, false, false, false, false, - test.action.keyCode, 0); - el.dispatchEvent(ev); - } - else { - var ev = new Event(test.action.event); - } - el.dispatchEvent(ev); - - return yield deferred.promise; - }); - - info("Element '" + test.action.selector + "' has been found"); - is(pgNumber, test.expectedPage, test.message); + // Dispatch the event for changing the page + if (test.action.event == "keydown") { + var ev = document.createEvent("KeyboardEvent"); + ev.initKeyEvent("keydown", true, true, null, false, false, false, false, + test.action.keyCode, 0); + el.dispatchEvent(ev); } + else { + var ev = new Event(test.action.event); + } + el.dispatchEvent(ev); + + + // When the promise gets resolved we call the next test if there are any left + // or else we call the final callback which will end the test + deferred.promise.then(function (pgNumber) { + is(pgNumber, test.expectedPage, test.message); + + if (TESTS.length) + runNextTest(document, window, endCallback); + else + endCallback(); + }, function () { + ok(false, "Test '" + test.message + "' failed with timeout."); + endCallback(); + }); } + +/** + * Outline Items gets appended to the document latter on we have to + * wait for them before we start to navigate though document + * + * @param document + * @returns {deferred.promise|*} + */ +function waitForOutlineItems(document) { + var deferred = Promise.defer(); + document.addEventListener("outlineloaded", function outlineLoaded(evt) { + document.removeEventListener("outlineloaded", outlineLoaded); + var outlineCount = evt.detail.outlineCount; + + if (document.querySelectorAll(".outlineItem").length === outlineCount) { + deferred.resolve(); + } else { + deferred.reject(); + } + }); + + return deferred.promise; +} + +/** + * The key navigation has to happen in page-fit, otherwise it won't scroll + * trough a complete page + * + * @param document + * @returns {deferred.promise|*} + */ +function setZoomToPageFit(document) { + var deferred = Promise.defer(); + document.addEventListener("pagerendered", function onZoom(e) { + document.removeEventListener("pagerendered", onZoom); + document.querySelector("#viewer").click(); + deferred.resolve(); + }); + + var select = document.querySelector("select#scaleSelect"); + select.selectedIndex = 2; + select.dispatchEvent(new Event("change")); + + return deferred.promise; +} + diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_views.js b/browser/extensions/pdfjs/test/browser_pdfjs_views.js index c8e6fd2aa208..6a5da3fad5ec 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_views.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_views.js @@ -4,7 +4,9 @@ const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; -add_task(function* test() { +function test() { + var tab; + let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf'); @@ -15,79 +17,60 @@ add_task(function* test() { info('Pref action: ' + handlerInfo.preferredAction); - yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, - function* (browser) { - // check that PDF is opened with internal viewer - let [ viewer, pdfjs ] = yield ContentTask.spawn(browser, null, function* () { - yield new Promise((resolve) => { - content.addEventListener("documentload", function documentload() { - content.removeEventListener("documentload", documentload); - resolve(); - }); - }); - return [ content.document.querySelector('div#viewer') !== null, - 'PDFJS' in content.wrappedJSObject ] - }); + waitForExplicitFinish(); + registerCleanupFunction(function() { + gBrowser.removeTab(tab); + }); - ok(viewer, "document content has viewer UI"); - ok(pdfjs, "window content has PDFJS object"); + tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + var newTabBrowser = gBrowser.getBrowserForTab(tab); + newTabBrowser.addEventListener("load", function eventHandler() { + newTabBrowser.removeEventListener("load", eventHandler, true); - //open sidebar - let sidebarOpen = yield ContentTask.spawn(browser, null, function* () { - var sidebar = content.document.querySelector('button#sidebarToggle'); - var outerContainer = content.document.querySelector('div#outerContainer'); + var document = newTabBrowser.contentDocument, + window = newTabBrowser.contentWindow; - sidebar.click(); - return outerContainer.classList.contains('sidebarOpen'); - }); + // Runs tests after all 'load' event handlers have fired off + window.addEventListener("documentload", function() { + runTests(document, window, finish); + }, false, true); + }, true); +} - ok(sidebarOpen, 'sidebar opens on click'); +function runTests(document, window, callback) { + // check that PDF is opened with internal viewer + ok(document.querySelector('div#viewer'), "document content has viewer UI"); + ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); - // check that thumbnail view is open - let [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { - var thumbnailView = content.document.querySelector('div#thumbnailView'); - var outlineView = content.document.querySelector('div#outlineView'); + //open sidebar + var sidebar = document.querySelector('button#sidebarToggle'); + var outerContainer = document.querySelector('div#outerContainer'); - return [ thumbnailView.getAttribute('class'), - outlineView.getAttribute('class') ] - }); + sidebar.click(); + ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click'); - is(thumbnailClass, null, 'Initial view is thumbnail view'); - is(outlineClass, 'hidden', 'Outline view is hidden initially'); + // check that thumbnail view is open + var thumbnailView = document.querySelector('div#thumbnailView'); + var outlineView = document.querySelector('div#outlineView'); - //switch to outline view - [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { - var viewOutlineButton = content.document.querySelector('button#viewOutline'); - viewOutlineButton.click(); + is(thumbnailView.getAttribute('class'), null, 'Initial view is thumbnail view'); + is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden initially'); - var thumbnailView = content.document.querySelector('div#thumbnailView'); - var outlineView = content.document.querySelector('div#outlineView'); + //switch to outline view + var viewOutlineButton = document.querySelector('button#viewOutline'); + viewOutlineButton.click(); - return [ thumbnailView.getAttribute('class'), - outlineView.getAttribute('class') ]; - }); + is(outlineView.getAttribute('class'), '', 'Outline view is visible when selected'); + is(thumbnailView.getAttribute('class'), 'hidden', 'Thumbnail view is hidden when outline is selected'); - is(thumbnailClass, 'hidden', 'Thumbnail view is hidden when outline is selected'); - is(outlineClass, '', 'Outline view is visible when selected'); + //switch back to thumbnail view + var viewThumbnailButton = document.querySelector('button#viewThumbnail'); + viewThumbnailButton.click(); - //switch back to thumbnail view - [ thumbnailClass, outlineClass ] = yield ContentTask.spawn(browser, null, function* () { - var viewThumbnailButton = content.document.querySelector('button#viewThumbnail'); - viewThumbnailButton.click(); + is(thumbnailView.getAttribute('class'), '', 'Thumbnail view is visible when selected'); + is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden when thumbnail is selected'); - var thumbnailView = content.document.querySelector('div#thumbnailView'); - var outlineView = content.document.querySelector('div#outlineView'); + sidebar.click(); - let rval = [ thumbnailView.getAttribute('class'), - outlineView.getAttribute('class') ]; - - var sidebar = content.document.querySelector('button#sidebarToggle'); - sidebar.click(); - - return rval; - }); - - is(thumbnailClass, '', 'Thumbnail view is visible when selected'); - is(outlineClass, 'hidden', 'Outline view is hidden when thumbnail is selected'); - }); -}); + callback(); +} diff --git a/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js b/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js index e8a79abfd60f..af555e0147ea 100644 --- a/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js +++ b/browser/extensions/pdfjs/test/browser_pdfjs_zoom.js @@ -28,7 +28,6 @@ const TESTS = [ { action: { keyboard: true, - keyCode: 61, event: "+" }, expectedZoom: 1, // 1 - zoom in @@ -38,7 +37,6 @@ const TESTS = [ { action: { keyboard: true, - keyCode: 109, event: "-" }, expectedZoom: -1, // -1 - zoom out @@ -56,7 +54,11 @@ const TESTS = [ } ]; -add_task(function* test() { +var initialWidth; // the initial width of the PDF document +var previousWidth; // the width of the PDF document at previous step/test + +function test() { + var tab; let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"] .getService(Ci.nsIHandlerService); let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); @@ -70,101 +72,104 @@ add_task(function* test() { info('Pref action: ' + handlerInfo.preferredAction); - yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" }, - function* (newTabBrowser) { - let initialWidth = 0; // the initial width of the PDF document - let previousWidth = 0; // the width of the PDF document at previous step/test + waitForExplicitFinish(); + registerCleanupFunction(function() { + gBrowser.removeTab(tab); + }); - initialWidth = previousWidth = - yield ContentTask.spawn(newTabBrowser, null, function* () { - // Runs tests after all 'load' event handlers have fired off - return yield new Promise((resolve) => { - content.addEventListener("documentload", function loaded() { - content.removeEventListener("documentload", loaded); - resolve(parseInt(content.document.querySelector("div#pageContainer1").style.width)); - }, false, true); - }); - }); + tab = gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + var newTabBrowser = gBrowser.getBrowserForTab(tab); - // Basic tests. - let [ viewer, pdfjs ] = yield ContentTask.spawn(newTabBrowser, null, function* () { - // check that PDF is opened with internal viewer - return [ content.document.querySelector('div#viewer') !== null, - 'PDFJS' in content.wrappedJSObject ]; - }); + newTabBrowser.addEventListener("load", function eventHandler() { + newTabBrowser.removeEventListener("load", eventHandler, true); - ok(viewer, "document content has viewer UI"); - ok(pdfjs, "window content has PDFJS object"); + var document = newTabBrowser.contentDocument, + window = newTabBrowser.contentWindow; - for (let test of TESTS) { - yield ContentTask.spawn(newTabBrowser, test, function* (test) { - let document = content.document; + // Runs tests after all 'load' event handlers have fired off + window.addEventListener("documentload", function() { + initialWidth = parseInt(document.querySelector("div#pageContainer1").style.width); + previousWidth = initialWidth; + runTests(document, window, finish); + }, false, true); + }, true); +} - function waitForRender() { - return new Promise((resolve) => { - document.addEventListener("pagerendered", function onPageRendered(e) { - if(e.detail.pageNumber !== 1) { - return; - } +function runTests(document, window, callback) { + // check that PDF is opened with internal viewer + ok(document.querySelector('div#viewer'), "document content has viewer UI"); + ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); - document.removeEventListener("pagerendered", onPageRendered, true); - resolve(); - }, true); - }); - } + // Start the zooming tests after the document is loaded + waitForDocumentLoad(document).then(function () { + zoomPDF(document, window, TESTS.shift(), finish); + }); +} - // We zoom using an UI element - var ev; - if (test.action.selector) { - // Get the element and trigger the action for changing the zoom - var el = document.querySelector(test.action.selector); +function waitForDocumentLoad(document) { + var deferred = Promise.defer(); + var interval = setInterval(function () { + if (document.querySelector("div#pageContainer1") != null){ + clearInterval(interval); + deferred.resolve(); + } + }, 500); - if (test.action.index){ - el.selectedIndex = test.action.index; - } + return deferred.promise; +} - // Dispatch the event for changing the zoom - ev = new Event(test.action.event); - } - // We zoom using keyboard - else { - // Simulate key press - ev = new content.KeyboardEvent("keydown", - { key: test.action.event, - keyCode: test.action.keyCode, - ctrlKey: true }); - el = content; - } +function zoomPDF(document, window, test, endCallback) { + var renderedPage; - el.dispatchEvent(ev); - yield waitForRender(); - }); + document.addEventListener("pagerendered", function onPageRendered(e) { + if(e.detail.pageNumber !== 1) { + return; + } - if (test.action.selector) { - info("Element '" + test.action.selector + "' has been found"); - } + document.removeEventListener("pagerendered", onPageRendered, true); - let { actualWidth, zoomValue } = yield ContentTask.spawn(newTabBrowser, null, function* () { - var pageZoomScale = content.document.querySelector('select#scaleSelect'); + var pageZoomScale = document.querySelector('select#scaleSelect'); - // The zoom value displayed in the zoom select - var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML; + // The zoom value displayed in the zoom select + var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML; - let pageContainer = content.document.querySelector('div#pageContainer1'); - let actualWidth = parseInt(pageContainer.style.width); + let pageContainer = document.querySelector('div#pageContainer1'); + let actualWidth = parseInt(pageContainer.style.width); - return { actualWidth, zoomValue }; - }); + // the actual zoom of the PDF document + let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%"; + is(computedZoomValue, zoomValue, "Content has correct zoom"); - // the actual zoom of the PDF document - let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%"; - is(computedZoomValue, zoomValue, "Content has correct zoom"); + // Check that document zooms in the expected way (in/out) + let zoom = (actualWidth - previousWidth) * test.expectedZoom; + ok(zoom > 0, test.message); - // Check that document zooms in the expected way (in/out) - let zoom = (actualWidth - previousWidth) * test.expectedZoom; - ok(zoom > 0, test.message); + // Go to next test (if there is any) or finish + var nextTest = TESTS.shift(); + if (nextTest) { + previousWidth = actualWidth; + zoomPDF(document, window, nextTest, endCallback); + } + else + endCallback(); + }, true); - previousWidth = actualWidth; - } - }); -}); + // We zoom using an UI element + if (test.action.selector) { + // Get the element and trigger the action for changing the zoom + var el = document.querySelector(test.action.selector); + ok(el, "Element '" + test.action.selector + "' has been found"); + + if (test.action.index){ + el.selectedIndex = test.action.index; + } + + // Dispatch the event for changing the zoom + el.dispatchEvent(new Event(test.action.event)); + } + // We zoom using keyboard + else { + // Simulate key press + EventUtils.synthesizeKey(test.action.event, { ctrlKey: true }); + } +} diff --git a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm index 7533ffa637a8..2dcf60ad88f1 100644 --- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm +++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm @@ -321,7 +321,7 @@ this.BrowserTestUtils = { * Waits for an event to be fired on a specified element. * * Usage: - * let promiseEvent = BrowserTestUtils.waitForEvent(element, "eventName"); + * let promiseEvent = BrowserTestUtil.waitForEvent(element, "eventName"); * // Do some processing here that will cause the event to be fired * // ... * // Now yield until the Promise is fulfilled diff --git a/uriloader/exthandler/ExternalHelperAppParent.cpp b/uriloader/exthandler/ExternalHelperAppParent.cpp index 352c05bbffbd..cd5b41d80d97 100644 --- a/uriloader/exthandler/ExternalHelperAppParent.cpp +++ b/uriloader/exthandler/ExternalHelperAppParent.cpp @@ -396,9 +396,7 @@ ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset) NS_IMETHODIMP ExternalHelperAppParent::GetContentDisposition(uint32_t *aContentDisposition) { - // NB: mContentDisposition may or may not be set to a non UINT32_MAX value in - // nsExternalHelperAppService::DoContentContentProcessHelper - if (mContentDispositionHeader.IsEmpty() && mContentDisposition == UINT32_MAX) + if (mContentDispositionHeader.IsEmpty()) return NS_ERROR_NOT_AVAILABLE; *aContentDisposition = mContentDisposition; From f8fad054ff9bd75cb9a23ffc1a0263eb0afdca67 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 13 Oct 2015 22:06:10 -0700 Subject: [PATCH 79/79] Bug 1214488 - Allow native callers in GetEntryGlobal. r=me --- dom/base/ScriptSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index 98bd8a1860f4..88e8a523269a 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -175,7 +175,7 @@ ClampToSubject(nsIGlobalObject* aGlobalOrNull) nsIPrincipal* globalPrin = aGlobalOrNull->PrincipalOrNull(); NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal()); - if (!nsContentUtils::SubjectPrincipal()->SubsumesConsideringDomain(globalPrin)) { + if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->SubsumesConsideringDomain(globalPrin)) { return GetCurrentGlobal(); }