author | Ryan VanderMeulen <ryanvm@gmail.com> |
Wed, 16 Apr 2014 22:29:41 -0400 | |
changeset 178925 | e71ed4135461b57a9c7f35995e4e1f1dc5f0e8bf |
parent 178898 | 84536adf61090b2cfcff13a4c72f3ca52a806029 (current diff) |
parent 178924 | b3ea0d746ee49ac5aa7d6839db33951a101c128e (diff) |
child 178926 | 6196c121c4f4f7241931e7ce1608c8c97c7433d6 |
child 178941 | f011f98832e26151590465d8211cdb759acaa05d |
child 178971 | ccc9cd25ebda0454adaf5b870ba446ebbd51597d |
child 178988 | f1f58acc81549b859c6846aacfca32c6527253a2 |
push id | 26600 |
push user | ryanvm@gmail.com |
push date | Thu, 17 Apr 2014 02:29:53 +0000 |
treeherder | mozilla-central@e71ed4135461 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 31.0a1 |
first release with | nightly linux32
e71ed4135461
/
31.0a1
/
20140417030203
/
files
nightly linux64
e71ed4135461
/
31.0a1
/
20140417030203
/
files
nightly mac
e71ed4135461
/
31.0a1
/
20140417030203
/
files
nightly win32
e71ed4135461
/
31.0a1
/
20140417030203
/
files
nightly win64
e71ed4135461
/
31.0a1
/
20140417030203
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
31.0a1
/
20140417030203
/
pushlog to previous
nightly linux64
31.0a1
/
20140417030203
/
pushlog to previous
nightly mac
31.0a1
/
20140417030203
/
pushlog to previous
nightly win32
31.0a1
/
20140417030203
/
pushlog to previous
nightly win64
31.0a1
/
20140417030203
/
pushlog to previous
|
browser/base/content/aboutaccounts/fonts/clearsans-regular.woff | file | annotate | diff | comparison | revisions | |
browser/base/content/aboutaccounts/fonts/firasans-light.woff | file | annotate | diff | comparison | revisions | |
browser/base/content/aboutaccounts/fonts/firasans-regular.woff | file | annotate | diff | comparison | revisions | |
browser/components/customizableui/test/browser_996364_defaultCollapsed.js | file | annotate | diff | comparison | revisions | |
browser/themes/linux/devtools/ruleview.css | file | annotate | diff | comparison | revisions | |
browser/themes/osx/devtools/ruleview.css | file | annotate | diff | comparison | revisions | |
browser/themes/shared/ClearSans-Regular.ttf | file | annotate | diff | comparison | revisions | |
browser/themes/windows/devtools/ruleview.css | file | annotate | diff | comparison | revisions |
--- a/b2g/chrome/content/devtools.js +++ b/b2g/chrome/content/devtools.js @@ -2,34 +2,34 @@ * 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'; 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; }); XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() { return Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {}).DebuggerClient; }); 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; }); /** * The Developer HUD is an on-device developer tool that displays widgets, * showing visual debug information about apps. Each widget corresponds to a * metric as tracked by a metric watcher (e.g. consoleWatcher). */ @@ -42,17 +42,17 @@ let developerHUD = { _watchers: [], _logging: true, /** * This method registers a metric watcher that will watch one or more metrics * 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); }, init: function dwp_init() { if (this._client) return; @@ -205,25 +205,34 @@ Target.prototype = { register: function target_register(metric) { this.metrics.set(metric, 0); }, /** * 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 }; // FIXME(Bug 982066) Remove this loop. if (metrics && metrics.size > 0) { for (let name of metrics.keys()) { data.metrics.push({name: name, value: metrics.get(name)}); } @@ -235,25 +244,27 @@ Target.prototype = { this._send(data); }, /** * Nicer way to call update() when the metric value is a number that needs * 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); }, /** * Void a metric value and make sure it isn't displayed on the front-end * anymore. */ clear: function target_clear(metric) { - this.update(metric, 0); + metric.value = 0; + this.update(metric); }, /** * Tear everything down, including the front-end by sending a message without * widgets. */ destroy: function target_destroy() { delete this.metrics; @@ -302,17 +313,17 @@ let consoleWatcher = { SettingsListener.observe('hud.' + metric, watching[metric], watch => { // Watch or unwatch the metric. if (watching[metric] = watch) { return; } // If unwatched, remove any existing widgets for that metric. for (let target of this._targets.values()) { - target.clear(metric); + target.clear({name: metric}); } }); } client.addListener('logMessage', this.consoleListener); client.addListener('pageError', this.consoleListener); client.addListener('consoleAPICall', this.consoleListener); client.addListener('reflowActivity', this.consoleListener); @@ -340,72 +351,76 @@ let consoleWatcher = { listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] }, (res) => { }); this._targets.delete(target.actor.consoleActor); }, consoleListener: function cw_consoleListener(type, packet) { let target = this._targets.get(packet.from); - let metric; + let metric = {}; let output = ''; switch (packet.type) { case 'pageError': 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; output += category + '): "' + (errorMessage.initial || errorMessage) + '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber; break; case 'consoleAPICall': 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; default: return; } 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; } target.bump(metric, output); }, formatSourceURL: function cw_formatSourceURL(packet) { // Abbreviate source URL @@ -441,29 +456,29 @@ let eventLoopLagWatcher = { // Toggle the state of existing fronts. let fronts = this._fronts; for (let target of fronts.keys()) { if (value) { fronts.get(target).start(); } else { fronts.get(target).stop(); - target.clear('jank'); + target.clear({name: 'jank'}); } } }, trackTarget: function(target) { target.register('jank'); let front = new EventLoopLagFront(this._client, target.actor); 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) { front.start(); } }, untrackTarget: function(target) { @@ -509,17 +524,17 @@ let memoryWatcher = { SettingsListener.observe('hud.appmemory', false, enabled => { if (this._active = enabled) { for (let target of this._fronts.keys()) { this.measure(target); } } else { for (let target of this._fronts.keys()) { clearTimeout(this._timers.get(target)); - target.clear('memory'); + target.clear({name: 'memory'}); } } }); }, measure: function mw_measure(target) { // TODO Also track USS (bug #976024). @@ -545,17 +560,17 @@ let memoryWatcher = { if (watch.style) { total += parseInt(data.styleSize); } if (watch.other) { total += parseInt(data.otherSize); } // 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); }, (err) => { console.error(err); }); },
--- a/browser/base/content/aboutaccounts/fonts.css +++ b/browser/base/content/aboutaccounts/fonts.css @@ -1,25 +1,24 @@ @font-face { font-family: 'Fira Sans'; font-style: normal; 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'; font-style: normal; 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'; font-style: normal; font-weight: 400; src: local('Clear Sans'), local('ClearSans'), - url('fonts/clearsans-regular.woff') format('woff'); + url('../fonts/ClearSans-Regular.woff') format('woff'); } -
--- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -58,16 +58,20 @@ var StarUI = { // nsIDOMEventListener handleEvent: function SU_handleEvent(aEvent) { switch (aEvent.type) { case "popuphidden": if (aEvent.originalTarget == this.panel) { 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) { PlacesUtils.transactionManager.endBatch(false); this._batching = false; } switch (this._actionOnHide) { @@ -181,16 +185,31 @@ var StarUI = { this._element("editBookmarkPanelRemoveButton").label = label; // unset the unstarred state, if set this._element("editBookmarkPanelStarIcon").removeAttribute("unstarred"); 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, { hiddenRows: ["description", "location", "loadInSidebar", "keyword"] }); }, panelShown:
--- a/browser/base/content/browser-syncui.js +++ b/browser/base/content/browser-syncui.js @@ -232,20 +232,16 @@ let gSyncUI = { )); let notification = new Weave.Notification( title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons); Weave.Notifications.replaceTitle(notification); }, _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"); }, onEOLNotice: function (data) { let code = data.code; let kind = (code == "hard-eol") ? "error" : "warning"; let url = data.url || gSyncUI.DEFAULT_EOL_URL;
rename from browser/base/content/aboutaccounts/fonts/clearsans-regular.woff rename to browser/base/content/fonts/ClearSans-Regular.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-light.woff rename to browser/base/content/fonts/FiraSans-Light.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-regular.woff rename to browser/base/content/fonts/FiraSans-Regular.woff
--- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -51,19 +51,16 @@ browser.jar: content/browser/abouthealthreport/abouthealth.css (content/abouthealthreport/abouthealth.css) #endif content/browser/aboutaccounts/aboutaccounts.xhtml (content/aboutaccounts/aboutaccounts.xhtml) content/browser/aboutaccounts/aboutaccounts.js (content/aboutaccounts/aboutaccounts.js) content/browser/aboutaccounts/aboutaccounts.css (content/aboutaccounts/aboutaccounts.css) 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) content/browser/certerror/aboutCertError.xhtml (content/aboutcerterror/aboutCertError.xhtml) content/browser/certerror/aboutCertError.css (content/aboutcerterror/aboutCertError.css) content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png) @@ -72,16 +69,19 @@ browser.jar: content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js) content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml) * content/browser/browser.css (content/browser.css) * content/browser/browser.js (content/browser.js) * content/browser/browser.xul (content/browser.xul) * 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) content/browser/newtab/preloaderContent.js (content/newtab/preloaderContent.js) * content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul) content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js) content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css) content/browser/pageinfo/pageInfo.xml (content/pageinfo/pageInfo.xml)
--- a/browser/components/customizableui/src/CustomizableUI.jsm +++ b/browser/components/customizableui/src/CustomizableUI.jsm @@ -292,21 +292,22 @@ let CustomizableUIInternal = { registerArea: function(aName, aProperties, aInternalCaller) { if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) { throw new Error("Invalid area name"); } 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])) { props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x )); } else { props.set(key, aProperties[key]); } } @@ -3453,18 +3454,18 @@ function WidgetSingleWrapper(aWidget, aN this.node = aNode; this.provider = CustomizableUI.PROVIDER_API; const kGlobalProps = ["id", "type"]; for (let prop of kGlobalProps) { 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. this.__defineGetter__(propertyName, function() aNode.getAttribute(propertyName)); } this.__defineGetter__("disabled", function() aNode.disabled);
--- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -100,11 +100,11 @@ skip-if = os == "linux" [browser_985815_propagate_setToolbarVisibility.js] [browser_981305_separator_insertion.js] [browser_987177_destroyWidget_xul.js] [browser_987177_xul_wrapper_updating.js] [browser_987492_window_api.js] [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]
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js +++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js @@ -53,43 +53,62 @@ add_task(function*() { ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette"); is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar"); ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar."); let otherWin = yield openAndLoadWindow({}, true); 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); ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette"); ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette."); ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too."); simulateItemDrag(syncButton, toolbar); ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette"); is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar"); ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar."); 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: is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper."); isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance."); yield gCustomizeMode.reset();
rename from browser/components/customizableui/test/browser_996364_defaultCollapsed.js rename to browser/components/customizableui/test/browser_996364_registerArea_different_properties.js --- a/browser/components/customizableui/test/browser_996364_defaultCollapsed.js +++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js @@ -15,42 +15,98 @@ add_task(function() { } CustomizableUI.unregisterArea("area-996364", true); }); add_task(function() { let exceptionThrown = false; try { - CustomizableUI.registerArea("area-996364-2", {"type": CustomizableUI.TYPE_TOOLBAR, "defaultCollapsed": "false"}); + 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}); + 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}); + 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); +});
--- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -673,18 +673,16 @@ let SessionStoreInternal = { this.restoreTabContent(tab); } } break; default: debug("received unknown message '" + aMessage.name + "'"); break; } - - this._clearRestoringWindows(); }, /** * Record telemetry measurements stored in an object. * @param telemetry * {histogramID: value, ...} An object mapping histogramIDs to the * value to be recorded for that ID, */ @@ -3395,16 +3393,25 @@ let SessionStoreInternal = { !!this._closedWindows[normalWindowIndex].isPopup) normalWindowIndex++; if (normalWindowIndex >= this._max_windows_undo) spliceTo = normalWindowIndex + 1; #endif 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; } }, /** * Reset state to prepare for a new session state to be restored.
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js +++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js @@ -110,35 +110,37 @@ function test_3() { waitForTabLoad(aWindow, "http://www.example.com/", function() { let curState = JSON.parse(ss.getBrowserState()); is(curState.windows.length, 4, "Browser has opened 4 windows"); is(curState.windows[2].isPrivate, true, "Window 2 is private"); 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(); }); }); }); }); }); }); }); });
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest @@ -0,0 +1,1 @@ +content browser_dbg_addon4 .
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul @@ -0,0 +1,8 @@ +<?xml version="1.0"?> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="text/javascript" src="testxul.js"/> + <label value="test.xul"/> +</window>
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul @@ -0,0 +1,8 @@ +<?xml version="1.0"?> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="text/javascript" src="testxul2.js"/> + <label value="test2.xul"/> +</window>
new file mode 100644 --- /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"; +});
new file mode 100644 --- /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"; +});
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest @@ -0,0 +1,1 @@ +content browser_dbg_addon5 .
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul @@ -0,0 +1,8 @@ +<?xml version="1.0"?> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="text/javascript" src="testxul.js"/> + <label value="test.xul"/> +</window>
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul @@ -0,0 +1,8 @@ +<?xml version="1.0"?> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="text/javascript" src="testxul2.js"/> + <label value="test2.xul"/> +</window>
new file mode 100644 --- /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"; +});
new file mode 100644 --- /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"; +});
index a654b7e011b029859b2be10071d13ecb4e9e78eb..31c5331b69dee6d15183647bb598f90195ff1c2a GIT binary patch literal 2918 zc$^FHW@Zs#U}E54@a?a132>Y;EtQdhA)J|kfrmkcAt^t<q`0Igu|O}YI5dQlfq7H8 zaWKPto8Zz4ZU#n{Z$PC$-3$y@Cpr2n8}hWi|E#^naw~^w_Yuw`iJ^QYTiY*n8G8vE z^PW1Qe4A19NWHr3mDHn$xcZ)?J$?GKy6g?(pEJ=POmZyCq+2xv3|!ueFl#jC35cc6 zUDRIuD)!7W#)jTk1xahuOQhak2)-XI=6vU7qDXsSw)}*Xax>+{_;N1)SQS{&GDGy| zvC1jJGmbicIN90L+OBTVEcul=^^DeX-{Rm+*F7X%WV0pJ@*dv!TEvmp>8IiUaHG=R zeTJ^dLc-Z+tuiHBxvJOfkX`&%b4p86_=)n3LNlUY-hP=`>ail==+^)9cY7>zjy2G% z^b*%=Z~2pT)31DU#rqkjoA%6oU+kB5F=eKH;Ju38-qmvjuY^W+yXo%UFuCk(iT;V} ziFadn3uwr1H~r{cvYCBH)VbBpTQ`W+P3C^^;5t{FQeBbS|8E<+7X996^LKB9??s32 zKbv_&+E&jg6WMM5Ilj;6)xJX?ZNE+S_Ii9_9%BGXR4ImKelP%re-aY|12-_LGV_W{ z5_59&ic-?xF{L&GBc@6xoy}`D5NLUC)9RWxwS)64D~rn1MRHnSFNN)OQ?uv{{jX51 zxy3*JIHUTKwfXb@rj;Kr+V_gpeSV1avJ^qRXN5bonicAA+9*X&T*lGQ;M-Psz4Y_D zx^-U|^)HzmEo_>sa_Os`QM{0cyr(fYbBWct8G(i$xxSvYP+#XLblltL=t*1dw-zm* zculR(N^Qti2wExDwc)Cfbd2O=Hjd{L6(+r1$@tpJ_teT05wT%WrERZrV`aB3SvNIi z-9e{kRT+Kf*L>$)=so-9)nmKaRRp)xY_6T~R`TXvD>nBpU%KXn-Yv?SbK3D<kR~ge zNv78Y-O>ZDpF{*|7ks#2GUqMFkC~UlB~0aoraY48x%NL*D)8Ww-vUo%-gwPuS|a~- zw{eBwvDOdkdu4v6H%VI@|0X>3AU|rL7vFpOq8k{B3xJpd80aOb#U;S3k&7?HO-~)< zYH|>9d-&JpXur4ky<2L!T&1BJHy3qq%$6)s*lTo;sr#O-VAQ<B?uur2InMrl5qp>8 z4nuP9<*5<Oi5|&;Ht+eDPb`SusTaf`HL=ch$=<a`_O5xh?P*@ejq6v=-#9bv-Zf+0 z#jJ`dOTVPByj*#L|G3G{sn7qK-JcrqSSaPpLDPSeS1$Yg^VlnPRL?x#Y9$Es3@6kx zMr8O#=(ecWHVvhuS!lj71p4OiUx}K#9Df*IuQ89B(`vA!P-Fi0cJmWEukP~}X>eN- zFF5nTmLJoN?`*rn%h^8bm*nl6mu|BzOWmY!WXY77JqguX-G>Wj-(U6FPP<I>+76eQ zd>2jsf_<|L**7&|%`Wdc!@V~F9mvRt6g3s4IbhH1o^Klr!f2lH?LR2gWWeL{zQ$F( zTzaon!~Gz`OI{f>)uKMUUR(5W+Rd~3a&Dcr+FThpZ9)>edUcEUeUrE0b{%;>k2<gX z@cGWiHvh6u`jLs3uNs~bQEIxFyO3{6*ipw6_9+7SD`#|dUTO@F%~~@h>G>DFGv}7s zJaW1H#zph-iz#Z0miE2UoXndP{N(I9|F(UG%cd%}yZ+C&y>t4lmc+@!;i7AQe^YGO z&$C<m>U$ac%<}pjueR>^{(3e)s-GWN+<U(b=nrN_<QOFE=}SOQ14{sqr@y{nu=9S} zzeOl&S*O^)<=amkjZQQFoq9R$`pmQ4n_5JyEp95u{9cx6|H-i=S;&9MvGiT#20!Mc z?NaEQlh+rxOhB+FkGpii7A-y{>jf=8rgyEJp&?swb?GrL%`(6LjW=&jai5bhd#*;R z%-l;ZTdoA!rfzb~>DqJi>&Xk|$F>+f+3@21+V<+5v8>9KKUOR%{huSx^n-Wf?!emf zA19an{=*u!`RLxn`+JZIzv}2_m+4!|e-#7$(h9^}P>%z>4XdRzSJ(!tt-$cP?rBH9 zCIbQ13$^|qFN><U@j2XidCvPvnU}hz@iHEP<UQ6pG5hx<9++#yop^EPnhib)jtku` zuxYCwIhKD|#%{(5fvsU(ZYSUBcz)0Jc)4-njmhH53$OhQUDftP|HNvS<f-e9UuXP3 zA+)f$zV(^=_t);_3`p^X=4@_+vyEWx)&aU%YtXox3+QeJa60>@-!NSk$Od74pu3YZ zit=+)^>P#QGSh%wz?a&R^Ycnl^GXzwit@{gQ;XtLlG5W7Q&RHtOceCE0=yZS<d|_a zKO`7H0LW!n(g<RqHbz(>MHHHK=q94plE@~m22v<>CUFL$)&R%`DgYggs1JxU4YdeH zHtj9cG$Ue-!z=@ljoZz_fK(!~LZXX+X{e<OvT5sC8Ia2w!p33dS!Cl@urZ+IU{**D z#^*eY%!F)SJUatw)?$TZEvyFOO6AA~igPevrg>bxW@Tdl$0jGkWuVEm93UP5@Gl)6
index 2c18f6da191746c1a7c658087fbce264a410e5a6..16991f7a06aeaf2bb32a045d7c925f1d41372d9e GIT binary patch literal 2933 zc$~$Sc{o)2AIA@47)!QmD$M;w%D#@|+Vk8&*SHz{&?U<lV~eqjtt8pEvSfsiY(t_& z_Fa~&C4<P;Ey<d23nBMt`8C6@ZqM(Z-#pLvnRA}!ocDRZ&iniMd=3T;Vc-Gi0T|$B z7=R+N|Dl4X0{~M90I&fFz{b_plj!Mzb(3}?8vmOafMjPY8PR2^8hQD$0(1=Tz)Qiq z0ige~roNCITj;{FM4?hC>~LowYeZ84V#<jl7j91yw&Np3>XbpmBeqT`=XXYh!V&G= z9i7W7bAyo8l=5eegC287SqucMBgVuSG4!JXk{!xg9IyJSlYfT*{QZA6n?0I3GM1TF zmnRukaj!{~J$pc1AVCeOA&D3yFB)gRfyqfMU0N0uk&O<2mhclVD~G-tqx=k0N3!vW z)Jd}K?RaE_@&HnA<o?~+mz*Qq>6mNxaaw2naZ#;@ga@vA^&(l|?@qd_Xb&5SGPm4{ zTd+ASTi#nvq0Gc#GNVp!Y52tJg;!Y{E|H{9u`{pr7pK3rTO5;1f}T+sf0fpi)sD2v zs#)aYH&qeJzgfKZl9@MFWd7>3W!&wis%mdRj5^`;^Q0*|4!6=Y({LxO)Q0fBhQ{0Q z8q~&w-iLV{Tx$h)=Di<XYF6OuWhVZ7HdCc}QSX4sdIY}DKlFv)oJbO>HB$|Op^3^s z5Pn_*eE-q(0Kf`H<wziUVx66(J#6j%laxgAuB5y!cM|T)a%!!tu}I8`L&HlfI75#e z?$gR8JS{Mvu!ihCk9wDrx%r+?L@p<GPL=q&t2UdbGl6F+n76aktofcJpG>EyxaB}> zn-|HVndyS^g9?{nM?aN*yIA|>HAEio!{X*13mXl1oKe=?p_rbv<@;&v@g_4e(hQ4` z;v=<9de{0B28({pKPg|WP{U{siPu%U6TzRoWSL0B2g2fyXRXHk;a0Fr4r))M6eFuj zyPO?L$2oONtE>Wp=ic_x`#AT!%|s^+t%UgiJn@C+h(t`bQ?VK{YUE8bud@=Ohaz!y zpoFXIY-L_>SudaDe#0bdzR5te7-n>YwYUD)0}(^=zWJvc%Nc?y7c0ZeDi|H4Vh|=< zp$9PS{eBsh)eXj2w#yVu{d5BwD;pA^v^0^ye7*td9bnGuzas<U*vqMC@TFb{7Yxk6 z6HoL6E5+q|0Vs4dvIHID(f)H&wIvq4Z|teC6pNR!=ulP!ES1+&pcXksA3dhVWp=Ge zNATz<tb23HViYz4;4V=TPeQQAaR#aj9C`6>=9SWh0AKuht(@AT=Gwx^vX_L2!6$u> z2D`3|4aiGnLj@1z{$<NBeWQ)z!I8?uSDQ!26HmV2w(V+E_>gdeyuQ{t!$b@7qEwmd z3k>sT807yz!#xbwEfYOxb9D!e97xl&x&PcKYy+4rR5VKqmCbP%%~%OnY^&_AL-SnF z&avW3c~-KTBtKF%vWGeR>U-Ydq26IA8DA{WoI^^vXzeE+-Q=D+Ua+h#;SC?CK&7xh zR@nSVL#C!VXA+Eh9chX#1`X2DQAOkH<@^z*Iz!FKGD~eI%<r*{+(EKzsD*P{B0l`J z$`{5B<$84;QiRRk%ocepUK#4HbAH;XeD93Gl{gzF5x)@h_>p;2^$3FA^T@tcy%l!G z42qt8b3CPAu7l@b&|{ZOc9KbprY#eR)AdGjRAg_UsfAM^$>!Bx>|GDZs?Slwb11PF zQzYT6+?W}$ggrJ!6WzD;!|LS7iGtx;Tdry&o%7=R+nY?`MeFYbFVwSDOY|=wG#q^b zDrQP6R%TN<Xqlh=GPY0#azN;)6QqXTUb~@tLFkYL)otjvQ-C`9Wo!wz898$AhrIHR z7IQnrbv(uLNlJHgaR`sfFGE77*2#_<OPZcIZvC8A`zjyV)ik>*ftWNxi~*UG>mq^G z>w1Ye`$3iKA*)GIH<Cqv_U+GY)fMwTu@yKpMAAufNKF^TBhq_OC4B~J_+m}xsG6a- z?LCUECCG_8Qwv4mew7wbp);%bSzcSt2k2M#+^sh7f3%q3y}ki8xz|#Q9j~GL3hrwj zj7lo;c~1mcLczuI863p^GPH#9)r=7NyU3+FHQ9q?IiWrN`im6!A#L_!BhwGjecrkv zV)A4*PF#(O<f-}^Y(qMd75g})@Q$9fW~O!zql8Fvt7{WNJ-Lmu)Feu~eO~gnmD9(k z@5T=%>=ViySTimNn~-U{iNYn`dhmp9E6&(GI3RRVXJuB$2l#5+eTQw<ueOn2eD4K4 z=kDI7|0mxppl{&gK1(>RD)TdVyuCO;-#7;kR~Njr3zpz$2O@lLx8Ym~o_K<%fQ^T% z4-xNSWou(^g|)SHB`63;vtZD4^#6i<>uY2`u>Av1ft<kYBie5h=%*I7<8eC`X@@4Y z;!W_6W`zEjAngR87L)-^f1L+ErbgR>sns?<t08|>Zg&r)mg`^us5&C_Q(XU`M%!Je z)#{)Cb+7qnx!pBOEmzJ6&{Qz=Qw4uVZ+9_K>k*g$+R}o4Dy{!2_^n+|Ehr2FcJKLb TQ9~Jlk7+Uk6j1phZ2RnQ9pEq>
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js +++ b/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js @@ -3,46 +3,59 @@ // Make sure the add-on actor can see loaded JS Modules from an add-on 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."); // 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(); }); }
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules.js +++ b/browser/devtools/debugger/test/browser_dbg_addon-modules.js @@ -3,46 +3,59 @@ // Make sure the add-on actor can see loaded JS Modules from an add-on 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."); // 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(); }); }
--- a/browser/devtools/debugger/test/head.js +++ b/browser/devtools/debugger/test/head.js @@ -113,17 +113,21 @@ function addAddon(aUrl) { let deferred = promise.defer(); AddonManager.getInstallForURL(aUrl, aInstaller => { aInstaller.install(); 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); }, "application/x-xpinstall"); return deferred.promise; }
--- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -608,16 +608,17 @@ toolbarbutton[sdk-button="true"][cui-are width: 32px; } #nav-bar #PanelUI-menu-button { -moz-padding-start: 7px; -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, :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon { background-color: hsla(0,0%,100%,.3); background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.2)); border: 1px solid rgb(154,154,154); box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset, @@ -626,33 +627,34 @@ toolbarbutton[sdk-button="true"][cui-are } :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { margin-top: 4px; 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 { background-color: rgba(154,154,154,.5); background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4)); border: 1px solid rgb(154,154,154); box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset, 0 0 1px hsla(0,0%,0%,.3) inset; transition-duration: 10ms; } :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon { background-color: rgba(90%,90%,90%,.4); 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; } :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before { content: ""; display: -moz-box;
deleted file mode 100644 --- 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; -}
--- a/browser/themes/linux/jar.mn +++ b/browser/themes/linux/jar.mn @@ -100,17 +100,16 @@ browser.jar: skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png) 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/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) skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png) skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png) skin/classic/browser/places/bookmarks-notification-finish.png (places/bookmarks-notification-finish.png) skin/classic/browser/places/bookmarks-menu-arrow.png (places/bookmarks-menu-arrow.png) skin/classic/browser/places/calendar.png (places/calendar.png) @@ -196,17 +195,17 @@ browser.jar: skin/classic/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png) skin/classic/browser/devtools/command-tilt.png (../shared/devtools/images/command-tilt.png) skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png) skin/classic/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png) skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png) 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) 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) skin/classic/browser/devtools/editor-breakpoint.png (devtools/editor-breakpoint.png) skin/classic/browser/devtools/editor-debug-location.png (devtools/editor-debug-location.png)
--- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -507,31 +507,33 @@ toolbar .toolbarbutton-1 > .toolbarbutto transition-duration: 250ms; } toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forward-button)) { padding: 0 4px; } 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 { border-color: hsla(0,0%,0%,.2); box-shadow: 0 1px 0 hsla(0,0%,100%,.5), 0 1px 0 hsla(0,0%,100%,.5) inset; } toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover, toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover] > .toolbarbutton-menubutton-button, toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover > .toolbarbutton-menubutton-dropmarker { background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box; } 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 { background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), hsla(0,0%,0%,0)) border-box; border-color: hsla(0,0%,0%,.3); box-shadow: 0 1px 0 hsla(0,0%,100%,.5), 0 1px 0 hsla(0,0%,0%,.05) inset, 0 1px 1px hsla(0,0%,0%,.2) inset;
deleted file mode 100644 --- a/browser/themes/osx/devtools/ruleview.css +++ /dev/null @@ -1,154 +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; - -moz-user-select: none; - word-wrap: break-word; -} - -.ruleview-rule-pseudo-element { - padding-left:20px; - border-left: solid 10px; -} - -.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; -}
--- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -164,17 +164,16 @@ browser.jar: skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css) skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png) 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) skin/classic/browser/setDesktopBackground.css skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png) * skin/classic/browser/places/places.css (places/places.css) @@ -317,17 +316,17 @@ browser.jar: skin/classic/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png) skin/classic/browser/devtools/command-tilt.png (../shared/devtools/images/command-tilt.png) skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png) skin/classic/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png) skin/classic/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png) 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) skin/classic/browser/devtools/editor-breakpoint.png (devtools/editor-breakpoint.png) skin/classic/browser/devtools/editor-debug-location.png (devtools/editor-debug-location.png) * 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)
deleted file mode 100644 index fe686f8d2a1343973005977cf21b00b8a388d56a..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/browser/themes/shared/devtools/ruleview.css @@ -0,0 +1,161 @@ +/* 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; + -moz-user-select: none; + word-wrap: break-word; +%ifndef XP_MACOSX + margin-top: 4px; +%endif +} + +.ruleview-rule-pseudo-element { + padding-left:20px; + border-left: solid 10px; +} + +.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: 3px solid transparent; + clear: right; +} + +.ruleview-property > * { + vertical-align: middle; +} + +.theme-dark .ruleview-property[dirty] { + border-left-color: #70bf53; /* Green */ +} + +.theme-light .ruleview-property[dirty] { + border-left-color: #2cbb0f; /* Green */ +} + +.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; +}
--- a/browser/themes/shared/incontentprefs/preferences.css +++ b/browser/themes/shared/incontentprefs/preferences.css @@ -2,17 +2,17 @@ /* - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this file, - You can obtain one at http://mozilla.org/MPL/2.0/. */ %endif @namespace html "http://www.w3.org/1999/xhtml"; @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 { -moz-appearance: none; background-image: linear-gradient(#FFFFFF, #EDEDED 100px); } caption {
--- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -725,16 +725,17 @@ toolbarbutton[sdk-button="true"][cui-are background-repeat: no-repeat; background-size: 1px 16px; } @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .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, #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text, #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container, @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon, #nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon { background-color: hsla(210,4%,10%,.08); @@ -794,17 +795,17 @@ toolbarbutton[sdk-button="true"][cui-are background-color: hsla(210,48%,96%,.75); box-shadow: 0 0 1px hsla(210,54%,20%,.03), 0 0 2px hsla(210,54%,20%,.1); } %ifdef WINDOWS_AERO } %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, #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container { background-color: hsla(210,4%,10%,.12); border-top-color: hsla(210,4%,10%,.2); box-shadow: 0 1px 0 0 hsla(210,4%,10%,.1) inset; transition-duration: 10ms;
deleted file mode 100644 --- 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; -}
--- a/browser/themes/windows/jar.mn +++ b/browser/themes/windows/jar.mn @@ -121,17 +121,16 @@ browser.jar: skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.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/feeds/videoFeedIcon.png (feeds/feedIcon.png) 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) * skin/classic/browser/places/organizer.css (places/organizer.css) skin/classic/browser/places/bookmark.png (places/bookmark.png) skin/classic/browser/places/query.png (places/query.png) skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png) skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png) @@ -221,17 +220,17 @@ browser.jar: * skin/classic/browser/devtools/dark-theme.css (../shared/devtools/dark-theme.css) * skin/classic/browser/devtools/light-theme.css (../shared/devtools/light-theme.css) skin/classic/browser/devtools/filters.svg (../shared/devtools/filters.svg) skin/classic/browser/devtools/controls.png (../shared/devtools/images/controls.png) skin/classic/browser/devtools/controls@2x.png (../shared/devtools/images/controls@2x.png) * 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) skin/classic/browser/devtools/command-responsivemode.png (../shared/devtools/images/command-responsivemode.png) skin/classic/browser/devtools/command-responsivemode@2x.png (../shared/devtools/images/command-responsivemode@2x.png) skin/classic/browser/devtools/command-scratchpad.png (../shared/devtools/images/command-scratchpad.png) skin/classic/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png) skin/classic/browser/devtools/command-tilt.png (../shared/devtools/images/command-tilt.png) @@ -486,17 +485,16 @@ browser.jar: skin/classic/aero/browser/feeds/feedIcon.png (feeds/feedIcon-aero.png) skin/classic/aero/browser/feeds/feedIcon16.png (feeds/feedIcon16-aero.png) skin/classic/aero/browser/feeds/audioFeedIcon.png (feeds/feedIcon-aero.png) skin/classic/aero/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16-aero.png) skin/classic/aero/browser/feeds/videoFeedIcon.png (feeds/feedIcon-aero.png) 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) * skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css) skin/classic/aero/browser/places/bookmark.png (places/bookmark-aero.png) skin/classic/aero/browser/places/query.png (places/query-aero.png) skin/classic/aero/browser/places/bookmarksMenu.png (places/bookmarksMenu-aero.png) skin/classic/aero/browser/places/bookmarksToolbar.png (places/bookmarksToolbar-aero.png) @@ -597,17 +595,17 @@ browser.jar: skin/classic/aero/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png) skin/classic/aero/browser/devtools/command-tilt.png (../shared/devtools/images/command-tilt.png) skin/classic/aero/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png) skin/classic/aero/browser/devtools/command-pick.png (../shared/devtools/images/command-pick.png) skin/classic/aero/browser/devtools/command-pick@2x.png (../shared/devtools/images/command-pick@2x.png) 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) skin/classic/aero/browser/devtools/editor-breakpoint.png (devtools/editor-breakpoint.png) skin/classic/aero/browser/devtools/editor-debug-location.png (devtools/editor-debug-location.png) * skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css) skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css) skin/classic/aero/browser/devtools/webconsole.png (devtools/webconsole.png)
--- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -486,75 +486,17 @@ abstract public class BrowserApp extends mBrowserSearchContainer = findViewById(R.id.search_container); mBrowserSearch = (BrowserSearch) getSupportFragmentManager().findFragmentByTag(BROWSER_SEARCH_TAG); if (mBrowserSearch == null) { mBrowserSearch = BrowserSearch.newInstance(); 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); registerEventListener("CharEncoding:Data"); registerEventListener("CharEncoding:State"); registerEventListener("Feedback:LastUrl"); registerEventListener("Feedback:OpenPlayStore"); @@ -634,16 +576,78 @@ abstract public class BrowserApp extends @Override public void onPause() { super.onPause(); // Register for Prompt:ShowTop so we can foreground this activity even if it's hidden. 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() { @Override public void onPromptFinished(String result) { int itemId = -1; try { itemId = new JSONObject(result).getInt("button");
--- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -3,26 +3,22 @@ * 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/. */ 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; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.Queue; @@ -105,17 +101,16 @@ import android.view.ContextThemeWrapper; import android.view.HapticFeedbackConstants; import android.view.Surface; import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.webkit.MimeTypeMap; import android.widget.AbsoluteLayout; -import android.widget.Toast; public class GeckoAppShell { private static final String LOGTAG = "GeckoAppShell"; private static final boolean LOGGING = false; // We have static members only. private GeckoAppShell() { }
--- a/mobile/android/base/WebappImpl.java +++ b/mobile/android/base/WebappImpl.java @@ -18,23 +18,23 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.view.animation.AnimationUtils; 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; private View mSplashscreen; protected int getIndex() { return 0; } @Override @@ -64,28 +64,28 @@ public class WebappImpl extends GeckoApp if (!action.startsWith(ACTION_WEBAPP_PREFIX)) { Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!"); return; } // 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; } // 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); } } } @Override protected void loadStartupTab(String uri) { String action = getIntent().getAction(); @@ -159,38 +159,38 @@ public class WebappImpl extends GeckoApp @Override public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) { switch(msg) { case SELECTED: 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 // the titlebar and return, otherwise show the titlebar // and the full url if (!urlString.startsWith("app://")) { mTitlebar.setVisibility(View.VISIBLE); } else { mTitlebar.setVisibility(View.GONE); } 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); } } break; case LOADED: if (mSplashscreen != null && mSplashscreen.getVisibility() == View.VISIBLE) { Animation fadeout = AnimationUtils.loadAnimation(this, android.R.anim.fade_out); fadeout.setAnimationListener(new Animation.AnimationListener() {
--- a/mobile/android/base/background/nativecode/NativeCrypto.java +++ b/mobile/android/base/background/nativecode/NativeCrypto.java @@ -1,22 +1,40 @@ /* 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/. */ 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); + } + } + } } /** * Wrapper to perform PBKDF2-HMAC-SHA-256 in native code. */ public native static byte[] pbkdf2SHA256(byte[] password, byte[] salt, int c, int dkLen) throws GeneralSecurityException;
--- a/mobile/android/base/db/PasswordsProvider.java +++ b/mobile/android/base/db/PasswordsProvider.java @@ -1,27 +1,27 @@ /* 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/. */ 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.DeletedPasswords; import org.mozilla.gecko.db.BrowserContract.Passwords; -import org.mozilla.gecko.db.BrowserContract.DeletedPasswords; -import org.mozilla.gecko.db.BrowserContract; +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; import android.database.Cursor; import android.net.Uri; import android.text.TextUtils; import android.util.Log; @@ -71,17 +71,20 @@ public class PasswordsProvider extends S PASSWORDS_PROJECTION_MAP.put(Passwords.TIMES_USED, Passwords.TIMES_USED); URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS); DELETED_PASSWORDS_PROJECTION_MAP = new HashMap<String, String>(); 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() { super(LOG_TAG); } @Override protected String getDBName(){
--- a/mobile/android/base/mozglue/GeckoLoader.java.in +++ b/mobile/android/base/mozglue/GeckoLoader.java.in @@ -1,8 +1,9 @@ +#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 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.mozglue; import android.content.Context; @@ -15,16 +16,19 @@ import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; 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; private static final Object sLibLoadingLock = new Object(); // Must hold sLibLoadingLock while accessing the following boolean variables. private static boolean sSQLiteLibsLoaded; private static boolean sNSSLibsLoaded; @@ -254,25 +258,44 @@ public final class GeckoLoader { sNSSLibsLoaded = true; } loadMozGlue(); loadLibsSetup(context); 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) { return; } sMozGlueLoaded = true; } - System.loadLibrary("mozglue"); + doLoadLibrary("mozglue"); } public static void loadGeckoLibs(Context context, String apkName) { loadLibsSetup(context); loadGeckoLibsNative(apkName); } private static void setupLocaleEnvironment() {
--- a/mobile/android/base/util/GeckoJarReader.java +++ b/mobile/android/base/util/GeckoJarReader.java @@ -11,17 +11,18 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.util.Log; import org.mozilla.gecko.mozglue.RobocopTarget; 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 * jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png */ public final class GeckoJarReader { private static final String LOGTAG = "GeckoJarReader"; @@ -42,16 +43,18 @@ public final class GeckoJarReader { // Load the initial jar file as a zip zip = getZipFile(jarUrls.pop()); inputStream = getStream(zip, jarUrls, url); if (inputStream != null) { bitmap = new BitmapDrawable(resources, inputStream); } } catch (IOException ex) { Log.e(LOGTAG, "Exception ", ex); + } catch (URISyntaxException ex) { + Log.e(LOGTAG, "Exception ", ex); } finally { if (inputStream != null) { try { inputStream.close(); } catch(IOException ex) { Log.e(LOGTAG, "Error closing stream", ex); } } @@ -73,34 +76,36 @@ public final class GeckoJarReader { zip = getZipFile(jarUrls.pop()); InputStream input = getStream(zip, jarUrls, url); if (input != null) { reader = new BufferedReader(new InputStreamReader(input)); text = reader.readLine(); } } catch (IOException ex) { Log.e(LOGTAG, "Exception ", ex); + } catch (URISyntaxException ex) { + Log.e(LOGTAG, "Exception ", ex); } finally { if (reader != null) { try { reader.close(); } catch(IOException ex) { Log.e(LOGTAG, "Error closing reader", ex); } } if (zip != null) { zip.close(); } } 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()); } @RobocopTarget public static InputStream getStream(String url) { Stack<String> jarUrls = parseUrl(url); try { NativeZip zip = getZipFile(jarUrls.pop());
--- a/mobile/android/base/util/JSONUtils.java +++ b/mobile/android/base/util/JSONUtils.java @@ -1,51 +1,22 @@ /* 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/. */ 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; } public static void putUUID(String name, UUID uuid, JSONObject json) { String uuidString = uuid.toString(); try {
--- a/mobile/android/base/webapp/InstallListener.java +++ b/mobile/android/base/webapp/InstallListener.java @@ -2,18 +2,16 @@ * 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/. */ 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; import org.mozilla.gecko.GeckoThread; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent;
--- a/mobile/android/base/webapp/WebappImpl.java +++ b/mobile/android/base/webapp/WebappImpl.java @@ -2,55 +2,48 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 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; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoEvent; 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; import android.os.Bundle; import android.util.Log; import android.view.Display; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; 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; private View mSplashscreen; private boolean mIsApk = true; private ApkResources mApkResources; private String mManifestUrl; @@ -267,38 +260,38 @@ public class WebappImpl extends GeckoApp // Don't show the titlebar for about:blank, which we load // into the initial tab we create while waiting for the app // to load. if (urlString != null && urlString.equals("about:blank")) { mTitlebar.setVisibility(View.GONE); 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 // the titlebar and return, otherwise show the titlebar // and the full url if (urlString != null && !urlString.startsWith("app://")) { mTitlebar.setVisibility(View.VISIBLE); } else { mTitlebar.setVisibility(View.GONE); } 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); } } break; case LOADED: hideSplash(); break; case START: @@ -345,31 +338,31 @@ public class WebappImpl extends GeckoApp @Override public void installErrored(InstallHelper installHelper, Exception exception) { Log.e(LOGTAG, "Install errored", exception); } 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; } // If that failed fall back to the origin stored in the shortcut. if (!mIsApk) { Log.i(LOGTAG, "Origin is app: URL; falling back to intent URL"); 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); } } } } } public void launchWebapp(String origin) {
--- a/python/mozbuild/mozbuild/backend/android_eclipse.py +++ b/python/mozbuild/mozbuild/backend/android_eclipse.py @@ -233,16 +233,17 @@ class AndroidEclipseBackend(CommonBacken defines['IDE_PROJECT_LIBRARY_REFERENCES'] = '\n'.join( 'android.library.reference.%s=%s' % (i + 1, ref) for i, ref in enumerate(sorted(data.included_projects))) if data.filtered_resources: filteredResources = self._Element_for_filtered_resources(data.filtered_resources) 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) for input_filename, f in itertools.chain(finder.find('**'), finder.find('.**')): if input_filename == 'AndroidManifest.xml' and not data.is_library: # Main projects supply their own manifests. continue copier.add(input_filename, PreprocessedFile(
--- a/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties +++ b/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties @@ -4,11 +4,11 @@ # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # Project target. -target=android-16 +target=android-@ANDROID_TARGET_SDK@ @IDE_PROJECT_LIBRARY_SETTING@ @IDE_PROJECT_LIBRARY_REFERENCES@
--- a/python/mozbuild/mozbuild/test/backend/common.py +++ b/python/mozbuild/mozbuild/test/backend/common.py @@ -24,16 +24,23 @@ log_manager = LoggingManager() log_manager.add_terminal_logging() test_data_path = mozpath.abspath(mozpath.dirname(__file__)) 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'), ('MOZ_TRUE_2', '1'), ], 'non_global_defines': [ ('MOZ_NONGLOBAL_1', '1'), ('MOZ_NONGLOBAL_2', '1'),
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm +++ b/toolkit/components/osfile/modules/osfile_async_front.jsm @@ -174,18 +174,18 @@ function summarizeObject(obj) { for (let k of Object.keys(obj)) { result[k] = summarizeObject(obj[k]); } return result; } 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. */ launched: false, /** * |true| once shutdown has begun i.e. we should reject any @@ -233,16 +233,35 @@ let Scheduler = { }, /** * A timer used to automatically shut down the worker after some time. */ 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. */ restartTimer: function(arg) { let delay; try { delay = Services.prefs.getIntPref("osfile.reset_worker_delay"); } catch(e) { // Don't auto-shutdown if we don't have a delay preference set. @@ -268,34 +287,41 @@ let Scheduler = { * would not cause leaks. Otherwise, assume that the worker will be shutdown * through some other mean. */ kill: function({shutdown, reset}) { return Task.spawn(function*() { 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; } // Deactivate the queue, to ensure that no message is sent // to an obsolete worker (we reactivate it in the |finally|). 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; try { resources = (yield promise).ok; Scheduler.latestReceived = [Date.now(), message]; } catch (ex) { @@ -324,17 +350,17 @@ let Scheduler = { openedDirectoryIterators.join("\n"); } LOG("WARNING: File descriptors leaks detected.\n" + msg); } // Make sure that we do not leave an invalid |worker| around. if (killed || shutdown) { - worker = null; + this._worker = null; } this.shutdown = shutdown; return resources; } finally { // Resume accepting messages. If we have set |shutdown| to |true|, @@ -371,55 +397,56 @@ let Scheduler = { * must be clonable. * @return {Promise} A promise conveying the result/error caused by * calling |method| with arguments |args|. */ post: function post(method, ...args) { 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++; } // By convention, the last argument of any message may be an |options| object. let options; let methodArgs = args[0]; if (methodArgs) { 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; Scheduler.Debugging.latestSent = [Date.now(), method, summarizeObject(methodArgs)]; // Don't kill the worker just yet Scheduler.restartTimer(); let data; let reply; let isError = false; try { try { - data = yield worker.post(method, ...args); + data = yield this.worker.post(method, ...args); } finally { Scheduler.Debugging.messagesReceived++; } reply = data; } catch (error) { reply = error; isError = true; if (error instanceof PromiseWorker.WorkerError) { @@ -469,25 +496,26 @@ let Scheduler = { let durationMs = Math.max(0, data.durationMs); // Accumulate (or initialize) outExecutionDuration if (typeof options.outExecutionDuration == "number") { options.outExecutionDuration += durationMs; } else { options.outExecutionDuration = durationMs; } return data.ok; - })); + }.bind(this))); }, /** * Post Telemetry statistics. * * 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, // the timestamps are absent. As this case is a developer error, // let's not waste time attempting to extract telemetry from it. return; } let HISTOGRAM_LAUNCH = Services.telemetry.getHistogramById("OSFILE_WORKER_LAUNCH_MS"); @@ -1477,17 +1505,17 @@ AsyncShutdown.profileBeforeChange.addBlo } else { return Scheduler.queue; } }, function getDetails() { let result = { launched: Scheduler.launched, shutdown: Scheduler.shutdown, - worker: !!worker, + worker: !!Scheduler._worker, pendingReset: !!Scheduler.resetTimer, latestSent: Scheduler.Debugging.latestSent, latestReceived: Scheduler.Debugging.latestReceived, messagesSent: Scheduler.Debugging.messagesSent, messagesReceived: Scheduler.Debugging.messagesReceived, messagesQueued: Scheduler.Debugging.messagesQueued, DEBUG: SharedAll.Config.DEBUG };
--- a/toolkit/components/osfile/modules/osfile_async_worker.js +++ b/toolkit/components/osfile/modules/osfile_async_worker.js @@ -76,17 +76,17 @@ const EXCEPTION_NAMES = { let durationMs; try { let method = data.fun; LOG("Calling method", method); result = Agent[method].apply(Agent, data.args); 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) { // Record duration durationMs = Date.now() - start; LOG("Method took", durationMs, "ms"); }
--- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -151,58 +151,73 @@ this.PlacesUtils = { /** * Determines whether or not a ResultNode is a Bookmark folder. * @param aNode * A result node * @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); }, /** * Determines whether or not a ResultNode represents a bookmarked URI. * @param aNode * A result node * @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; }, /** * Determines whether or not a ResultNode is a Bookmark separator. * @param aNode * A result node * @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; }, /** * Determines whether or not a ResultNode is a URL item. * @param aNode * A result node * @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; }, /** * Determines whether or not a ResultNode is a Query item. * @param aNode * A result node * @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; }, /** * Generator for a node's ancestors. * @param aNode * A result node */ @@ -352,16 +367,19 @@ this.PlacesUtils = { /** * Determines if a node is read only (children cannot be inserted, sometimes * they cannot be removed depending on the circumstance) * @param aNode * A result node * @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; } if (this.nodeIsQuery(aNode) && asQuery(aNode).queryOptions.resultType != Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS) @@ -371,59 +389,71 @@ this.PlacesUtils = { /** * Determines whether or not a ResultNode is a host container. * @param aNode * A result node * @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 == Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY; }, /** * Determines whether or not a ResultNode is a day container. * @param node * A NavHistoryResultNode * @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 && ((resultType = asQuery(aNode.parent).queryOptions.resultType) == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY || resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY); }, /** * Determines whether or not a result-node is a tag container. * @param aNode * A result-node * @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; }, /** * Determines whether or not a ResultNode is a container. * @param aNode * A result node * @returns true if the node is a container item, false otherwise */ containerTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER, 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; }, /** * Determines whether or not a ResultNode is an history related container. * @param node * A result node * @returns true if the node is an history related container, false otherwise
new file mode 100644 --- /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/); + } +} +
--- a/toolkit/components/places/tests/unit/xpcshell.ini +++ b/toolkit/components/places/tests/unit/xpcshell.ini @@ -112,16 +112,17 @@ fail-if = os == "android" skip-if = true [test_null_interfaces.js] [test_onItemChanged_tags.js] [test_pageGuid_bookmarkGuid.js] [test_frecency_observers.js] [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 skip-if = os == "android" [test_preventive_maintenance_checkAndFixDatabase.js] # Bug 676989: test hangs consistently on Android skip-if = os == "android" [test_preventive_maintenance_runTasks.js]
--- a/toolkit/devtools/server/actors/highlighter.js +++ b/toolkit/devtools/server/actors/highlighter.js @@ -66,17 +66,21 @@ let HighlighterActor = protocol.ActorCla get conn() this._inspector && this._inspector.conn, /** * Can the host support the box model highlighter which requires a parent * XUL node to attach itself. */ _supportsBoxModelHighlighter: function() { - return this._tabActor.browser && !!this._tabActor.browser.parentNode; + // Note that <browser>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() { protocol.Actor.prototype.destroy.call(this); if (this._boxModelHighlighter) { this._boxModelHighlighter.off("ready", this._highlighterReady); this._boxModelHighlighter.off("hide", this._highlighterHidden); this._boxModelHighlighter.destroy();
--- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -19,18 +19,19 @@ let addonManager = null; /** * This is a wrapper around amIAddonManager.mapURIToAddonID which always returns * false on B2G to avoid loading the add-on manager there and reports any * exceptions rather than throwing so that the caller doesn't have to worry * 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"]. getService(Ci.amIAddonManager); } try { return addonManager.mapURIToAddonID(uri, id); @@ -4772,29 +4773,56 @@ function AddonThreadActor(aConnect, aHoo AddonThreadActor.prototype = Object.create(ThreadActor.prototype); update(AddonThreadActor.prototype, { constructor: AddonThreadActor, // 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 * add-ons. */ _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; }, /** * An object that will be used by ThreadActors to tailor their * behaviour depending on the debugging context being required (chrome, * addon or content). The methods that this object provides must @@ -4831,44 +4859,72 @@ update(AddonThreadActor.prototype, { }, /** * Checks if the provided global belongs to the debugged add-on. * * @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; } } return false; } }); +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. */ function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate, aOnNewSource) { this._thread = aThreadActor; this._useSourceMaps = aUseSourceMaps;
--- a/toolkit/modules/ShortcutUtils.jsm +++ b/toolkit/modules/ShortcutUtils.jsm @@ -29,26 +29,26 @@ let ShortcutUtils = { * @param boolean aNoCloverLeaf * Pass true to use a descriptive string instead of the cloverleaf symbol. (OS X only) * @return string * A prettified and properly separated modifier keys string. */ prettifyShortcut: function(aElemKey, aNoCloverLeaf) { let elemString = ""; let elemMod = aElemKey.getAttribute("modifiers"); + let haveCloverLeaf = false; if (elemMod.match("accel")) { if (Services.appinfo.OS == "Darwin") { // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until // Orion adds variable height lines. if (aNoCloverLeaf) { elemString += "Cmd-"; } else { - elemString += PlatformKeys.GetStringFromName("VK_META") + - PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR"); + haveCloverLeaf = true; } } else { elemString += PlatformKeys.GetStringFromName("VK_CONTROL") + PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR"); } } if (elemMod.match("access")) { if (Services.appinfo.OS == "Darwin") { @@ -75,16 +75,21 @@ let ShortcutUtils = { elemString += PlatformKeys.GetStringFromName("VK_CONTROL") + PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR"); } if (elemMod.match("meta")) { elemString += PlatformKeys.GetStringFromName("VK_META") + PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR"); } + if (haveCloverLeaf) { + elemString += PlatformKeys.GetStringFromName("VK_META") + + PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR"); + } + let key; let keyCode = aElemKey.getAttribute("keycode"); if (keyCode) { try { // Some keys might not exist in the locale file, which will throw: key = Keys.GetStringFromName(keyCode.toUpperCase()); } catch (ex) { Cu.reportError("Error finding " + keyCode + ": " + ex);
--- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -13,16 +13,20 @@ const Cr = Components.results; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/AddonManager.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); 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"; const KEY_APPDIR = "XCurProcD"; const FILE_BLOCKLIST = "blocklist.xml"; const PREF_BLOCKLIST_LASTUPDATETIME = "app.update.lastUpdateTime.blocklist-background-update-timer"; const PREF_BLOCKLIST_URL = "extensions.blocklist.url"; const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL"; @@ -562,47 +566,47 @@ Blocklist.prototype = { request.send(null); // When the blocklist loads we need to compare it to the current copy so // make sure we have loaded it. if (!this._addonEntries) 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); } catch (e) { 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); - 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 { var request = aEvent.target; // the following may throw (e.g. a local file or timeout) var status = request.status; } catch (e) { @@ -699,27 +703,56 @@ Blocklist.prototype = { _loadBlocklistFromFile: function Blocklist_loadBlocklistFromFile(file) { if (!gBlocklistEnabled) { LOG("Blocklist::_loadBlocklistFromFile: blocklist is disabled"); return; } 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" + "Received: " + doc.documentElement.namespaceURI); return; } var childNodes = doc.documentElement.childNodes; @@ -741,17 +774,16 @@ Blocklist.prototype = { null); } } } catch (e) { LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e); return; } - fileStream.close(); }, _processItemNodes: function Blocklist_processItemNodes(itemNodes, prefix, handler) { var result = []; var itemName = prefix + "Item"; for (var i = 0; i < itemNodes.length; ++i) { var blocklistElement = itemNodes.item(i); if (!(blocklistElement instanceof Ci.nsIDOMElement) ||