Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-03-07 15:18:32 +01:00
commit 41ba400533
432 changed files with 21141 additions and 16452 deletions

View File

@ -131,3 +131,4 @@ d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
f80dc9fc34680105b714a49b4704bb843f5f7004 FIREFOX_AURORA_53_BASE
6583496f169cd8a13c531ed16e98e8bf313eda8e FIREFOX_AURORA_54_BASE

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1343432 - jemalloc update needs a clobber
Merge day clobber

View File

@ -29,7 +29,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Sprintf.h"
#include "nsXPCOMStrings.h"
#include "nsComponentManagerUtils.h"
#include "nsIPersistentProperties2.h"

View File

@ -169,6 +169,8 @@ pref("extensions.dss.switchPending", false); // Non-dynamic switch pending af
pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
pref("extensions.webextensions.themes.icons.buttons", "back,forward,reload,stop,bookmark_star,bookmark_menu,downloads,home,app_menu,cut,copy,paste,new_window,new_private_window,save_page,print,history,full_screen,find,options,addons,developer,synced_tabs,open_file,sidebars,share_page,subscribe,text_encoding,email_link,forget,pocket");
pref("lightweightThemes.update.enabled", true);
pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"}]");
@ -1247,19 +1249,15 @@ pref("dom.debug.propagate_gesture_events_through_content", false);
// All the Geolocation preferences are here.
//
// The request URL of the GeoLocation backend.
#ifdef RELEASE_OR_BETA
// Geolocation preferences for the RELEASE channel.
// Some of these prefs are specified even though they are redundant; they are
// here for clarity and end-user experiments.
#ifdef RELEASE
pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
#else
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#endif
#ifdef XP_MACOSX
#ifdef RELEASE_OR_BETA
pref("geo.provider.use_corelocation", false);
#else
pref("geo.provider.use_corelocation", true);
#endif
#endif
#ifdef XP_WIN
@ -1267,13 +1265,28 @@ pref("geo.provider.ms-windows-location", false);
#endif
#ifdef MOZ_WIDGET_GTK
#ifdef MOZ_GPSD
#ifdef RELEASE_OR_BETA
pref("geo.provider.use_gpsd", false);
#endif
#else
// Geolocation preferences for Nightly/Aurora/Beta.
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#ifdef XP_MACOSX
pref("geo.provider.use_corelocation", true);
#endif
// The native Windows location provider is only enabled in Nightly and likely to
// be unstable. Set to false if things are really broken.
#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
pref("geo.provider.ms-windows-location", true);
#endif
#if defined(MOZ_WIDGET_GTK) && defined(MOZ_GPSD)
pref("geo.provider.use_gpsd", true);
#endif
#endif
#endif
// We keep allowing non-HTTPS geo requests on all the release

View File

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
if (AppConstants.MOZ_SERVICES_CLOUDSYNC) {
XPCOMUtils.defineLazyModuleGetter(this, "CloudSync",
@ -40,8 +41,6 @@ var gSyncUI = {
_syncAnimationTimer: 0,
init() {
Cu.import("resource://services-common/stringbundle.js");
// Proceed to set up the UI if Sync has already started up.
// Otherwise we'll do it when Sync is firing up.
if (this.weaveService.ready) {
@ -224,8 +223,9 @@ var gSyncUI = {
},
_getAppName() {
let brand = new StringBundle("chrome://branding/locale/brand.properties");
return brand.get("brandShortName");
let brand = Services.strings.createBundle(
"chrome://branding/locale/brand.properties");
return brand.GetStringFromName("brandShortName");
},
// Commands
@ -475,9 +475,8 @@ var gSyncUI = {
XPCOMUtils.defineLazyGetter(gSyncUI, "_stringBundle", function() {
// XXXzpao these strings should probably be moved from /services to /browser... (bug 583381)
// but for now just make it work
return Cc["@mozilla.org/intl/stringbundle;1"].
getService(Ci.nsIStringBundleService).
createBundle("chrome://weave/locale/services/sync.properties");
return Services.strings.createBundle(
"chrome://weave/locale/services/sync.properties");
});
XPCOMUtils.defineLazyGetter(gSyncUI, "log", function() {

View File

@ -1264,3 +1264,5 @@ toolbarpaletteitem[place="palette"][hidden] {
opacity: 0.65;
-moz-window-shadow: none;
}
%include theme-vars.inc.css

View File

@ -829,6 +829,8 @@ function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
return;
}
let contentPrincipal = browser.contentPrincipal;
// At this point we're still only just about to load this URI.
// When the async DNS lookup comes back, we may be in any of these states:
// 1) still on the previous URI, waiting for the preferredURI (keyword
@ -931,7 +933,8 @@ function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
};
try {
gDNSService.asyncResolve(hostName, 0, onLookupComplete, Services.tm.mainThread);
gDNSService.asyncResolve(hostName, 0, onLookupComplete, Services.tm.mainThread,
contentPrincipal.originAttributes);
} catch (ex) {
// Do nothing if the URL is invalid (we don't want to show a notification in that case).
if (ex.result != Cr.NS_ERROR_UNKNOWN_HOST) {
@ -6721,6 +6724,12 @@ var gIdentityHandler = {
*/
_state: 0,
/**
* This flag gets set if the identity popup was opened by a keypress,
* to be able to focus it on the popupshown event.
*/
_popupTriggeredByKeyboard: false,
get _isBroken() {
return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
},
@ -6855,6 +6864,10 @@ var gIdentityHandler = {
delete this._permissionReloadHint;
return this._permissionReloadHint = document.getElementById("identity-popup-permission-reload-hint");
},
get _popupExpander() {
delete this._popupExpander;
return this._popupExpander = document.getElementById("identity-popup-security-expander");
},
get _permissionAnchors() {
delete this._permissionAnchors;
let permissionAnchors = {};
@ -6876,10 +6889,18 @@ var gIdentityHandler = {
toggleSubView(name, anchor) {
let view = this._identityPopupMultiView;
let id = `identity-popup-${name}View`;
let subView = document.getElementById(id);
// Listen for the subview showing or hiding to change
// the tooltip on the expander button.
subView.addEventListener("ViewShowing", this);
subView.addEventListener("ViewHiding", this);
if (view.showingSubView) {
view.showMainView();
} else {
view.showSubView(`identity-popup-${name}View`, anchor);
view.showSubView(id, anchor);
}
// If an element is focused that's not the anchor, clear the focus.
@ -7188,6 +7209,9 @@ var gIdentityHandler = {
this._identityPopupInsecureLoginFormsLearnMore
.setAttribute("href", baseURL + "insecure-password");
// The expander switches its tooltip when toggled, change it to the default.
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
// Determine connection security information.
let connection = "not-secure";
if (this._isSecureInternalUI) {
@ -7361,6 +7385,8 @@ var gIdentityHandler = {
return;
}
this._popupTriggeredByKeyboard = event.type == "keypress";
// Make sure that the display:none style we set in xul is removed now that
// the popup is actually needed
this._identityPopup.hidden = false;
@ -7380,10 +7406,12 @@ var gIdentityHandler = {
onPopupShown(event) {
if (event.target == this._identityPopup) {
// Move focus to the next available element in the identity popup.
// This is required by role=alertdialog and fixes an issue where
// an already open panel would steal focus from the identity popup.
document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
if (this._popupTriggeredByKeyboard) {
// Move focus to the next available element in the identity popup.
// This is required by role=alertdialog and fixes an issue where
// an already open panel would steal focus from the identity popup.
document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
}
window.addEventListener("focus", this, true);
}
@ -7397,6 +7425,16 @@ var gIdentityHandler = {
},
handleEvent(event) {
// If the subview is shown or hidden, change the tooltip on the expander button.
if (event.type == "ViewShowing") {
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.hideDetails.tooltip");
return;
}
if (event.type == "ViewHiding") {
this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
return;
}
let elem = document.activeElement;
let position = elem.compareDocumentPosition(this._identityPopup);

View File

@ -97,10 +97,15 @@ browser[pending] {
display: none;
}
browser[pendingtabchild],
browser[pendingpaint] {
opacity: 0;
}
tabbrowser[pendingtabchild] {
background-color: #ffffff !important;
}
tabbrowser[pendingpaint] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
background-repeat: no-repeat;

View File

@ -3723,6 +3723,7 @@
visibleTab: this.selectedTab, // Tab that's on screen.
spinnerTab: null, // Tab showing a spinner.
blankTab: null, // Tab showing blank.
originalTab: this.selectedTab, // Tab that we started on.
tabbrowser: this, // Reference to gBrowser.
@ -3732,6 +3733,12 @@
// Map from tabs to STATE_* (below).
tabState: new Map(),
// Holds a collection of <xul:browser>'s for this tabbrowser
// that we cannot force paint since their TabChild's haven't
// been constructed yet. Instead, we show blank tabs for them
// when attempting to switch to them.
pendingTabChild: new WeakSet(),
// True if we're in the midst of switching tabs.
switchInProgress: false,
@ -3827,6 +3834,7 @@
window.addEventListener("sizemodechange", this);
window.addEventListener("SwapDocShells", this, true);
window.addEventListener("EndSwapDocShells", this, true);
window.addEventListener("MozTabChildNotReady", this, true);
if (!this.minimized) {
this.setTabState(this.requestedTab, this.STATE_LOADED);
}
@ -3849,6 +3857,7 @@
window.removeEventListener("sizemodechange", this);
window.removeEventListener("SwapDocShells", this, true);
window.removeEventListener("EndSwapDocShells", this, true);
window.removeEventListener("MozTabChildNotReady", this, true);
this.tabbrowser._switcher = null;
@ -3864,6 +3873,7 @@
this.assert(this.tabbrowser._switcher);
this.assert(this.tabbrowser._switcher === this);
this.assert(!this.spinnerTab);
this.assert(!this.blankTab);
this.assert(!this.loadTimer);
this.assert(!this.loadingTab);
this.assert(this.lastVisibleTab === this.requestedTab);
@ -3894,20 +3904,45 @@
// This function is called after all the main state changes to
// make sure we display the right tab.
updateDisplay() {
let requestedTabState = this.getTabState(this.requestedTab);
let shouldBeBlank =
this.pendingTabChild.has(this.requestedTab.linkedBrowser) &&
requestedTabState == this.STATE_LOADING;
// Figure out which tab we actually want visible right now.
let showTab = null;
if (this.getTabState(this.requestedTab) != this.STATE_LOADED &&
this.lastVisibleTab && this.loadTimer) {
if (requestedTabState != this.STATE_LOADED &&
this.lastVisibleTab && this.loadTimer && !shouldBeBlank) {
// If we can't show the requestedTab, and lastVisibleTab is
// available, show it.
showTab = this.lastVisibleTab;
} else {
// Show the requested tab. If it's not available, we'll show the spinner.
// Show the requested tab. If it's not available, we'll show the spinner or a blank tab.
showTab = this.requestedTab;
}
// First, let's deal with blank tabs, which we show instead
// of the spinner when the tab is not currently set up
// properly in the content process.
if (!shouldBeBlank && this.blankTab) {
this.tabbrowser.removeAttribute("pendingtabchild");
this.blankTab.linkedBrowser.removeAttribute("pendingtabchild");
this.blankTab = null;
} else if (shouldBeBlank && this.blankTab !== showTab) {
if (this.blankTab) {
this.blankTab.linkedBrowser.removeAttribute("pendingtabchild");
}
this.blankTab = showTab;
this.tabbrowser.setAttribute("pendingtabchild", "true");
this.blankTab.linkedBrowser.setAttribute("pendingtabchild", "true");
}
// Show or hide the spinner as needed.
let needSpinner = this.getTabState(showTab) != this.STATE_LOADED && !this.minimized;
let needSpinner = this.getTabState(showTab) != this.STATE_LOADED &&
!this.minimized &&
!shouldBeBlank;
if (!needSpinner && this.spinnerTab) {
this.spinnerHidden();
this.tabbrowser.removeAttribute("pendingpaint");
@ -3992,6 +4027,9 @@
if (this.lastVisibleTab && !this.lastVisibleTab.linkedBrowser) {
this.lastVisibleTab = null;
}
if (this.blankTab && !this.blankTab.linkedBrowser) {
this.blankTab = null;
}
if (this.spinnerTab && !this.spinnerTab.linkedBrowser) {
this.spinnerHidden();
this.spinnerTab = null;
@ -4104,8 +4142,9 @@
// Fires when the layers become available for a tab.
onLayersReady(browser) {
this.pendingTabChild.delete(browser);
let tab = this.tabbrowser.getTabForBrowser(browser);
this.logState(`onLayersReady(${tab._tPos})`);
this.logState(`onLayersReady(${tab._tPos}, ${browser.isRemoteBrowser})`);
this.assert(this.getTabState(tab) == this.STATE_LOADING ||
this.getTabState(tab) == this.STATE_LOADED);
@ -4130,6 +4169,7 @@
// Called when we're done clearing the layers for a tab.
onLayersCleared(browser) {
this.pendingTabChild.delete(browser);
let tab = this.tabbrowser.getTabForBrowser(browser);
if (tab) {
this.logState(`onLayersCleared(${tab._tPos})`);
@ -4150,6 +4190,15 @@
} else if (this.getTabState(tab) == this.STATE_UNLOADING) {
this.onLayersCleared(tab.linkedBrowser);
}
} else if (this.getTabState(tab) == this.STATE_LOADED) {
// A tab just changed from non-remote to remote, which means
// that it's gone back into the STATE_LOADING state until
// it sends up a layer tree. We also add the browser to
// the pendingTabChild set since this browser is unlikely
// to have its TabChild set up right away, and we want to
// make it appear "blank" instead of showing a spinner for it.
this.pendingTabChild.add(tab.linkedBrowser);
this.setTabState(tab, this.STATE_LOADING);
}
},
@ -4196,9 +4245,18 @@
let otherTabbrowser = otherBrowser.ownerGlobal.gBrowser;
let otherState;
let pendingTabChild = false;
if (otherTabbrowser && otherTabbrowser._switcher) {
let otherTab = otherTabbrowser.getTabForBrowser(otherBrowser);
otherState = otherTabbrowser._switcher.getTabState(otherTab);
let otherSwitcher = otherTabbrowser._switcher;
otherState = otherSwitcher.getTabState(otherTab);
pendingTabChild = otherSwitcher.pendingTabChild.has(otherBrowser);
if (pendingTabChild) {
this.assert(otherState == this.STATE_LOADING);
}
otherSwitcher.pendingTabChild.delete(otherBrowser);
} else {
otherState = (otherBrowser.docShellIsActive
? this.STATE_LOADED
@ -4208,7 +4266,10 @@
if (!this.swapMap) {
this.swapMap = new WeakMap();
}
this.swapMap.set(otherBrowser, otherState);
this.swapMap.set(otherBrowser, {
state: otherState,
pendingTabChild,
});
},
onEndSwapDocShells(ourBrowser, otherBrowser) {
@ -4227,12 +4288,17 @@
}
this.loadingTab = null;
let otherState = this.swapMap.get(otherBrowser);
let { state: otherState, pendingTabChild } =
this.swapMap.get(otherBrowser);
this.swapMap.delete(otherBrowser);
let ourTab = this.tabbrowser.getTabForBrowser(ourBrowser);
if (ourTab) {
this.setTabStateNoAction(ourTab, otherState);
if (pendingTabChild) {
this.pendingTabChild.add(ourTab.linkedBrowser);
}
}
},
@ -4247,6 +4313,28 @@
this.setTabState(tab, this.STATE_LOADING);
},
// The tab for this browser isn't currently set
// up in the content process, so we have no chance
// of painting it right away. We'll paint a blank
// tab instead.
onTabChildNotReady(browser) {
this.assert(browser.isRemoteBrowser);
let tab = this.tabbrowser.getTabForBrowser(browser);
this.assert(this.getTabState(tab) == this.STATE_LOADING);
this.logState(`onTabChildNotReady(${tab._tPos})`);
this.pendingTabChild.add(browser);
this.maybeFinishTabSwitch();
if (this.loadingTab === tab) {
this.clearTimer(this.loadTimer);
this.loadTimer = null;
this.loadingTab = null;
}
},
// Called when the user asks to switch to a given tab.
requestTab(tab) {
if (tab === this.requestedTab) {
@ -4302,6 +4390,8 @@
this.onSwapDocShells(event.originalTarget, event.detail);
} else if (event.type == "EndSwapDocShells") {
this.onEndSwapDocShells(event.originalTarget, event.detail);
} else if (event.type == "MozTabChildNotReady") {
this.onTabChildNotReady(event.originalTarget);
}
this.postActions();
@ -4328,7 +4418,8 @@
*/
maybeFinishTabSwitch() {
if (this.switchInProgress && this.requestedTab &&
this.getTabState(this.requestedTab) == this.STATE_LOADED) {
(this.getTabState(this.requestedTab) == this.STATE_LOADED ||
this.requestedTab === this.blankTab)) {
// After this point the tab has switched from the content thread's point of view.
// The changes will be visible after the next refresh driver tick + composite.
let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
@ -4419,6 +4510,7 @@
if (tab === this.lastVisibleTab) accum += "V";
if (tab === this.loadingTab) accum += "L";
if (tab === this.requestedTab) accum += "R";
if (tab === this.blankTab) accum += "B";
if (state == this.STATE_LOADED) accum += "(+)";
if (state == this.STATE_LOADING) accum += "(+?)";
if (state == this.STATE_UNLOADED) accum += "(-)";

View File

@ -192,9 +192,11 @@ add_task(function* checkAllTheProperties() {
ok(uris.length, `Found ${uris.length} .properties files to scan for misused characters`);
for (let uri of uris) {
let bundle = new StringBundle(uri.spec);
let entities = bundle.getAll();
for (let entity of entities) {
let bundle = Services.strings.createBundle(uri.spec);
let enumerator = bundle.getSimpleEnumeration();
while (enumerator.hasMoreElements()) {
let entity = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
testForErrors(uri.spec, entity.key, entity.value);
}
}

View File

@ -47,6 +47,7 @@ support-files =
[browser_identity_UI.js]
[browser_identityBlock_focus.js]
support-files = ../general/permissions.html
[browser_identityPopup_focus.js]
[browser_insecureLoginForms.js]
support-files =
insecure_opener.html

View File

@ -0,0 +1,27 @@
/* Tests the focus behavior of the identity popup. */
// Access the identity popup via mouseclick. Focus should not be moved inside.
add_task(function* testIdentityPopupFocusClick() {
yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
yield BrowserTestUtils.withNewTab("https://example.com", function*() {
let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(gIdentityHandler._identityBox, {});
yield shown;
isnot(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
});
});
// Access the identity popup via keyboard. Focus should be moved inside.
add_task(function* testIdentityPopupFocusKeyboard() {
yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
yield BrowserTestUtils.withNewTab("https://example.com", function*() {
let focused = BrowserTestUtils.waitForEvent(gIdentityHandler._identityBox, "focus");
gIdentityHandler._identityBox.focus();
yield focused;
let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
EventUtils.synthesizeKey(" ", {});
yield shown;
is(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
});
});

View File

@ -85,7 +85,15 @@ function* testProbe(aProbe) {
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({
set: [["dom.ipc.processCount", 1]]
set: [
["dom.ipc.processCount", 1],
// We can interrupt JS to paint now, which is great for
// users, but bad for testing spinners. We temporarily
// disable that feature for this test so that we can
// easily get ourselves into a predictable tab spinner
// state.
["browser.tabs.remote.force-paint", false],
]
});
});

View File

@ -172,6 +172,8 @@ add_task(function* () {
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
});
hookExtensionsTelemetry();
let changePromise = new Promise(resolve => {
ExtensionsUI.on("change", function listener() {
ExtensionsUI.off("change", listener);
@ -327,6 +329,9 @@ add_task(function* () {
addon4 = yield AddonManager.getAddonByID(ID4);
is(addon4.userDisabled, false, "Addon 4 should be enabled");
// We should have recorded 1 cancelled followed by 3 accepted sideloads.
expectTelemetry(["sideloadRejected", "sideloadAccepted", "sideloadAccepted", "sideloadAccepted"]);
isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);

View File

@ -52,6 +52,8 @@ add_task(function* setup() {
});
});
hookExtensionsTelemetry();
// Helper function to test background updates.
function* backgroundUpdateTest(url, id, checkIconFn) {
yield SpecialPowers.pushPrefEnv({set: [
@ -163,6 +165,9 @@ function* backgroundUpdateTest(url, id, checkIconFn) {
is(getBadgeStatus(), "", "Addon alert badge should be gone");
// Should have recorded 1 canceled followed by 1 accepted update.
expectTelemetry(["updateRejected", "updateAccepted"]);
addon.uninstall();
yield SpecialPowers.popPrefEnv();
}

View File

@ -39,4 +39,4 @@ async function installSearch(filename) {
EventUtils.synthesizeMouseAtCenter(button, {}, win);
}
add_task(() => testInstallMethod(installSearch));
add_task(() => testInstallMethod(installSearch, "installAmo"));

View File

@ -11,4 +11,4 @@ async function installTrigger(filename) {
});
}
add_task(() => testInstallMethod(installTrigger));
add_task(() => testInstallMethod(installTrigger, "installAmo"));

View File

@ -20,4 +20,4 @@ async function installFile(filename) {
contentWin.gViewController.doCommand("cmd_installFromFile");
}
add_task(() => testInstallMethod(installFile));
add_task(() => testInstallMethod(installFile, "installLocal"));

View File

@ -11,4 +11,4 @@ async function installMozAM(filename) {
});
}
add_task(() => testInstallMethod(installMozAM));
add_task(() => testInstallMethod(installMozAM, "installAmo"));

View File

@ -2,6 +2,8 @@
const BASE = getRootDirectory(gTestPath)
.replace("chrome://mochitests/content/", "https://example.com/");
Cu.import("resource:///modules/ExtensionsUI.jsm");
/**
* Wait for the given PopupNotification to display
*
@ -201,10 +203,13 @@ function checkNotification(panel, checkIcon, permissions) {
* Callable that takes the name of an xpi file to install and
* starts to install it. Should return a Promise that resolves
* when the install is finished or rejects if the install is canceled.
* @param {string} telemetryBase
* If supplied, the base type for telemetry events that should be
* recorded for this install method.
*
* @returns {Promise}
*/
async function testInstallMethod(installFn) {
async function testInstallMethod(installFn, telemetryBase) {
const PERMS_XPI = "browser_webext_permissions.xpi";
const NO_PERMS_XPI = "browser_webext_nopermissions.xpi";
const ID = "permissions@test.mozilla.org";
@ -217,6 +222,10 @@ async function testInstallMethod(installFn) {
["extensions.webextPermissionPrompts", true],
]});
if (telemetryBase !== undefined) {
hookExtensionsTelemetry();
}
let testURI = makeURI("https://example.com/");
Services.perms.add(testURI, "install", Services.perms.ALLOW_ACTION);
registerCleanupFunction(() => Services.perms.remove(testURI, "install"));
@ -316,6 +325,12 @@ async function testInstallMethod(installFn) {
// the extension to clean up.)
await runOnce(PERMS_XPI, false);
if (telemetryBase !== undefined) {
// Should see 2 canceled installs followed by 1 successful install
// for this method.
expectTelemetry([`${telemetryBase}Rejected`, `${telemetryBase}Rejected`, `${telemetryBase}Accepted`]);
}
await SpecialPowers.popPrefEnv();
}
@ -347,3 +362,21 @@ add_task(async function() {
}
});
});
let collectedTelemetry = [];
function hookExtensionsTelemetry() {
let originalHistogram = ExtensionsUI.histogram;
ExtensionsUI.histogram = {
add(value) { collectedTelemetry.push(value); },
};
registerCleanupFunction(() => {
is(collectedTelemetry.length, 0, "No unexamined telemetry after test is finished");
ExtensionsUI.histogram = originalHistogram;
});
}
function expectTelemetry(values) {
Assert.deepEqual(values, collectedTelemetry);
collectedTelemetry = [];
}

View File

@ -0,0 +1,166 @@
%if 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/. */
%endif
:root[lwthemeicons~="--back-icon"] #back-button:-moz-lwtheme {
list-style-image: var(--back-icon) !important;
}
:root[lwthemeicons~="--forward-icon"] #forward-button:-moz-lwtheme {
list-style-image: var(--forward-icon) !important;
}
:root[lwthemeicons~="--reload-icon"] #urlbar-reload-button:-moz-lwtheme {
list-style-image: var(--reload-icon) !important;
}
:root[lwthemeicons~="--stop-icon"] #urlbar-stop-button:-moz-lwtheme {
list-style-image: var(--stop-icon) !important;
}
:root[lwthemeicons~="--bookmark_star-icon"] #bookmarks-menu-button:-moz-lwtheme {
list-style-image: var(--bookmark_star-icon) !important;
}
:root[lwthemeicons~="--bookmark_menu-icon"] #bookmarks-menu-button[cui-areatype='toolbar'] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-lwtheme {
list-style-image: var(--bookmark_menu-icon) !important;
}
:root[lwthemeicons~="--downloads-icon"] #downloads-button:-moz-lwtheme {
list-style-image: var(--downloads-icon) !important;
}
:root[lwthemeicons~="--home-icon"] #home-button:-moz-lwtheme {
list-style-image: var(--home-icon) !important;
}
:root[lwthemeicons~="--app_menu-icon"] #PanelUI-menu-button:-moz-lwtheme {
list-style-image: var(--app_menu-icon) !important;
}
:root[lwthemeicons~="--cut-icon"] #cut-button:-moz-lwtheme {
list-style-image: var(--cut-icon) !important;
}
:root[lwthemeicons~="--copy-icon"] #copy-button:-moz-lwtheme {
list-style-image: var(--copy-icon) !important;
}
:root[lwthemeicons~="--paste-icon"] #paste-button:-moz-lwtheme {
list-style-image: var(--paste-icon) !important;
}
:root[lwthemeicons~="--new_window-icon"] #new-window-button:-moz-lwtheme {
list-style-image: var(--new_window-icon) !important;
}
:root[lwthemeicons~="--new_private_window-icon"] #privatebrowsing-button:-moz-lwtheme {
list-style-image: var(--new_private_window-icon) !important;
}
:root[lwthemeicons~="--save_page-icon"] #save-page-button:-moz-lwtheme {
list-style-image: var(--save_page-icon) !important;
}
:root[lwthemeicons~="--print-icon"] #print-button:-moz-lwtheme {
list-style-image: var(--print-icon) !important;
}
:root[lwthemeicons~="--history-icon"] #history-panelmenu:-moz-lwtheme {
list-style-image: var(--history-icon) !important;
}
:root[lwthemeicons~="--full_screen-icon"] #fullscreen-button:-moz-lwtheme {
list-style-image: var(--full_screen-icon) !important;
}
:root[lwthemeicons~="--find-icon"] #find-button:-moz-lwtheme {
list-style-image: var(--find-icon) !important;
}
:root[lwthemeicons~="--options-icon"] #preferences-button:-moz-lwtheme {
list-style-image: var(--options-icon) !important;
}
:root[lwthemeicons~="--addons-icon"] #add-ons-button:-moz-lwtheme {
list-style-image: var(--addons-icon) !important;
}
:root[lwthemeicons~="--developer-icon"] #developer-button:-moz-lwtheme {
list-style-image: var(--developer-icon) !important;
}
:root[lwthemeicons~="--synced_tabs-icon"] #sync-button:-moz-lwtheme {
list-style-image: var(--synced_tabs-icon) !important;
}
:root[lwthemeicons~="--open_file-icon"] #open-file-button:-moz-lwtheme {
list-style-image: var(--open_file-icon) !important;
}
:root[lwthemeicons~="--sidebars-icon"] #sidebar-button:-moz-lwtheme {
list-style-image: var(--sidebars-icon) !important;
}
:root[lwthemeicons~="--share_page-icon"] #social-share-button:-moz-lwtheme {
list-style-image: var(--share_page-icon) !important;
}
:root[lwthemeicons~="--subscribe-icon"] #feed-button:-moz-lwtheme {
list-style-image: var(--subscribe-icon) !important;
}
:root[lwthemeicons~="--text_encoding-icon"] #characterencoding-button:-moz-lwtheme {
list-style-image: var(--text_encoding-icon) !important;
}
:root[lwthemeicons~="--email_link-icon"] #email-link-button:-moz-lwtheme {
list-style-image: var(--email_link-icon) !important;
}
:root[lwthemeicons~="--forget-icon"] #panic-button:-moz-lwtheme {
list-style-image: var(--forget-icon) !important;
}
:root[lwthemeicons~="--pocket-icon"] #pocket-button:-moz-lwtheme {
list-style-image: var(--pocket-icon) !important;
}
:root[lwthemeicons~="--back-icon"] #back-button:-moz-lwtheme,
:root[lwthemeicons~="--forward-icon"] #forward-button:-moz-lwtheme,
:root[lwthemeicons~="--bookmark_star-icon"] #bookmarks-menu-button:-moz-lwtheme,
:root[lwthemeicons~="--bookmark_menu-icon"] #bookmarks-menu-button[cui-areatype='toolbar'] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-lwtheme,
:root[lwthemeicons~="--downloads-icon"] #downloads-button:-moz-lwtheme,
:root[lwthemeicons~="--home-icon"] #home-button:-moz-lwtheme,
:root[lwthemeicons~="--app_menu-icon"] #PanelUI-menu-button:-moz-lwtheme,
:root[lwthemeicons~="--cut-icon"] #cut-button:-moz-lwtheme,
:root[lwthemeicons~="--copy-icon"] #copy-button:-moz-lwtheme,
:root[lwthemeicons~="--paste-icon"] #paste-button:-moz-lwtheme,
:root[lwthemeicons~="--new_window-icon"] #new-window-button:-moz-lwtheme,
:root[lwthemeicons~="--new_private_window-icon"] #privatebrowsing-button:-moz-lwtheme,
:root[lwthemeicons~="--save_page-icon"] #save-page-button:-moz-lwtheme,
:root[lwthemeicons~="--print-icon"] #print-button:-moz-lwtheme,
:root[lwthemeicons~="--history-icon"] #history-panelmenu:-moz-lwtheme,
:root[lwthemeicons~="--full_screen-icon"] #fullscreen-button:-moz-lwtheme,
:root[lwthemeicons~="--find-icon"] #find-button:-moz-lwtheme,
:root[lwthemeicons~="--options-icon"] #preferences-button:-moz-lwtheme,
:root[lwthemeicons~="--addons-icon"] #add-ons-button:-moz-lwtheme,
:root[lwthemeicons~="--developer-icon"] #developer-button:-moz-lwtheme,
:root[lwthemeicons~="--synced_tabs-icon"] #sync-button:-moz-lwtheme,
:root[lwthemeicons~="--open_file-icon"] #open-file-button:-moz-lwtheme,
:root[lwthemeicons~="--sidebars-icon"] #sidebar-button:-moz-lwtheme,
:root[lwthemeicons~="--share_page-icon"] #social-share-button:-moz-lwtheme,
:root[lwthemeicons~="--subscribe-icon"] #feed-button:-moz-lwtheme,
:root[lwthemeicons~="--text_encoding-icon"] #characterencoding-button:-moz-lwtheme,
:root[lwthemeicons~="--email_link-icon"] #email-link-button:-moz-lwtheme,
:root[lwthemeicons~="--forget-icon"] #panic-button:-moz-lwtheme,
:root[lwthemeicons~="--pocket-icon"] #pocket-button:-moz-lwtheme {
-moz-image-region: rect(0, 18px, 18px, 0) !important;
}
:root[lwthemeicons~="--reload-icon"] #urlbar-reload-button:-moz-lwtheme,
:root[lwthemeicons~="--stop-icon"] #urlbar-stop-button:-moz-lwtheme {
-moz-image-region: rect(0, 14px, 14px, 0) !important;
}

View File

@ -8,8 +8,6 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
// Bug 1320736 tracks creating a generic precedence manager for handling
// multiple addons modifying the same properties, and bug 1330494 has been filed
@ -19,85 +17,32 @@ XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
let overrides = {
// A queue of extensions in line to override the newtab page (sorted oldest to newest).
newtab: [],
// A queue of extensions in line to override the home page (sorted oldest to newest).
home: [],
};
/**
* Resets the specified page to its default value.
*
* @param {string} page The page to override. Accepted values are "newtab" and "home".
*/
function resetPage(page) {
switch (page) {
case "newtab":
aboutNewTabService.resetNewTabURL();
break;
case "home":
Preferences.reset("browser.startup.homepage");
break;
default:
throw new Error("Unrecognized override type");
}
}
/**
* Overrides the specified page to the specified URL.
*
* @param {string} page The page to override. Accepted values are "newtab" and "home".
* @param {string} url The resolved URL to use for the page override.
*/
function overridePage(page, url) {
switch (page) {
case "newtab":
aboutNewTabService.newTabURL = url;
break;
case "home":
Preferences.set("browser.startup.homepage", url);
break;
default:
throw new Error("Unrecognized override type");
}
}
/**
* Updates the page to the URL specified by the extension next in line. If no extensions
* are in line, the page is reset to its default value.
*
* @param {string} page The page to override.
*/
function updatePage(page) {
if (overrides[page].length) {
overridePage(page, overrides[page][0].url);
} else {
resetPage(page);
}
}
/* eslint-disable mozilla/balanced-listeners */
extensions.on("manifest_chrome_url_overrides", (type, directive, extension, manifest) => {
if (Object.keys(overrides).length > 1) {
extension.manifestError("Extensions can override only one page.");
}
if (manifest.chrome_url_overrides.newtab) {
let newtab = manifest.chrome_url_overrides.newtab;
let url = extension.baseURI.resolve(newtab);
for (let page of Object.keys(overrides)) {
if (manifest.chrome_url_overrides[page]) {
let relativeURL = manifest.chrome_url_overrides[page];
let url = extension.baseURI.resolve(relativeURL);
// Store the extension ID instead of a hard reference to the extension.
overrides[page].push({id: extension.id, url});
updatePage(page);
break;
// Only set the newtab URL if no other extension is overriding it.
if (!overrides.newtab.length) {
aboutNewTabService.newTabURL = url;
}
overrides.newtab.push({id: extension.id, url});
}
});
extensions.on("shutdown", (type, extension) => {
for (let page of Object.keys(overrides)) {
let i = overrides[page].findIndex(o => o.id === extension.id);
if (i !== -1) {
overrides[page].splice(i, 1);
updatePage(page);
let i = overrides.newtab.findIndex(o => o.id === extension.id);
if (i !== -1) {
overrides.newtab.splice(i, 1);
if (overrides.newtab.length) {
aboutNewTabService.newTabURL = overrides.newtab[0].url;
} else {
aboutNewTabService.resetNewTabURL();
}
}
});

View File

@ -14,11 +14,6 @@
"optional": true,
"preprocess": "localize"
},
"home": {
"$ref": "ExtensionURL",
"optional": true,
"preprocess": "localize"
},
"bookmarks": {
"unsupported": true,
"$ref": "ExtensionURL",

View File

@ -116,9 +116,8 @@ support-files =
[browser_ext_tabs_update.js]
[browser_ext_tabs_zoom.js]
[browser_ext_tabs_update_url.js]
[browser_ext_themes_icons.js]
[browser_ext_topwindowid.js]
[browser_ext_url_overrides_all.js]
[browser_ext_url_overrides_home.js]
[browser_ext_url_overrides_newtab.js]
[browser_ext_webRequest.js]
[browser_ext_webNavigation_frameId0.js]

View File

@ -7,8 +7,7 @@ add_task(function* () {
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
let encodedImageData = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
let decodedImageData = atob(encodedImageData);
const IMAGE_ARRAYBUFFER = Uint8Array.from(decodedImageData, byte => byte.charCodeAt(0)).buffer;
const IMAGE_ARRAYBUFFER = imageBufferFromDataURI(encodedImageData);
let extension = ExtensionTestUtils.loadExtension({
manifest: {

View File

@ -0,0 +1,275 @@
"use strict";
const ENCODED_IMAGE_DATA = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNjQgNjQiPjxwYXRoIGQ9Im01NS45IDMyLjFsLTIyLjctMTQuOWMwIDAgMTIuOS0xNy40IDE5LjQtMTQuOSAzLjEgMS4xIDUuNCAyNS4xIDMuMyAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTU0LjkgMzMuOWwtOS00LjFjMCAwLTUuMy0xNCA2LjEtMjQuMSAyLjQgMiA1LjEgMjUgMi45IDI4LjIiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJtOC4xIDMyLjFsMjIuNi0xNC45YzAgMC0xMi45LTE3LjQtMTkuNC0xNC45LTMgMS4xLTUuMyAyNS4xLTMuMiAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTkuMSAzMy45bDktNC4xYzAgMCA1LjMtMTQtNi4xLTI0LjEtMi40IDItNS4xIDI1LTIuOSAyOC4yIiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTMyLDEzQzE4LjksMTMsMiwzMy42LDIsNDUuNEMyMC41LDQ1LjQsMTkuNyw2MiwzMiw2MnMxMS41LTE2LjYsMzAtMTYuNkM2MiwzMy42LDQ1LjEsMTMsMzIsMTN6IiBmaWxsPSIjZmY4NzM2Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTMyLDU2LjJjMCw1LjEsOS42LDQuMiw5LjUtMi45YzYuNy05LjQsMTkuOS04LjcsMTkuOS04LjdDMzkuNiwzMi40LDMyLDU2LjIsMzIsNTYuMnoiLz48cGF0aCBkPSJNMzIsNTYuMmMwLDUuMS05LjYsNC4yLTkuNS0yLjlDMTUuOCw0NCwyLjYsNDQuNywyLjYsNDQuN0MyNC40LDMyLjQsMzIsNTYuMiwzMiw1Ni4yeiIvPjwvZz48ZyBmaWxsPSIjZmY4NzM2Ij48cGF0aCBkPSJtNTMuNCAxOC41Yy00IC43LTQuOSA2LjMtNC45IDYuM2w2IDUuM2MtMi4zLTUuOS0xLjEtMTEuNi0xLjEtMTEuNiIvPjxwYXRoIGQ9Im01MS4xIDEzLjVjLTQuNCAzLjktNS4xIDguNy01LjEgOC43bDYgNS4zYy0yLjQtNS44LS45LTE0LS45LTE0Ii8+PHBhdGggZD0ibTEwLjYgMTguNWM0IC43IDQuOSA2LjMgNC45IDYuM2wtNiA1LjNjMi4zLTUuOSAxLjEtMTEuNiAxLjEtMTEuNiIvPjxwYXRoIGQ9Im0xMi45IDEzLjVjNC40IDMuOSA1LjEgOC43IDUuMSA4LjdsLTYgNS4zYzIuNC01LjguOS0xNCAuOS0xNCIvPjwvZz48cGF0aCBkPSJtNTIuOCAzMS4xYy01LjctMS44LTEwLjktMy40LTEzLjguOS0yLjQgMy43LjcgOS40LjcgOS40IDExLjIgMS4yIDEzLjEtMTAuMyAxMy4xLTEwLjMiIGZpbGw9IiMzZTQzNDciLz48ZWxsaXBzZSBjeD0iNDMiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjQzIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im0xMS4yIDMxLjFjNS43LTEuOCAxMC45LTMuNCAxMy43LjkgMi40IDMuNy0uNyA5LjQtLjcgOS40LTExLjEgMS4yLTEzLTEwLjMtMTMtMTAuMyIvPjwvZz48ZWxsaXBzZSBjeD0iMjEiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjIxIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im00MS4yIDQ3LjljLS43LTIuMy0xLjgtNC40LTMtNi41IDEuMSAyLjEgMiA0LjMgMi41IDYuNi41IDIuMy43IDQuNyAwIDYuOC0uNCAxLTEgMi0xLjggMi42LS44LjYtMS44IDEtMi43IDEtLjkgMC0xLjktLjMtMi41LTEtLjYtLjctLjktMS42LS44LTIuNmwtLjkuMmgtLjljMCAxLS4yIDEuOS0uOCAyLjYtLjYuNy0xLjUgMS0yLjUgMS0uOSAwLTEuOS0uNC0yLjctMS0uOC0uNi0xLjQtMS42LTEuOC0yLjYtLjgtMi4xLS42LTQuNiAwLTYuOC41LTIuMyAxLjUtNC41IDIuNS02LjYtMS4yIDItMi4zIDQuMS0zIDYuNS0uNyAyLjMtMS4xIDQuOC0uNCA3LjMuMyAxLjIgMSAyLjQgMS45IDMuMy45LjkgMi4xIDEuNCAzLjQgMS41IDEuMi4xIDIuNi0uMiAzLjctMS4yLjMtLjIuNS0uNS43LS44LjIuMy40LjYuNy44IDEgMSAyLjQgMS4zIDMuNyAxLjIgMS4zLS4xIDIuNC0uNyAzLjQtMS41LjktLjkgMS42LTIgMS45LTMuMy41LTIuNi4xLTUuMi0uNi03LjUiLz48cGF0aCBkPSJtMzcuNiA1MC4zYy0xLjEtMS4xLTQuNS0xLjItNS42LTEuMi0xIDAtNC41LjEtNS42IDEuMi0uOC44LS4yIDIuOCAxLjkgNC41IDEuMyAxLjEgMi42IDEuNCAzLjYgMS40IDEgMCAyLjMtLjMgMy42LTEuNCAyLjMtMS43IDIuOS0zLjcgMi4xLTQuNSIvPjwvZz48L3N2Zz4=";
/**
* Verifies that the button uses the expected icon.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {boolean} shouldHaveCustomStyling True if the button should
* have custom styling, False otherwise.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonProperties(selector, shouldHaveCustomStyling, message) {
try {
let element;
// This selector is different than the others because it's the only
// toolbarbutton that we ship by default that has type="menu-button",
// which don't place a unique ID on the associated dropmarker-icon.
if (selector == "#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon") {
if (message.includes("panel")) {
// The dropmarker isn't shown in the menupanel.
return;
}
element = document.querySelector("#bookmarks-menu-button");
element = document.getAnonymousElementByAttribute(element, "class", "toolbarbutton-menubutton-dropmarker");
element = document.getAnonymousElementByAttribute(element, "class", "dropmarker-icon");
} else {
element = document.querySelector(selector);
}
let listStyleImage = getComputedStyle(element).listStyleImage;
info(`listStyleImage for fox.svg is ${listStyleImage}`);
is(listStyleImage.includes("fox.svg"), shouldHaveCustomStyling, message);
} catch (ex) {
ok(false, `Unable to verify ${selector}: ${ex}`);
}
}
/**
* Verifies that the button uses default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonWithoutCustomStyling(selector, message) {
verifyButtonProperties(selector, false, message);
}
/**
* Verifies that the button uses non-default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonWithCustomStyling(selector, message) {
verifyButtonProperties(selector, true, message);
}
/**
* Loops through all of the buttons to confirm that they are styled
* as expected (either with or without custom styling).
*
* @param {object} icons Array of an array that specifies which buttons should
* have custom icons.
* @param {object} iconInfo An array of arrays that maps API names to
* CSS selectors.
* @param {string} area The name of the area that the button resides in.
*/
function checkButtons(icons, iconInfo, area) {
for (let button of iconInfo) {
let iconInfo = icons.find(arr => arr[0] == button[0]);
if (iconInfo[1]) {
verifyButtonWithCustomStyling(button[1],
`The ${button[1]} should have it's icon customized in the ${area}`);
} else {
verifyButtonWithoutCustomStyling(button[1],
`The ${button[1]} should not have it's icon customized in the ${area}`);
}
}
}
function* runTestWithIcons(icons) {
const FRAME_COLOR = [71, 105, 91];
const TAB_TEXT_COLOR = [207, 221, 192, .9];
let manifest = {
"theme": {
"images": {
"theme_frame": "fox.svg",
},
"colors": {
"frame": FRAME_COLOR,
"tab_text": TAB_TEXT_COLOR,
},
"icons": {},
},
};
let files = {
"fox.svg": imageBufferFromDataURI(ENCODED_IMAGE_DATA),
};
// Each item in this array has the following setup:
// At position 0: The name that is used in the theme manifest.
// At position 1: The CSS selector for the button in the DOM.
// At position 2: The CustomizableUI name for the widget, only defined
// if customizable.
const ICON_INFO = [
["back", "#back-button"],
["forward", "#forward-button"],
["reload", "#urlbar-reload-button"],
["stop", "#urlbar-stop-button"],
["bookmark_star", "#bookmarks-menu-button", "bookmarks-menu-button"],
["bookmark_menu", "#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon"],
["downloads", "#downloads-button", "downloads-button"],
["home", "#home-button", "home-button"],
["app_menu", "#PanelUI-menu-button"],
["cut", "#cut-button", "edit-controls"],
["copy", "#copy-button"],
["paste", "#paste-button"],
["new_window", "#new-window-button", "new-window-button"],
["new_private_window", "#privatebrowsing-button", "privatebrowsing-button"],
["save_page", "#save-page-button", "save-page-button"],
["print", "#print-button", "print-button"],
["history", "#history-panelmenu", "history-panelmenu"],
["full_screen", "#fullscreen-button", "fullscreen-button"],
["find", "#find-button", "find-button"],
["options", "#preferences-button", "preferences-button"],
["addons", "#add-ons-button", "add-ons-button"],
["developer", "#developer-button", "developer-button"],
["synced_tabs", "#sync-button", "sync-button"],
["open_file", "#open-file-button", "open-file-button"],
["sidebars", "#sidebar-button", "sidebar-button"],
["share_page", "#social-share-button", "social-share-button"],
["subscribe", "#feed-button", "feed-button"],
["text_encoding", "#characterencoding-button", "characterencoding-button"],
["email_link", "#email-link-button", "email-link-button"],
["forget", "#panic-button", "panic-button"],
["pocket", "#pocket-button", "pocket-button"],
];
window.maximize();
for (let button of ICON_INFO) {
if (button[2]) {
CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_NAVBAR);
}
verifyButtonWithoutCustomStyling(button[1],
`The ${button[1]} should not have it's icon customized when the test starts`);
let iconInfo = icons.find(arr => arr[0] == button[0]);
manifest.theme.icons[button[0]] = iconInfo[1];
}
let extension = ExtensionTestUtils.loadExtension({manifest, files});
yield extension.startup();
checkButtons(icons, ICON_INFO, "toolbar");
for (let button of ICON_INFO) {
if (button[2]) {
CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_PANEL);
}
}
yield PanelUI.show();
checkButtons(icons, ICON_INFO, "panel");
yield PanelUI.hide();
yield extension.unload();
for (let button of ICON_INFO) {
verifyButtonWithoutCustomStyling(button[1],
`The ${button[1]} should not have it's icon customized when the theme is unloaded`);
}
}
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({
set: [["extensions.webextensions.themes.enabled", true],
["extensions.webextensions.themes.icons.enabled", true]],
});
});
add_task(function* test_all_icons() {
let icons = [
["back", "fox.svg"],
["forward", "fox.svg"],
["reload", "fox.svg"],
["stop", "fox.svg"],
["bookmark_star", "fox.svg"],
["bookmark_menu", "fox.svg"],
["downloads", "fox.svg"],
["home", "fox.svg"],
["app_menu", "fox.svg"],
["cut", "fox.svg"],
["copy", "fox.svg"],
["paste", "fox.svg"],
["new_window", "fox.svg"],
["new_private_window", "fox.svg"],
["save_page", "fox.svg"],
["print", "fox.svg"],
["history", "fox.svg"],
["full_screen", "fox.svg"],
["find", "fox.svg"],
["options", "fox.svg"],
["addons", "fox.svg"],
["developer", "fox.svg"],
["synced_tabs", "fox.svg"],
["open_file", "fox.svg"],
["sidebars", "fox.svg"],
["share_page", "fox.svg"],
["subscribe", "fox.svg"],
["text_encoding", "fox.svg"],
["email_link", "fox.svg"],
["forget", "fox.svg"],
["pocket", "fox.svg"],
];
yield runTestWithIcons(icons);
});
add_task(function* teardown() {
CustomizableUI.reset();
window.restore();
});
add_task(function* test_some_icons() {
let icons = [
["back", ""],
["forward", ""],
["reload", "fox.svg"],
["stop", ""],
["bookmark_star", ""],
["bookmark_menu", ""],
["downloads", ""],
["home", "fox.svg"],
["app_menu", "fox.svg"],
["cut", ""],
["copy", ""],
["paste", ""],
["new_window", ""],
["new_private_window", ""],
["save_page", ""],
["print", ""],
["history", ""],
["full_screen", ""],
["find", ""],
["options", ""],
["addons", ""],
["developer", ""],
["synced_tabs", ""],
["open_file", ""],
["sidebars", ""],
["share_page", ""],
["subscribe", ""],
["text_encoding", ""],
["email_link", ""],
["forget", ""],
["pocket", "fox.svg"],
];
yield runTestWithIcons(icons);
});
add_task(function* teardown() {
CustomizableUI.reset();
window.restore();
});

View File

@ -1,97 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
const NEWTAB_URI = "webext-newtab.html";
const HOME_URI = "webext-home.html";
add_task(function* test_extensions_overriding_different_pages() {
let defaultHomePage = Preferences.get("browser.startup.homepage");
let defaultNewtabPage = aboutNewTabService.newTabURL;
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should be ${defaultHomePage}`);
is(aboutNewTabService.newTabURL, defaultNewtabPage,
`Default newtab url should be ${defaultNewtabPage}`);
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {}},
});
let ext2 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI}},
});
let ext3 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {home: HOME_URI}},
});
yield ext1.startup();
is(aboutNewTabService.newTabURL, defaultNewtabPage,
`Default newtab url should still be ${defaultNewtabPage}`);
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should be ${defaultHomePage}`);
yield ext2.startup();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
"Newtab url should be overriden by the second extension.");
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should be ${defaultHomePage}`);
yield ext1.unload();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
"Newtab url should still be overriden by the second extension.");
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should be ${defaultHomePage}`);
yield ext3.startup();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
"Newtab url should still be overriden by the second extension.");
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
"Home url should be overriden by the third extension.");
yield ext2.unload();
is(aboutNewTabService.newTabURL, defaultNewtabPage,
`Newtab url should be reset to ${defaultNewtabPage}`);
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
"Home url should still be overriden by the third extension.");
yield ext3.unload();
is(aboutNewTabService.newTabURL, defaultNewtabPage,
`Newtab url should be reset to ${defaultNewtabPage}`);
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Home url should be reset to ${defaultHomePage}`);
});
add_task(function* test_extensions_with_multiple_overrides() {
let ext = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {
newtab: NEWTAB_URI,
home: HOME_URI,
}},
});
SimpleTest.waitForExplicitFinish();
let waitForConsole = new Promise(resolve => {
SimpleTest.monitorConsole(resolve, [{
message: /Extensions can override only one page./,
}]);
});
yield ext.startup();
yield ext.unload();
SimpleTest.endMonitorConsole();
yield waitForConsole;
});

View File

@ -1,74 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
const HOME_URI_1 = "webext-home-1.html";
const HOME_URI_2 = "webext-home-2.html";
const HOME_URI_3 = "webext-home-3.html";
add_task(function* test_multiple_extensions_overriding_newtab_page() {
let defaultHomePage = Preferences.get("browser.startup.homepage");
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should be ${defaultHomePage}`);
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {}},
});
let ext2 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {home: HOME_URI_1}},
});
let ext3 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {home: HOME_URI_2}},
});
let ext4 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {home: HOME_URI_3}},
});
yield ext1.startup();
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Default home url should still be ${defaultHomePage}`);
yield ext2.startup();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
"Home url should be overriden by the second extension.");
yield ext1.unload();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
"Home url should still be overriden by the second extension.");
yield ext3.startup();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
"Home url should still be overriden by the second extension.");
yield ext2.unload();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
"Home url should be overriden by the third extension.");
yield ext4.startup();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
"Home url should be overriden by the third extension.");
yield ext4.unload();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
"Home url should be overriden by the third extension.");
yield ext3.unload();
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
`Home url should be reset to ${defaultHomePage}`);
});

View File

@ -76,11 +76,11 @@ add_task(function* test_sending_message_from_newtab_page() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"chrome_url_overrides": {
newtab: NEWTAB_URI_1,
newtab: NEWTAB_URI_2,
},
},
files: {
[NEWTAB_URI_1]: `
[NEWTAB_URI_2]: `
<!DOCTYPE html>
<head>
<meta charset="utf-8"/></head>

View File

@ -12,7 +12,8 @@
* openExtensionContextMenu closeExtensionContextMenu
* openActionContextMenu openSubmenu closeActionContextMenu
* openTabContextMenu closeTabContextMenu
* imageBuffer getListStyleImage getPanelForNode
* imageBuffer imageBufferFromDataURI
* getListStyleImage getPanelForNode
* awaitExtensionPanel awaitPopupResize
* promiseContentDimensions alterContent
*/
@ -64,8 +65,13 @@ var focusWindow = Task.async(function* focusWindow(win) {
yield promise;
});
function imageBufferFromDataURI(encodedImageData) {
let decodedImageData = atob(encodedImageData);
return Uint8Array.from(decodedImageData, byte => byte.charCodeAt(0)).buffer;
}
let img = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==";
var imageBuffer = Uint8Array.from(atob(img), byte => byte.charCodeAt(0)).buffer;
var imageBuffer = imageBufferFromDataURI(img);
function getListStyleImage(button) {
let style = button.ownerGlobal.getComputedStyle(button);

View File

@ -5,6 +5,7 @@
#include "nsFeedSniffer.h"
#include "mozilla/Unused.h"
#include "nsNetCID.h"
#include "nsXPCOM.h"
@ -57,8 +58,8 @@ nsFeedSniffer::ConvertEncodedData(nsIRequest* request,
return NS_ERROR_NO_INTERFACE;
nsAutoCString contentEncoding;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
mozilla::Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
if (!contentEncoding.IsEmpty()) {
nsCOMPtr<nsIStreamConverterService> converterService(do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID));
if (converterService) {
@ -213,7 +214,7 @@ nsFeedSniffer::GetMIMETypeFromContent(nsIRequest* request,
// Check that this is a GET request, since you can't subscribe to a POST...
nsAutoCString method;
channel->GetRequestMethod(method);
mozilla::Unused << channel->GetRequestMethod(method);
if (!method.EqualsLiteral("GET")) {
sniffedType.Truncate();
return NS_OK;
@ -265,8 +266,10 @@ nsFeedSniffer::GetMIMETypeFromContent(nsIRequest* request,
// set the feed header as a response header, since we have good metadata
// telling us that the feed is supposed to be RSS or Atom
channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
NS_LITERAL_CSTRING("1"), false);
mozilla::DebugOnly<nsresult> rv =
channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
NS_LITERAL_CSTRING("1"), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
sniffedType.AssignLiteral(TYPE_MAYBE_FEED);
return NS_OK;
}

View File

@ -313,7 +313,7 @@ var PlacesOrganizer = {
// The command execution function will take care of seeing if the
// selection is a folder or a different container type, and will
// load its contents in tabs.
PlacesUIUtils.openContainerNodeInTabs(selectedNode, aEvent, this._places);
PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._places);
}
}
},

View File

@ -39,6 +39,7 @@ support-files =
[browser_library_downloads.js]
[browser_library_infoBox.js]
[browser_library_left_pane_fixnames.js]
[browser_library_left_pane_middleclick.js]
[browser_library_left_pane_select_hierarchy.js]
[browser_library_middleclick.js]
[browser_library_open_leak.js]

View File

@ -0,0 +1,196 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Tests middle-clicking items in the Library.
*/
const ENABLE_HISTORY_PREF = "places.history.enabled";
var gLibrary = null;
var gTests = [];
var gCurrentTest = null;
// Listener for TabOpen and tabs progress.
var gTabsListener = {
_loadedURIs: [],
_openTabsCount: 0,
handleEvent(aEvent) {
if (aEvent.type != "TabOpen")
return;
if (++this._openTabsCount == gCurrentTest.URIs.length) {
is(gBrowser.tabs.length, gCurrentTest.URIs.length + 1,
"We have opened " + gCurrentTest.URIs.length + " new tab(s)");
}
var tab = aEvent.target;
is(tab.ownerGlobal, window,
"Tab has been opened in current browser window");
},
onLocationChange(aBrowser, aWebProgress, aRequest, aLocationURI,
aFlags) {
var spec = aLocationURI.spec;
ok(true, spec);
// When a new tab is opened, location is first set to "about:blank", so
// we can ignore those calls.
// Ignore multiple notifications for the same URI too.
if (spec == "about:blank" || this._loadedURIs.includes(spec))
return;
ok(gCurrentTest.URIs.includes(spec),
"Opened URI found in list: " + spec);
if (gCurrentTest.URIs.includes(spec))
this._loadedURIs.push(spec);
if (this._loadedURIs.length == gCurrentTest.URIs.length) {
// We have correctly opened all URIs.
// Reset arrays.
this._loadedURIs.length = 0;
this._openTabsCount = 0;
executeSoon(function() {
// Close all tabs.
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
// Test finished. This will move to the next one.
waitForFocus(gCurrentTest.finish, gBrowser.ownerGlobal);
});
}
}
}
// ------------------------------------------------------------------------------
// Open a folder in tabs.
gTests.push({
desc: "Open a folder in tabs.",
URIs: ["about:buildconfig", "about:"],
_folderId: -1,
setup() {
var bs = PlacesUtils.bookmarks;
// Create a new folder.
var folderId = bs.createFolder(bs.unfiledBookmarksFolder,
"Folder",
bs.DEFAULT_INDEX);
this._folderId = folderId;
// Add bookmarks in folder.
this.URIs.forEach(function(aURI) {
bs.insertBookmark(folderId,
PlacesUtils._uri(aURI),
bs.DEFAULT_INDEX,
"Title");
});
// Select unsorted bookmarks root in the left pane.
gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
isnot(gLibrary.PlacesOrganizer._places.selectedNode, null,
"We correctly have selection in the Library left pane");
// Get our bookmark in the right pane.
var folderNode = gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
is(folderNode.title, "Folder", "Found folder in the right pane");
},
finish() {
setTimeout(runNextTest, 0);
},
cleanup() {
PlacesUtils.bookmarks.removeItem(this._folderId);
}
});
// ------------------------------------------------------------------------------
function test() {
waitForExplicitFinish();
// Sanity checks.
ok(PlacesUtils, "PlacesUtils in context");
ok(PlacesUIUtils, "PlacesUIUtils in context");
// Add tabs listeners.
gBrowser.tabContainer.addEventListener("TabOpen", gTabsListener);
gBrowser.addTabsProgressListener(gTabsListener);
// Temporary disable history, so we won't record pages navigation.
gPrefService.setBoolPref(ENABLE_HISTORY_PREF, false);
// Open Library window.
openLibrary(function(library) {
gLibrary = library;
// Kick off tests.
runNextTest();
});
}
function runNextTest() {
// Cleanup from previous test.
if (gCurrentTest)
gCurrentTest.cleanup();
if (gTests.length > 0) {
// Goto next test.
gCurrentTest = gTests.shift();
info("Start of test: " + gCurrentTest.desc);
// Test setup will set Library so that the bookmark to be opened is the
// first node in the content (right pane) tree.
gCurrentTest.setup();
gLibrary.focus();
waitForFocus(function() {
// Open the "Other Bookmarks" folder.
gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = true;
// Now middle-click on the bookmark contained with it.
let bookmarkedNode = gLibrary.PlacesOrganizer._places.selectedNode.getChild(0);
mouseEventOnCell(gLibrary.PlacesOrganizer._places,
gLibrary.PlacesOrganizer._places.view.treeIndexForNode(bookmarkedNode),
0,
{ button: 1 });
}, gLibrary);
} else {
// No more tests.
// We must close "Other Bookmarks" ready for other tests.
gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = false;
// Close Library window.
gLibrary.close();
// Remove tabs listeners.
gBrowser.tabContainer.removeEventListener("TabOpen", gTabsListener);
gBrowser.removeTabsProgressListener(gTabsListener);
// Restore history.
try {
gPrefService.clearUserPref(ENABLE_HISTORY_PREF);
} catch (ex) {}
finish();
}
}
function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
var selection = aTree.view.selection;
selection.select(aRowIndex);
aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
var column = aTree.columns[aColumnIndex];
// get cell coordinates
var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
aEventDetails, gLibrary);
}

View File

@ -20,7 +20,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageStyle",
XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition",
"resource://gre/modules/ScrollPosition.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
"resource:///modules/sessionstore/SessionHistory.jsm");
"resource://gre/modules/sessionstore/SessionHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Utils",

View File

@ -28,7 +28,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageStyle",
XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition",
"resource://gre/modules/ScrollPosition.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
"resource:///modules/sessionstore/SessionHistory.jsm");
"resource://gre/modules/sessionstore/SessionHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");

View File

@ -33,7 +33,6 @@ EXTRA_JS_MODULES.sessionstore = [
'RunState.jsm',
'SessionCookies.jsm',
'SessionFile.jsm',
'SessionHistory.jsm',
'SessionMigration.jsm',
'SessionSaver.jsm',
'SessionStorage.jsm',

View File

@ -1 +1 @@
54.0a1
55.0a1

View File

@ -1 +1 @@
54.0a1
55.0a1

View File

@ -443,6 +443,8 @@ identity.identified.verified_by_you=You have added a security exception for this
identity.identified.state_and_country=%S, %S
identity.icon.tooltip=Show site information
identity.showDetails.tooltip=Show connection details
identity.hideDetails.tooltip=Hide connection details
trackingProtection.intro.title=How Tracking Protection works
# LOCALIZATION NOTE (trackingProtection.intro.description2):

View File

@ -195,7 +195,7 @@ var DirectoryLinksProvider = {
if (matchOS) {
return Cc["@mozilla.org/intl/ospreferences;1"].
getService(Ci.mozIOSPreferences).getSystemLocale();
getService(Ci.mozIOSPreferences).systemLocale;
}
try {

View File

@ -33,8 +33,11 @@ this.ExtensionsUI = {
sideloaded: new Set(),
updates: new Set(),
sideloadListener: null,
histogram: null,
init() {
this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT");
Services.obs.addObserver(this, "webextension-permission-prompt", false);
Services.obs.addObserver(this, "webextension-update-permissions", false);
Services.obs.addObserver(this, "webextension-install-notify", false);
@ -88,13 +91,13 @@ this.ExtensionsUI = {
});
},
showAddonsManager(browser, strings, icon) {
showAddonsManager(browser, strings, icon, histkey) {
let global = browser.selectedBrowser.ownerGlobal;
return global.BrowserOpenAddonsMgr("addons://list/extension").then(aomWin => {
let aomBrowser = aomWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.chromeEventHandler;
return this.showPermissionsPrompt(aomBrowser, strings, icon);
return this.showPermissionsPrompt(aomBrowser, strings, icon, histkey);
});
},
@ -108,13 +111,14 @@ this.ExtensionsUI = {
permissions: addon.userPermissions,
type: "sideload",
});
this.showAddonsManager(browser, strings, addon.iconURL).then(answer => {
addon.userDisabled = !answer;
});
this.showAddonsManager(browser, strings, addon.iconURL, "sideload")
.then(answer => {
addon.userDisabled = !answer;
});
},
showUpdate(browser, info) {
this.showAddonsManager(browser, info.strings, info.addon.iconURL)
this.showAddonsManager(browser, info.strings, info.addon.iconURL, "update")
.then(answer => {
if (answer) {
info.resolve();
@ -147,13 +151,27 @@ this.ExtensionsUI = {
return;
}
this.showPermissionsPrompt(target, strings, info.icon).then(answer => {
if (answer) {
info.resolve();
} else {
info.reject();
}
});
let histkey;
if (info.type == "sideload") {
histkey = "sideload";
} else if (info.type == "update") {
histkey = "update";
} else if (info.source == "AMO") {
histkey = "installAmo";
} else if (info.source == "local") {
histkey = "installLocal";
} else {
histkey = "installWeb";
}
this.showPermissionsPrompt(target, strings, info.icon, histkey)
.then(answer => {
if (answer) {
info.resolve();
} else {
info.reject();
}
});
} else if (topic == "webextension-update-permissions") {
let info = subject.wrappedJSObject;
info.type = "update";
@ -307,7 +325,7 @@ this.ExtensionsUI = {
return result;
},
showPermissionsPrompt(browser, strings, icon) {
showPermissionsPrompt(browser, strings, icon, histkey) {
function eventCallback(topic) {
if (topic == "showing") {
let doc = this.browser.ownerDocument;
@ -349,13 +367,19 @@ this.ExtensionsUI = {
let action = {
label: strings.acceptText,
accessKey: strings.acceptKey,
callback: () => resolve(true),
callback: () => {
this.histogram.add(histkey + "Accepted");
resolve(true);
},
};
let secondaryActions = [
{
label: strings.cancelText,
accessKey: strings.cancelKey,
callback: () => resolve(false),
callback: () => {
this.histogram.add(histkey + "Rejected");
resolve(false);
},
},
];

View File

@ -804,6 +804,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
}
.fxaSyncIllustration {
width: 180px;
height: var(--panel-ui-sync-illustration-height);
}

View File

@ -2,7 +2,7 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="320" height="280" viewBox="0 0 320 280" xmlns:xlink="http://www.w3.org/1999/xlink" >
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 320 280" xmlns:xlink="http://www.w3.org/1999/xlink" >
<style>
#blueFill:target ~ use,
#blueFill:target ~ g {

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -64,7 +64,6 @@
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "nsILoadInfo.h"
#include "nsXPCOMStrings.h"
// This should be probably defined on some other place... but I couldn't find it
#define WEBAPPS_PERM_NAME "webapps-manage"

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
54.0a1
55.0a1

View File

@ -13,7 +13,7 @@
"use strict";
const { interfaces: Ci, utils: Cu } = Components;
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const kDebuggerPrefs = [
"devtools.debugger.remote-enabled",
"devtools.chrome.enabled"
@ -124,9 +124,28 @@ DevToolsStartup.prototype = {
if (!this._isRemoteDebuggingEnabled()) {
return;
}
let devtoolsThreadResumed = false;
let pauseOnStartup = cmdLine.handleFlag("wait-for-jsdebugger", false);
if (pauseOnStartup) {
let observe = function (subject, topic, data) {
devtoolsThreadResumed = true;
Services.obs.removeObserver(observe, "devtools-thread-resumed");
};
Services.obs.addObserver(observe, "devtools-thread-resumed", false);
}
const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
BrowserToolboxProcess.init();
if (pauseOnStartup) {
// Spin the event loop until the debugger connects.
let thread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
while (!devtoolsThreadResumed) {
thread.processNextEvent(true);
}
}
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
cmdLine.preventDefault = true;
}
@ -203,6 +222,9 @@ DevToolsStartup.prototype = {
/* eslint-disable max-len */
helpInfo: " --jsconsole Open the Browser Console.\n" +
" --jsdebugger Open the Browser Toolbox.\n" +
" --wait-for-jsdebugger Spin event loop until JS debugger connects.\n" +
" Enables debugging (some) application startup code paths.\n" +
" Only has an effect when `--jsdebugger` is also supplied.\n" +
" --devtools Open DevTools on initial load.\n" +
" --start-debugger-server [ws:][ <port> | <path> ] Start the debugger server on\n" +
" a TCP port or Unix domain socket path. Defaults to TCP port\n" +

View File

@ -60,13 +60,15 @@ return /******/ (function(modules) { // webpackBootstrap
createFactories,
parseURLEncodedText,
parseURLParams,
getSelectableInInspectorGrips
getSelectableInInspectorGrips,
maybeEscapePropertyName
} = __webpack_require__(4);
module.exports = {
REPS,
MODE,
createFactories,
maybeEscapePropertyName,
parseURLEncodedText,
parseURLParams,
getSelectableInInspectorGrips
@ -354,6 +356,29 @@ return /******/ (function(modules) { // webpackBootstrap
}) + "\"";
}
/**
* Escape a property name, if needed. "Escaping" in this context
* means surrounding the property name with quotes.
*
* @param {String}
* name the property name
* @return {String} either the input, or the input surrounded by
* quotes, properly quoted in JS syntax.
*/
function maybeEscapePropertyName(name) {
// Quote the property name if it needs quoting. This particular
// test is an approximation; see
// https://mathiasbynens.be/notes/javascript-properties. However,
// the full solution requires a fair amount of Unicode data, and so
// let's defer that until either it's important, or the \p regexp
// syntax lands, see
// https://github.com/tc39/proposal-regexp-unicode-property-escapes.
if (!/^\w+$/.test(name)) {
name = escapeString(name);
}
return name;
}
function cropMultipleLines(text, limit) {
return escapeNewLines(cropString(text, limit));
}
@ -587,7 +612,8 @@ return /******/ (function(modules) { // webpackBootstrap
parseURLEncodedText,
getFileName,
getURLDisplayString,
getSelectableInInspectorGrips
getSelectableInInspectorGrips,
maybeEscapePropertyName
};
/***/ },
@ -978,9 +1004,9 @@ return /******/ (function(modules) { // webpackBootstrap
return x === y.toString();
}
let props = Object.getOwnPropertyNames(array);
for (let i = 0; i < props.length; i++) {
let p = props[i];
let propsArray = Object.getOwnPropertyNames(array);
for (let i = 0; i < propsArray.length; i++) {
let p = propsArray[i];
// Valid indexes are skipped
if (isInteger(p)) {
@ -1268,6 +1294,7 @@ return /******/ (function(modules) { // webpackBootstrap
const React = __webpack_require__(3);
const {
createFactories,
maybeEscapePropertyName,
wrapRender
} = __webpack_require__(4);
const { MODE } = __webpack_require__(1);
@ -1295,7 +1322,11 @@ return /******/ (function(modules) { // webpackBootstrap
attachedActorIds: React.PropTypes.array,
onDOMNodeMouseOver: React.PropTypes.func,
onDOMNodeMouseOut: React.PropTypes.func,
onInspectIconClick: React.PropTypes.func
onInspectIconClick: React.PropTypes.func,
// Normally a PropRep will quote a property name that isn't valid
// when unquoted; but this flag can be used to suppress the
// quoting.
suppressQuotes: React.PropTypes.bool
},
render: wrapRender(function () {
@ -1305,14 +1336,18 @@ return /******/ (function(modules) { // webpackBootstrap
name,
mode,
equal,
delim
delim,
suppressQuotes
} = this.props;
let key;
// The key can be a simple string, for plain objects,
// or another object for maps and weakmaps.
if (typeof this.props.name === "string") {
key = span({ "className": "nodeName" }, this.props.name);
if (typeof name === "string") {
if (!suppressQuotes) {
name = maybeEscapePropertyName(name);
}
key = span({ "className": "nodeName" }, name);
} else {
key = Rep(Object.assign({}, this.props, {
object: name,
@ -1424,19 +1459,24 @@ return /******/ (function(modules) { // webpackBootstrap
}
const truncate = Object.keys(properties).length > max;
let props = this.getProps(properties, indexes, truncate);
// The server synthesizes some property names for a Proxy, like
// <target> and <handler>; we don't want to quote these because,
// as synthetic properties, they appear more natural when
// unquoted.
const suppressQuotes = object.class === "Proxy";
let propsArray = this.getProps(properties, indexes, truncate, suppressQuotes);
if (truncate) {
// There are some undisplayed props. Then display "more...".
let objectLink = this.props.objectLink || span;
props.push(Caption({
propsArray.push(Caption({
object: objectLink({
object: object
}, `${propertiesLength - max} more…`)
}));
}
return props;
return propsArray;
},
/**
@ -1445,10 +1485,12 @@ return /******/ (function(modules) { // webpackBootstrap
* @param {Object} properties Props object.
* @param {Array} indexes Indexes of props.
* @param {Boolean} truncate true if the grip will be truncated.
* @param {Boolean} suppressQuotes true if we should suppress quotes
* on property names.
* @return {Array} Props.
*/
getProps: function (properties, indexes, truncate) {
let props = [];
getProps: function (properties, indexes, truncate, suppressQuotes) {
let propsArray = [];
// Make indexes ordered by ascending.
indexes.sort(function (a, b) {
@ -1459,7 +1501,7 @@ return /******/ (function(modules) { // webpackBootstrap
let name = Object.keys(properties)[i];
let value = this.getPropValue(properties[name]);
props.push(PropRep(Object.assign({}, this.props, {
propsArray.push(PropRep(Object.assign({}, this.props, {
mode: MODE.TINY,
name: name,
object: value,
@ -1467,11 +1509,12 @@ return /******/ (function(modules) { // webpackBootstrap
delim: i !== indexes.length - 1 || truncate ? ", " : "",
defaultRep: Grip,
// Do not propagate title to properties reps
title: undefined
title: undefined,
suppressQuotes
})));
});
return props;
return propsArray;
},
/**
@ -1530,7 +1573,7 @@ return /******/ (function(modules) { // webpackBootstrap
render: wrapRender(function () {
let object = this.props.object;
let props = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
let propsArray = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY) {
@ -1543,7 +1586,7 @@ return /******/ (function(modules) { // webpackBootstrap
return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
className: "objectLeftBrace",
object: object
}, " { "), ...props, objectLink({
}, " { "), ...propsArray, objectLink({
className: "objectRightBrace",
object: object
}, " }"));
@ -2114,7 +2157,8 @@ return /******/ (function(modules) { // webpackBootstrap
name: `<${key}>`,
object,
equal: ": ",
delim: i < keys.length - 1 ? ", " : ""
delim: i < keys.length - 1 ? ", " : "",
suppressQuotes: true
}));
});
},
@ -2136,11 +2180,11 @@ return /******/ (function(modules) { // webpackBootstrap
}, " }"));
}
const props = this.getProps(promiseState);
const propsArray = this.getProps(promiseState);
return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
className: "objectLeftBrace",
object: object
}, " { "), ...props, objectLink({
}, " { "), ...propsArray, objectLink({
className: "objectRightBrace",
object: object
}, " }"));
@ -2456,7 +2500,7 @@ return /******/ (function(modules) { // webpackBootstrap
draggable: false,
// TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
title: "Click to select the node in the inspector",
onClick: () => onInspectIconClick(object)
onClick: e => onInspectIconClick(object, e)
});
}
}
@ -2747,7 +2791,7 @@ return /******/ (function(modules) { // webpackBootstrap
draggable: false,
// TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
title: "Click to select the node in the inspector",
onClick: () => onInspectIconClick(grip)
onClick: e => onInspectIconClick(grip, e)
});
}
}
@ -3404,7 +3448,7 @@ return /******/ (function(modules) { // webpackBootstrap
render: wrapRender(function () {
let object = this.props.object;
let props = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
let propsArray = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY) {
@ -3417,7 +3461,7 @@ return /******/ (function(modules) { // webpackBootstrap
return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
className: "objectLeftBrace",
object: object
}, " { "), props, objectLink({
}, " { "), propsArray, objectLink({
className: "objectRightBrace",
object: object
}, " }"));

View File

@ -14,8 +14,8 @@ Test ArrayRep rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
/* import-globals-from head.js */

View File

@ -14,8 +14,8 @@ Test Attribute rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test comment-node rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {

View File

@ -14,8 +14,8 @@ Test DateTime rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, DateTime } = REPS;

View File

@ -14,8 +14,8 @@ Test Document rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Document } = REPS;

View File

@ -14,8 +14,8 @@ Test Element node rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {
@ -233,8 +233,11 @@ window.onload = Task.async(function* () {
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null;
let onInspectIconClick = (object) => {
let inspectIconClickedEvent = null;
let onInspectIconClick = (object, event) => {
inspectIconClickedValue = object;
inspectIconClickedEvent = event;
};
const renderedComponentWithoutInspectIcon = renderComponent(ElementNode.rep, {
@ -265,6 +268,8 @@ window.onload = Task.async(function* () {
is(inspectIconClickedValue, grips[0],
"onInspectIconClick is called with expected value when inspect icon is clicked");
ok(inspectIconClickedEvent !== null && inspectIconClickedEvent.type === "click",
"onInspectIconClick forwarded the original event to the callback");
}
function getGripStub(name) {

View File

@ -14,8 +14,8 @@ Test Error rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {

View File

@ -14,8 +14,8 @@ Test Event rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
REPS,

View File

@ -14,8 +14,8 @@ Test fallback for rep rendering when a rep fails to render.
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test Func rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Func } = REPS;

View File

@ -14,8 +14,8 @@ Test GripArray rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
REPS,

View File

@ -14,8 +14,8 @@ Test GripMap rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {
@ -156,7 +156,7 @@ window.onload = Task.async(function* () {
// `new Map([["key-a","value-a"], ["key-b","value-b"], ["key-c","value-c"]])`
const testName = "testMaxEntries";
const defaultOutput = `Map { key-a: "value-a", key-b: "value-b", key-c: "value-c" }`;
const defaultOutput = `Map { "key-a": "value-a", "key-b": "value-b", "key-c": "value-c" }`;
const modeTests = [
{
@ -186,10 +186,10 @@ window.onload = Task.async(function* () {
const testName = "testMoreThanMaxEntries";
const defaultOutput =
`Map { key-0: "value-0", key-1: "value-1", key-2: "value-2", 98 more… }`;
`Map { "key-0": "value-0", "key-1": "value-1", "key-2": "value-2", 98 more… }`;
// Generate string with 101 entries, which is the max limit for 'long' mode.
let longString = Array.from({length: 10}).map((_, i) => `key-${i}: "value-${i}"`);
let longString = Array.from({length: 10}).map((_, i) => `"key-${i}": "value-${i}"`);
const longOutput = `Map { ${longString.join(", ")}, 91 more… }`;
const modeTests = [
@ -220,9 +220,9 @@ window.onload = Task.async(function* () {
const testName = "testUninterestingEntries";
const defaultOutput =
`Map { key-a: null, key-c: "value-c", key-d: 4, 1 more… }`;
`Map { "key-a": null, "key-c": "value-c", "key-d": 4, 1 more… }`;
const longOutput =
`Map { key-a: null, key-b: undefined, key-c: "value-c", key-d: 4 }`;
`Map { "key-a": null, "key-b": undefined, "key-c": "value-c", "key-d": 4 }`;
const modeTests = [
{

View File

@ -14,8 +14,8 @@ Test grip rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
REPS,

View File

@ -14,8 +14,8 @@ Test Infinity rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {

View File

@ -14,8 +14,8 @@ Test LongString rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, LongStringRep } = REPS;

View File

@ -14,8 +14,8 @@ Test NaN rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {

View File

@ -14,8 +14,8 @@ Test Null rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test Number rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Number } = REPS;

View File

@ -14,8 +14,8 @@ Test ObjectWithText rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test ObjectWithURL rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");

View File

@ -14,8 +14,8 @@ Test Obj rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Obj } = REPS;
@ -30,6 +30,9 @@ window.onload = Task.async(function* () {
yield testMoreThanMaxProps();
yield testUninterestingProps();
// Test that unusual property names are escaped.
yield testEscapedPropertyNames();
// Test that properties are rendered as expected by PropRep
yield testNested();
@ -159,6 +162,32 @@ window.onload = Task.async(function* () {
testRepRenderModes(modeTests, "testUninterestingProps", componentUnderTest, stub);
}
function testEscapedPropertyNames() {
const stub = {"":1, "quote-this":2, noquotes:3};
const defaultOutput = `Object { "": 1, "quote-this": 2, noquotes: 3 }`;
const modeTests = [
{
mode: undefined,
expectedOutput: defaultOutput,
},
{
mode: MODE.TINY,
expectedOutput: `Object`,
},
{
mode: MODE.SHORT,
expectedOutput: defaultOutput,
},
{
mode: MODE.LONG,
expectedOutput: defaultOutput,
}
];
testRepRenderModes(modeTests, "testEscapedPropertyNames", componentUnderTest, stub);
}
function testNested() {
const stub = {
objProp: {

View File

@ -14,8 +14,8 @@ Test Promise rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {

View File

@ -14,8 +14,8 @@ Test RegExp rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test String rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, StringRep } = REPS;

View File

@ -14,8 +14,8 @@ Test Stylesheet rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");

View File

@ -14,8 +14,8 @@ Test Symbol rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
/* import-globals-from head.js */

View File

@ -14,8 +14,8 @@ Test text-node rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
"use strict";
window.onload = Task.async(function* () {
@ -172,8 +172,11 @@ window.onload = Task.async(function* () {
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null;
let onInspectIconClick = (object) => {
let inspectIconClickedEvent = null;
let onInspectIconClick = (object, event) => {
inspectIconClickedValue = object;
inspectIconClickedEvent = event;
};
const renderedComponentWithoutInspectIcon = renderComponent(TextNode.rep, {
@ -196,6 +199,8 @@ window.onload = Task.async(function* () {
is(inspectIconClickedValue, grips[0],
"onInspectIconClick is called with expected value when inspect icon is clicked");
ok(inspectIconClickedEvent !== null && inspectIconClickedEvent.type === "click",
"onInspectIconClick forwarded the original event to the callback");
}
});
</script>

View File

@ -14,8 +14,8 @@ Test undefined rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");

View File

@ -14,8 +14,8 @@ Test window rep
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");

View File

@ -50,7 +50,18 @@ function ChromeActor(connection) {
if (!window) {
window = Services.wm.getMostRecentWindow(null);
}
// On xpcshell, there is no window/docshell
// We really want _some_ window at least, so fallback to the hidden window if
// there's nothing else (such as during early startup).
if (!window) {
try {
window = Services.appShell.hiddenDOMWindow;
} catch (e) {
// On XPCShell, the above line will throw.
}
}
// On XPCShell, there is no window/docshell
let docShell = window ? window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
: null;

View File

@ -1020,8 +1020,8 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
let packet = this._resumed();
this._popThreadPause();
// Tell anyone who cares of the resume (as of now, that's the xpcshell
// harness)
// Tell anyone who cares of the resume (as of now, that's the xpcshell harness and
// devtools-startup.js when handling the --wait-for-jsdebugger flag)
if (Services.obs) {
Services.obs.notifyObservers(this, "devtools-thread-resumed", null);
}

View File

@ -3223,6 +3223,7 @@ exports.CSS_PROPERTIES = {
"dialog",
"difference",
"disabled",
"distribute",
"dotted",
"double",
"drag",
@ -3283,6 +3284,8 @@ exports.CSS_PROPERTIES = {
"inline-table",
"inset",
"inside",
"inter-character",
"inter-word",
"intersect",
"isolate",
"italic",
@ -8812,6 +8815,23 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"text-justify": {
"isInherited": true,
"subproperties": [
"text-justify"
],
"supports": [],
"values": [
"auto",
"distribute",
"inherit",
"initial",
"inter-character",
"inter-word",
"none",
"unset"
]
},
"text-orientation": {
"isInherited": true,
"subproperties": [

View File

@ -428,8 +428,8 @@ nsDSURIContentListener::CheckFrameOptions(nsIRequest* aRequest)
}
nsAutoCString xfoHeaderCValue;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
xfoHeaderCValue);
Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
xfoHeaderCValue);
NS_ConvertUTF8toUTF16 xfoHeaderValue(xfoHeaderCValue);
// if no header value, there's nothing to do.

View File

@ -541,24 +541,31 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
// This is needed in order for 3rd-party cookie blocking to work.
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
nsresult rv;
if (httpInternal) {
httpInternal->SetDocumentURI(doc->GetDocumentURI());
rv = httpInternal->SetDocumentURI(doc->GetDocumentURI());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
rv = httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Remove extraneous request headers (to reduce request size)
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
EmptyCString(), false);
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
EmptyCString(), false);
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
EmptyCString(), false);
rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
EmptyCString(), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
EmptyCString(), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
EmptyCString(), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Always send a Ping-To header.
nsAutoCString pingTo;
if (NS_SUCCEEDED(info->target->GetSpec(pingTo))) {
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
nsCOMPtr<nsIScriptSecurityManager> sm =
@ -567,7 +574,7 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
if (sm && info->referrer) {
bool referrerIsSecure;
uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
// Default to sending less data if NS_URIChainHasFlags() fails.
referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
@ -582,8 +589,9 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
if (sameOrigin || !referrerIsSecure) {
nsAutoCString pingFrom;
if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom))) {
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom,
false);
rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"),
pingFrom, false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
@ -591,7 +599,8 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
// over an encrypted connection and its address does not have the same
// origin as "ping URL", send a referrer.
if (!sameOrigin && !referrerIsSecure) {
httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
rv = httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
@ -7505,7 +7514,7 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
uint32_t responseStatus = 0;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
if (httpChannel) {
(void)httpChannel->GetResponseStatus(&responseStatus);
Unused << httpChannel->GetResponseStatus(&responseStatus);
}
// Add visit N -1 => N
@ -11150,16 +11159,20 @@ nsDocShell::DoURILoad(nsIURI* aURI,
do_QueryInterface(channel));
if (httpChannelInternal) {
if (aForceAllowCookies) {
httpChannelInternal->SetThirdPartyFlags(
rv = httpChannelInternal->SetThirdPartyFlags(
nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
if (aFirstParty) {
httpChannelInternal->SetDocumentURI(aURI);
rv = httpChannelInternal->SetDocumentURI(aURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
} else {
httpChannelInternal->SetDocumentURI(aReferrerURI);
rv = httpChannelInternal->SetDocumentURI(aReferrerURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
httpChannelInternal->SetRedirectMode(
rv = httpChannelInternal->SetRedirectMode(
nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
@ -11240,7 +11253,8 @@ nsDocShell::DoURILoad(nsIURI* aURI,
// Set the referrer explicitly
if (aReferrerURI && aSendReferrer) {
// Referrer is currenly only set for link clicks here.
httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
@ -12332,8 +12346,10 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
uint32_t loadFlags;
aChannel->GetLoadFlags(&loadFlags);
loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
httpChannel->GetReferrer(getter_AddRefs(referrerURI));
httpChannel->GetReferrerPolicy(&referrerPolicy);
rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI));
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
discardLayoutState = ShouldDiscardLayoutState(httpChannel);
}
@ -12975,7 +12991,7 @@ nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel)
// figure out if SH should be saving layout state
bool noStore = false;
aChannel->IsNoStoreResponse(&noStore);
Unused << aChannel->IsNoStoreResponse(&noStore);
return noStore;
}
@ -13047,7 +13063,7 @@ nsDocShell::ChannelIsPost(nsIChannel* aChannel)
}
nsAutoCString method;
httpChannel->GetRequestMethod(method);
Unused << httpChannel->GetRequestMethod(method);
return method.EqualsLiteral("POST");
}

View File

@ -224,7 +224,7 @@ void
Element::UpdateState(bool aNotify)
{
EventStates oldState = mState;
mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
mState = IntrinsicState() | (oldState & EXTERNALLY_MANAGED_STATES);
if (aNotify) {
EventStates changedStates = oldState ^ mState;
if (!changedStates.IsEmpty()) {

View File

@ -515,24 +515,39 @@ private:
EventStates StyleStateFromLocks() const;
protected:
// Methods for the ESM to manage state bits. These will handle
// setting up script blockers when they notify, so no need to do it
// in the callers unless desired.
// Methods for the ESM, nsGlobalWindow and focus manager to manage state bits.
// These will handle setting up script blockers when they notify, so no need
// to do it in the callers unless desired. States passed here must only be
// those in EXTERNALLY_MANAGED_STATES.
virtual void AddStates(EventStates aStates)
{
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
"Should only be adding ESM-managed states here");
"Should only be adding externally-managed states here");
AddStatesSilently(aStates);
NotifyStateChange(aStates);
}
virtual void RemoveStates(EventStates aStates)
{
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
"Should only be removing ESM-managed states here");
"Should only be removing externally-managed states here");
RemoveStatesSilently(aStates);
NotifyStateChange(aStates);
}
public:
// Public methods to manage state bits in MANUALLY_MANAGED_STATES.
void AddManuallyManagedStates(EventStates aStates)
{
MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
"Should only be adding manually-managed states here");
AddStates(aStates);
}
void RemoveManuallyManagedStates(EventStates aStates)
{
MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
"Should only be removing manually-managed states here");
RemoveStates(aStates);
}
virtual void UpdateEditableState(bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,

View File

@ -995,18 +995,22 @@ EventSourceImpl::SetupHttpChannel()
{
AssertIsOnMainThread();
MOZ_ASSERT(!IsShutDown());
mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
DebugOnly<nsresult> rv =
mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
MOZ_ASSERT(NS_SUCCEEDED(rv));
/* set the http request headers */
mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
rv = mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING(TEXT_EVENT_STREAM), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
// LOAD_BYPASS_CACHE already adds the Cache-Control: no-cache header
if (!mLastEventID.IsEmpty()) {
mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
rv = mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
NS_ConvertUTF16toUTF8(mLastEventID), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}

View File

@ -1349,7 +1349,8 @@ Navigator::SendBeaconInternal(const nsAString& aUrl,
aRv.Throw(NS_ERROR_DOM_BAD_URI);
return false;
}
httpChannel->SetReferrer(documentURI);
rv = httpChannel->SetReferrer(documentURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> in;
nsAutoCString contentTypeWithCharset;
@ -1379,7 +1380,8 @@ Navigator::SendBeaconInternal(const nsAString& aUrl,
NS_LITERAL_CSTRING("POST"),
false);
} else {
httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);

View File

@ -894,7 +894,8 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
}
if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
nsHTMLDNSPrefetch::PrefetchLow(hostname);
nsHTMLDNSPrefetch::PrefetchLow(hostname,
mDocument->NodePrincipal()->OriginAttributesRef());
}
}

View File

@ -4094,6 +4094,70 @@ nsDOMWindowUtils::IsTimeoutTracking(uint32_t aTimeoutId, bool* aResult)
return NS_OK;
}
struct StateTableEntry
{
const char* mStateString;
EventStates mState;
};
static constexpr StateTableEntry kManuallyManagedStates[] = {
// none yet; but for example: { "highlight", NS_EVENT_STATE_HIGHLIGHT },
{ nullptr, EventStates() },
};
static_assert(!kManuallyManagedStates[ArrayLength(kManuallyManagedStates) - 1]
.mStateString,
"last kManuallyManagedStates entry must be a sentinel with "
"mStateString == nullptr");
static EventStates
GetEventStateForString(const nsAString& aStateString)
{
for (const StateTableEntry* entry = kManuallyManagedStates;
entry->mStateString; ++entry) {
if (aStateString.EqualsASCII(entry->mStateString)) {
return entry->mState;
}
}
return EventStates();
}
NS_IMETHODIMP
nsDOMWindowUtils::AddManuallyManagedState(nsIDOMElement* aElement,
const nsAString& aStateString)
{
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (!element) {
return NS_ERROR_INVALID_ARG;
}
EventStates state = GetEventStateForString(aStateString);
if (state.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
element->AddManuallyManagedStates(state);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::RemoveManuallyManagedState(nsIDOMElement* aElement,
const nsAString& aStateString)
{
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (!element) {
return NS_ERROR_INVALID_ARG;
}
EventStates state = GetEventStateForString(aStateString);
if (state.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
element->RemoveManuallyManagedStates(state);
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)

View File

@ -2638,11 +2638,11 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
if (httpChannel) {
httpChannel->GetResponseHeader(
Unused << httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("content-security-policy"),
tCspHeaderValue);
httpChannel->GetResponseHeader(
Unused << httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("content-security-policy-report-only"),
tCspROHeaderValue);
}
@ -4796,7 +4796,8 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
do_QueryInterface(GetChannel());
if (internalChannel) {
nsCOMArray<nsISecurityConsoleMessage> messages;
internalChannel->TakeAllSecurityMessages(messages);
DebugOnly<nsresult> rv = internalChannel->TakeAllSecurityMessages(messages);
MOZ_ASSERT(NS_SUCCEEDED(rv));
SendToConsole(messages);
}

View File

@ -1132,6 +1132,7 @@ GK_ATOM(scrollbarUpTop, "scrollbar-up-top")
GK_ATOM(scrollbox, "scrollbox")
GK_ATOM(scrollcorner, "scrollcorner")
GK_ATOM(scrolling, "scrolling")
GK_ATOM(scrollPosition, "scroll-position")
GK_ATOM(section, "section")
GK_ATOM(select, "select")
GK_ATOM(selectable, "selectable")

View File

@ -2599,8 +2599,9 @@ nsObjectLoadingContent::OpenChannel()
// Referrer
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
if (httpChan) {
httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
doc->GetReferrerPolicy());
rv = httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
doc->GetReferrerPolicy());
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Set the initiator type
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));

View File

@ -1298,15 +1298,18 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest)
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
// HTTP content negotation has little value in this context.
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("*/*"),
false);
httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
aRequest->mReferrerPolicy);
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("*/*"),
false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
aRequest->mReferrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel));
if (internalChannel) {
internalChannel->SetIntegrityMetadata(aRequest->mIntegrity.GetIntegrityString());
rv = internalChannel->SetIntegrityMetadata(aRequest->mIntegrity.GetIntegrityString());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}

View File

@ -143,15 +143,17 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
mChannel = aChannel;
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(mChannel);
if (http) {
http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
false);
rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (loadInfo) {
nsCOMPtr<nsIURI> loaderUri;
loadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(loaderUri));
if (loaderUri) {
http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy);
rv = http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
}

View File

@ -314,12 +314,34 @@ private:
#define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED | \
NS_EVENT_STATE_FOCUS_WITHIN)
// Event states that can be added and removed through
// Element::{Add,Remove}ManuallyManagedStates.
//
// Take care when manually managing state bits. You are responsible for
// setting or clearing the bit when an Element is added or removed from a
// document (e.g. in BindToTree and UnbindFromTree), if that is an
// appropriate thing to do for your state bit.
#define MANUALLY_MANAGED_STATES ( \
mozilla::EventStates() /* none so far */ \
)
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
// Event states that are managed externally to an element (by the
// EventStateManager, or by other code). As opposed to those in
// INTRINSIC_STATES, which are are computed by the element itself
// and returned from Element::IntrinsicState.
#define EXTERNALLY_MANAGED_STATES ( \
MANUALLY_MANAGED_STATES | \
NS_EVENT_STATE_ACTIVE | \
NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FOCUS_WITHIN | \
NS_EVENT_STATE_FULL_SCREEN | \
NS_EVENT_STATE_HOVER | \
NS_EVENT_STATE_UNRESOLVED | \
NS_EVENT_STATE_URLTARGET \
)
#define INTRINSIC_STATES (~EXTERNALLY_MANAGED_STATES)
#endif // mozilla_EventStates_h_

View File

@ -298,11 +298,15 @@ FetchDriver::HttpFetch()
// Conversion between enumerations is safe due to static asserts in
// dom/workers/ServiceWorkerManager.cpp
internalChan->SetCorsMode(static_cast<uint32_t>(mRequest->Mode()));
internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
rv = internalChan->SetCorsMode(static_cast<uint32_t>(mRequest->Mode()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
mRequest->MaybeSkipCacheIfPerformingRevalidation();
internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
internalChan->SetIntegrityMetadata(mRequest->GetIntegrity());
rv = internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = internalChan->SetIntegrityMetadata(mRequest->GetIntegrity());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
// Step 5. Proxy authentication will be handled by Necko.
@ -451,7 +455,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
if (httpChannel) {
uint32_t responseStatus;
httpChannel->GetResponseStatus(&responseStatus);
rv = httpChannel->GetResponseStatus(&responseStatus);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) {
if (mRequest->GetRedirectMode() == RequestRedirect::Error) {
@ -464,7 +469,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
}
nsAutoCString statusText;
httpChannel->GetResponseStatusText(statusText);
rv = httpChannel->GetResponseStatusText(statusText);
MOZ_ASSERT(NS_SUCCEEDED(rv));
response = new InternalResponse(responseStatus, statusText);
@ -739,8 +745,8 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(aOldChannel);
nsAutoCString tRPHeaderCValue;
if (oldHttpChannel) {
oldHttpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"),
tRPHeaderCValue);
Unused << oldHttpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"),
tRPHeaderCValue);
}
// "HTTP-redirect fetch": step 14 "Append locationURL to request's URL list."
@ -836,24 +842,32 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
hasAccept = true;
}
if (headers[i].mValue.IsEmpty()) {
aChannel->SetEmptyRequestHeader(headers[i].mName);
DebugOnly<nsresult> rv = aChannel->SetEmptyRequestHeader(headers[i].mName);
MOZ_ASSERT(NS_SUCCEEDED(rv));
} else {
aChannel->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
DebugOnly<nsresult> rv =
aChannel->SetRequestHeader(headers[i].mName, headers[i].mValue,
false /* merge */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
if (!hasAccept) {
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
NS_LITERAL_CSTRING("*/*"),
false /* merge */);
DebugOnly<nsresult> rv =
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
NS_LITERAL_CSTRING("*/*"),
false /* merge */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
if (mRequest->ForceOriginHeader()) {
nsAutoString origin;
if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
NS_ConvertUTF16toUTF8(origin),
false /* merge */);
DebugOnly<nsresult> rv =
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
NS_ConvertUTF16toUTF8(origin),
false /* merge */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
}

View File

@ -148,7 +148,7 @@ FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal,
}
nsCOMPtr<nsIURI> referrerURI;
aChannel->GetReferrer(getter_AddRefs(referrerURI));
Unused << aChannel->GetReferrer(getter_AddRefs(referrerURI));
// Step 8 https://fetch.spec.whatwg.org/#main-fetch
// If requests referrer is not "no-referrer", set requests referrer to

View File

@ -355,7 +355,10 @@ InternalHeaders::FillResponseHeaders(nsIRequest* aRequest)
}
RefPtr<FillHeaders> visitor = new FillHeaders(this);
httpChannel->VisitResponseHeaders(visitor);
nsresult rv = httpChannel->VisitResponseHeaders(visitor);
if (NS_FAILED(rv)) {
NS_WARNING("failed to fill headers");
}
}
bool

View File

@ -291,7 +291,9 @@ HttpServer::TransportProvider::MaybeNotify()
RefPtr<TransportProvider> self = this;
nsCOMPtr<nsIRunnable> event = NS_NewRunnableFunction([self, this] ()
{
mListener->OnTransportAvailable(mTransport, mInput, mOutput);
DebugOnly<nsresult> rv = mListener->OnTransportAvailable(mTransport,
mInput, mOutput);
MOZ_ASSERT(NS_SUCCEEDED(rv));
});
NS_DispatchToCurrentThread(event);
}

View File

@ -693,15 +693,6 @@ nsresult nsGeolocationService::Init()
mProvider = new AndroidLocationProvider();
#endif
#ifdef MOZ_WIDGET_GONK
// GonkGPSGeolocationProvider can be started at boot up time for initialization reasons.
// do_getService gets hold of the already initialized component and starts
// processing location requests immediately.
// do_Createinstance will create multiple instances of the provider which is not right.
// bug 993041
mProvider = do_GetService(GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID);
#endif
#ifdef MOZ_WIDGET_GTK
#ifdef MOZ_GPSD
if (Preferences::GetBool("geo.provider.use_gpsd", false)) {
@ -733,11 +724,11 @@ nsresult nsGeolocationService::Init()
// "geo.provider.testing" is always set for all plain and browser chrome
// mochitests, and also for xpcshell tests.
if (!mProvider || Preferences::GetBool("geo.provider.testing", false)) {
nsCOMPtr<nsIGeolocationProvider> geo_net_provider =
nsCOMPtr<nsIGeolocationProvider> geoTestProvider =
do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
if (geo_net_provider) {
mProvider = geo_net_provider;
if (geoTestProvider) {
mProvider = geoTestProvider;
}
}

View File

@ -32,7 +32,6 @@
#include "nsError.h"
#include "nsNodeInfoManager.h"
#include "nsNetUtil.h"
#include "nsXPCOMStrings.h"
#include "xpcpublic.h"
#include "nsThreadUtils.h"
#include "nsIThreadInternal.h"
@ -517,7 +516,7 @@ HTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest* aRequest,
if (hc && NS_SUCCEEDED(hc->GetRequestSucceeded(&succeeded)) && !succeeded) {
element->NotifyLoadError();
uint32_t responseStatus = 0;
hc->GetResponseStatus(&responseStatus);
Unused << hc->GetResponseStatus(&responseStatus);
nsAutoString code;
code.AppendInt(responseStatus);
nsAutoString src;
@ -1169,9 +1168,10 @@ public:
// Use a byte range request from the start of the resource.
// This enables us to detect if the stream supports byte range
// requests, and therefore seeking, early.
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
NS_LITERAL_CSTRING("bytes=0-"),
false);
rv = hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
NS_LITERAL_CSTRING("bytes=0-"),
false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
aElement->SetRequestHeaders(hc);
}
@ -6455,12 +6455,15 @@ void HTMLMediaElement::SetRequestHeaders(nsIHttpChannel* aChannel)
// and a length spec in the container are not present either) and from seeking.
// So, disable the standard "Accept-Encoding: gzip,deflate" that we usually send.
// See bug 614760.
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
EmptyCString(), false);
DebugOnly<nsresult> rv =
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
EmptyCString(), false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Set the Referer header
aChannel->SetReferrerWithPolicy(OwnerDoc()->GetDocumentURI(),
OwnerDoc()->GetReferrerPolicy());
rv = aChannel->SetReferrerWithPolicy(OwnerDoc()->GetDocumentURI(),
OwnerDoc()->GetReferrerPolicy());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
void HTMLMediaElement::FireTimeUpdate(bool aPeriodic)

Some files were not shown because too many files have changed in this diff Show More