diff --git a/b2g/chrome/content/devtools.js b/b2g/chrome/content/devtools.js
index 862f27417352..e2b5ab5e5e21 100644
--- a/b2g/chrome/content/devtools.js
+++ b/b2g/chrome/content/devtools.js
@@ -7,7 +7,7 @@
const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD';
XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
- const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+ const {devtools} = Cu.import('resource://gre/modules/devtools/Loader.jsm', {});
return devtools;
});
@@ -16,15 +16,15 @@ XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() {
});
XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() {
- return devtools.require("devtools/toolkit/webconsole/utils").Utils;
+ return devtools.require('devtools/toolkit/webconsole/utils').Utils;
});
XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
- return devtools.require("devtools/server/actors/eventlooplag").EventLoopLagFront;
+ return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
});
XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
- return devtools.require("devtools/server/actors/memory").MemoryFront;
+ return devtools.require('devtools/server/actors/memory').MemoryFront;
});
@@ -47,7 +47,7 @@ let developerHUD = {
* on app frames that are being tracked. A watcher must implement the
* `trackTarget(target)` and `untrackTarget(target)` methods, register
* observed metrics with `target.register(metric)`, and keep them up-to-date
- * with `target.update(metric, value, message)` when necessary.
+ * with `target.update(metric, message)` when necessary.
*/
registerWatcher: function dwp_registerWatcher(watcher) {
this._watchers.unshift(watcher);
@@ -210,15 +210,24 @@ Target.prototype = {
* Modify one of a target's metrics, and send out an event to notify relevant
* parties (e.g. the developer HUD, automated tests, etc).
*/
- update: function target_update(metric, value = 0, message) {
+ update: function target_update(metric, message) {
+ if (!metric.name) {
+ throw new Error('Missing metric.name');
+ }
+
+ if (!metric.value) {
+ metric.value = 0;
+ }
+
let metrics = this.metrics;
- metrics.set(metric, value);
+ if (metrics) {
+ metrics.set(metric.name, metric.value);
+ }
let data = {
metrics: [], // FIXME(Bug 982066) Remove this field.
manifest: this.frame.appManifestURL,
metric: metric,
- value: value,
message: message
};
@@ -240,7 +249,8 @@ Target.prototype = {
* to be incremented.
*/
bump: function target_bump(metric, message) {
- this.update(metric, this.metrics.get(metric) + 1, message);
+ metric.value = (this.metrics.get(metric.name) || 0) + 1;
+ this.update(metric, message);
},
/**
@@ -248,7 +258,8 @@ Target.prototype = {
* anymore.
*/
clear: function target_clear(metric) {
- this.update(metric, 0);
+ metric.value = 0;
+ this.update(metric);
},
/**
@@ -307,7 +318,7 @@ let consoleWatcher = {
// If unwatched, remove any existing widgets for that metric.
for (let target of this._targets.values()) {
- target.clear(metric);
+ target.clear({name: metric});
}
});
}
@@ -345,7 +356,7 @@ let consoleWatcher = {
consoleListener: function cw_consoleListener(type, packet) {
let target = this._targets.get(packet.from);
- let metric;
+ let metric = {};
let output = '';
switch (packet.type) {
@@ -354,15 +365,15 @@ let consoleWatcher = {
let pageError = packet.pageError;
if (pageError.warning || pageError.strict) {
- metric = 'warnings';
+ metric.name = 'warnings';
output += 'warning (';
} else {
- metric = 'errors';
+ metric.name = 'errors';
output += 'error (';
}
if (this._security.indexOf(pageError.category) > -1) {
- metric = 'security';
+ metric.name = 'security';
}
let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError;
@@ -374,12 +385,12 @@ let consoleWatcher = {
switch (packet.message.level) {
case 'error':
- metric = 'errors';
+ metric.name = 'errors';
output += 'error (console)';
break;
case 'warn':
- metric = 'warnings';
+ metric.name = 'warnings';
output += 'warning (console)';
break;
@@ -389,18 +400,22 @@ let consoleWatcher = {
break;
case 'reflowActivity':
- metric = 'reflows';
+ metric.name = 'reflows';
- let {start, end, sourceURL} = packet;
+ let {start, end, sourceURL, interruptible} = packet;
+ metric.interruptible = interruptible;
let duration = Math.round((end - start) * 100) / 100;
output += 'reflow: ' + duration + 'ms';
if (sourceURL) {
output += ' ' + this.formatSourceURL(packet);
}
break;
+
+ default:
+ return;
}
- if (!this._watching[metric]) {
+ if (!this._watching[metric.name]) {
return;
}
@@ -446,7 +461,7 @@ let eventLoopLagWatcher = {
fronts.get(target).start();
} else {
fronts.get(target).stop();
- target.clear('jank');
+ target.clear({name: 'jank'});
}
}
},
@@ -458,7 +473,7 @@ let eventLoopLagWatcher = {
this._fronts.set(target, front);
front.on('event-loop-lag', time => {
- target.update('jank', time, 'jank: ' + time + 'ms');
+ target.update({name: 'jank', value: time}, 'jank: ' + time + 'ms');
});
if (this._active) {
@@ -514,7 +529,7 @@ let memoryWatcher = {
} else {
for (let target of this._fronts.keys()) {
clearTimeout(this._timers.get(target));
- target.clear('memory');
+ target.clear({name: 'memory'});
}
}
});
@@ -550,7 +565,7 @@ let memoryWatcher = {
}
// TODO Also count images size (bug #976007).
- target.update('memory', total);
+ target.update({name: 'memory', value: total});
let duration = parseInt(data.jsMilliseconds) + parseInt(data.nonJSMilliseconds);
let timer = setTimeout(() => this.measure(target), 100 * duration);
this._timers.set(target, timer);
diff --git a/browser/base/content/aboutaccounts/fonts.css b/browser/base/content/aboutaccounts/fonts.css
index 07bef17e1789..df9da3ad9066 100644
--- a/browser/base/content/aboutaccounts/fonts.css
+++ b/browser/base/content/aboutaccounts/fonts.css
@@ -4,7 +4,7 @@
font-weight: 400;
src: local('Fira Sans'),
local('FiraSans'),
- url('fonts/firasans-regular.woff') format('woff');
+ url('../fonts/FiraSans-Regular.woff') format('woff');
}
@font-face {
font-family: 'Fira Sans';
@@ -12,7 +12,7 @@
font-weight: 300;
src: local('Fira Sans Light'),
local('FiraSansLight'),
- url('fonts/firasans-light.woff') format('woff');
+ url('../fonts/FiraSans-Light.woff') format('woff');
}
@font-face {
font-family: 'Clear Sans';
@@ -20,6 +20,5 @@
font-weight: 400;
src: local('Clear Sans'),
local('ClearSans'),
- url('fonts/clearsans-regular.woff') format('woff');
+ url('../fonts/ClearSans-Regular.woff') format('woff');
}
-
diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index e8a59e975133..bcc5e179deed 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -63,6 +63,10 @@ var StarUI = {
if (!this._element("editBookmarkPanelContent").hidden)
this.quitEditMode();
+ if (this._anchorToolbarButton) {
+ this._anchorToolbarButton.removeAttribute("open");
+ this._anchorToolbarButton = null;
+ }
this._restoreCommandsState();
this._itemId = -1;
if (this._batching) {
@@ -186,6 +190,21 @@ var StarUI = {
this._itemId = aItemId !== undefined ? aItemId : this._itemId;
this.beginBatch();
+ if (aAnchorElement) {
+ // Set the open=true attribute if the anchor is a
+ // descendent of a toolbarbutton.
+ let parent = aAnchorElement.parentNode;
+ while (parent) {
+ if (parent.localName == "toolbarbutton") {
+ break;
+ }
+ parent = parent.parentNode;
+ }
+ if (parent) {
+ this._anchorToolbarButton = parent;
+ parent.setAttribute("open", "true");
+ }
+ }
this.panel.openPopup(aAnchorElement, aPosition);
gEditItemOverlay.initPanel(this._itemId,
diff --git a/browser/base/content/browser-syncui.js b/browser/base/content/browser-syncui.js
index a7954e872dae..9d55cd6f0c2c 100644
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -237,10 +237,6 @@ let gSyncUI = {
},
_getAppName: function () {
- try {
- let syncStrings = new StringBundle("chrome://browser/locale/sync.properties");
- return syncStrings.getFormattedString("sync.defaultAccountApplication", [brandName]);
- } catch (ex) {}
let brand = new StringBundle("chrome://branding/locale/brand.properties");
return brand.get("brandShortName");
},
diff --git a/browser/base/content/aboutaccounts/fonts/clearsans-regular.woff b/browser/base/content/fonts/ClearSans-Regular.woff
similarity index 100%
rename from browser/base/content/aboutaccounts/fonts/clearsans-regular.woff
rename to browser/base/content/fonts/ClearSans-Regular.woff
diff --git a/browser/base/content/aboutaccounts/fonts/firasans-light.woff b/browser/base/content/fonts/FiraSans-Light.woff
similarity index 100%
rename from browser/base/content/aboutaccounts/fonts/firasans-light.woff
rename to browser/base/content/fonts/FiraSans-Light.woff
diff --git a/browser/base/content/aboutaccounts/fonts/firasans-regular.woff b/browser/base/content/fonts/FiraSans-Regular.woff
similarity index 100%
rename from browser/base/content/aboutaccounts/fonts/firasans-regular.woff
rename to browser/base/content/fonts/FiraSans-Regular.woff
diff --git a/browser/base/jar.mn b/browser/base/jar.mn
index 61ac60625e33..026cadcb5d64 100644
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -56,9 +56,6 @@ browser.jar:
content/browser/aboutaccounts/main.css (content/aboutaccounts/main.css)
content/browser/aboutaccounts/normalize.css (content/aboutaccounts/normalize.css)
content/browser/aboutaccounts/fonts.css (content/aboutaccounts/fonts.css)
- content/browser/aboutaccounts/fonts/clearsans-regular.woff (content/aboutaccounts/fonts/clearsans-regular.woff)
- content/browser/aboutaccounts/fonts/firasans-light.woff (content/aboutaccounts/fonts/firasans-light.woff)
- content/browser/aboutaccounts/fonts/firasans-regular.woff (content/aboutaccounts/fonts/firasans-regular.woff)
content/browser/aboutaccounts/images/fox.png (content/aboutaccounts/images/fox.png)
content/browser/aboutaccounts/images/graphic_sync_intro.png (content/aboutaccounts/images/graphic_sync_intro.png)
content/browser/aboutaccounts/images/graphic_sync_intro@2x.png (content/aboutaccounts/images/graphic_sync_intro@2x.png)
@@ -77,6 +74,9 @@ browser.jar:
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
* content/browser/chatWindow.xul (content/chatWindow.xul)
content/browser/content.js (content/content.js)
+ content/browser/fonts/ClearSans-Regular.woff (content/fonts/ClearSans-Regular.woff)
+ content/browser/fonts/FiraSans-Regular.woff (content/fonts/FiraSans-Regular.woff)
+ content/browser/fonts/FiraSans-Light.woff (content/fonts/FiraSans-Light.woff)
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
diff --git a/browser/components/customizableui/src/CustomizableUI.jsm b/browser/components/customizableui/src/CustomizableUI.jsm
index 01c12ddcf985..61b8b4c6b905 100644
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -297,11 +297,12 @@ let CustomizableUIInternal = {
let areaIsKnown = gAreas.has(aName);
let props = areaIsKnown ? gAreas.get(aName) : new Map();
- if (areaIsKnown && aProperties["type"] &&
- props.get("type") != aProperties["type"]) {
- throw new Error("An area cannot change types");
- }
+ const kImmutableProperties = new Set(["type", "legacy", "overflowable"]);
for (let key in aProperties) {
+ if (areaIsKnown && kImmutableProperties.has(key) &&
+ props.get(key) != aProperties[key]) {
+ throw new Error("An area cannot change the property for '" + key + "'");
+ }
//XXXgijs for special items, we need to make sure they have an appropriate ID
// so we aren't perpetually in a non-default state:
if (key == "defaultPlacements" && Array.isArray(aProperties[key])) {
@@ -3458,8 +3459,8 @@ function WidgetSingleWrapper(aWidget, aNode) {
this[prop] = aWidget[prop];
}
- const nodeProps = ["label", "tooltiptext"];
- for (let prop of nodeProps) {
+ const kNodeProps = ["label", "tooltiptext"];
+ for (let prop of kNodeProps) {
let propertyName = prop;
// Look at the node for these, instead of the widget data, to ensure the
// wrapper always reflects this live instance.
diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini
index 900fef499337..f3bbfd204fea 100644
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -105,6 +105,6 @@ skip-if = os == "linux"
[browser_992747_toggle_noncustomizable_toolbar.js]
[browser_993322_widget_notoolbar.js]
[browser_995164_registerArea_during_customize_mode.js]
-[browser_996364_defaultCollapsed.js]
+[browser_996364_registerArea_different_properties.js]
[browser_bootstrapped_custom_toolbar.js]
[browser_panel_toggle.js]
diff --git a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
index f10f8fd17ea4..04b2896a6ecb 100644
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -58,7 +58,19 @@ add_task(function*() {
let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
otherTB.id = TOOLBARID;
otherTB.setAttribute("customizable", "true");
+ let wasInformedCorrectlyOfAreaAppearing = false;
+ let listener = {
+ onAreaNodeRegistered: function(aArea, aNode) {
+ if (aNode == otherTB) {
+ wasInformedCorrectlyOfAreaAppearing = true;
+ }
+ }
+ };
+ CustomizableUI.addListener(listener);
otherWin.gNavToolbox.appendChild(otherTB);
+ ok(wasInformedCorrectlyOfAreaAppearing, "Should have been told area was registered.");
+ CustomizableUI.removeListener(listener);
+
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
simulateItemDrag(syncButton, gNavToolbox.palette);
@@ -73,18 +85,25 @@ add_task(function*() {
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
let wasInformedCorrectlyOfAreaDisappearing = false;
- let listener = {
+ let windowClosed = null;
+ listener = {
onAreaNodeUnregistered: function(aArea, aNode, aReason) {
if (aArea == TOOLBARID) {
is(aNode, otherTB, "Should be informed about other toolbar");
is(aReason, CustomizableUI.REASON_WINDOW_CLOSED, "Reason should be correct.");
wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_WINDOW_CLOSED);
}
- }
+ },
+ onWindowClosed: function(aWindow) {
+ if (aWindow == otherWin) {
+ windowClosed = aWindow;
+ }
+ },
};
CustomizableUI.addListener(listener);
yield promiseWindowClosed(otherWin);
+ is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
CustomizableUI.removeListener(listener);
// Closing the other window should not be counted against this window's customize mode:
diff --git a/browser/components/customizableui/test/browser_996364_defaultCollapsed.js b/browser/components/customizableui/test/browser_996364_defaultCollapsed.js
deleted file mode 100644
index 95ada210f57a..000000000000
--- a/browser/components/customizableui/test/browser_996364_defaultCollapsed.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Calling CustomizableUI.registerArea twice with no
-// properties should not throw an exception.
-add_task(function() {
- try {
- CustomizableUI.registerArea("area-996364", {});
- CustomizableUI.registerArea("area-996364", {});
- } catch (ex) {
- ok(false, ex.message);
- }
-
- CustomizableUI.unregisterArea("area-996364", true);
-});
-
-add_task(function() {
- let exceptionThrown = false;
- try {
- CustomizableUI.registerArea("area-996364-2", {"type": CustomizableUI.TYPE_TOOLBAR, "defaultCollapsed": "false"});
- } catch (ex) {
- exceptionThrown = true;
- }
- ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
-
- // No need to unregister the area because registration fails.
-});
-
-add_task(function() {
- let exceptionThrown;
- try {
- CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_TOOLBAR});
- CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_MENU_PANEL});
- } catch (ex) {
- exceptionThrown = ex;
- }
- ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-
- CustomizableUI.unregisterArea("area-996364-3", true);
-});
-
-add_task(function() {
- let exceptionThrown;
- try {
- CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_MENU_PANEL});
- CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_TOOLBAR});
- } catch (ex) {
- exceptionThrown = ex;
- }
- ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-
- CustomizableUI.unregisterArea("area-996364-4", true);
-});
diff --git a/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
new file mode 100644
index 000000000000..7444b65a327d
--- /dev/null
+++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
@@ -0,0 +1,112 @@
+/* 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";
+
+// Calling CustomizableUI.registerArea twice with no
+// properties should not throw an exception.
+add_task(function() {
+ try {
+ CustomizableUI.registerArea("area-996364", {});
+ CustomizableUI.registerArea("area-996364", {});
+ } catch (ex) {
+ ok(false, ex.message);
+ }
+
+ CustomizableUI.unregisterArea("area-996364", true);
+});
+
+add_task(function() {
+ let exceptionThrown = false;
+ try {
+ CustomizableUI.registerArea("area-996364-2", {type: CustomizableUI.TYPE_TOOLBAR, defaultCollapsed: "false"});
+ } catch (ex) {
+ exceptionThrown = true;
+ }
+ ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
+
+ // No need to unregister the area because registration fails.
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_TOOLBAR});
+ CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_MENU_PANEL});
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+ CustomizableUI.unregisterArea("area-996364-3", true);
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_MENU_PANEL});
+ CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_TOOLBAR});
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+ CustomizableUI.unregisterArea("area-996364-4", true);
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996899-1", { anchor: "PanelUI-menu-button",
+ type: CustomizableUI.TYPE_MENU_PANEL,
+ defaultPlacements: [] });
+ CustomizableUI.registerArea("area-996899-1", { anchor: "home-button",
+ type: CustomizableUI.TYPE_MENU_PANEL,
+ defaultPlacements: [] });
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(!exceptionThrown, "Changing anchors shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+ CustomizableUI.unregisterArea("area-996899-1", true);
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+ type: CustomizableUI.TYPE_MENU_PANEL,
+ defaultPlacements: [] });
+ CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+ type: CustomizableUI.TYPE_MENU_PANEL,
+ defaultPlacements: ["feed-button"] });
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+ CustomizableUI.unregisterArea("area-996899-2", true);
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996899-3", { legacy: true });
+ CustomizableUI.registerArea("area-996899-3", { legacy: false });
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+ CustomizableUI.unregisterArea("area-996899-3", true);
+});
+
+add_task(function() {
+ let exceptionThrown;
+ try {
+ CustomizableUI.registerArea("area-996899-4", { overflowable: true });
+ CustomizableUI.registerArea("area-996899-4", { overflowable: false });
+ } catch (ex) {
+ exceptionThrown = ex;
+ }
+ ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+ CustomizableUI.unregisterArea("area-996899-4", true);
+});
diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm
index b7bf3519f549..9fb38addf13a 100644
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -678,8 +678,6 @@ let SessionStoreInternal = {
debug("received unknown message '" + aMessage.name + "'");
break;
}
-
- this._clearRestoringWindows();
},
/**
@@ -3400,6 +3398,15 @@ let SessionStoreInternal = {
this._closedWindows.splice(spliceTo, this._closedWindows.length);
},
+ /**
+ * Clears the set of windows that are "resurrected" before writing to disk to
+ * make closing windows one after the other until shutdown work as expected.
+ *
+ * This function should only be called when we are sure that there has been
+ * a user action that indicates the browser is actively being used and all
+ * windows that have been closed before are not part of a series of closing
+ * windows.
+ */
_clearRestoringWindows: function ssi_clearRestoringWindows() {
for (let i = 0; i < this._closedWindows.length; i++) {
delete this._closedWindows[i]._shouldRestore;
diff --git a/browser/components/sessionstore/test/browser_819510_perwindowpb.js b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
index fc4e93a0003d..562c5aed9f37 100644
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -115,25 +115,27 @@ function test_3() {
is(curState.selectedWindow, 4, "Last window opened is the one selected");
waitForWindowClose(normalWindow, function() {
- // Load another tab before checking the written state so that
+ // Pin and unpin a tab before checking the written state so that
// the list of restoring windows gets cleared. Otherwise the
// window we just closed would be marked as not closed.
- waitForTabLoad(aWindow, "http://www.example.com/", function() {
- forceWriteState(function(state) {
- is(state.windows.length, 2,
- "sessionstore state: 2 windows in data being written to disk");
- is(state.selectedWindow, 2,
- "Selected window is updated to match one of the saved windows");
- state.windows.forEach(function(win) {
- is(!win.isPrivate, true, "Saved window is not private");
- });
- is(state._closedWindows.length, 1,
- "sessionstore state: 1 closed window in data being written to disk");
- state._closedWindows.forEach(function(win) {
- is(!win.isPrivate, true, "Closed window is not private");
- });
- runNextTest();
+ let tab = aWindow.gBrowser.tabs[0];
+ aWindow.gBrowser.pinTab(tab);
+ aWindow.gBrowser.unpinTab(tab);
+
+ forceWriteState(function(state) {
+ is(state.windows.length, 2,
+ "sessionstore state: 2 windows in data being written to disk");
+ is(state.selectedWindow, 2,
+ "Selected window is updated to match one of the saved windows");
+ state.windows.forEach(function(win) {
+ is(!win.isPrivate, true, "Saved window is not private");
});
+ is(state._closedWindows.length, 1,
+ "sessionstore state: 1 closed window in data being written to disk");
+ state._closedWindows.forEach(function(win) {
+ is(!win.isPrivate, true, "Closed window is not private");
+ });
+ runNextTest();
});
});
});
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest
new file mode 100644
index 000000000000..ccb88ddf1410
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest
@@ -0,0 +1 @@
+content browser_dbg_addon4 .
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul
new file mode 100644
index 000000000000..733817ad81ea
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul
new file mode 100644
index 000000000000..372d0558768d
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul.js b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul.js
new file mode 100644
index 000000000000..7ac4eabc7882
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+ window.foo = "bar";
+});
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul2.js b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul2.js
new file mode 100644
index 000000000000..7ac4eabc7882
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+ window.foo = "bar";
+});
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest
new file mode 100644
index 000000000000..ceef8d06d5d6
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest
@@ -0,0 +1 @@
+content browser_dbg_addon5 .
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul
new file mode 100644
index 000000000000..733817ad81ea
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul
new file mode 100644
index 000000000000..372d0558768d
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul.js b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul.js
new file mode 100644
index 000000000000..7ac4eabc7882
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+ window.foo = "bar";
+});
diff --git a/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul2.js b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul2.js
new file mode 100644
index 000000000000..7ac4eabc7882
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+ window.foo = "bar";
+});
diff --git a/browser/devtools/debugger/test/addon4.xpi b/browser/devtools/debugger/test/addon4.xpi
index a654b7e011b0..31c5331b69de 100644
Binary files a/browser/devtools/debugger/test/addon4.xpi and b/browser/devtools/debugger/test/addon4.xpi differ
diff --git a/browser/devtools/debugger/test/addon5.xpi b/browser/devtools/debugger/test/addon5.xpi
index 2c18f6da1917..16991f7a06ae 100644
Binary files a/browser/devtools/debugger/test/addon5.xpi and b/browser/devtools/debugger/test/addon5.xpi differ
diff --git a/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js b/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
index 4e9d724ccc6a..382f56c4a913 100644
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
@@ -8,6 +8,8 @@ const ADDON_URL = EXAMPLE_URL + "addon5.xpi";
function test() {
Task.spawn(function () {
let addon = yield addAddon(ADDON_URL);
+ let tab1 = yield addTab("chrome://browser_dbg_addon5/content/test.xul");
+
let addonDebugger = yield initAddonDebugger(ADDON_URL);
is(addonDebugger.title, "Debugger - Test unpacked add-on with JS Modules", "Saw the right toolbox title.");
@@ -15,33 +17,44 @@ function test() {
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
- is(groups.length, 1, "Should be only one group.");
+ is(groups[1].name, "chrome://global", "XUL code should be the second group");
+ is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
- is(sources.length, 2, "Should be two sources");
- ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
- is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
- is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
- is(sources[1].label, "test.jsm", "correct label for addon code")
-
- // Load a new module and check it appears in the list of sources
- Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
-
- groups = yield addonDebugger.getSourceGroups();
- is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
- is(groups.length, 1, "Should be only one group.");
-
- sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
is(sources[1].label, "test.jsm", "correct label for addon code")
- is(sources[2].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
- is(sources[2].label, "test2.jsm", "correct label for addon code")
+ is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+ is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+ // Load a new module and tab and check they appear in the list of sources
+ Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
+ let tab2 = yield addTab("chrome://browser_dbg_addon5/content/test2.xul");
+
+ groups = yield addonDebugger.getSourceGroups();
+ is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
+ is(groups[1].name, "chrome://global", "XUL code should be the second group");
+ is(groups.length, 2, "Should be only two groups.");
+
+ sources = groups[0].sources;
+ is(sources.length, 5, "Should be five sources");
+ ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
+ is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+ is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
+ is(sources[1].label, "test.jsm", "correct label for addon code")
+ is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+ is(sources[2].label, "testxul.js", "correct label for addon tab code")
+ is(sources[3].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
+ is(sources[3].label, "test2.jsm", "correct label for addon code")
+ is(sources[4].url, "chrome://browser_dbg_addon5/content/testxul2.js", "correct url for addon tab code")
+ is(sources[4].label, "testxul2.js", "correct label for addon tab code")
Cu.unload("resource://browser_dbg_addon5/test2.jsm");
yield addonDebugger.destroy();
+ yield removeTab(tab1);
+ yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
diff --git a/browser/devtools/debugger/test/browser_dbg_addon-modules.js b/browser/devtools/debugger/test/browser_dbg_addon-modules.js
index 29cea2beca50..1f4ae393d79c 100644
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules.js
@@ -8,6 +8,8 @@ const ADDON_URL = EXAMPLE_URL + "addon4.xpi";
function test() {
Task.spawn(function () {
let addon = yield addAddon(ADDON_URL);
+ let tab1 = yield addTab("chrome://browser_dbg_addon4/content/test.xul");
+
let addonDebugger = yield initAddonDebugger(ADDON_URL);
is(addonDebugger.title, "Debugger - Test add-on with JS Modules", "Saw the right toolbox title.");
@@ -15,33 +17,44 @@ function test() {
// Check the inital list of sources is correct
let groups = yield addonDebugger.getSourceGroups();
is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
- is(groups.length, 1, "Should be only one group.");
+ is(groups[1].name, "chrome://global", "XUL code should be the second group");
+ is(groups.length, 2, "Should be only two groups.");
let sources = groups[0].sources;
- is(sources.length, 2, "Should be two sources");
- ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
- is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
- is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
- is(sources[1].label, "test.jsm", "correct label for addon code")
-
- // Load a new module and check it appears in the list of sources
- Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
-
- groups = yield addonDebugger.getSourceGroups();
- is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
- is(groups.length, 1, "Should be only one group.");
-
- sources = groups[0].sources;
is(sources.length, 3, "Should be three sources");
ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
is(sources[1].label, "test.jsm", "correct label for addon code")
- is(sources[2].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
- is(sources[2].label, "test2.jsm", "correct label for addon code")
+ is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+ is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+ // Load a new module and tab and check they appear in the list of sources
+ Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
+ let tab2 = yield addTab("chrome://browser_dbg_addon4/content/test2.xul");
+
+ groups = yield addonDebugger.getSourceGroups();
+ is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
+ is(groups[1].name, "chrome://global", "XUL code should be the second group");
+ is(groups.length, 2, "Should be only two groups.");
+
+ sources = groups[0].sources;
+ is(sources.length, 5, "Should be five sources");
+ ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
+ is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+ is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
+ is(sources[1].label, "test.jsm", "correct label for addon code")
+ is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+ is(sources[2].label, "testxul.js", "correct label for addon tab code")
+ is(sources[3].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
+ is(sources[3].label, "test2.jsm", "correct label for addon code")
+ is(sources[4].url, "chrome://browser_dbg_addon4/content/testxul2.js", "correct url for addon tab code")
+ is(sources[4].label, "testxul2.js", "correct label for addon tab code")
Cu.unload("resource://browser_dbg_addon4/test2.jsm");
yield addonDebugger.destroy();
+ yield removeTab(tab1);
+ yield removeTab(tab2);
yield removeAddon(addon);
finish();
});
diff --git a/browser/devtools/debugger/test/head.js b/browser/devtools/debugger/test/head.js
index 4ded0886290a..b8e83ea6326b 100644
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -118,7 +118,11 @@ function addAddon(aUrl) {
let listener = {
onInstallEnded: function(aAddon, aAddonInstall) {
aInstaller.removeListener(listener);
- deferred.resolve(aAddonInstall);
+
+ // Wait for add-on's startup scripts to execute. See bug 997408
+ executeSoon(function() {
+ deferred.resolve(aAddonInstall);
+ });
}
};
aInstaller.addListener(listener);
diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css
index 76cce35181ab..9b28c5654560 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -613,6 +613,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-padding-end: 5px;
}
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container > .toolbarbutton-icon,
@@ -631,7 +632,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
margin-bottom: 4px;
}
-:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container > .toolbarbutton-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
@@ -648,6 +649,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
transition: background-color 150ms;
}
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button[open],
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:hover:active,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover:active {
padding: 3px;
diff --git a/browser/themes/linux/devtools/ruleview.css b/browser/themes/linux/devtools/ruleview.css
deleted file mode 100644
index 102f48f0d02a..000000000000
--- a/browser/themes/linux/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.ruleview {
- height: 100%;
-}
-
-.ruleview-rule-source {
- -moz-padding-start: 5px;
- cursor: pointer;
- text-align: right;
- float: right;
- -moz-user-select: none;
-}
-
-.ruleview-header {
- border-top-width: 1px;
- border-bottom-width: 1px;
- border-top-style: solid;
- border-bottom-style: solid;
- padding: 1px 4px;
- margin-top: 4px;
- -moz-user-select: none;
- word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
- text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
- padding: 2px 4px;
-}
-
-#noResults {
- font: message-box;
- color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
- border-top-width: 1px;
- border-top-style: dotted;
-}
-
-.ruleview-warning {
- background: url("chrome://browser/skin/devtools/alerticon-warning.png");
- -moz-margin-start: 5px;
- display: inline-block;
- vertical-align: top;
- width: 13px;
- height: 12px;
-}
-
-.ruleview-ruleopen {
- -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
- cursor: text;
- padding-right: 20px;
-}
-
-.ruleview-propertylist {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
- visibility: hidden;
-}
-
-.ruleview-expander {
- display: inline-block;
-}
-
-.ruleview-newproperty {
- /* (enable checkbox width: 12px) + (expander width: 15px) */
- -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
- text-decoration: inherit;
-}
-
-.ruleview-computedlist {
- list-style: none;
- padding: 0;
-}
-
-.ruleview-computed {
- -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
- border-radius: 50%;
- width: 1em;
- height: 1em;
- vertical-align: text-top;
- -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
- text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
- -moz-text-decoration-color: #667380; /* Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
- border: 1px solid #CCC;
- padding: 0;
-}
-
-.ruleview-property {
- border-left: 2px solid transparent;
- clear: right;
-}
-
-.ruleview-property > * {
- vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
- border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
- border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
- border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
- word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
- color: #888;
-}
diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn
index 094729462553..7d4f63028094 100644
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -105,7 +105,6 @@ browser.jar:
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
- skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
@@ -201,7 +200,7 @@ browser.jar:
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
- skin/classic/browser/devtools/ruleview.css (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index ce578014748c..88be0b72fa44 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -512,6 +512,7 @@ toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forwar
}
toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker,
toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button,
toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker,
toolbar .toolbaritem-combined-buttons:hover > .toolbarbutton-combined {
@@ -527,6 +528,7 @@ toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[bu
}
toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],#back-button,#forward-button)):-moz-any(:hover:active,[open],[checked]),
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open],
toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover]:active > .toolbarbutton-menubutton-button,
toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover:active > .toolbarbutton-menubutton-dropmarker,
toolbar .toolbarbutton-1[type="menu-button"][open]:not([disabled]) > .toolbarbutton-menubutton-dropmarker {
diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn
index e59620da004a..18a53dc4dabc 100644
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -169,7 +169,6 @@ browser.jar:
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
- skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (newtab/controls@2x.png)
@@ -322,7 +321,7 @@ browser.jar:
skin/classic/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
- skin/classic/browser/devtools/ruleview.css (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
skin/classic/browser/devtools/editor-error.png (devtools/editor-error.png)
diff --git a/browser/themes/shared/ClearSans-Regular.ttf b/browser/themes/shared/ClearSans-Regular.ttf
deleted file mode 100644
index fe686f8d2a13..000000000000
Binary files a/browser/themes/shared/ClearSans-Regular.ttf and /dev/null differ
diff --git a/browser/themes/osx/devtools/ruleview.css b/browser/themes/shared/devtools/ruleview.css
similarity index 91%
rename from browser/themes/osx/devtools/ruleview.css
rename to browser/themes/shared/devtools/ruleview.css
index 895e984e1ebe..2ca54f555714 100644
--- a/browser/themes/osx/devtools/ruleview.css
+++ b/browser/themes/shared/devtools/ruleview.css
@@ -22,6 +22,9 @@
padding: 1px 4px;
-moz-user-select: none;
word-wrap: break-word;
+%ifndef XP_MACOSX
+ margin-top: 4px;
+%endif
}
.ruleview-rule-pseudo-element {
@@ -123,7 +126,7 @@
}
.ruleview-property {
- border-left: 2px solid transparent;
+ border-left: 3px solid transparent;
clear: right;
}
@@ -131,8 +134,12 @@
vertical-align: middle;
}
-.ruleview-property[dirty] {
- border-left-color: #68E268;
+.theme-dark .ruleview-property[dirty] {
+ border-left-color: #70bf53; /* Green */
+}
+
+.theme-light .ruleview-property[dirty] {
+ border-left-color: #2cbb0f; /* Green */
}
.ruleview-namecontainer > .ruleview-propertyname,
diff --git a/browser/themes/shared/incontentprefs/preferences.css b/browser/themes/shared/incontentprefs/preferences.css
index 76b18a7aaafb..79c6350c272d 100644
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -7,7 +7,7 @@
@font-face {
font-family: "Clear Sans";
- src: url("chrome://browser/skin/fonts/ClearSans-Regular.ttf");
+ src: url("chrome://browser/content/fonts/ClearSans-Regular.woff") format('woff');
}
page {
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index 08fff4b5c1d0..98c87e9347bf 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -730,6 +730,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
border-color: hsla(210,4%,10%,.1);
}
+#nav-bar .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
@@ -799,7 +800,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
}
%endif
-#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
diff --git a/browser/themes/windows/devtools/ruleview.css b/browser/themes/windows/devtools/ruleview.css
deleted file mode 100644
index 102f48f0d02a..000000000000
--- a/browser/themes/windows/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.ruleview {
- height: 100%;
-}
-
-.ruleview-rule-source {
- -moz-padding-start: 5px;
- cursor: pointer;
- text-align: right;
- float: right;
- -moz-user-select: none;
-}
-
-.ruleview-header {
- border-top-width: 1px;
- border-bottom-width: 1px;
- border-top-style: solid;
- border-bottom-style: solid;
- padding: 1px 4px;
- margin-top: 4px;
- -moz-user-select: none;
- word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
- text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
- padding: 2px 4px;
-}
-
-#noResults {
- font: message-box;
- color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
- border-top-width: 1px;
- border-top-style: dotted;
-}
-
-.ruleview-warning {
- background: url("chrome://browser/skin/devtools/alerticon-warning.png");
- -moz-margin-start: 5px;
- display: inline-block;
- vertical-align: top;
- width: 13px;
- height: 12px;
-}
-
-.ruleview-ruleopen {
- -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
- cursor: text;
- padding-right: 20px;
-}
-
-.ruleview-propertylist {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
- visibility: hidden;
-}
-
-.ruleview-expander {
- display: inline-block;
-}
-
-.ruleview-newproperty {
- /* (enable checkbox width: 12px) + (expander width: 15px) */
- -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
- text-decoration: inherit;
-}
-
-.ruleview-computedlist {
- list-style: none;
- padding: 0;
-}
-
-.ruleview-computed {
- -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
- border-radius: 50%;
- width: 1em;
- height: 1em;
- vertical-align: text-top;
- -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
- text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
- -moz-text-decoration-color: #667380; /* Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
- border: 1px solid #CCC;
- padding: 0;
-}
-
-.ruleview-property {
- border-left: 2px solid transparent;
- clear: right;
-}
-
-.ruleview-property > * {
- vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
- border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
- border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
- border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
- word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
- color: #888;
-}
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn
index 341094f980fe..12cc5f511c8d 100644
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -126,7 +126,6 @@ browser.jar:
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
- skin/classic/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/places/places.css (places/places.css)
@@ -226,7 +225,7 @@ browser.jar:
* skin/classic/browser/devtools/widgets.css (devtools/widgets.css)
skin/classic/browser/devtools/commandline-icon.png (devtools/commandline-icon.png)
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
- skin/classic/browser/devtools/ruleview.css (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/browser/devtools/command-paintflashing.png (../shared/devtools/images/command-paintflashing.png)
skin/classic/browser/devtools/command-paintflashing@2x.png (../shared/devtools/images/command-paintflashing@2x.png)
@@ -491,7 +490,6 @@ browser.jar:
skin/classic/aero/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16-aero.png)
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
- skin/classic/aero/browser/fonts/ClearSans-Regular.ttf (../shared/ClearSans-Regular.ttf)
skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/aero/browser/newtab/controls.png (../shared/newtab/controls.png)
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
@@ -602,7 +600,7 @@ browser.jar:
skin/classic/aero/browser/devtools/command-console.png (../shared/devtools/images/command-console.png)
skin/classic/aero/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/aero/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
- skin/classic/aero/browser/devtools/ruleview.css (devtools/ruleview.css)
+* skin/classic/aero/browser/devtools/ruleview.css (../shared/devtools/ruleview.css)
skin/classic/aero/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/aero/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
skin/classic/aero/browser/devtools/editor-error.png (devtools/editor-error.png)
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 24e5304f49d7..719b43bbc3e5 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -491,65 +491,7 @@ abstract public class BrowserApp extends GeckoApp
mBrowserSearch.setUserVisibleHint(false);
}
- mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
- public void onActivate() {
- enterEditingMode();
- }
- });
-
- mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
- public void onCommit() {
- commitEditingMode();
- }
- });
-
- mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
- public void onDismiss() {
- mBrowserToolbar.cancelEdit();
- }
- });
-
- mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
- public void onFilter(String searchText, AutocompleteHandler handler) {
- filterEditingMode(searchText, handler);
- }
- });
-
- mBrowserToolbar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (isHomePagerVisible()) {
- mHomePager.onToolbarFocusChange(hasFocus);
- }
- }
- });
-
- mBrowserToolbar.setOnStartEditingListener(new BrowserToolbar.OnStartEditingListener() {
- public void onStartEditing() {
- // Temporarily disable doorhanger notifications.
- mDoorHangerPopup.disable();
- }
- });
-
- mBrowserToolbar.setOnStopEditingListener(new BrowserToolbar.OnStopEditingListener() {
- public void onStopEditing() {
- selectTargetTabForEditingMode();
-
- // Since the underlying LayerView is set visible in hideHomePager, we would
- // ordinarily want to call it first. However, hideBrowserSearch changes the
- // visibility of the HomePager and hideHomePager will take no action if the
- // HomePager is hidden, so we want to call hideBrowserSearch to restore the
- // HomePager visibility first.
- hideBrowserSearch();
- hideHomePager();
-
- // Re-enable doorhanger notifications. They may trigger on the selected tab above.
- mDoorHangerPopup.enable();
- }
- });
-
- // Intercept key events for gamepad shortcuts
- mBrowserToolbar.setOnKeyListener(this);
+ setBrowserToolbarListeners();
mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
@@ -639,6 +581,68 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Prompt:ShowTop");
}
+ private void setBrowserToolbarListeners() {
+ mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
+ public void onActivate() {
+ enterEditingMode();
+ }
+ });
+
+ mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
+ public void onCommit() {
+ commitEditingMode();
+ }
+ });
+
+ mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
+ public void onDismiss() {
+ mBrowserToolbar.cancelEdit();
+ }
+ });
+
+ mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
+ public void onFilter(String searchText, AutocompleteHandler handler) {
+ filterEditingMode(searchText, handler);
+ }
+ });
+
+ mBrowserToolbar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (isHomePagerVisible()) {
+ mHomePager.onToolbarFocusChange(hasFocus);
+ }
+ }
+ });
+
+ mBrowserToolbar.setOnStartEditingListener(new BrowserToolbar.OnStartEditingListener() {
+ public void onStartEditing() {
+ // Temporarily disable doorhanger notifications.
+ mDoorHangerPopup.disable();
+ }
+ });
+
+ mBrowserToolbar.setOnStopEditingListener(new BrowserToolbar.OnStopEditingListener() {
+ public void onStopEditing() {
+ selectTargetTabForEditingMode();
+
+ // Since the underlying LayerView is set visible in hideHomePager, we would
+ // ordinarily want to call it first. However, hideBrowserSearch changes the
+ // visibility of the HomePager and hideHomePager will take no action if the
+ // HomePager is hidden, so we want to call hideBrowserSearch to restore the
+ // HomePager visibility first.
+ hideBrowserSearch();
+ hideHomePager();
+
+ // Re-enable doorhanger notifications. They may trigger on the selected tab above.
+ mDoorHangerPopup.enable();
+ }
+ });
+
+ // Intercept key events for gamepad shortcuts
+ mBrowserToolbar.setOnKeyListener(this);
+ }
+
private void showBookmarkDialog() {
final Tab tab = Tabs.getInstance().getSelectedTab();
final Prompt ps = new Prompt(this, new Prompt.PromptCallback() {
diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java
index d265e4f2e12a..ffeb465720d7 100644
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -8,16 +8,12 @@ package org.mozilla.gecko;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.Proxy;
-import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
@@ -110,7 +106,6 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.MimeTypeMap;
import android.widget.AbsoluteLayout;
-import android.widget.Toast;
public class GeckoAppShell
{
diff --git a/mobile/android/base/WebappImpl.java b/mobile/android/base/WebappImpl.java
index 4de0ad7ec863..51fd07b002e9 100644
--- a/mobile/android/base/WebappImpl.java
+++ b/mobile/android/base/WebappImpl.java
@@ -23,13 +23,13 @@ import android.view.animation.Animation;
import android.widget.ImageView;
import android.view.Display;
-import java.net.URL;
import java.io.File;
+import java.net.URI;
public class WebappImpl extends GeckoApp {
private static final String LOGTAG = "GeckoWebappImpl";
- private URL mOrigin;
+ private URI mOrigin;
private TextView mTitlebarText = null;
private View mTitlebar = null;
@@ -69,8 +69,8 @@ public class WebappImpl extends GeckoApp {
// Try to use the origin stored in the WebappAllocator first
String origin = WebappAllocator.getInstance(this).getAppForIndex(getIndex());
try {
- mOrigin = new URL(origin);
- } catch (java.net.MalformedURLException ex) {
+ mOrigin = new URI(origin);
+ } catch (java.net.URISyntaxException ex) {
// If we can't parse the this is an app protocol, just settle for not having an origin
if (!origin.startsWith("app://")) {
return;
@@ -79,8 +79,8 @@ public class WebappImpl extends GeckoApp {
// If that failed fall back to the origin stored in the shortcut
Log.i(LOGTAG, "Webapp is not registered with allocator");
try {
- mOrigin = new URL(getIntent().getData().toString());
- } catch (java.net.MalformedURLException ex2) {
+ mOrigin = new URI(getIntent().getData().toString());
+ } catch (java.net.URISyntaxException ex2) {
Log.e(LOGTAG, "Unable to parse intent url: ", ex);
}
}
@@ -164,11 +164,11 @@ public class WebappImpl extends GeckoApp {
case LOCATION_CHANGE:
if (Tabs.getInstance().isSelectedTab(tab)) {
final String urlString = tab.getURL();
- final URL url;
+ final URI uri;
try {
- url = new URL(urlString);
- } catch (java.net.MalformedURLException ex) {
+ uri = new URI(urlString);
+ } catch (java.net.URISyntaxException ex) {
mTitlebarText.setText(urlString);
// If we can't parse the url, and its an app protocol hide
@@ -182,10 +182,10 @@ public class WebappImpl extends GeckoApp {
return;
}
- if (mOrigin != null && mOrigin.getHost().equals(url.getHost())) {
+ if (mOrigin != null && mOrigin.getHost().equals(uri.getHost())) {
mTitlebar.setVisibility(View.GONE);
} else {
- mTitlebarText.setText(url.getProtocol() + "://" + url.getHost());
+ mTitlebarText.setText(uri.getScheme() + "://" + uri.getHost());
mTitlebar.setVisibility(View.VISIBLE);
}
}
diff --git a/mobile/android/base/background/nativecode/NativeCrypto.java b/mobile/android/base/background/nativecode/NativeCrypto.java
index 64b42d0409ae..a48c4862716c 100644
--- a/mobile/android/base/background/nativecode/NativeCrypto.java
+++ b/mobile/android/base/background/nativecode/NativeCrypto.java
@@ -4,14 +4,32 @@
package org.mozilla.gecko.background.nativecode;
+import java.security.GeneralSecurityException;
+
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.mozglue.RobocopTarget;
-import java.security.GeneralSecurityException;
+import android.util.Log;
@RobocopTarget
public class NativeCrypto {
static {
- System.loadLibrary("mozglue");
+ try {
+ System.loadLibrary("mozglue");
+ } catch (UnsatisfiedLinkError e) {
+ Log.wtf("NativeCrypto", "Couldn't load mozglue. Trying /data/app-lib path.");
+ try {
+ System.load("/data/app-lib/" + AppConstants.ANDROID_PACKAGE_NAME + "/libmozglue.so");
+ } catch (Throwable ee) {
+ try {
+ Log.wtf("NativeCrypto", "Couldn't load mozglue: " + ee + ". Trying /data/data path.");
+ System.load("/data/data/" + AppConstants.ANDROID_PACKAGE_NAME + "/lib/libmozglue.so");
+ } catch (UnsatisfiedLinkError eee) {
+ Log.wtf("NativeCrypto", "Failed every attempt to load mozglue. Giving up.");
+ throw new RuntimeException("Unable to load mozglue", eee);
+ }
+ }
+ }
}
/**
diff --git a/mobile/android/base/db/PasswordsProvider.java b/mobile/android/base/db/PasswordsProvider.java
index 573a284da938..1fe93c911c25 100644
--- a/mobile/android/base/db/PasswordsProvider.java
+++ b/mobile/android/base/db/PasswordsProvider.java
@@ -4,19 +4,19 @@
package org.mozilla.gecko.db;
-import java.lang.IllegalArgumentException;
import java.util.HashMap;
+
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.NSSBridge;
-import org.mozilla.gecko.db.DBUtils;
-import org.mozilla.gecko.db.BrowserContract.Passwords;
import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
-import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.db.BrowserContract.Passwords;
+import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.sqlite.MatrixBlobCursor;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.sync.Utils;
+
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
@@ -76,7 +76,10 @@ public class PasswordsProvider extends SQLiteBridgeContentProvider {
DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.ID, DeletedPasswords.ID);
DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.GUID, DeletedPasswords.GUID);
DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.TIME_DELETED, DeletedPasswords.TIME_DELETED);
- System.loadLibrary("mozglue");
+
+ // We don't use .loadMozGlue because we're in a different process,
+ // and we just want to reuse code rather than use the loader lock etc.
+ GeckoLoader.doLoadLibrary("mozglue");
}
public PasswordsProvider() {
diff --git a/mobile/android/base/mozglue/GeckoLoader.java.in b/mobile/android/base/mozglue/GeckoLoader.java.in
index b0a7a1cb4e82..76e3fb85801b 100644
--- a/mobile/android/base/mozglue/GeckoLoader.java.in
+++ b/mobile/android/base/mozglue/GeckoLoader.java.in
@@ -1,3 +1,4 @@
+#filter substitution
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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
@@ -20,6 +21,9 @@ import java.util.Locale;
public final class GeckoLoader {
private static final String LOGTAG = "GeckoLoader";
+ // This matches AppConstants, but we're built earlier.
+ private static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
+
private static volatile Intent sIntent;
private static File sCacheFile;
private static File sGREDir;
@@ -259,6 +263,25 @@ public final class GeckoLoader {
loadNSSLibsNative(apkName, false);
}
+ public static void doLoadLibrary(final String lib) {
+ try {
+ System.loadLibrary(lib);
+ } catch (UnsatisfiedLinkError e) {
+ Log.wtf(LOGTAG, "Couldn't load " + lib + ". Trying /data/app-lib path.");
+ try {
+ System.load("/data/app-lib/" + ANDROID_PACKAGE_NAME + "/lib" + lib + ".so");
+ } catch (Throwable ee) {
+ try {
+ Log.wtf(LOGTAG, "Couldn't load " + lib + ": " + ee + ". Trying /data/data path.");
+ System.load("/data/data/" + ANDROID_PACKAGE_NAME + "/lib/lib" + lib + ".so");
+ } catch (Throwable eee) {
+ Log.wtf(LOGTAG, "Failed every attempt to load " + lib + ". Giving up.");
+ throw new RuntimeException("Unable to load " + lib, eee);
+ }
+ }
+ }
+ }
+
public static void loadMozGlue() {
synchronized (sLibLoadingLock) {
if (sMozGlueLoaded) {
@@ -267,7 +290,7 @@ public final class GeckoLoader {
sMozGlueLoaded = true;
}
- System.loadLibrary("mozglue");
+ doLoadLibrary("mozglue");
}
public static void loadGeckoLibs(Context context, String apkName) {
diff --git a/mobile/android/base/util/GeckoJarReader.java b/mobile/android/base/util/GeckoJarReader.java
index e53be214802b..496d3d4299a1 100644
--- a/mobile/android/base/util/GeckoJarReader.java
+++ b/mobile/android/base/util/GeckoJarReader.java
@@ -16,7 +16,8 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.net.URL;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Stack;
/* Reads out of a multiple level deep jar file such as
@@ -47,6 +48,8 @@ public final class GeckoJarReader {
}
} catch (IOException ex) {
Log.e(LOGTAG, "Exception ", ex);
+ } catch (URISyntaxException ex) {
+ Log.e(LOGTAG, "Exception ", ex);
} finally {
if (inputStream != null) {
try {
@@ -78,6 +81,8 @@ public final class GeckoJarReader {
}
} catch (IOException ex) {
Log.e(LOGTAG, "Exception ", ex);
+ } catch (URISyntaxException ex) {
+ Log.e(LOGTAG, "Exception ", ex);
} finally {
if (reader != null) {
try {
@@ -94,8 +99,8 @@ public final class GeckoJarReader {
return text;
}
- private static NativeZip getZipFile(String url) throws IOException {
- URL fileUrl = new URL(url);
+ private static NativeZip getZipFile(String url) throws IOException, URISyntaxException {
+ URI fileUrl = new URI(url);
return new NativeZip(fileUrl.getPath());
}
diff --git a/mobile/android/base/util/JSONUtils.java b/mobile/android/base/util/JSONUtils.java
index b883d7f979c7..3631898d8ec2 100644
--- a/mobile/android/base/util/JSONUtils.java
+++ b/mobile/android/base/util/JSONUtils.java
@@ -4,43 +4,14 @@
package org.mozilla.gecko.util;
+import java.util.UUID;
+
import org.json.JSONException;
import org.json.JSONObject;
-import android.util.Log;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.UUID;
-
public final class JSONUtils {
- private static final String LOGTAG = "JSONUtils";
-
private JSONUtils() {}
- public static URL getURL(String name, JSONObject json) {
- String url = json.optString(name, null);
- if (url == null) {
- return null;
- }
-
- try {
- return new URL(url);
- } catch (MalformedURLException e) {
- Log.e(LOGTAG, "", new IllegalStateException(name + "=" + url, e));
- return null;
- }
- }
-
- public static void putURL(String name, URL url, JSONObject json) {
- String urlString = url.toString();
- try {
- json.put(name, urlString);
- } catch (JSONException e) {
- throw new IllegalArgumentException(name + "=" + urlString, e);
- }
- }
-
public static UUID getUUID(String name, JSONObject json) {
String uuid = json.optString(name, null);
return (uuid != null) ? UUID.fromString(uuid) : null;
diff --git a/mobile/android/base/webapp/InstallListener.java b/mobile/android/base/webapp/InstallListener.java
index 6a450c333457..b947ff58c903 100644
--- a/mobile/android/base/webapp/InstallListener.java
+++ b/mobile/android/base/webapp/InstallListener.java
@@ -7,8 +7,6 @@ package org.mozilla.gecko.webapp;
import java.io.File;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
import org.json.JSONException;
import org.json.JSONObject;
diff --git a/mobile/android/base/webapp/WebappImpl.java b/mobile/android/base/webapp/WebappImpl.java
index 3ee916f572aa..5adc670b59f1 100644
--- a/mobile/android/base/webapp/WebappImpl.java
+++ b/mobile/android/base/webapp/WebappImpl.java
@@ -7,8 +7,7 @@ package org.mozilla.gecko.webapp;
import java.io.File;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import org.json.JSONException;
import org.json.JSONObject;
@@ -19,17 +18,11 @@ import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.webapp.ApkResources;
-import org.mozilla.gecko.webapp.InstallHelper;
import org.mozilla.gecko.webapp.InstallHelper.InstallCallback;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Bitmap;
import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
@@ -45,7 +38,7 @@ import android.widget.TextView;
public class WebappImpl extends GeckoApp implements InstallCallback {
private static final String LOGTAG = "GeckoWebappImpl";
- private URL mOrigin;
+ private URI mOrigin;
private TextView mTitlebarText = null;
private View mTitlebar = null;
@@ -272,11 +265,11 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
return;
}
- final URL url;
+ final URI uri;
try {
- url = new URL(urlString);
- } catch (java.net.MalformedURLException ex) {
+ uri = new URI(urlString);
+ } catch (java.net.URISyntaxException ex) {
mTitlebarText.setText(urlString);
// If we can't parse the url, and its an app protocol hide
@@ -290,10 +283,10 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
return;
}
- if (mOrigin != null && mOrigin.getHost().equals(url.getHost())) {
+ if (mOrigin != null && mOrigin.getHost().equals(uri.getHost())) {
mTitlebar.setVisibility(View.GONE);
} else {
- mTitlebarText.setText(url.getProtocol() + "://" + url.getHost());
+ mTitlebarText.setText(uri.getScheme() + "://" + uri.getHost());
mTitlebar.setVisibility(View.VISIBLE);
}
}
@@ -350,8 +343,8 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
private void setOrigin(String origin) {
try {
- mOrigin = new URL(origin);
- } catch (java.net.MalformedURLException ex) {
+ mOrigin = new URI(origin);
+ } catch (java.net.URISyntaxException ex) {
// If this isn't an app: URL, just settle for not having an origin.
if (!origin.startsWith("app://")) {
return;
@@ -363,8 +356,8 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
Uri data = getIntent().getData();
if (data != null) {
try {
- mOrigin = new URL(data.toString());
- } catch (java.net.MalformedURLException ex2) {
+ mOrigin = new URI(data.toString());
+ } catch (java.net.URISyntaxException ex2) {
Log.e(LOGTAG, "Unable to parse intent URL: ", ex);
}
}
diff --git a/python/mozbuild/mozbuild/backend/android_eclipse.py b/python/mozbuild/mozbuild/backend/android_eclipse.py
index c14edd766f12..41ed63ddb4ef 100644
--- a/python/mozbuild/mozbuild/backend/android_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/android_eclipse.py
@@ -238,6 +238,7 @@ class AndroidEclipseBackend(CommonBackend):
defines['IDE_PROJECT_FILTERED_RESOURCES'] = pretty_print(filteredResources).strip()
else:
defines['IDE_PROJECT_FILTERED_RESOURCES'] = ''
+ defines['ANDROID_TARGET_SDK'] = self.environment.substs['ANDROID_TARGET_SDK']
copier = FileCopier()
finder = FileFinder(template_directory)
diff --git a/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties b/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties
index 3fe950aa0112..f34d1d0180bc 100644
--- a/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties
+++ b/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties
@@ -9,6 +9,6 @@
# project structure.
# Project target.
-target=android-16
+target=android-@ANDROID_TARGET_SDK@
@IDE_PROJECT_LIBRARY_SETTING@
@IDE_PROJECT_LIBRARY_REFERENCES@
diff --git a/python/mozbuild/mozbuild/test/backend/common.py b/python/mozbuild/mozbuild/test/backend/common.py
index b9ed94ddc2db..7cfec3c76096 100644
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -29,6 +29,13 @@ test_data_path = mozpath.join(test_data_path, 'data')
CONFIGS = DefaultOnReadDict({
+ 'android_eclipse': {
+ 'defines': [],
+ 'non_global_defines': [],
+ 'substs': [
+ ('ANDROID_TARGET_SDK', '16'),
+ ],
+ },
'stub0': {
'defines': [
('MOZ_TRUE_1', '1'),
diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm
index 1949bcba94ef..9ba198557222 100644
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -179,8 +179,8 @@ function summarizeObject(obj) {
return obj;
}
-let worker = null;
let Scheduler = {
+
/**
* |true| once we have sent at least one message to the worker.
* This field is unaffected by resetting the worker.
@@ -237,6 +237,25 @@ let Scheduler = {
*/
resetTimer: null,
+ /**
+ * The worker to which to send requests.
+ *
+ * If the worker has never been created or has been reset, this is a
+ * fresh worker, initialized with osfile_async_worker.js.
+ *
+ * @type {PromiseWorker}
+ */
+ get worker() {
+ if (!this._worker) {
+ // Either the worker has never been created or it has been reset
+ this._worker = new PromiseWorker(
+ "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
+ }
+ return this._worker;
+ },
+
+ _worker: null,
+
/**
* Prepare to kill the OS.File worker after a few seconds.
*/
@@ -273,10 +292,14 @@ let Scheduler = {
yield this.queue;
- if (!this.launched || this.shutdown || !worker) {
+ // Enter critical section: no yield in this block
+ // (we want to make sure that we remain the only
+ // request in the queue).
+
+ if (!this.launched || this.shutdown || !this._worker) {
// Nothing to kill
this.shutdown = this.shutdown || shutdown;
- worker = null;
+ this._worker = null;
return null;
}
@@ -285,12 +308,15 @@ let Scheduler = {
let deferred = Promise.defer();
this.queue = deferred.promise;
+
+ // Exit critical section
+
let message = ["Meta_shutdown", [reset]];
try {
Scheduler.latestReceived = [];
Scheduler.latestSent = [Date.now(), ...message];
- let promise = worker.post(...message);
+ let promise = this._worker.post(...message);
// Wait for result
let resources;
@@ -329,7 +355,7 @@ let Scheduler = {
// Make sure that we do not leave an invalid |worker| around.
if (killed || shutdown) {
- worker = null;
+ this._worker = null;
}
this.shutdown = shutdown;
@@ -376,19 +402,14 @@ let Scheduler = {
if (this.shutdown) {
LOG("OS.File is not available anymore. The following request has been rejected.",
method, args);
- return Promise.reject(new Error("OS.File has been shut down."));
- }
- if (!worker) {
- // Either the worker has never been created or it has been reset
- worker = new PromiseWorker(
- "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
+ return Promise.reject(new Error("OS.File has been shut down. Rejecting post to " + method));
}
let firstLaunch = !this.launched;
this.launched = true;
if (firstLaunch && SharedAll.Config.DEBUG) {
// If we have delayed sending SET_DEBUG, do it now.
- worker.post("SET_DEBUG", [true]);
+ this.worker.post("SET_DEBUG", [true]);
Scheduler.Debugging.messagesSent++;
}
@@ -399,7 +420,13 @@ let Scheduler = {
options = methodArgs[methodArgs.length - 1];
}
Scheduler.Debugging.messagesQueued++;
- return this.push(() => Task.spawn(function*() {
+ return this.push(Task.async(function*() {
+ if (this.shutdown) {
+ LOG("OS.File is not available anymore. The following request has been rejected.",
+ method, args);
+ throw new Error("OS.File has been shut down. Rejecting request to " + method);
+ }
+
// Update debugging information. As |args| may be quite
// expensive, we only keep a shortened version of it.
Scheduler.Debugging.latestReceived = null;
@@ -414,7 +441,7 @@ let Scheduler = {
let isError = false;
try {
try {
- data = yield worker.post(method, ...args);
+ data = yield this.worker.post(method, ...args);
} finally {
Scheduler.Debugging.messagesReceived++;
}
@@ -474,7 +501,7 @@ let Scheduler = {
options.outExecutionDuration = durationMs;
}
return data.ok;
- }));
+ }.bind(this)));
},
/**
@@ -483,6 +510,7 @@ let Scheduler = {
* This is only useful on first launch.
*/
_updateTelemetry: function() {
+ let worker = this.worker;
let workerTimeStamps = worker.workerTimeStamps;
if (!workerTimeStamps) {
// If the first call to OS.File results in an uncaught errors,
@@ -1482,7 +1510,7 @@ AsyncShutdown.profileBeforeChange.addBlocker(
let result = {
launched: Scheduler.launched,
shutdown: Scheduler.shutdown,
- worker: !!worker,
+ worker: !!Scheduler._worker,
pendingReset: !!Scheduler.resetTimer,
latestSent: Scheduler.Debugging.latestSent,
latestReceived: Scheduler.Debugging.latestReceived,
diff --git a/toolkit/components/osfile/modules/osfile_async_worker.js b/toolkit/components/osfile/modules/osfile_async_worker.js
index 2fff72687e14..1813f3f447f6 100644
--- a/toolkit/components/osfile/modules/osfile_async_worker.js
+++ b/toolkit/components/osfile/modules/osfile_async_worker.js
@@ -81,7 +81,7 @@ const EXCEPTION_NAMES = {
LOG("Method", method, "succeeded");
} catch (ex) {
exn = ex;
- LOG("Error while calling agent method", exn, exn.stack || "");
+ LOG("Error while calling agent method", exn, exn.moduleStack || exn.stack || "");
}
if (start) {
diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm
index 9036a0de25b5..2dbae65f2f7b 100644
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -156,6 +156,9 @@ this.PlacesUtils = {
* @returns true if the node is a Bookmark folder, false otherwise
*/
nodeIsFolder: function PU_nodeIsFolder(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT);
},
@@ -167,6 +170,9 @@ this.PlacesUtils = {
* @returns true if the node represents a bookmarked URI, false otherwise
*/
nodeIsBookmark: function PU_nodeIsBookmark(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI &&
aNode.itemId != -1;
},
@@ -178,6 +184,9 @@ this.PlacesUtils = {
* @returns true if the node is a Bookmark separator, false otherwise
*/
nodeIsSeparator: function PU_nodeIsSeparator(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR;
},
@@ -188,6 +197,9 @@ this.PlacesUtils = {
* @returns true if the node is a URL item, false otherwise
*/
nodeIsURI: function PU_nodeIsURI(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI;
},
@@ -198,6 +210,9 @@ this.PlacesUtils = {
* @returns true if the node is a Query item, false otherwise
*/
nodeIsQuery: function PU_nodeIsQuery(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
},
@@ -357,6 +372,9 @@ this.PlacesUtils = {
* @returns true if the node is readonly, false otherwise
*/
nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
let itemId = aNode.itemId;
if (itemId != -1) {
return this._readOnly.indexOf(itemId) != -1;
@@ -376,6 +394,9 @@ this.PlacesUtils = {
* @returns true if the node is a host container, false otherwise
*/
nodeIsHost: function PU_nodeIsHost(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
aNode.parent &&
asQuery(aNode.parent).queryOptions.resultType ==
@@ -389,6 +410,9 @@ this.PlacesUtils = {
* @returns true if the node is a day container, false otherwise
*/
nodeIsDay: function PU_nodeIsDay(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
var resultType;
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
aNode.parent &&
@@ -404,6 +428,9 @@ this.PlacesUtils = {
* @returns true if the node is a tag container, false otherwise
*/
nodeIsTagQuery: function PU_nodeIsTagQuery(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
asQuery(aNode).queryOptions.resultType ==
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS;
@@ -419,6 +446,9 @@ this.PlacesUtils = {
Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT,
Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY],
nodeIsContainer: function PU_nodeIsContainer(aNode) {
+ if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+ throw new Error("Invalid Places node");
+ }
return this.containerTypes.indexOf(aNode.type) != -1;
},
diff --git a/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js b/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js
new file mode 100644
index 000000000000..511643831771
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js
@@ -0,0 +1,24 @@
+
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+ let nodeIsMethods = [
+ "nodeIsFolder",
+ "nodeIsBookmark",
+ "nodeIsSeparator",
+ "nodeIsURI",
+ "nodeIsQuery",
+ "nodeIsReadOnly",
+ "nodeIsHost",
+ "nodeIsDay",
+ "nodeIsTagQuery",
+ "nodeIsContainer",
+ "nodeIsHistoryContainer",
+ "nodeIsQuery"
+ ];
+ for (let methodName of nodeIsMethods) {
+ Assert.throws(() => PlacesUtils[methodName](true), /Invalid Places node/);
+ }
+}
+
diff --git a/toolkit/components/places/tests/unit/xpcshell.ini b/toolkit/components/places/tests/unit/xpcshell.ini
index 3165288b9b1c..8ad70b4554e1 100644
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -117,6 +117,7 @@ skip-if = true
[test_placeURIs.js]
[test_PlacesUtils_asyncGetBookmarkIds.js]
[test_PlacesUtils_lazyobservers.js]
+[test_PlacesUtils_nodeIsXXX_invalidArg.js]
[test_placesTxn.js]
[test_preventive_maintenance.js]
# Bug 676989: test hangs consistently on Android
diff --git a/toolkit/devtools/server/actors/highlighter.js b/toolkit/devtools/server/actors/highlighter.js
index 2719ba8a0a2d..864fc02a2079 100644
--- a/toolkit/devtools/server/actors/highlighter.js
+++ b/toolkit/devtools/server/actors/highlighter.js
@@ -71,7 +71,11 @@ let HighlighterActor = protocol.ActorClass({
* XUL node to attach itself.
*/
_supportsBoxModelHighlighter: function() {
- return this._tabActor.browser && !!this._tabActor.browser.parentNode;
+ // Note that s on Fennec also have a XUL parentNode but the box
+ // model highlighter doesn't display correctly on Fennec (bug 993190)
+ return this._tabActor.browser &&
+ !!this._tabActor.browser.parentNode &&
+ Services.appinfo.ID !== "{aa3c5121-dab2-40e2-81ca-7ea25febc110}";
},
destroy: function() {
diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js
index af6e1d1ccf90..ce0ce668fbf9 100644
--- a/toolkit/devtools/server/actors/script.js
+++ b/toolkit/devtools/server/actors/script.js
@@ -24,8 +24,9 @@ let addonManager = null;
* about them.
*/
function mapURIToAddonID(uri, id) {
- if (Services.appinfo.ID == B2G_ID)
+ if (Services.appinfo.ID == B2G_ID) {
return false;
+ }
if (!addonManager) {
addonManager = Cc["@mozilla.org/addons/integration;1"].
@@ -4777,6 +4778,31 @@ update(AddonThreadActor.prototype, {
// A constant prefix that will be used to form the actor ID by the server.
actorPrefix: "addonThread",
+ onAttach: function(aRequest) {
+ if (!this.attached) {
+ Services.obs.addObserver(this, "document-element-inserted", false);
+ }
+ return ThreadActor.prototype.onAttach.call(this, aRequest);
+ },
+
+ disconnect: function() {
+ if (this.attached) {
+ Services.obs.removeObserver(this, "document-element-inserted");
+ }
+ return ThreadActor.prototype.disconnect.call(this);
+ },
+
+ /**
+ * Called when a new DOM document element is created. Check if the DOM was
+ * laoded from an add-on and if so make the window a debuggee.
+ */
+ observe: function(aSubject, aTopic, aData) {
+ let id = {};
+ if (mapURIToAddonID(aSubject.documentURIObject, id) && id.value === this.addonID) {
+ this.dbg.addDebuggee(aSubject.defaultView);
+ }
+ },
+
/**
* Override the eligibility check for scripts and sources to make
* sure every script and source with a URL is stored when debugging
@@ -4784,12 +4810,14 @@ update(AddonThreadActor.prototype, {
*/
_allowSource: function(aSourceURL) {
// Hide eval scripts
- if (!aSourceURL)
+ if (!aSourceURL) {
return false;
+ }
// XPIProvider.jsm evals some code in every add-on's bootstrap.js. Hide it
- if (aSourceURL == "resource://gre/modules/addons/XPIProvider.jsm")
+ if (aSourceURL == "resource://gre/modules/addons/XPIProvider.jsm") {
return false;
+ }
return true;
},
@@ -4836,27 +4864,50 @@ update(AddonThreadActor.prototype, {
* @param aGlobal Debugger.Object
*/
_checkGlobal: function ADA_checkGlobal(aGlobal) {
+ let obj = null;
+ try {
+ obj = aGlobal.unsafeDereference();
+ }
+ catch (e) {
+ // Because of bug 991399 we sometimes get bad objects here. If we can't
+ // dereference them then they won't be useful to us
+ return false;
+ }
+
try {
// This will fail for non-Sandbox objects, hence the try-catch block.
- let metadata = Cu.getSandboxMetadata(aGlobal.unsafeDereference());
- if (metadata)
+ let metadata = Cu.getSandboxMetadata(obj);
+ if (metadata) {
return metadata.addonID === this.addonID;
+ }
} catch (e) {
}
+ if (obj instanceof Ci.nsIDOMWindow) {
+ let id = {};
+ if (mapURIToAddonID(obj.document.documentURIObject, id)) {
+ return id.value === this.addonID;
+ }
+ return false;
+ }
+
// Check the global for a __URI__ property and then try to map that to an
// add-on
let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__");
- if (uridescriptor && "value" in uridescriptor) {
+ if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
+ let uri;
try {
- let uri = Services.io.newURI(uridescriptor.value, null, null);
- let id = {};
- if (mapURIToAddonID(uri, id)) {
- return id.value === this.addonID;
- }
+ uri = Services.io.newURI(uridescriptor.value, null, null);
}
catch (e) {
- DevToolsUtils.reportException("AddonThreadActor.prototype._checkGlobal", e);
+ DevToolsUtils.reportException("AddonThreadActor.prototype._checkGlobal",
+ new Error("Invalid URI: " + uridescriptor.value));
+ return false;
+ }
+
+ let id = {};
+ if (mapURIToAddonID(uri, id)) {
+ return id.value === this.addonID;
}
}
@@ -4864,6 +4915,11 @@ update(AddonThreadActor.prototype, {
}
});
+AddonThreadActor.prototype.requestTypes = Object.create(ThreadActor.prototype.requestTypes);
+update(AddonThreadActor.prototype.requestTypes, {
+ "attach": AddonThreadActor.prototype.onAttach
+});
+
/**
* Manages the sources for a thread. Handles source maps, locations in the
* sources, etc for ThreadActors.
diff --git a/toolkit/modules/ShortcutUtils.jsm b/toolkit/modules/ShortcutUtils.jsm
index 3215d81f8612..ce4474118b04 100644
--- a/toolkit/modules/ShortcutUtils.jsm
+++ b/toolkit/modules/ShortcutUtils.jsm
@@ -34,6 +34,7 @@ let ShortcutUtils = {
prettifyShortcut: function(aElemKey, aNoCloverLeaf) {
let elemString = "";
let elemMod = aElemKey.getAttribute("modifiers");
+ let haveCloverLeaf = false;
if (elemMod.match("accel")) {
if (Services.appinfo.OS == "Darwin") {
@@ -42,8 +43,7 @@ let ShortcutUtils = {
if (aNoCloverLeaf) {
elemString += "Cmd-";
} else {
- elemString += PlatformKeys.GetStringFromName("VK_META") +
- PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+ haveCloverLeaf = true;
}
} else {
elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
@@ -80,6 +80,11 @@ let ShortcutUtils = {
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
}
+ if (haveCloverLeaf) {
+ elemString += PlatformKeys.GetStringFromName("VK_META") +
+ PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+ }
+
let key;
let keyCode = aElemKey.getAttribute("keycode");
if (keyCode) {
diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js
index cbc2b350a067..9c8a9ba9ec05 100644
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -18,6 +18,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+ "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+ "resource://gre/modules/Task.jsm");
const TOOLKIT_ID = "toolkit@mozilla.org"
const KEY_PROFILEDIR = "ProfD";
@@ -567,8 +571,8 @@ Blocklist.prototype = {
this._loadBlocklist();
},
- onXMLLoad: function Blocklist_onXMLLoad(aEvent) {
- var request = aEvent.target;
+ onXMLLoad: Task.async(function* (aEvent) {
+ let request = aEvent.target;
try {
gCertUtils.checkCert(request.channel);
}
@@ -576,28 +580,28 @@ Blocklist.prototype = {
LOG("Blocklist::onXMLLoad: " + e);
return;
}
- var responseXML = request.responseXML;
+ let responseXML = request.responseXML;
if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
(request.status != 200 && request.status != 0)) {
LOG("Blocklist::onXMLLoad: there was an error during load");
return;
}
- var blocklistFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
- if (blocklistFile.exists())
- blocklistFile.remove(false);
- var fos = FileUtils.openSafeFileOutputStream(blocklistFile);
- fos.write(request.responseText, request.responseText.length);
- FileUtils.closeSafeFileOutputStream(fos);
var oldAddonEntries = this._addonEntries;
var oldPluginEntries = this._pluginEntries;
this._addonEntries = [];
this._pluginEntries = [];
- this._loadBlocklistFromFile(FileUtils.getFile(KEY_PROFILEDIR,
- [FILE_BLOCKLIST]));
+ this._loadBlocklistFromString(request.responseText);
this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
- },
+
+ try {
+ let path = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
+ yield OS.File.writeAtomic(path, request.responseText, {tmpPath: path + ".tmp"});
+ } catch (e) {
+ LOG("Blocklist::onXMLLoad: " + e);
+ }
+ }),
onXMLError: function Blocklist_onXMLError(aEvent) {
try {
@@ -704,17 +708,46 @@ Blocklist.prototype = {
}
if (!file.exists()) {
- LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist");
+ LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist " + file.path);
return;
}
- var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Components.interfaces.nsIFileInputStream);
- fileStream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+ let text = "";
+ let fstream = null;
+ let cstream = null;
+
+ try {
+ fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Components.interfaces.nsIFileInputStream);
+ cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(Components.interfaces.nsIConverterInputStream);
+
+ fstream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+ cstream.init(fstream, "UTF-8", 0, 0);
+
+ let (str = {}) {
+ let read = 0;
+
+ do {
+ read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
+ text += str.value;
+ } while (read != 0);
+ }
+ } catch (e) {
+ LOG("Blocklist::_loadBlocklistFromFile: Failed to load XML file " + e);
+ } finally {
+ cstream.close();
+ fstream.close();
+ }
+
+ text && this._loadBlocklistFromString(text);
+ },
+
+ _loadBlocklistFromString : function Blocklist_loadBlocklistFromString(text) {
try {
var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
createInstance(Ci.nsIDOMParser);
- var doc = parser.parseFromStream(fileStream, "UTF-8", file.fileSize, "text/xml");
+ var doc = parser.parseFromString(text, "text/xml");
if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
LOG("Blocklist::_loadBlocklistFromFile: aborting due to incorrect " +
"XML Namespace.\r\nExpected: " + XMLURI_BLOCKLIST + "\r\n" +
@@ -746,7 +779,6 @@ Blocklist.prototype = {
LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
return;
}
- fileStream.close();
},
_processItemNodes: function Blocklist_processItemNodes(itemNodes, prefix, handler) {