Merge m-c to autoland, a=merge
@ -197,6 +197,16 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
||||
kNoReqStates,
|
||||
eReadonlyUntilEditable
|
||||
},
|
||||
{ // feed
|
||||
&nsGkAtoms::feed,
|
||||
roles::GROUPING,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kGenericAccType,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // form
|
||||
&nsGkAtoms::form,
|
||||
roles::FORM,
|
||||
|
@ -410,7 +410,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHODIMP Notify(nsITimer* aTimer) final
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) final
|
||||
{
|
||||
if (!mContent->IsInUncomposedDoc())
|
||||
return NS_OK;
|
||||
|
@ -31,6 +31,7 @@
|
||||
testAttrs("section", {"xml-roles" : "region"}, true);
|
||||
testAttrs("main", {"xml-roles" : "main"}, true); // // ARIA override
|
||||
testAttrs("form", {"xml-roles" : "form"}, true);
|
||||
testAttrs("feed", {"xml-roles" : "feed"}, true);
|
||||
testAttrs("article", {"xml-roles" : "article"}, true);
|
||||
testAttrs("main_element", {"xml-roles" : "main"}, true);
|
||||
|
||||
@ -159,6 +160,7 @@
|
||||
<section id="section">a section</section>
|
||||
<article id="main" role="main">a main area</article>
|
||||
<article id="form" role="form">a form area</article>
|
||||
<div id="feed" role="feed">a feed</div>
|
||||
<article id="article">article</article>
|
||||
<main id="main_element">another main area</main>
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
testRole("aria_directory", ROLE_LIST);
|
||||
testRole("aria_document", ROLE_DOCUMENT);
|
||||
testRole("aria_form", ROLE_FORM);
|
||||
testRole("aria_feed", ROLE_GROUPING);
|
||||
testRole("aria_grid", ROLE_TABLE);
|
||||
testRole("aria_gridcell", ROLE_GRID_CELL);
|
||||
testRole("aria_group", ROLE_GROUPING);
|
||||
@ -207,6 +208,7 @@
|
||||
<span id="aria_directory" role="directory"/>
|
||||
<span id="aria_document" role="document"/>
|
||||
<span id="aria_form" role="form"/>
|
||||
<span id="aria_feed" role="feed"/>
|
||||
<span id="aria_grid" role="grid"/>
|
||||
<span id="aria_gridcell" role="gridcell"/>
|
||||
<span id="aria_group" role="group"/>
|
||||
|
@ -7207,6 +7207,8 @@ var gIdentityHandler = {
|
||||
if (event.target == this._identityPopup) {
|
||||
window.addEventListener("focus", this, true);
|
||||
}
|
||||
this._identityPopupMultiView._mainView.style.height =
|
||||
this._identityPopup.getBoundingClientRect().height + "px";
|
||||
},
|
||||
|
||||
onPopupHidden(event) {
|
||||
|
@ -160,7 +160,7 @@
|
||||
popuponly menulist to be its immediate parent. -->
|
||||
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
|
||||
<menupopup rolluponmousewheel="true"
|
||||
activateontab="true"
|
||||
activateontab="true" position="after_start"
|
||||
#ifdef XP_WIN
|
||||
consumeoutsideclicks="false" ignorekeys="handled"
|
||||
#endif
|
||||
|
@ -473,5 +473,15 @@ add_task(function* test_mousemove_correcttarget() {
|
||||
|
||||
yield hideSelectPopup(selectPopup);
|
||||
|
||||
// The popup should be closed when fullscreen mode is entered or exited.
|
||||
for (let steps = 0; steps < 2; steps++) {
|
||||
yield openSelectPopup(selectPopup, true);
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
let sizeModeChanged = BrowserTestUtils.waitForEvent(window, "sizemodechange");
|
||||
BrowserFullScreen();
|
||||
yield sizeModeChanged;
|
||||
yield popupHiddenPromise;
|
||||
}
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
@ -152,7 +152,7 @@ const PanelUI = {
|
||||
anchor = aEvent.target;
|
||||
}
|
||||
|
||||
this.panel.addEventListener("popupshown", function onPopupShown() {
|
||||
this.panel.addEventListener("popupshown", function onPopupShown(event) {
|
||||
this.removeEventListener("popupshown", onPopupShown);
|
||||
resolve();
|
||||
});
|
||||
|
@ -58,8 +58,7 @@
|
||||
<field name="_anchorElement">null</field>
|
||||
<field name="_mainViewHeight">0</field>
|
||||
<field name="_subViewObserver">null</field>
|
||||
<field name="__transitioning">false</field>
|
||||
<field name="_ignoreMutations">false</field>
|
||||
<field name="__transitioning">true</field>
|
||||
|
||||
<property name="showingSubView" readonly="true"
|
||||
onget="return this._viewStack.getAttribute('viewtype') == 'subview'"/>
|
||||
@ -69,22 +68,6 @@
|
||||
<property name="showingSubViewAsMainView" readonly="true"
|
||||
onget="return this.getAttribute('mainViewIsSubView') == 'true'"/>
|
||||
|
||||
<property name="ignoreMutations">
|
||||
<getter>
|
||||
return this._ignoreMutations;
|
||||
</getter>
|
||||
<setter><![CDATA[
|
||||
this._ignoreMutations = val;
|
||||
if (!val && this._panel.state == "open") {
|
||||
if (this.showingSubView) {
|
||||
this._syncContainerWithSubView();
|
||||
} else {
|
||||
this._syncContainerWithMainView();
|
||||
}
|
||||
}
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<property name="_transitioning">
|
||||
<getter>
|
||||
return this.__transitioning;
|
||||
@ -223,7 +206,10 @@
|
||||
let container = this._viewContainer;
|
||||
this._transitioning = true;
|
||||
|
||||
let onTransitionEnd = () => {
|
||||
let onTransitionEnd = (event) => {
|
||||
if (event.propertyName != "transform") {
|
||||
return;
|
||||
}
|
||||
container.removeEventListener("transitionend", onTransitionEnd);
|
||||
this._transitioning = false;
|
||||
};
|
||||
@ -296,7 +282,6 @@
|
||||
}
|
||||
break;
|
||||
case "popupshowing":
|
||||
this.setAttribute("panelopen", "true");
|
||||
// Bug 941196 - The panel can get taller when opening a subview. Disabling
|
||||
// autoPositioning means that the panel won't jump around if an opened
|
||||
// subview causes the panel to exceed the dimensions of the screen in the
|
||||
@ -312,9 +297,18 @@
|
||||
subtree: true
|
||||
});
|
||||
|
||||
break;
|
||||
case "popupshown":
|
||||
this._setMaxHeight();
|
||||
let onTransitionEnd = (event) => {
|
||||
if (event.propertyName != "transform") {
|
||||
return;
|
||||
}
|
||||
let panel = event.target;
|
||||
panel.removeEventListener("tranitionend", onTransitionEnd);
|
||||
// Needed in case the panel is closed before the transition ends.
|
||||
if (panel.state == "open") {
|
||||
this.setAttribute("panelopen", "true");
|
||||
}
|
||||
};
|
||||
this._panel.addEventListener("transitionend", onTransitionEnd);
|
||||
break;
|
||||
case "popuphidden":
|
||||
this.removeAttribute("panelopen");
|
||||
@ -338,22 +332,9 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_setMaxHeight">
|
||||
<body><![CDATA[
|
||||
if (!this._shouldSetHeight())
|
||||
return;
|
||||
|
||||
// Ignore the mutation that'll fire when we set the height of
|
||||
// the main view.
|
||||
this.ignoreMutations = true;
|
||||
this._mainView.style.height =
|
||||
this.getBoundingClientRect().height + "px";
|
||||
this.ignoreMutations = false;
|
||||
]]></body>
|
||||
</method>
|
||||
<method name="_adjustContainerHeight">
|
||||
<body><![CDATA[
|
||||
if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
|
||||
if (!this.showingSubView && !this._transitioning) {
|
||||
let height;
|
||||
if (this.showingSubViewAsMainView) {
|
||||
height = this._heightOfSubview(this._mainView);
|
||||
@ -371,7 +352,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.ignoreMutations && this.showingSubView) {
|
||||
if (this.showingSubView) {
|
||||
let newHeight = this._heightOfSubview(this._currentSubView, this._subViews);
|
||||
this._viewContainer.style.height = newHeight + "px";
|
||||
}
|
||||
|
@ -149,7 +149,8 @@ skip-if = os == "mac"
|
||||
[browser_1096763_seen_widgets_post_reset.js]
|
||||
[browser_1161838_inserted_new_default_buttons.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
[browser_check_tooltips_in_navbar.js]
|
||||
[browser_customizemode_contextmenu_menubuttonstate.js]
|
||||
[browser_no_mutationrecords_during_panel_opening.js]
|
||||
[browser_panel_toggle.js]
|
||||
[browser_switch_to_customize_mode.js]
|
||||
[browser_check_tooltips_in_navbar.js]
|
||||
|
@ -0,0 +1,88 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test that we don't get unexpected mutations during the opening of the
|
||||
* browser menu.
|
||||
*/
|
||||
|
||||
add_task(function* test_setup() {
|
||||
yield resetCustomization();
|
||||
yield PanelUI.show();
|
||||
let hiddenPromise = promisePanelHidden(window);
|
||||
PanelUI.hide();
|
||||
yield hiddenPromise;
|
||||
});
|
||||
|
||||
add_task(function* no_mutation_events_during_opening() {
|
||||
let panel = PanelUI.panel;
|
||||
yield PanelUI.ensureReady();
|
||||
|
||||
let failures = 0;
|
||||
let observer = new MutationObserver(function(mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.target.localName == "panel" &&
|
||||
mutation.type == "attributes" &&
|
||||
mutation.attributeName == "animate") {
|
||||
// This mutation is allowed because it triggers the CSS transition.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mutation.type == "attributes" &&
|
||||
mutation.attributeName == "panelopen") {
|
||||
// This mutation is allowed because it is set after the panel has
|
||||
// finished the transition.
|
||||
continue;
|
||||
}
|
||||
|
||||
let newValue = null;
|
||||
if (mutation.type == "attributes") {
|
||||
newValue = mutation.target.getAttribute(mutation.attributeName);
|
||||
} else if (mutation.type == "characterData") {
|
||||
newValue = mutation.target.textContent;
|
||||
}
|
||||
|
||||
if (AppConstants.isPlatformAndVersionAtMost("win", "6.1") &&
|
||||
mutation.target.className == "panel-arrowbox" &&
|
||||
mutation.attributeName == "style" &&
|
||||
newValue.startsWith("transform:")) {
|
||||
// Windows 7 and earlier has an alignment offset on the arrowbox.
|
||||
// This is allowed here as it is no longer used on newer platforms.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newValue == mutation.oldValue) {
|
||||
// Mutations records are observed even when the new and old value are
|
||||
// identical. This is unlikely to invalidate the panel, so ignore these.
|
||||
continue;
|
||||
}
|
||||
|
||||
let nodeIdentifier = `${mutation.target.localName}#${mutation.target.id}.${mutation.target.className};`;
|
||||
ok(false, `Observed: ${mutation.type}; ${nodeIdentifier} ${mutation.attributeName}; oldValue: ${mutation.oldValue}; newValue: ${newValue}`);
|
||||
failures++;
|
||||
}
|
||||
});
|
||||
observer.observe(panel, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
subtree: true,
|
||||
attributeOldValue: true,
|
||||
characterDataOldValue: true,
|
||||
});
|
||||
let shownPromise = promisePanelShown(window);
|
||||
PanelUI.show();
|
||||
yield shownPromise;
|
||||
observer.disconnect();
|
||||
|
||||
is(failures, 0, "There should be no unexpected mutation events during opening of the panel");
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
let hiddenPromise = promisePanelHidden(window);
|
||||
PanelUI.hide();
|
||||
yield hiddenPromise;
|
||||
});
|
@ -13,6 +13,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
|
||||
"@mozilla.org/content/style-sheet-service;1",
|
||||
"nsIStyleSheetService");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "colorUtils", () => {
|
||||
return require("devtools/shared/css-color").colorUtils;
|
||||
});
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
@ -95,17 +99,16 @@ class BasePopup {
|
||||
this.browserStyle = browserStyle;
|
||||
this.window = viewNode.ownerGlobal;
|
||||
|
||||
this.panel = this.viewNode;
|
||||
while (this.panel.localName != "panel") {
|
||||
this.panel = this.panel.parentNode;
|
||||
}
|
||||
|
||||
this.contentReady = new Promise(resolve => {
|
||||
this._resolveContentReady = resolve;
|
||||
});
|
||||
|
||||
this.viewNode.addEventListener(this.DESTROY_EVENT, this);
|
||||
|
||||
let doc = viewNode.ownerDocument;
|
||||
let arrowContent = doc.getAnonymousElementByAttribute(this.panel, "class", "panel-arrowcontent");
|
||||
this.borderColor = doc.defaultView.getComputedStyle(arrowContent).borderTopColor;
|
||||
|
||||
this.browser = null;
|
||||
this.browserReady = this.createBrowser(viewNode, popupURI);
|
||||
}
|
||||
@ -121,6 +124,9 @@ class BasePopup {
|
||||
this.viewNode.style.maxHeight = "";
|
||||
this.browser.remove();
|
||||
|
||||
this.panel.style.setProperty("--panel-arrowcontent-background", "");
|
||||
this.panel.style.setProperty("--panel-arrow-image-vertical", "");
|
||||
|
||||
this.browser = null;
|
||||
this.viewNode = null;
|
||||
});
|
||||
@ -136,6 +142,14 @@ class BasePopup {
|
||||
return false;
|
||||
}
|
||||
|
||||
get panel() {
|
||||
let panel = this.viewNode;
|
||||
while (panel.localName != "panel") {
|
||||
panel = panel.parentNode;
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case this.DESTROY_EVENT:
|
||||
@ -263,6 +277,21 @@ class BasePopup {
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = this.browser.contentDocument;
|
||||
if (!doc || !doc.documentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
let root = doc.documentElement;
|
||||
let body = doc.body;
|
||||
if (!body || doc.compatMode == "BackCompat") {
|
||||
// In quirks mode, the root element is used as the scroll frame, and the
|
||||
// body lies about its scroll geometry, and returns the values for the
|
||||
// root instead.
|
||||
body = root;
|
||||
}
|
||||
|
||||
|
||||
if (this.fixedWidth) {
|
||||
// If we're in a fixed-width area (namely a slide-in subview of the main
|
||||
// menu panel), we need to calculate the view height based on the
|
||||
@ -270,20 +299,6 @@ class BasePopup {
|
||||
// current width, rather than the complete preferred dimensions of the
|
||||
// content window.
|
||||
|
||||
let doc = this.browser.contentDocument;
|
||||
if (!doc || !doc.documentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
let root = doc.documentElement;
|
||||
let body = doc.body;
|
||||
if (!body || doc.compatMode == "BackCompat") {
|
||||
// In quirks mode, the root element is used as the scroll frame, and the
|
||||
// body lies about its scroll geometry, and returns the values for the
|
||||
// root instead.
|
||||
body = root;
|
||||
}
|
||||
|
||||
// Compensate for any offsets (margin, padding, ...) between the scroll
|
||||
// area of the body and the outer height of the document.
|
||||
let getHeight = elem => elem.getBoundingClientRect(elem).height;
|
||||
@ -307,6 +322,32 @@ class BasePopup {
|
||||
height = Math.max(height, this.viewHeight);
|
||||
this.viewNode.style.maxHeight = `${height}px`;
|
||||
} else {
|
||||
// Copy the background color of the document's body to the panel if it's
|
||||
// fully opaque.
|
||||
let panelBackground = "";
|
||||
let panelArrow = "";
|
||||
|
||||
let background = doc.defaultView.getComputedStyle(body).backgroundColor;
|
||||
if (background != "transparent") {
|
||||
let bgColor = colorUtils.colorToRGBA(background);
|
||||
if (bgColor.a == 1) {
|
||||
panelBackground = background;
|
||||
let borderColor = this.borderColor || background;
|
||||
|
||||
panelArrow = `url("data:image/svg+xml,${encodeURIComponent(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="10">
|
||||
<path d="M 0,10 L 10,0 20,10 z" fill="${borderColor}"/>
|
||||
<path d="M 1,10 L 10,1 19,10 z" fill="${background}"/>
|
||||
</svg>
|
||||
`)}")`;
|
||||
}
|
||||
}
|
||||
|
||||
this.panel.style.setProperty("--panel-arrowcontent-background", panelBackground);
|
||||
this.panel.style.setProperty("--panel-arrow-image-vertical", panelArrow);
|
||||
|
||||
|
||||
// Adjust the size of the browser based on its content's preferred size.
|
||||
let width, height;
|
||||
try {
|
||||
let w = {}, h = {};
|
||||
|
@ -20,6 +20,7 @@ support-files =
|
||||
[browser_ext_browserAction_context.js]
|
||||
[browser_ext_browserAction_disabled.js]
|
||||
[browser_ext_browserAction_pageAction_icon.js]
|
||||
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
||||
[browser_ext_browserAction_popup.js]
|
||||
[browser_ext_browserAction_popup_resize.js]
|
||||
[browser_ext_browserAction_simple.js]
|
||||
@ -43,6 +44,7 @@ support-files =
|
||||
[browser_ext_pageAction_popup_resize.js]
|
||||
[browser_ext_pageAction_simple.js]
|
||||
[browser_ext_popup_api_injection.js]
|
||||
[browser_ext_popup_background.js]
|
||||
[browser_ext_popup_corners.js]
|
||||
[browser_ext_runtime_openOptionsPage.js]
|
||||
[browser_ext_runtime_openOptionsPage_uninstall.js]
|
||||
|
@ -317,212 +317,3 @@ add_task(function* testDetailsObjects() {
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
// Test that an error is thrown when providing invalid icon sizes
|
||||
add_task(function* testInvalidIconSizes() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {},
|
||||
"page_action": {},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
let promises = [];
|
||||
for (let api of ["pageAction", "browserAction"]) {
|
||||
// helper function to run setIcon and check if it fails
|
||||
let assertSetIconThrows = function(detail, error, message) {
|
||||
detail.tabId = tabId;
|
||||
promises.push(
|
||||
browser[api].setIcon(detail).then(
|
||||
() => {
|
||||
browser.test.fail("Expected an error on invalid icon size.");
|
||||
browser.test.notifyFail("setIcon with invalid icon size");
|
||||
},
|
||||
error => {
|
||||
browser.test.succeed("setIcon with invalid icon size");
|
||||
}));
|
||||
};
|
||||
|
||||
let imageData = new ImageData(1, 1);
|
||||
|
||||
// test invalid icon size inputs
|
||||
for (let type of ["path", "imageData"]) {
|
||||
let img = type == "imageData" ? imageData : "test.png";
|
||||
|
||||
assertSetIconThrows({[type]: {"abcdef": img}});
|
||||
assertSetIconThrows({[type]: {"48px": img}});
|
||||
assertSetIconThrows({[type]: {"20.5": img}});
|
||||
assertSetIconThrows({[type]: {"5.0": img}});
|
||||
assertSetIconThrows({[type]: {"-300": img}});
|
||||
assertSetIconThrows({[type]: {"abc": img, "5": img}});
|
||||
}
|
||||
|
||||
assertSetIconThrows({imageData: {"abcdef": imageData}, path: {"5": "test.png"}});
|
||||
assertSetIconThrows({path: {"abcdef": "test.png"}, imageData: {"5": imageData}});
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
browser.test.notifyPass("setIcon with invalid icon size");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitFinish("setIcon with invalid icon size")]);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
// Test that default icon details in the manifest.json file are handled
|
||||
// correctly.
|
||||
add_task(function* testDefaultDetails() {
|
||||
// TODO: Test localized variants.
|
||||
let icons = [
|
||||
"foo/bar.png",
|
||||
"/foo/bar.png",
|
||||
{"19": "foo/bar.png"},
|
||||
{"38": "foo/bar.png"},
|
||||
{"19": "foo/bar.png", "38": "baz/quux.png"},
|
||||
];
|
||||
|
||||
let expectedURL = new RegExp(String.raw`^moz-extension://[^/]+/foo/bar\.png$`);
|
||||
|
||||
for (let icon of icons) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {"default_icon": icon},
|
||||
"page_action": {"default_icon": icon},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
browser.pageAction.show(tabId).then(() => {
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"foo/bar.png": imageBuffer,
|
||||
"baz/quux.png": imageBuffer,
|
||||
},
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("ready")]);
|
||||
|
||||
let browserActionId = makeWidgetId(extension.id) + "-browser-action";
|
||||
let pageActionId = makeWidgetId(extension.id) + "-page-action";
|
||||
|
||||
let browserActionButton = document.getElementById(browserActionId);
|
||||
let image = getListStyleImage(browserActionButton);
|
||||
|
||||
ok(expectedURL.test(image), `browser action image ${image} matches ${expectedURL}`);
|
||||
|
||||
let pageActionImage = document.getElementById(pageActionId);
|
||||
image = getListStyleImage(pageActionImage);
|
||||
|
||||
ok(expectedURL.test(image), `page action image ${image} matches ${expectedURL}`);
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
let node = document.getElementById(pageActionId);
|
||||
is(node, null, "pageAction image removed from document");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check that attempts to load a privileged URL as an icon image fail.
|
||||
add_task(function* testSecureURLsDenied() {
|
||||
// Test URLs passed to setIcon.
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {},
|
||||
"page_action": {},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
let urls = ["chrome://browser/content/browser.xul",
|
||||
"javascript:true"];
|
||||
|
||||
let promises = [];
|
||||
for (let url of urls) {
|
||||
for (let api of ["pageAction", "browserAction"]) {
|
||||
promises.push(
|
||||
browser[api].setIcon({tabId, path: url}).then(
|
||||
() => {
|
||||
browser.test.fail(`Load of '${url}' succeeded. Expected failure.`);
|
||||
browser.test.notifyFail("setIcon security tests");
|
||||
},
|
||||
error => {
|
||||
browser.test.succeed(`Load of '${url}' failed. Expected failure. ${error}`);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
browser.test.notifyPass("setIcon security tests");
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("setIcon security tests");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testSecureManifestURLsDenied() {
|
||||
// Test URLs included in the manifest.
|
||||
|
||||
let urls = ["chrome://browser/content/browser.xul",
|
||||
"javascript:true"];
|
||||
|
||||
let apis = ["browser_action", "page_action"];
|
||||
|
||||
for (let url of urls) {
|
||||
for (let api of apis) {
|
||||
info(`TEST ${api} icon url: ${url}`);
|
||||
|
||||
let matchURLForbidden = url => ({
|
||||
message: new RegExp(`match the format "strictRelativeUrl"`),
|
||||
});
|
||||
|
||||
let messages = [matchURLForbidden(url)];
|
||||
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
// Not necessary in browser-chrome tests, but monitorConsole gripes
|
||||
// if we don't call it.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SimpleTest.monitorConsole(resolve, messages);
|
||||
});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
[api]: {
|
||||
"default_icon": url,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
yield Assert.rejects(extension.startup(),
|
||||
null,
|
||||
"Manifest rejected");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,212 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
// Test that an error is thrown when providing invalid icon sizes
|
||||
add_task(function* testInvalidIconSizes() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {},
|
||||
"page_action": {},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
let promises = [];
|
||||
for (let api of ["pageAction", "browserAction"]) {
|
||||
// helper function to run setIcon and check if it fails
|
||||
let assertSetIconThrows = function(detail, error, message) {
|
||||
detail.tabId = tabId;
|
||||
promises.push(
|
||||
browser[api].setIcon(detail).then(
|
||||
() => {
|
||||
browser.test.fail("Expected an error on invalid icon size.");
|
||||
browser.test.notifyFail("setIcon with invalid icon size");
|
||||
},
|
||||
error => {
|
||||
browser.test.succeed("setIcon with invalid icon size");
|
||||
}));
|
||||
};
|
||||
|
||||
let imageData = new ImageData(1, 1);
|
||||
|
||||
// test invalid icon size inputs
|
||||
for (let type of ["path", "imageData"]) {
|
||||
let img = type == "imageData" ? imageData : "test.png";
|
||||
|
||||
assertSetIconThrows({[type]: {"abcdef": img}});
|
||||
assertSetIconThrows({[type]: {"48px": img}});
|
||||
assertSetIconThrows({[type]: {"20.5": img}});
|
||||
assertSetIconThrows({[type]: {"5.0": img}});
|
||||
assertSetIconThrows({[type]: {"-300": img}});
|
||||
assertSetIconThrows({[type]: {"abc": img, "5": img}});
|
||||
}
|
||||
|
||||
assertSetIconThrows({imageData: {"abcdef": imageData}, path: {"5": "test.png"}});
|
||||
assertSetIconThrows({path: {"abcdef": "test.png"}, imageData: {"5": imageData}});
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
browser.test.notifyPass("setIcon with invalid icon size");
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitFinish("setIcon with invalid icon size")]);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
// Test that default icon details in the manifest.json file are handled
|
||||
// correctly.
|
||||
add_task(function* testDefaultDetails() {
|
||||
// TODO: Test localized variants.
|
||||
let icons = [
|
||||
"foo/bar.png",
|
||||
"/foo/bar.png",
|
||||
{"19": "foo/bar.png"},
|
||||
{"38": "foo/bar.png"},
|
||||
{"19": "foo/bar.png", "38": "baz/quux.png"},
|
||||
];
|
||||
|
||||
let expectedURL = new RegExp(String.raw`^moz-extension://[^/]+/foo/bar\.png$`);
|
||||
|
||||
for (let icon of icons) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {"default_icon": icon},
|
||||
"page_action": {"default_icon": icon},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
browser.pageAction.show(tabId).then(() => {
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"foo/bar.png": imageBuffer,
|
||||
"baz/quux.png": imageBuffer,
|
||||
},
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("ready")]);
|
||||
|
||||
let browserActionId = makeWidgetId(extension.id) + "-browser-action";
|
||||
let pageActionId = makeWidgetId(extension.id) + "-page-action";
|
||||
|
||||
let browserActionButton = document.getElementById(browserActionId);
|
||||
let image = getListStyleImage(browserActionButton);
|
||||
|
||||
ok(expectedURL.test(image), `browser action image ${image} matches ${expectedURL}`);
|
||||
|
||||
let pageActionImage = document.getElementById(pageActionId);
|
||||
image = getListStyleImage(pageActionImage);
|
||||
|
||||
ok(expectedURL.test(image), `page action image ${image} matches ${expectedURL}`);
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
let node = document.getElementById(pageActionId);
|
||||
is(node, null, "pageAction image removed from document");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check that attempts to load a privileged URL as an icon image fail.
|
||||
add_task(function* testSecureURLsDenied() {
|
||||
// Test URLs passed to setIcon.
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {},
|
||||
"page_action": {},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
let tabId = tabs[0].id;
|
||||
|
||||
let urls = ["chrome://browser/content/browser.xul",
|
||||
"javascript:true"];
|
||||
|
||||
let promises = [];
|
||||
for (let url of urls) {
|
||||
for (let api of ["pageAction", "browserAction"]) {
|
||||
promises.push(
|
||||
browser[api].setIcon({tabId, path: url}).then(
|
||||
() => {
|
||||
browser.test.fail(`Load of '${url}' succeeded. Expected failure.`);
|
||||
browser.test.notifyFail("setIcon security tests");
|
||||
},
|
||||
error => {
|
||||
browser.test.succeed(`Load of '${url}' failed. Expected failure. ${error}`);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
browser.test.notifyPass("setIcon security tests");
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("setIcon security tests");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testSecureManifestURLsDenied() {
|
||||
// Test URLs included in the manifest.
|
||||
|
||||
let urls = ["chrome://browser/content/browser.xul",
|
||||
"javascript:true"];
|
||||
|
||||
let apis = ["browser_action", "page_action"];
|
||||
|
||||
for (let url of urls) {
|
||||
for (let api of apis) {
|
||||
info(`TEST ${api} icon url: ${url}`);
|
||||
|
||||
let matchURLForbidden = url => ({
|
||||
message: new RegExp(`match the format "strictRelativeUrl"`),
|
||||
});
|
||||
|
||||
let messages = [matchURLForbidden(url)];
|
||||
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
// Not necessary in browser-chrome tests, but monitorConsole gripes
|
||||
// if we don't call it.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SimpleTest.monitorConsole(resolve, messages);
|
||||
});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
[api]: {
|
||||
"default_icon": url,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
yield Assert.rejects(extension.startup(),
|
||||
null,
|
||||
"Manifest rejected");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
}
|
||||
}
|
||||
});
|
@ -175,17 +175,23 @@ function* testPopupSize(standardsMode, browserWin = window, arrowSide = "top") {
|
||||
let checkPanelPosition = () => {
|
||||
is(panel.getAttribute("side"), arrowSide, "Panel arrow is positioned as expected");
|
||||
|
||||
function isGreaterThanOrWithinPixelRoundingError(a, b, message) {
|
||||
let result = a + 1 >= b;
|
||||
ok(result, `${a} should be greater than or within one pixel of ${b}: ${message}`);
|
||||
}
|
||||
|
||||
let panelRect = panel.getBoundingClientRect();
|
||||
if (arrowSide == "top") {
|
||||
ok(panelRect.top, origPanelRect.top, "Panel has not moved downwards");
|
||||
ok(panelRect.bottom >= origPanelRect.bottom, `Panel has not shrunk from original size (${panelRect.bottom} >= ${origPanelRect.bottom})`);
|
||||
isGreaterThanOrWithinPixelRoundingError(panelRect.top, origPanelRect.top, "Panel has not moved downwards");
|
||||
isGreaterThanOrWithinPixelRoundingError(panelRect.bottom, origPanelRect.bottom, "Panel has not shrunk from original size");
|
||||
|
||||
let screenBottom = browserWin.screen.availTop + win.screen.availHeight;
|
||||
let panelBottom = browserWin.mozInnerScreenY + panelRect.bottom;
|
||||
ok(panelBottom <= screenBottom, `Bottom of popup should be on-screen. (${panelBottom} <= ${screenBottom})`);
|
||||
} else {
|
||||
ok(panelRect.bottom, origPanelRect.bottom, "Panel has not moved upwards");
|
||||
ok(panelRect.top <= origPanelRect.top, `Panel has not shrunk from original size (${panelRect.top} <= ${origPanelRect.top})`);
|
||||
isGreaterThanOrWithinPixelRoundingError(panelRect.bottom, origPanelRect.bottom, "Panel has not moved upwards");
|
||||
// The arguments here are reversed compared to the above calls due to the coordinate system.
|
||||
isGreaterThanOrWithinPixelRoundingError(origPanelRect.top, panelRect.top, "Panel has not shrunk from original size");
|
||||
|
||||
let panelTop = browserWin.mozInnerScreenY + panelRect.top;
|
||||
ok(panelTop >= browserWin.screen.availTop, `Top of popup should be on-screen. (${panelTop} >= ${browserWin.screen.availTop})`);
|
||||
|
@ -0,0 +1,147 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
function* awaitPanel(extension, win = window) {
|
||||
let {target} = yield BrowserTestUtils.waitForEvent(win.document, "load", true, (event) => {
|
||||
return event.target.location && event.target.location.href.endsWith("popup.html");
|
||||
});
|
||||
|
||||
return target.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
}
|
||||
|
||||
function* awaitResize(browser) {
|
||||
// Debouncing code makes this a bit racy.
|
||||
// Try to skip the first, early resize, and catch the resize event we're
|
||||
// looking for, but don't wait longer than a few seconds.
|
||||
|
||||
return Promise.race([
|
||||
BrowserTestUtils.waitForEvent(browser, "WebExtPopupResized")
|
||||
.then(() => BrowserTestUtils.waitForEvent(browser, "WebExtPopupResized")),
|
||||
new Promise(resolve => setTimeout(resolve, 5000)),
|
||||
]);
|
||||
}
|
||||
|
||||
add_task(function* testPopupBackground() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background() {
|
||||
browser.tabs.query({active: true, currentWindow: true}, tabs => {
|
||||
browser.pageAction.show(tabs[0].id);
|
||||
});
|
||||
},
|
||||
|
||||
manifest: {
|
||||
"browser_action": {
|
||||
"default_popup": "popup.html",
|
||||
"browser_style": false,
|
||||
},
|
||||
|
||||
"page_action": {
|
||||
"default_popup": "popup.html",
|
||||
"browser_style": false,
|
||||
},
|
||||
},
|
||||
|
||||
files: {
|
||||
"popup.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body style="width: 100px; height: 100px; background-color: green;">
|
||||
</body>
|
||||
</html>`,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
function* testPanel(browser, standAlone) {
|
||||
let panel = getPanelForNode(browser);
|
||||
let arrowContent = document.getAnonymousElementByAttribute(panel, "class", "panel-arrowcontent");
|
||||
let arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
|
||||
|
||||
let borderColor = getComputedStyle(arrowContent).borderTopColor;
|
||||
|
||||
let checkArrow = (background = null) => {
|
||||
let image = getComputedStyle(arrow).listStyleImage;
|
||||
|
||||
if (background == null || !standAlone) {
|
||||
ok(image.startsWith('url("chrome://'), `We should have the built-in background image (got: ${image})`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "mac") {
|
||||
// Panels have a drop shadow rather than a border on OS-X, so we extend
|
||||
// the background color through the border area instead.
|
||||
borderColor = background;
|
||||
}
|
||||
|
||||
image = decodeURIComponent(image);
|
||||
let borderIndex = image.indexOf(`fill="${borderColor}"`);
|
||||
let backgroundIndex = image.lastIndexOf(`fill="${background}"`);
|
||||
|
||||
ok(borderIndex >= 0, `Have border fill (index=${borderIndex})`);
|
||||
ok(backgroundIndex >= 0, `Have background fill (index=${backgroundIndex})`);
|
||||
is(getComputedStyle(arrowContent).backgroundColor, background, "Arrow content should have correct background");
|
||||
isnot(borderIndex, backgroundIndex, "Border and background fills are separate elements");
|
||||
};
|
||||
|
||||
let win = browser.contentWindow;
|
||||
let body = win.document.body;
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
info("Test that initial background color is applied");
|
||||
|
||||
checkArrow(win.getComputedStyle(body).backgroundColor);
|
||||
|
||||
info("Test that dynamically-changed background color is applied");
|
||||
|
||||
body.style.backgroundColor = "black";
|
||||
yield awaitResize(browser);
|
||||
|
||||
checkArrow(win.getComputedStyle(body).backgroundColor);
|
||||
|
||||
info("Test that non-opaque background color results in default styling");
|
||||
|
||||
body.style.backgroundColor = "rgba(1, 2, 3, .9)";
|
||||
yield awaitResize(browser);
|
||||
|
||||
checkArrow(null);
|
||||
}
|
||||
|
||||
{
|
||||
info("Test stand-alone browserAction popup");
|
||||
|
||||
clickBrowserAction(extension);
|
||||
let browser = yield awaitPanel(extension);
|
||||
yield testPanel(browser, true);
|
||||
yield closeBrowserAction(extension);
|
||||
}
|
||||
|
||||
{
|
||||
info("Test menu panel browserAction popup");
|
||||
|
||||
let widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||
|
||||
clickBrowserAction(extension);
|
||||
let browser = yield awaitPanel(extension);
|
||||
yield testPanel(browser, false);
|
||||
yield closeBrowserAction(extension);
|
||||
}
|
||||
|
||||
{
|
||||
info("Test pageAction popup");
|
||||
|
||||
clickPageAction(extension);
|
||||
let browser = yield awaitPanel(extension);
|
||||
yield testPanel(browser, true);
|
||||
yield closePageAction(extension);
|
||||
}
|
||||
|
||||
yield extension.unload();
|
||||
});
|
@ -1,3 +1,5 @@
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
|
@ -12,41 +12,21 @@ const TELEMETRY_RESULT_ENUM = {
|
||||
RESTORED_DEFAULT: 0,
|
||||
KEPT_CURRENT: 1,
|
||||
CHANGED_ENGINE: 2,
|
||||
CLOSED_PAGE: 3
|
||||
CLOSED_PAGE: 3,
|
||||
OPENED_SETTINGS: 4
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
let list = document.getElementById("defaultEngine");
|
||||
let originalDefault = Services.search.originalDefaultEngine.name;
|
||||
Services.search.getDefaultEngines().forEach(e => {
|
||||
let opt = document.createElement("option");
|
||||
opt.setAttribute("value", e.name);
|
||||
opt.engine = e;
|
||||
opt.textContent = e.name;
|
||||
if (e.iconURI)
|
||||
opt.style.backgroundImage = 'url("' + e.iconURI.spec + '")';
|
||||
if (e.name == originalDefault)
|
||||
opt.setAttribute("selected", "true");
|
||||
list.appendChild(opt);
|
||||
});
|
||||
|
||||
let updateIcon = () => {
|
||||
list.style.setProperty("--engine-icon-url",
|
||||
list.selectedOptions[0].style.backgroundImage);
|
||||
};
|
||||
|
||||
list.addEventListener("change", updateIcon);
|
||||
// When selecting using the keyboard, the 'change' event is only fired after
|
||||
// the user presses <enter> or moves the focus elsewhere.
|
||||
// keypress/keyup fire too late and cause flicker when updating the icon.
|
||||
// keydown fires too early and the selected option isn't changed yet.
|
||||
list.addEventListener("keydown", () => {
|
||||
Services.tm.mainThread.dispatch(updateIcon, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
});
|
||||
updateIcon();
|
||||
let defaultEngine = document.getElementById("defaultEngine");
|
||||
let originalDefault = Services.search.originalDefaultEngine;
|
||||
defaultEngine.textContent = originalDefault.name;
|
||||
defaultEngine.style.backgroundImage =
|
||||
'url("' + originalDefault.iconURI.spec + '")';
|
||||
|
||||
document.getElementById("searchResetChangeEngine").focus();
|
||||
window.addEventListener("unload", recordPageClosed);
|
||||
document.getElementById("linkSettingsPage")
|
||||
.addEventListener("click", openingSettings);
|
||||
};
|
||||
|
||||
function doSearch() {
|
||||
@ -77,6 +57,11 @@ function doSearch() {
|
||||
win.openUILinkIn(submission.uri.spec, "current", false, submission.postData);
|
||||
}
|
||||
|
||||
function openingSettings() {
|
||||
record(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
|
||||
window.removeEventListener("unload", recordPageClosed);
|
||||
}
|
||||
|
||||
function record(result) {
|
||||
Services.telemetry.getHistogramById("SEARCH_RESET_RESULT").add(result);
|
||||
}
|
||||
@ -90,18 +75,12 @@ function keepCurrentEngine() {
|
||||
}
|
||||
|
||||
function changeSearchEngine() {
|
||||
let list = document.getElementById("defaultEngine");
|
||||
let engine = list.selectedOptions[0].engine;
|
||||
let engine = Services.search.originalDefaultEngine;
|
||||
if (engine.hidden)
|
||||
engine.hidden = false;
|
||||
Services.search.currentEngine = engine;
|
||||
|
||||
// Record if we restored the original default or changed to another engine.
|
||||
let originalDefault = Services.search.originalDefaultEngine.name;
|
||||
let code = TELEMETRY_RESULT_ENUM.CHANGED_ENGINE;
|
||||
if (Services.search.originalDefaultEngine.name == engine.name)
|
||||
code = TELEMETRY_RESULT_ENUM.RESTORED_DEFAULT;
|
||||
record(code);
|
||||
record(TELEMETRY_RESULT_ENUM.RESTORED_DEFAULT);
|
||||
|
||||
doSearch();
|
||||
}
|
||||
|
@ -39,9 +39,7 @@
|
||||
|
||||
<div class="description">
|
||||
<p>&searchreset.pageInfo1;</p>
|
||||
<p>&searchreset.selector.label;
|
||||
<select id="defaultEngine"></select>
|
||||
</p>
|
||||
<p>&searchreset.selector.label;<span id="defaultEngine"/></p>
|
||||
|
||||
<p>&searchreset.beforelink.pageInfo2;<a id="linkSettingsPage" href="about:preferences#search">&searchreset.link.pageInfo2;</a>&searchreset.afterlink.pageInfo2;</p>
|
||||
</div>
|
||||
|
@ -6,7 +6,8 @@ const TELEMETRY_RESULT_ENUM = {
|
||||
RESTORED_DEFAULT: 0,
|
||||
KEPT_CURRENT: 1,
|
||||
CHANGED_ENGINE: 2,
|
||||
CLOSED_PAGE: 3
|
||||
CLOSED_PAGE: 3,
|
||||
OPENED_SETTINGS: 4
|
||||
};
|
||||
|
||||
const kSearchStr = "a search";
|
||||
@ -77,12 +78,15 @@ var gTests = [
|
||||
run: function* () {
|
||||
let currentEngine = Services.search.currentEngine;
|
||||
let originalEngine = Services.search.originalDefaultEngine;
|
||||
let doc = gBrowser.contentDocument;
|
||||
let defaultEngineSpan = doc.getElementById("defaultEngine");
|
||||
is(defaultEngineSpan.textContent, originalEngine.name,
|
||||
"the name of the original default engine is displayed");
|
||||
|
||||
let expectedURL = originalEngine.
|
||||
getSubmission(kSearchStr, null, kSearchPurpose).
|
||||
uri.spec;
|
||||
|
||||
let loadPromise = promiseStoppedLoad(expectedURL);
|
||||
let doc = gBrowser.contentDocument;
|
||||
let button = doc.getElementById("searchResetChangeEngine");
|
||||
is(doc.activeElement, button,
|
||||
"the 'Change Search Engine' button is focused");
|
||||
@ -98,41 +102,15 @@ var gTests = [
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Test the engine selector drop down.",
|
||||
desc: "Click the settings link.",
|
||||
run: function* () {
|
||||
let originalEngineName = Services.search.originalDefaultEngine.name;
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
let list = doc.getElementById("defaultEngine");
|
||||
is(list.value, originalEngineName,
|
||||
"the default selection of the dropdown is the original default engine");
|
||||
|
||||
let defaultEngines = Services.search.getDefaultEngines();
|
||||
is(list.childNodes.length, defaultEngines.length,
|
||||
"the dropdown has the correct count of engines");
|
||||
|
||||
// Select an engine that isn't the original default one.
|
||||
let engine;
|
||||
for (let i = 0; i < defaultEngines.length; ++i) {
|
||||
if (defaultEngines[i].name != originalEngineName) {
|
||||
engine = defaultEngines[i];
|
||||
engine.hidden = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list.value = engine.name;
|
||||
|
||||
let expectedURL = engine.getSubmission(kSearchStr, null, kSearchPurpose)
|
||||
.uri.spec;
|
||||
let loadPromise = promiseStoppedLoad(expectedURL);
|
||||
doc.getElementById("searchResetChangeEngine").click();
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:preferences#search")
|
||||
gBrowser.contentDocument.getElementById("linkSettingsPage").click();
|
||||
yield loadPromise;
|
||||
|
||||
ok(!engine.hidden, "the selected engine has been unhidden");
|
||||
is(engine, Services.search.currentEngine,
|
||||
"the current engine is what was selected in the drop down");
|
||||
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.CHANGED_ENGINE);
|
||||
checkTelemetryRecords(TELEMETRY_RESULT_ENUM.OPENED_SETTINGS);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -32,11 +32,9 @@
|
||||
|
||||
--toolbarbutton-checkedhover-backgroundcolor: rgba(200,200,200,.5);
|
||||
|
||||
--identity-box-verified-background-color: #fff;
|
||||
|
||||
--panel-separator-color: ThreeDShadow;
|
||||
|
||||
--urlbar-separator-color: hsla(0,0%,16%,.2);
|
||||
--urlbar-separator-color: ThreeDShadow;
|
||||
}
|
||||
|
||||
#menubar-items {
|
||||
@ -817,6 +815,15 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
toolbaritem[cui-areatype="menu-panel"] > :-moz-any(@nestedButtons@) > .toolbarbutton-icon {
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
opacity: 0.7 !important; /* !important overrides .toolbarbutton-1[disabled=true] rule */
|
||||
}
|
||||
|
||||
/* Fullscreen window controls */
|
||||
#window-controls {
|
||||
-moz-box-align: start;
|
||||
@ -948,7 +955,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
}
|
||||
|
||||
#urlbar-search-footer {
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
background-color: hsla(210,4%,10%,.07);
|
||||
}
|
||||
|
||||
@ -1010,10 +1017,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
border-bottom-right-radius: 1.5px;
|
||||
}
|
||||
|
||||
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
|
||||
background-color: var(--identity-box-verified-background-color);
|
||||
}
|
||||
|
||||
#identity-box:-moz-focusring {
|
||||
outline: 1px dotted #000;
|
||||
outline-offset: -3px;
|
||||
@ -1956,14 +1959,9 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
|
||||
}
|
||||
|
||||
.webextension-popup-browser {
|
||||
margin-right: -1px;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
#PanelUI-popup .webextension-popup-browser {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menuitem-iconic[usercontextid] > .menu-iconic-left > .menu-iconic-icon {
|
||||
visibility: visible;
|
||||
}
|
||||
|
@ -93,14 +93,6 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
|
||||
margin-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.PanelUI-subView toolbarseparator,
|
||||
.PanelUI-subView menuseparator,
|
||||
.cui-widget-panelview menuseparator,
|
||||
#PanelUI-footer-inner > toolbarseparator,
|
||||
#PanelUI-footer-fxa > toolbarseparator {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
.subviewradio > .radio-label-box {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 38 KiB |
@ -744,6 +744,13 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
%include ../shared/toolbarbuttons.inc.css
|
||||
%include ../shared/menupanel.inc.css
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
@media not all and (min-resolution: 1.1dppx) {
|
||||
#back-button:hover:active:not([disabled="true"]) {
|
||||
-moz-image-region: rect(18px, 36px, 36px, 18px);
|
||||
@ -1656,7 +1663,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
||||
}
|
||||
|
||||
#urlbar-search-footer {
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
background-color: hsla(210,4%,10%,.07);
|
||||
}
|
||||
|
||||
@ -3468,10 +3475,5 @@ menulist.translate-infobar-element > .menulist-dropmarker {
|
||||
}
|
||||
|
||||
.webextension-popup-browser {
|
||||
margin-right: -1px;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
#PanelUI-popup .webextension-popup-browser {
|
||||
margin: 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 84 KiB |
@ -144,7 +144,7 @@
|
||||
.panel-subviews {
|
||||
padding: 4px;
|
||||
background-clip: padding-box;
|
||||
border-left: 1px solid hsla(210,4%,10%,.3);
|
||||
border-left: 1px solid var(--panel-separator-color);
|
||||
box-shadow: 0 3px 5px hsla(210,4%,10%,.1),
|
||||
0 0 7px hsla(210,4%,10%,.1);
|
||||
margin-inline-start: var(--panel-ui-exit-subview-gutter-width);
|
||||
@ -186,7 +186,7 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan
|
||||
|
||||
.panel-subview-header {
|
||||
margin: -4px -4px 4px;
|
||||
box-shadow: 0 -1px 0 hsla(210,4%,10%,.05) inset;
|
||||
border-bottom: 1px solid var(--panel-separator-color);
|
||||
color: GrayText;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
@ -577,7 +577,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
||||
#PanelUI-footer-inner,
|
||||
#PanelUI-footer-fxa:not([hidden]) {
|
||||
display: flex;
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
}
|
||||
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-inner,
|
||||
@ -588,7 +588,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
||||
#PanelUI-footer-inner > toolbarseparator,
|
||||
#PanelUI-footer-fxa > toolbarseparator {
|
||||
border: 0;
|
||||
border-left: 1px solid hsla(210,4%,10%,.14);
|
||||
border-left: 1px solid var(--panel-separator-color);
|
||||
margin: 7px 0 7px;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
@ -617,7 +617,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
@ -1099,27 +1099,25 @@ menuitem.subviewbutton@menuStateActive@,
|
||||
.widget-overflow-list .toolbarbutton-1@buttonStateActive@,
|
||||
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton@buttonStateActive@ {
|
||||
background-color: hsla(210,4%,10%,.12);
|
||||
border-color: hsla(210,4%,10%,.14);
|
||||
border-color: var(--panel-separator-color);
|
||||
box-shadow: 0 1px 0 hsla(210,4%,10%,.03) inset;
|
||||
}
|
||||
|
||||
.subviewbutton.panel-subview-footer {
|
||||
margin: 4px -4px -4px;
|
||||
background-color: hsla(210,4%,10%,.07);
|
||||
border-top: 1px solid hsla(210,4%,10%,.12);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
menuitem.panel-subview-footer@menuStateHover@,
|
||||
.subviewbutton.panel-subview-footer@buttonStateHover@ {
|
||||
background-color: hsla(210,4%,10%,.15);
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
}
|
||||
|
||||
menuitem.panel-subview-footer@menuStateActive@,
|
||||
.subviewbutton.panel-subview-footer@buttonStateActive@ {
|
||||
background-color: hsla(210,4%,10%,.19);
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
|
||||
}
|
||||
|
||||
@ -1522,23 +1520,21 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
|
||||
-moz-box-align: center;
|
||||
padding: 1px;
|
||||
margin: 0 0 2px;
|
||||
background-color: hsla(210,4%,10%,0);
|
||||
background-color: transparent;
|
||||
border-radius: 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: hsla(210,4%,10%,0);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.subviewradio@buttonStateHover@ {
|
||||
background-color: hsla(210,4%,10%,.08);
|
||||
border-color: hsla(210,4%,10%,.11);
|
||||
border-color: var(--panel-separator-color);
|
||||
}
|
||||
|
||||
.subviewradio[selected],
|
||||
.subviewradio[selected]:hover,
|
||||
.subviewradio@buttonStateActive@ {
|
||||
background-color: hsla(210,4%,10%,.12);
|
||||
border-color: hsla(210,4%,10%,.14);
|
||||
border-color: var(--panel-separator-color);
|
||||
box-shadow: 0 1px 0 hsla(210,4%,10%,.03) inset;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,6 @@
|
||||
|
||||
:root[devtoolstheme="dark"] #identity-box {
|
||||
--identity-box-chrome-color: #46afe3;
|
||||
--identity-box-verified-background-color: transparent;
|
||||
}
|
||||
|
||||
:root[devtoolstheme="light"] {
|
||||
|
@ -38,15 +38,15 @@
|
||||
|
||||
.downloadsPanelFooter {
|
||||
background-color: hsla(210,4%,10%,.07);
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
}
|
||||
|
||||
.downloadsPanelFooter > toolbarseparator {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
min-width: 0;
|
||||
border-left: 1px solid hsla(210,4%,10%,.14);
|
||||
-moz-appearance: none !important;
|
||||
border-left: 1px solid var(--panel-separator-color);
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
.downloadsPanelFooterButton {
|
||||
|
@ -19,9 +19,9 @@
|
||||
font-size: .9em;
|
||||
padding: 3px 5px;
|
||||
overflow: hidden;
|
||||
/* The latter two properties have a transition to handle the delayed hiding of
|
||||
/* The padding-left and padding-right transitions handle the delayed hiding of
|
||||
the forward button when hovered. */
|
||||
transition: background-color 150ms ease, padding-left, padding-right;
|
||||
transition: padding-left, padding-right;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
|
||||
@ -62,6 +62,9 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url(chrome://browser/skin/identity-icon.svg#normal);
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
#identity-box:hover > #identity-icon:not(.no-hover),
|
||||
@ -80,10 +83,11 @@
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon {
|
||||
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon {
|
||||
opacity: 0.3;
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
#urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
|
||||
@ -91,7 +95,7 @@
|
||||
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 1;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
/* SHARING ICON */
|
||||
@ -145,11 +149,15 @@
|
||||
margin-inline-start: 2px;
|
||||
margin-inline-end: 0;
|
||||
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
|
||||
opacity: 1;
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
#tracking-protection-icon[state="loaded-tracking-content"] {
|
||||
list-style-image: url(chrome://browser/skin/tracking-protection-disabled-16.svg);
|
||||
filter: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#tracking-protection-icon[animate] {
|
||||
|
@ -8,7 +8,6 @@
|
||||
<style>
|
||||
path {
|
||||
fill-rule: evenodd;
|
||||
fill: #999999;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
@ -17,5 +17,5 @@
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="#808080" />
|
||||
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -1,18 +1,11 @@
|
||||
/* Menu panel and palette styles */
|
||||
|
||||
:root {
|
||||
--menupanel-list-style-image: url(chrome://browser/skin/menuPanel.png);
|
||||
--menupanel-list-style-image-2x: url(chrome://browser/skin/menuPanel@2x.png);
|
||||
--menupanel-small-list-style-image: url(chrome://browser/skin/menuPanel-small.png);
|
||||
--menupanel-small-list-style-image-2x: url(chrome://browser/skin/menuPanel-small@2x.png);
|
||||
}
|
||||
|
||||
@media not all and (min-resolution: 1.1dppx) {
|
||||
|
||||
toolbaritem[sdkstylewidget="true"] > toolbarbutton,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) {
|
||||
list-style-image: var(--menupanel-list-style-image);
|
||||
list-style-image: url(chrome://browser/skin/menuPanel.png);
|
||||
}
|
||||
|
||||
#home-button[cui-areatype="menu-panel"],
|
||||
@ -25,19 +18,11 @@
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 192px, 64px, 160px);
|
||||
}
|
||||
|
||||
#history-panelmenu[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #history-panelmenu {
|
||||
-moz-image-region: rect(0px, 224px, 32px, 192px);
|
||||
}
|
||||
|
||||
#history-panelmenu[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 224px, 64px, 192px);
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #downloads-button {
|
||||
-moz-image-region: rect(0px, 256px, 32px, 224px);
|
||||
@ -63,28 +48,16 @@
|
||||
-moz-image-region: rect(0px, 1024px, 32px, 992px);
|
||||
}
|
||||
|
||||
#sync-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 1024px, 64px, 992px);
|
||||
}
|
||||
|
||||
#containers-panelmenu[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #containers-panelmenu {
|
||||
-moz-image-region: rect(0px, 1056px, 32px, 1024px);
|
||||
}
|
||||
|
||||
#containers-panelmenu[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 1056px, 64px, 1024px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #feed-button {
|
||||
-moz-image-region: rect(0px, 416px, 32px, 384px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 416px, 64px, 384px);
|
||||
}
|
||||
|
||||
#social-share-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #social-share-button {
|
||||
-moz-image-region: rect(0px, 448px, 32px, 416px);
|
||||
@ -95,10 +68,6 @@
|
||||
-moz-image-region: rect(0px, 480px, 32px, 448px);
|
||||
}
|
||||
|
||||
#characterencoding-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 480px, 64px, 448px);
|
||||
}
|
||||
|
||||
#new-window-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #new-window-button {
|
||||
-moz-image-region: rect(0px, 512px, 32px, 480px);
|
||||
@ -139,10 +108,6 @@
|
||||
-moz-image-region: rect(0px, 736px, 32px, 704px);
|
||||
}
|
||||
|
||||
#developer-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 736px, 64px, 704px);
|
||||
}
|
||||
|
||||
#preferences-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #preferences-button {
|
||||
-moz-image-region: rect(0px, 768px, 32px, 736px);
|
||||
@ -158,19 +123,11 @@
|
||||
-moz-image-region: rect(0, 864px, 32px, 832px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 864px, 64px, 832px);
|
||||
}
|
||||
|
||||
#panic-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #panic-button {
|
||||
-moz-image-region: rect(0, 896px, 32px, 864px);
|
||||
}
|
||||
|
||||
#panic-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 896px, 64px, 864px);
|
||||
}
|
||||
|
||||
#webide-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #webide-button {
|
||||
-moz-image-region: rect(0px, 960px, 32px, 928px);
|
||||
@ -186,7 +143,7 @@
|
||||
#zoom-controls@inAnyPanel@ > toolbarbutton,
|
||||
toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton,
|
||||
toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton {
|
||||
list-style-image: var(--menupanel-small-list-style-image);
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small.png);
|
||||
}
|
||||
|
||||
#edit-controls@inAnyPanel@ > #cut-button,
|
||||
@ -225,7 +182,7 @@
|
||||
toolbaritem[sdkstylewidget="true"] > toolbarbutton,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) {
|
||||
list-style-image: var(--menupanel-list-style-image-2x);
|
||||
list-style-image: url(chrome://browser/skin/menuPanel@2x.png);
|
||||
}
|
||||
|
||||
#home-button[cui-areatype="menu-panel"],
|
||||
@ -238,19 +195,11 @@
|
||||
-moz-image-region: rect(0px, 384px, 64px, 320px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 384px, 128px, 320px);
|
||||
}
|
||||
|
||||
#history-panelmenu[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #history-panelmenu {
|
||||
-moz-image-region: rect(0px, 448px, 64px, 384px);
|
||||
}
|
||||
|
||||
#history-panelmenu[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 448px, 128px, 384px);
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #downloads-button {
|
||||
-moz-image-region: rect(0px, 512px, 64px, 448px);
|
||||
@ -276,28 +225,16 @@
|
||||
-moz-image-region: rect(0px, 2048px, 64px, 1984px);
|
||||
}
|
||||
|
||||
#sync-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 2048px, 128px, 1984px);
|
||||
}
|
||||
|
||||
#containers-panelmenu[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #containers-panelmenu {
|
||||
-moz-image-region: rect(0px, 2112px, 64px, 2048px);
|
||||
}
|
||||
|
||||
#containers-panelmenu[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 2112px, 128px, 2048px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #feed-button {
|
||||
-moz-image-region: rect(0px, 832px, 64px, 768px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 832px, 128px, 768px);
|
||||
}
|
||||
|
||||
#social-share-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #social-share-button {
|
||||
-moz-image-region: rect(0px, 896px, 64px, 832px);
|
||||
@ -308,10 +245,6 @@
|
||||
-moz-image-region: rect(0, 960px, 64px, 896px);
|
||||
}
|
||||
|
||||
#characterencoding-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 960px, 128px, 896px);
|
||||
}
|
||||
|
||||
#new-window-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #new-window-button {
|
||||
-moz-image-region: rect(0px, 1024px, 64px, 960px);
|
||||
@ -357,10 +290,6 @@
|
||||
-moz-image-region: rect(0px, 1472px, 64px, 1408px);
|
||||
}
|
||||
|
||||
#developer-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 1472px, 128px, 1408px);
|
||||
}
|
||||
|
||||
#preferences-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #preferences-button {
|
||||
-moz-image-region: rect(0px, 1536px, 64px, 1472px);
|
||||
@ -376,19 +305,11 @@
|
||||
-moz-image-region: rect(0px, 1728px, 64px, 1664px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 1728px, 128px, 1664px);
|
||||
}
|
||||
|
||||
#panic-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #panic-button {
|
||||
-moz-image-region: rect(0, 1792px, 64px, 1728px);
|
||||
}
|
||||
|
||||
#panic-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 1792px, 128px, 1728px);
|
||||
}
|
||||
|
||||
toolbaritem[sdkstylewidget="true"] > toolbarbutton {
|
||||
-moz-image-region: rect(0, 1664px, 64px, 1600px);
|
||||
}
|
||||
@ -398,7 +319,7 @@
|
||||
#zoom-controls@inAnyPanel@ > toolbarbutton,
|
||||
toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton,
|
||||
toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton {
|
||||
list-style-image: var(--menupanel-small-list-style-image-2x);
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
|
||||
}
|
||||
|
||||
/* Wide items like the Cut/Copy/Paste and Zoom controls are special in that their icons
|
||||
|
@ -41,12 +41,6 @@
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
#notification-popup-box > .notification-anchor-icon:hover {
|
||||
fill: #606060;
|
||||
}
|
||||
|
||||
/* INDIVIDUAL NOTIFICATIONS */
|
||||
|
||||
.camera-icon,
|
||||
.geo-icon,
|
||||
.indexedDB-icon,
|
||||
@ -67,9 +61,16 @@
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"],
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: #999;
|
||||
fill: currentColor;
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:hover {
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
/* INDIVIDUAL NOTIFICATIONS */
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"],
|
||||
.desktop-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);
|
||||
@ -252,7 +253,8 @@
|
||||
|
||||
.plugin-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#plugin-blocked);
|
||||
fill: #d92215 !important; /* important! to override the default hover color */
|
||||
fill: #d92215;
|
||||
opacity: 1 !important; /* !important to override the default hover opacity */
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
|
@ -10,35 +10,13 @@ body {
|
||||
background-image: url("chrome://browser/skin/icon-search-64.svg");
|
||||
}
|
||||
|
||||
select {
|
||||
font: inherit;
|
||||
padding-inline-end: 24px;
|
||||
#defaultEngine {
|
||||
padding-inline-start: 26px;
|
||||
background-image: var(--engine-icon-url),
|
||||
url("chrome://global/skin/in-content/dropdown.svg#dropdown");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 8px center, calc(100% - 4px) center;
|
||||
background-position: 5px center;
|
||||
background-size: 16px, 16px;
|
||||
}
|
||||
|
||||
select:-moz-dir(rtl) {
|
||||
background-position: calc(100% - 8px) center, 4px center;
|
||||
}
|
||||
|
||||
select:-moz-focusring {
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--in-content-text-color);
|
||||
}
|
||||
|
||||
option {
|
||||
padding: 4px;
|
||||
padding-inline-start: 30px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 8px center;
|
||||
background-size: 16px;
|
||||
background-color: var(--in-content-page-background);
|
||||
}
|
||||
|
||||
option:-moz-dir(rtl) {
|
||||
background-position: calc(100% - 8px) center;
|
||||
#defaultEngine:-moz-dir(rtl) {
|
||||
background-position: calc(100% - 5px) center;
|
||||
}
|
||||
|
@ -36,8 +36,6 @@
|
||||
|
||||
--toolbarbutton-checkedhover-backgroundcolor: rgba(0,0,0,.1);
|
||||
|
||||
--identity-box-verified-background-color: #fff;
|
||||
|
||||
--urlbar-dropmarker-url: url("chrome://browser/skin/urlbar-history-dropmarker.png");
|
||||
--urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
|
||||
--urlbar-dropmarker-hover-region: rect(0px, 22px, 14px, 11px);
|
||||
@ -49,7 +47,7 @@
|
||||
|
||||
--panel-separator-color: ThreeDLightShadow;
|
||||
|
||||
--urlbar-separator-color: hsla(0,0%,16%,.2);
|
||||
--urlbar-separator-color: ThreeDLightShadow;
|
||||
}
|
||||
|
||||
#nav-bar[brighttext] {
|
||||
@ -659,7 +657,6 @@ menuitem.bookmark-item {
|
||||
/* ::::: primary toolbar buttons ::::: */
|
||||
|
||||
%include ../shared/toolbarbuttons.inc.css
|
||||
%include ../shared/menupanel.inc.css
|
||||
|
||||
@media (-moz-windows-theme: luna-silver) and (max-resolution: 1dppx) {
|
||||
:-moz-any(@primaryToolbarButtons@),
|
||||
@ -702,6 +699,28 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
max-width: 18px;
|
||||
}
|
||||
|
||||
%include ../shared/menupanel.inc.css
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"][panel-multiview-anchor=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
toolbaritem[cui-areatype="menu-panel"] > :-moz-any(@nestedButtons@) > .toolbarbutton-icon {
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
opacity: 0.7 !important; /* !important overrides .toolbarbutton-1[disabled=true] rule */
|
||||
}
|
||||
}
|
||||
|
||||
.findbar-button,
|
||||
#nav-bar .toolbarbutton-1,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
||||
@ -1372,7 +1391,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
|
||||
}
|
||||
|
||||
#urlbar-search-footer {
|
||||
border-top: 1px solid hsla(210,4%,10%,.14);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
background-color: hsla(210,4%,10%,.07);
|
||||
}
|
||||
|
||||
@ -1420,10 +1439,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
|
||||
|
||||
/* identity box */
|
||||
|
||||
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
|
||||
background-color: var(--identity-box-verified-background-color);
|
||||
}
|
||||
|
||||
#identity-box:-moz-focusring {
|
||||
outline: 1px dotted #000;
|
||||
outline-offset: -3px;
|
||||
@ -2728,10 +2743,5 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
|
||||
}
|
||||
|
||||
.webextension-popup-browser {
|
||||
margin-right: -1px;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
#PanelUI-popup .webextension-popup-browser {
|
||||
margin: 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 38 KiB |
@ -3,6 +3,10 @@ subsuite = screenshots
|
||||
support-files =
|
||||
head.js
|
||||
mozscreenshots/extension/lib/permissionPrompts.html
|
||||
mozscreenshots/extension/lib/controlCenter/password.html
|
||||
mozscreenshots/extension/lib/controlCenter/mixed.html
|
||||
mozscreenshots/extension/lib/controlCenter/mixed_active.html
|
||||
mozscreenshots/extension/lib/controlCenter/mixed_passive.html
|
||||
mozscreenshots/extension/lib/borderify.xpi
|
||||
|
||||
[browser_screenshots.js]
|
||||
|
6
browser/tools/mozscreenshots/controlCenter/browser.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[DEFAULT]
|
||||
subsuite = screenshots
|
||||
support-files =
|
||||
../head.js
|
||||
|
||||
[browser_controlCenter.js]
|
@ -0,0 +1,14 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* capture() {
|
||||
if (!shouldCapture()) {
|
||||
return;
|
||||
}
|
||||
let sets = ["LightweightThemes", "ControlCenter"];
|
||||
|
||||
yield TestRunner.start(sets, "controlCenter");
|
||||
});
|
@ -8,6 +8,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
# Each test is in it's own directory so it gets run in a clean profile with
|
||||
# run-by-dir.
|
||||
'browser.ini',
|
||||
'controlCenter/browser.ini',
|
||||
'devtools/browser.ini',
|
||||
'permissionPrompts/browser.ini',
|
||||
'preferences/browser.ini',
|
||||
|
@ -0,0 +1,238 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ControlCenter"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://testing-common/BrowserTestUtils.jsm");
|
||||
Cu.import("resource:///modules/SitePermissions.jsm");
|
||||
|
||||
let {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
|
||||
|
||||
const RESOURCE_PATH = "extensions/mozscreenshots/browser/chrome/mozscreenshots/lib/controlCenter";
|
||||
const HTTP_PAGE = "http://example.com/";
|
||||
const HTTPS_PAGE = "https://example.com/";
|
||||
const PERMISSIONS_PAGE = "https://test1.example.com/";
|
||||
const HTTP_PASSWORD_PAGE = `http://test2.example.org/${RESOURCE_PATH}/password.html`;
|
||||
const MIXED_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed.html`;
|
||||
const MIXED_ACTIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_active.html`;
|
||||
const MIXED_PASSIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_passive.html`;
|
||||
const TRACKING_PAGE = `http://tracking.example.org/${RESOURCE_PATH}/tracking.html`;
|
||||
|
||||
this.ControlCenter = {
|
||||
init(libDir) { },
|
||||
|
||||
configurations: {
|
||||
about: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage("about:home");
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
localFile: {
|
||||
applyConfig: Task.async(function* () {
|
||||
let filePath = "file:///";
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
filePath += "C:/";
|
||||
}
|
||||
yield loadPage(filePath);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
http: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTP_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
httpSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTP_PAGE);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
https: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTPS_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
httpsSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTPS_PAGE);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
singlePermission: {
|
||||
applyConfig: Task.async(function* () {
|
||||
let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
|
||||
SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
|
||||
|
||||
yield loadPage(PERMISSIONS_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
allPermissions: {
|
||||
applyConfig: Task.async(function* () {
|
||||
// there are 3 possible non-default permission states, so we alternate between them
|
||||
let states = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.SESSION];
|
||||
let uri = Services.io.newURI(PERMISSIONS_PAGE, null, null)
|
||||
SitePermissions.listPermissions().forEach(function (permission, index) {
|
||||
SitePermissions.set(uri, permission, states[index % 3]);
|
||||
});
|
||||
|
||||
yield loadPage(PERMISSIONS_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
mixed: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_CONTENT_URL);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
mixedSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_CONTENT_URL);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
mixedPassive: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_PASSIVE_CONTENT_URL);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
mixedPassiveSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_PASSIVE_CONTENT_URL);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
mixedActive: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
mixedActiveSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
mixedActiveUnblocked: {
|
||||
applyConfig: Task.async(function* () {
|
||||
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let gBrowser = browserWindow.gBrowser;
|
||||
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
|
||||
gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
mixedActiveUnblockedSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let gBrowser = browserWindow.gBrowser;
|
||||
yield loadPage(MIXED_ACTIVE_CONTENT_URL);
|
||||
gBrowser.ownerGlobal.gIdentityHandler.disableMixedContentProtection();
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, MIXED_ACTIVE_CONTENT_URL);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
httpPassword: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTP_PASSWORD_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
httpPasswordSubView: {
|
||||
applyConfig: Task.async(function* () {
|
||||
yield loadPage(HTTP_PASSWORD_PAGE);
|
||||
yield openIdentityPopup(true);
|
||||
}),
|
||||
},
|
||||
|
||||
trackingProtectionNoElements: {
|
||||
applyConfig: Task.async(function* () {
|
||||
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
|
||||
|
||||
yield loadPage(HTTP_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
trackingProtectionEnabled: {
|
||||
applyConfig: Task.async(function* () {
|
||||
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
|
||||
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
|
||||
yield UrlClassifierTestUtils.addTestTrackers();
|
||||
|
||||
yield loadPage(TRACKING_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
|
||||
trackingProtectionDisabled: {
|
||||
applyConfig: Task.async(function* () {
|
||||
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let gBrowser = browserWindow.gBrowser;
|
||||
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
|
||||
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
|
||||
yield UrlClassifierTestUtils.addTestTrackers();
|
||||
|
||||
yield loadPage(TRACKING_PAGE);
|
||||
yield openIdentityPopup();
|
||||
// unblock the page
|
||||
gBrowser.ownerGlobal.document.querySelector("#tracking-action-unblock").click();
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, TRACKING_PAGE);
|
||||
yield openIdentityPopup();
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function* loadPage(url) {
|
||||
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let gBrowser = browserWindow.gBrowser;
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, url);
|
||||
}
|
||||
|
||||
function* openIdentityPopup(expand) {
|
||||
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let gBrowser = browserWindow.gBrowser;
|
||||
let { gIdentityHandler } = gBrowser.ownerGlobal;
|
||||
gIdentityHandler._identityPopup.hidePopup();
|
||||
gIdentityHandler._identityBox.querySelector("#identity-icon").click();
|
||||
if (expand) {
|
||||
// give some time for opening to avoid weird style issues
|
||||
yield new Promise((c) => setTimeout(c, 500));
|
||||
gIdentityHandler._identityPopup.querySelector("#identity-popup-security-expander").click();
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ let lastTab = null;
|
||||
this.PermissionPrompts = {
|
||||
init(libDir) {
|
||||
Services.prefs.setBoolPref("media.navigator.permission.fake", true);
|
||||
Services.prefs.setBoolPref("media.getusermedia.screensharing.allow_on_old_platforms", true);
|
||||
Services.prefs.setCharPref("media.getusermedia.screensharing.allowed_domains",
|
||||
"test1.example.com");
|
||||
Services.prefs.setBoolPref("extensions.install.requireBuiltInCerts", false);
|
||||
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Mixed Content test</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="visibility:hidden" src="http://example.com"></iframe>
|
||||
<img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Mixed Active Content test</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="visibility:hidden" src="http://example.com"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Mixed Passive Content test</title>
|
||||
</head>
|
||||
<body>
|
||||
<img style="visibility:hidden" src="http://example.com/tests/image/test/mochitest/blue.png"></img>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>HTTP Password test</title>
|
||||
</head>
|
||||
<body>
|
||||
<form>
|
||||
<input type="password" />
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Tracking test</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="visibility:hidden" src="http://tracking.example.com/"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -181,7 +181,6 @@ def old_configure_options(*options):
|
||||
'--enable-faststripe',
|
||||
'--enable-feeds',
|
||||
'--enable-gamepad',
|
||||
'--enable-gc-trace',
|
||||
'--enable-gconf',
|
||||
'--enable-gczeal',
|
||||
'--enable-gio',
|
||||
@ -203,7 +202,6 @@ def old_configure_options(*options):
|
||||
'--enable-media-navigator',
|
||||
'--enable-memory-sanitizer',
|
||||
'--enable-mobile-optimize',
|
||||
'--enable-more-deterministic',
|
||||
'--enable-mozril-geoloc',
|
||||
'--enable-necko-protocols',
|
||||
'--enable-necko-wifi',
|
||||
@ -215,7 +213,6 @@ def old_configure_options(*options):
|
||||
'--enable-oom-breakpoint',
|
||||
'--enable-optimize',
|
||||
'--enable-parental-controls',
|
||||
'--enable-perf',
|
||||
'--enable-permissions',
|
||||
'--enable-pie',
|
||||
'--enable-png-arm-neon-support',
|
||||
|
@ -71,8 +71,8 @@ public:
|
||||
|
||||
NS_DECL_NSIEXPANDEDPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
|
||||
NS_IMETHODIMP_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
|
||||
NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
|
||||
NS_IMETHOD GetURI(nsIURI** aURI) override;
|
||||
|
@ -76,7 +76,7 @@ using namespace mozilla::dom;
|
||||
|
||||
nsIIOService *nsScriptSecurityManager::sIOService = nullptr;
|
||||
nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr;
|
||||
JSRuntime *nsScriptSecurityManager::sRuntime = 0;
|
||||
JSContext *nsScriptSecurityManager::sContext = nullptr;
|
||||
bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
|
||||
|
||||
///////////////////////////
|
||||
@ -1413,19 +1413,18 @@ nsresult nsScriptSecurityManager::Init()
|
||||
|
||||
//-- Register security check callback in the JS engine
|
||||
// Currently this is used to control access to function.caller
|
||||
sRuntime = xpc::GetJSRuntime();
|
||||
sContext = danger::GetJSContext();
|
||||
|
||||
static const JSSecurityCallbacks securityCallbacks = {
|
||||
ContentSecurityPolicyPermitsJSAction,
|
||||
JSPrincipalsSubsume,
|
||||
};
|
||||
|
||||
JSContext* cx = JS_GetContext(sRuntime);
|
||||
MOZ_ASSERT(!JS_GetSecurityCallbacks(cx));
|
||||
JS_SetSecurityCallbacks(cx, &securityCallbacks);
|
||||
JS_InitDestroyPrincipalsCallback(cx, nsJSPrincipals::Destroy);
|
||||
MOZ_ASSERT(!JS_GetSecurityCallbacks(sContext));
|
||||
JS_SetSecurityCallbacks(sContext, &securityCallbacks);
|
||||
JS_InitDestroyPrincipalsCallback(sContext, nsJSPrincipals::Destroy);
|
||||
|
||||
JS_SetTrustedPrincipals(cx, system);
|
||||
JS_SetTrustedPrincipals(sContext, system);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1448,10 +1447,10 @@ nsScriptSecurityManager::~nsScriptSecurityManager(void)
|
||||
void
|
||||
nsScriptSecurityManager::Shutdown()
|
||||
{
|
||||
if (sRuntime) {
|
||||
JS_SetSecurityCallbacks(JS_GetContext(sRuntime), nullptr);
|
||||
JS_SetTrustedPrincipals(JS_GetContext(sRuntime), nullptr);
|
||||
sRuntime = nullptr;
|
||||
if (sContext) {
|
||||
JS_SetSecurityCallbacks(sContext, nullptr);
|
||||
JS_SetTrustedPrincipals(sContext, nullptr);
|
||||
sContext = nullptr;
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(sIOService);
|
||||
|
@ -148,7 +148,7 @@ private:
|
||||
|
||||
static nsIIOService *sIOService;
|
||||
static nsIStringBundle *sStrBundle;
|
||||
static JSRuntime *sRuntime;
|
||||
static JSContext *sContext;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -19,7 +19,6 @@ const { LocationStore, serialize, deserialize } = require("./location-store");
|
||||
function SourceMapService(target) {
|
||||
this._target = target;
|
||||
this._locationStore = new LocationStore();
|
||||
this._isInitialResolve = true;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
@ -41,7 +40,6 @@ function SourceMapService(target) {
|
||||
* Clears the store containing the cached resolved locations and promises
|
||||
*/
|
||||
SourceMapService.prototype.reset = function () {
|
||||
this._isInitialResolve = true;
|
||||
this._locationStore.clear();
|
||||
};
|
||||
|
||||
@ -51,7 +49,6 @@ SourceMapService.prototype.destroy = function () {
|
||||
this._target.off("navigate", this.reset);
|
||||
this._target.off("will-navigate", this.reset);
|
||||
this._target.off("close", this.destroy);
|
||||
this._isInitialResolve = null;
|
||||
this._target = this._locationStore = null;
|
||||
};
|
||||
|
||||
@ -63,10 +60,7 @@ SourceMapService.prototype.destroy = function () {
|
||||
SourceMapService.prototype.subscribe = function (location, callback) {
|
||||
this.on(serialize(location), callback);
|
||||
this._locationStore.set(location);
|
||||
if (this._isInitialResolve) {
|
||||
this._resolveAndUpdate(location);
|
||||
this._isInitialResolve = false;
|
||||
}
|
||||
this._resolveAndUpdate(location);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -76,7 +70,12 @@ SourceMapService.prototype.subscribe = function (location, callback) {
|
||||
*/
|
||||
SourceMapService.prototype.unsubscribe = function (location, callback) {
|
||||
this.off(serialize(location), callback);
|
||||
this._locationStore.clearByURL(location.url);
|
||||
// Check to see if the store exists before attempting to clear a location
|
||||
// Sometimes un-subscribe happens during the destruction cascades and this
|
||||
// condition is to protect against that. Could be looked into in the future.
|
||||
if (this._locationStore) {
|
||||
this._locationStore.clearByURL(location.url);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -87,16 +86,10 @@ SourceMapService.prototype.unsubscribe = function (location, callback) {
|
||||
*/
|
||||
SourceMapService.prototype._resolveAndUpdate = function (location) {
|
||||
this._resolveLocation(location).then(resolvedLocation => {
|
||||
// We try to source map the first console log to initiate the source-updated event from
|
||||
// target. The isSameLocation check is to make sure we don't update the frame, if the
|
||||
// location is not source-mapped.
|
||||
if (resolvedLocation) {
|
||||
if (this._isInitialResolve) {
|
||||
if (!isSameLocation(location, resolvedLocation)) {
|
||||
this.emit(serialize(location), location, resolvedLocation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We try to source map the first console log to initiate the source-updated
|
||||
// event from target. The isSameLocation check is to make sure we don't update
|
||||
// the frame, if the location is not source-mapped.
|
||||
if (resolvedLocation && !isSameLocation(location, resolvedLocation)) {
|
||||
this.emit(serialize(location), location, resolvedLocation);
|
||||
}
|
||||
});
|
||||
@ -182,7 +175,6 @@ function resolveLocation(target, location) {
|
||||
if (newLocation.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return newLocation;
|
||||
});
|
||||
}
|
||||
@ -197,4 +189,4 @@ function isSameLocation(location, resolvedLocation) {
|
||||
return location.url === resolvedLocation.url &&
|
||||
location.line === resolvedLocation.line &&
|
||||
location.column === resolvedLocation.column;
|
||||
};
|
||||
}
|
||||
|
@ -19,25 +19,22 @@ const PAGE_URL = `${DEBUGGER_ROOT}doc_empty-tab-01.html`;
|
||||
const JS_URL = `${URL_ROOT}code_binary_search.js`;
|
||||
const COFFEE_URL = `${URL_ROOT}code_binary_search.coffee`;
|
||||
const { SourceMapService } = require("devtools/client/framework/source-map-service");
|
||||
const { serialize } = require("devtools/client/framework/location-store");
|
||||
|
||||
add_task(function* () {
|
||||
const toolbox = yield openNewTabAndToolbox(PAGE_URL, "jsdebugger");
|
||||
|
||||
const service = new SourceMapService(toolbox.target);
|
||||
|
||||
const aggregator = [];
|
||||
let aggregator = new Map();
|
||||
|
||||
function onUpdate(e, oldLoc, newLoc) {
|
||||
if (oldLoc.line === 6) {
|
||||
checkLoc1(oldLoc, newLoc);
|
||||
} else if (oldLoc.line === 8) {
|
||||
checkLoc2(oldLoc, newLoc);
|
||||
} else if (oldLoc.line === 2) {
|
||||
checkLoc3(oldLoc, newLoc);
|
||||
} else {
|
||||
throw new Error(`Unexpected location update: ${JSON.stringify(oldLoc)}`);
|
||||
}
|
||||
aggregator.push(newLoc);
|
||||
aggregator.set(serialize(oldLoc), newLoc);
|
||||
}
|
||||
|
||||
let loc1 = { url: JS_URL, line: 6 };
|
||||
@ -51,7 +48,9 @@ add_task(function* () {
|
||||
yield createScript(JS_URL);
|
||||
yield sourceShown;
|
||||
|
||||
yield waitUntil(() => aggregator.length === 2);
|
||||
yield waitUntil(() => aggregator.size === 2);
|
||||
|
||||
aggregator = Array.from(aggregator.values());
|
||||
|
||||
ok(aggregator.find(i => i.url === COFFEE_URL && i.line === 4), "found first updated location");
|
||||
ok(aggregator.find(i => i.url === COFFEE_URL && i.line === 6), "found second updated location");
|
||||
|
@ -591,7 +591,12 @@ Toolbox.prototype = {
|
||||
["forceReload2", true]
|
||||
].forEach(([id, force]) => {
|
||||
let key = toolboxStrings("toolbox." + id + ".key");
|
||||
shortcuts.on(key, this.reloadTarget.bind(this, force));
|
||||
shortcuts.on(key, (name, event) => {
|
||||
this.reloadTarget(force);
|
||||
|
||||
// Prevent Firefox shortcuts from reloading the page
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -17,7 +17,9 @@ const {LocalizationHelper} = require("devtools/client/shared/l10n");
|
||||
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/shared.properties";
|
||||
const STRINGS_INSPECTOR = "chrome://devtools-shared/locale/styleinspector.properties";
|
||||
const SHARED_L10N = new LocalizationHelper(STRINGS_URI);
|
||||
const INSPECTOR_L10N = new LocalizationHelper(STRINGS_INSPECTOR);
|
||||
const NUMERIC = /^-?[\d\.]+$/;
|
||||
const LONG_TEXT_ROTATE_LIMIT = 3;
|
||||
|
||||
@ -734,8 +736,14 @@ LayoutView.prototype = {
|
||||
title += "\n" + sourceRule.selectors.join(", ");
|
||||
}
|
||||
if (sourceRule && sourceRule.parentStyleSheet) {
|
||||
title += "\n" + sourceRule.parentStyleSheet.href + ":" + sourceRule.line;
|
||||
if (sourceRule.parentStyleSheet.href) {
|
||||
title += "\n" + sourceRule.parentStyleSheet.href + ":" + sourceRule.line;
|
||||
} else {
|
||||
title += "\n" + INSPECTOR_L10N.getStr("rule.sourceInline") +
|
||||
":" + sourceRule.line;
|
||||
}
|
||||
}
|
||||
|
||||
el.setAttribute("title", title);
|
||||
},
|
||||
|
||||
|
@ -28,45 +28,45 @@ const VALUES_TEST_DATA = [{
|
||||
values: [{
|
||||
name: "margin-top",
|
||||
ruleSelector: "#div1",
|
||||
styleSheetLocation: "null:1"
|
||||
styleSheetLocation: "inline:1"
|
||||
}, {
|
||||
name: "margin-right",
|
||||
ruleSelector: "#div1",
|
||||
styleSheetLocation: "null:1"
|
||||
styleSheetLocation: "inline:1"
|
||||
}, {
|
||||
name: "margin-bottom",
|
||||
ruleSelector: "#div1",
|
||||
styleSheetLocation: "null:1"
|
||||
styleSheetLocation: "inline:1"
|
||||
}, {
|
||||
name: "margin-left",
|
||||
ruleSelector: "#div1",
|
||||
styleSheetLocation: "null:1"
|
||||
styleSheetLocation: "inline:1"
|
||||
}]
|
||||
}, {
|
||||
selector: "#div2",
|
||||
values: [{
|
||||
name: "border-bottom-width",
|
||||
ruleSelector: "#div2",
|
||||
styleSheetLocation: "null:2"
|
||||
styleSheetLocation: "inline:2"
|
||||
}]
|
||||
}, {
|
||||
selector: "#div3",
|
||||
values: [{
|
||||
name: "padding-top",
|
||||
ruleSelector: "html, body, #div3",
|
||||
styleSheetLocation: "null:3"
|
||||
styleSheetLocation: "inline:3"
|
||||
}, {
|
||||
name: "padding-right",
|
||||
ruleSelector: "html, body, #div3",
|
||||
styleSheetLocation: "null:3"
|
||||
styleSheetLocation: "inline:3"
|
||||
}, {
|
||||
name: "padding-bottom",
|
||||
ruleSelector: "html, body, #div3",
|
||||
styleSheetLocation: "null:3"
|
||||
styleSheetLocation: "inline:3"
|
||||
}, {
|
||||
name: "padding-left",
|
||||
ruleSelector: "html, body, #div3",
|
||||
styleSheetLocation: "null:3"
|
||||
styleSheetLocation: "inline:3"
|
||||
}]
|
||||
}];
|
||||
|
||||
|
@ -14,7 +14,7 @@ add_task(function* () {
|
||||
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
|
||||
helper.prefix = ID;
|
||||
|
||||
let {show, synthesizeKey, finalize} = helper;
|
||||
let {show, finalize} = helper;
|
||||
|
||||
info("Show the eyedropper with the copyOnSelect option");
|
||||
yield show("html", {copyOnSelect: true});
|
||||
@ -24,8 +24,7 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboard(() => {
|
||||
info("Activate the eyedropper so the background color is copied");
|
||||
let generateKey = synthesizeKey({key: "VK_RETURN", options: {}});
|
||||
generateKey.next();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}, "#FF0000");
|
||||
|
||||
ok(true, "The clipboard contains the right value");
|
||||
|
@ -35,7 +35,7 @@ add_task(function* () {
|
||||
|
||||
function* respondsToMoveEvents(helper) {
|
||||
info("Checking that the eyedropper responds to events from the mouse and keyboard");
|
||||
let {mouse, synthesizeKey} = helper;
|
||||
let {mouse} = helper;
|
||||
|
||||
for (let {type, x, y, key, shift, expected} of MOVE_EVENTS_DATA) {
|
||||
info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
|
||||
@ -43,7 +43,7 @@ function* respondsToMoveEvents(helper) {
|
||||
yield mouse.move(x, y);
|
||||
} else if (type === "keyboard") {
|
||||
let options = shift ? {shiftKey: true} : {};
|
||||
yield synthesizeKey({key, options});
|
||||
yield EventUtils.synthesizeKey(key, options);
|
||||
}
|
||||
yield checkPosition(expected, helper);
|
||||
}
|
||||
@ -55,17 +55,17 @@ function* checkPosition({x, y}, {getElementAttribute}) {
|
||||
`The eyedropper is at the expected ${x} ${y} position`);
|
||||
}
|
||||
|
||||
function* respondsToReturnAndEscape({synthesizeKey, isElementHidden, show}) {
|
||||
function* respondsToReturnAndEscape({isElementHidden, show}) {
|
||||
info("Simulating return to select the color and hide the eyedropper");
|
||||
|
||||
yield synthesizeKey({key: "VK_RETURN", options: {}});
|
||||
yield EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
let hidden = yield isElementHidden("root");
|
||||
ok(hidden, "The eyedropper has been hidden");
|
||||
|
||||
info("Showing the eyedropper again and simulating escape to hide it");
|
||||
|
||||
yield show("html");
|
||||
yield synthesizeKey({key: "VK_ESCAPE", options: {}});
|
||||
yield EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
hidden = yield isElementHidden("root");
|
||||
ok(hidden, "The eyedropper has been hidden again");
|
||||
}
|
||||
|
@ -465,10 +465,6 @@ const getHighlighterHelperFor = (type) => Task.async(
|
||||
yield testActor.synthesizeMouse(options);
|
||||
},
|
||||
|
||||
synthesizeKey: function* (options) {
|
||||
yield testActor.synthesizeKey(options);
|
||||
},
|
||||
|
||||
// This object will synthesize any "mouse" prefixed event to the
|
||||
// `testActor`, using the name of method called as suffix for the
|
||||
// event's name.
|
||||
|
@ -56,6 +56,10 @@ function makeMemoryTest(url, generator) {
|
||||
return Task.async(function* () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// It can take a long time to save a snapshot to disk, read the snapshots
|
||||
// back from disk, and finally perform analyses on them.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const tab = yield addTab(url);
|
||||
const results = yield openMemoryPanel(tab);
|
||||
|
||||
|
@ -112,7 +112,6 @@ skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
|
||||
[browser_net_reload-markers.js]
|
||||
[browser_net_req-resp-bodies.js]
|
||||
[browser_net_resend.js]
|
||||
skip-if = e10s # Bug 1091612
|
||||
[browser_net_security-details.js]
|
||||
[browser_net_security-error.js]
|
||||
[browser_net_security-icon-click.js]
|
||||
|
@ -17,9 +17,9 @@ function test() {
|
||||
"-H 'Accept: */*'",
|
||||
"-H 'Accept-Language: " + navigator.language + "'",
|
||||
"--compressed",
|
||||
"-H 'x-custom-header-1: Custom value'",
|
||||
"-H 'x-custom-header-2: 8.8.8.8'",
|
||||
"-H 'x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
|
||||
"-H 'X-Custom-Header-1: Custom value'",
|
||||
"-H 'X-Custom-Header-2: 8.8.8.8'",
|
||||
"-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
|
||||
"-H 'Referer: " + CURL_URL + "'",
|
||||
"-H 'Connection: keep-alive'",
|
||||
"-H 'Pragma: no-cache'",
|
||||
@ -34,9 +34,9 @@ function test() {
|
||||
'-H "Accept: */*"',
|
||||
'-H "Accept-Language: ' + navigator.language + '"',
|
||||
"--compressed",
|
||||
'-H "x-custom-header-1: Custom value"',
|
||||
'-H "x-custom-header-2: 8.8.8.8"',
|
||||
'-H "x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
|
||||
'-H "X-Custom-Header-1: Custom value"',
|
||||
'-H "X-Custom-Header-2: 8.8.8.8"',
|
||||
'-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"',
|
||||
'-H "Referer: ' + CURL_URL + '"',
|
||||
'-H "Connection: keep-alive"',
|
||||
'-H "Pragma: no-cache"',
|
||||
|
@ -154,7 +154,7 @@ function testSentRequest(aData, aOrigData) {
|
||||
is(aData.url, aOrigData.url + "&" + ADD_QUERY, "correct url in sent request");
|
||||
|
||||
let hasHeader = aData.requestHeaders.headers.some((header) => {
|
||||
return (header.name.toLowerCase() + ": " + header.value) == ADD_HEADER.toLowerCase();
|
||||
return (header.name + ": " + header.value) == ADD_HEADER;
|
||||
});
|
||||
ok(hasHeader, "new header added to sent request");
|
||||
|
||||
|
@ -180,6 +180,16 @@ function tunnelToInnerBrowser(outer, inner) {
|
||||
outer.setDocShellIsActiveAndForeground = value => {
|
||||
inner.frameLoader.tabParent.setDocShellIsActiveAndForeground(value);
|
||||
};
|
||||
|
||||
// Make the PopupNotifications object available on the iframe's owner
|
||||
// This is used for permission doorhangers
|
||||
Object.defineProperty(inner.ownerGlobal, "PopupNotifications", {
|
||||
get() {
|
||||
return outer.ownerGlobal.PopupNotifications;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
});
|
||||
}),
|
||||
|
||||
stop() {
|
||||
@ -210,6 +220,9 @@ function tunnelToInnerBrowser(outer, inner) {
|
||||
delete outer.docShellIsActive;
|
||||
delete outer.setDocShellIsActiveAndForeground;
|
||||
|
||||
// Delete the PopupNotifications getter added for permission doorhangers
|
||||
delete inner.ownerGlobal.PopupNotifications;
|
||||
|
||||
mmTunnel.destroy();
|
||||
mmTunnel = null;
|
||||
|
||||
|
@ -6,6 +6,7 @@ skip-if = !e10s
|
||||
support-files =
|
||||
devices.json
|
||||
doc_page_state.html
|
||||
geolocation.html
|
||||
head.js
|
||||
!/devtools/client/commandline/test/helpers.js
|
||||
!/devtools/client/framework/test/shared-head.js
|
||||
@ -25,6 +26,7 @@ support-files =
|
||||
[browser_mouse_resize.js]
|
||||
[browser_navigation.js]
|
||||
[browser_page_state.js]
|
||||
[browser_permission_doorhanger.js]
|
||||
[browser_resize_cmd.js]
|
||||
skip-if = true # GCLI target confused after swap, will fix in bug 1240912
|
||||
[browser_screenshot_button.js]
|
||||
|
@ -0,0 +1,52 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that permission popups asking for user approval still appear in RDM
|
||||
const DUMMY_URL = "http://example.com/";
|
||||
const TEST_URL = `${URL_ROOT}geolocation.html`;
|
||||
|
||||
function waitForGeolocationPrompt(win, browser) {
|
||||
return new Promise(resolve => {
|
||||
win.PopupNotifications.panel.addEventListener("popupshown", function popupShown() {
|
||||
let notification = win.PopupNotifications.getNotification("geolocation", browser);
|
||||
if (notification) {
|
||||
win.PopupNotifications.panel.removeEventListener("popupshown", popupShown);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let tab = yield addTab(DUMMY_URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
let win = browser.ownerGlobal;
|
||||
|
||||
let waitPromptPromise = waitForGeolocationPrompt(win, browser);
|
||||
|
||||
// Checks if a geolocation permission doorhanger appears when openning a page
|
||||
// requesting geolocation
|
||||
yield load(browser, TEST_URL);
|
||||
yield waitPromptPromise;
|
||||
|
||||
ok(true, "Permission doorhanger appeared without RDM enabled");
|
||||
|
||||
// Lets switch back to the dummy website and enable RDM
|
||||
yield load(browser, DUMMY_URL);
|
||||
let { ui } = yield openRDM(tab);
|
||||
let newBrowser = ui.getViewportBrowser();
|
||||
|
||||
waitPromptPromise = waitForGeolocationPrompt(win, newBrowser);
|
||||
|
||||
// Checks if the doorhanger appeared again when reloading the geolocation
|
||||
// page inside RDM
|
||||
yield load(browser, TEST_URL);
|
||||
yield waitPromptPromise;
|
||||
|
||||
ok(true, "Permission doorhanger appeared inside RDM");
|
||||
|
||||
yield closeRDM(tab);
|
||||
yield removeTab(tab);
|
||||
});
|
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Geolocation permission test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
navigator.geolocation.getCurrentPosition(function (pos) {});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -15,7 +15,6 @@
|
||||
* (Telemetry.prototype._histograms):
|
||||
* mytoolname: {
|
||||
* histogram: "DEVTOOLS_MYTOOLNAME_OPENED_COUNT",
|
||||
* userHistogram: "DEVTOOLS_MYTOOLNAME_OPENED_PER_USER_FLAG",
|
||||
* timerHistogram: "DEVTOOLS_MYTOOLNAME_TIME_ACTIVE_SECONDS"
|
||||
* },
|
||||
*
|
||||
@ -62,179 +61,142 @@ Telemetry.prototype = {
|
||||
_histograms: {
|
||||
toolbox: {
|
||||
histogram: "DEVTOOLS_TOOLBOX_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
options: {
|
||||
histogram: "DEVTOOLS_OPTIONS_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webconsole: {
|
||||
histogram: "DEVTOOLS_WEBCONSOLE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
browserconsole: {
|
||||
histogram: "DEVTOOLS_BROWSERCONSOLE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_BROWSERCONSOLE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_BROWSERCONSOLE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
inspector: {
|
||||
histogram: "DEVTOOLS_INSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
ruleview: {
|
||||
histogram: "DEVTOOLS_RULEVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
computedview: {
|
||||
histogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
fontinspector: {
|
||||
histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
animationinspector: {
|
||||
histogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
jsdebugger: {
|
||||
histogram: "DEVTOOLS_JSDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
jsbrowserdebugger: {
|
||||
histogram: "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSBROWSERDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
styleeditor: {
|
||||
histogram: "DEVTOOLS_STYLEEDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
shadereditor: {
|
||||
histogram: "DEVTOOLS_SHADEREDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webaudioeditor: {
|
||||
histogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
canvasdebugger: {
|
||||
histogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
performance: {
|
||||
histogram: "DEVTOOLS_JSPROFILER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
memory: {
|
||||
histogram: "DEVTOOLS_MEMORY_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_MEMORY_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_MEMORY_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
netmonitor: {
|
||||
histogram: "DEVTOOLS_NETMONITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
storage: {
|
||||
histogram: "DEVTOOLS_STORAGE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
paintflashing: {
|
||||
histogram: "DEVTOOLS_PAINTFLASHING_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
scratchpad: {
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SCRATCHPAD_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
"scratchpad-window": {
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SCRATCHPAD_WINDOW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
responsive: {
|
||||
histogram: "DEVTOOLS_RESPONSIVE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
eyedropper: {
|
||||
histogram: "DEVTOOLS_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
menueyedropper: {
|
||||
histogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
pickereyedropper: {
|
||||
histogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
toolbareyedropper: {
|
||||
histogram: "DEVTOOLS_TOOLBAR_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_TOOLBAR_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
developertoolbar: {
|
||||
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
aboutdebugging: {
|
||||
histogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_ABOUTDEBUGGING_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webide: {
|
||||
histogram: "DEVTOOLS_WEBIDE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webideProjectEditor: {
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webideProjectEditorSave: {
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG",
|
||||
},
|
||||
webideNewProject: {
|
||||
histogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG",
|
||||
},
|
||||
webideImportProject: {
|
||||
histogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG",
|
||||
},
|
||||
custom: {
|
||||
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
reloadAddonInstalled: {
|
||||
histogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT",
|
||||
userHistogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG",
|
||||
},
|
||||
reloadAddonReload: {
|
||||
histogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT",
|
||||
userHistogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG",
|
||||
},
|
||||
},
|
||||
|
||||
@ -251,9 +213,6 @@ Telemetry.prototype = {
|
||||
if (charts.histogram) {
|
||||
this.log(charts.histogram, true);
|
||||
}
|
||||
if (charts.userHistogram) {
|
||||
this.logOncePerBrowserVersion(charts.userHistogram, true);
|
||||
}
|
||||
if (charts.timerHistogram) {
|
||||
this.startTimer(charts.timerHistogram);
|
||||
}
|
||||
|
@ -42,10 +42,7 @@ function checkResults(histIdFocus, Telemetry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
if (histId.endsWith("OPENED_COUNT")) {
|
||||
is(value.length, 1, histId + " has one entry");
|
||||
|
||||
let okay = value.every(element => element === true);
|
||||
|
@ -68,10 +68,7 @@ function checkResults(histIdFocus, Telemetry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function (element) {
|
||||
|
@ -72,10 +72,7 @@ function checkResults(histIdFocus, Telemetry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function (element) {
|
||||
|
@ -103,10 +103,7 @@ function checkResults(histIdFocus, Telemetry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function (element) {
|
||||
|
@ -59,10 +59,7 @@ function checkResults(Telemetry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId === "DEVTOOLS_TOOLBOX_OPENED_COUNT") {
|
||||
if (histId === "DEVTOOLS_TOOLBOX_OPENED_COUNT") {
|
||||
is(value.length, 1, histId + " has only one entry");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
@ -166,10 +166,7 @@ function checkTelemetryResults(Telemetry) {
|
||||
for (let histId in result) {
|
||||
let value = result[histId];
|
||||
|
||||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function (element) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- 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" width="16" height="16" viewBox="0 0 16 16" fill="#0b0b0b">
|
||||
<path d="M6.7 8l3.6-3.6c.2-.2.2-.5 0-.7-.2-.2-.5-.2-.7 0L6 7.3 2.4 3.7c-.2-.2-.5-.2-.7 0-.2.2-.2.5 0 .7L5.3 8l-3.6 3.6c-.2.2-.2.5 0 .7.2.2.5.2.7 0L6 8.7l3.6 3.6c.2.2.5.2.7 0 .2-.2.2-.5 0-.7L6.7 8z"/>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
|
||||
<path d="M8.707 8l4.23 4.23a.5.5 0 1 1-.707.707L8 8.707l-4.23 4.23a.5.5 0 1 1-.707-.707L7.293 8l-4.23-4.23a.5.5 0 1 1 .707-.707L8 7.293l4.23-4.23a.5.5 0 0 1 .707.707L8.707 8z" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 518 B |
@ -164,10 +164,7 @@
|
||||
function checkResults() {
|
||||
let result = Telemetry.prototype.telemetryInfo;
|
||||
for (let [histId, value] of Iterator(result)) {
|
||||
if (histId.endsWith("_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && !!value[0],
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") {
|
||||
if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") {
|
||||
ok(value.length === 1 && !!value[0],
|
||||
histId + " has 1 successful entry");
|
||||
} else if (histId ===
|
||||
|
@ -158,7 +158,7 @@ EyeDropper.prototype = {
|
||||
this.moveTo(DEFAULT_START_POS_X, DEFAULT_START_POS_Y);
|
||||
|
||||
// Focus the content so the keyboard can be used.
|
||||
this.win.document.documentElement.focus();
|
||||
this.win.focus();
|
||||
|
||||
return true;
|
||||
},
|
||||
@ -360,14 +360,22 @@ EyeDropper.prototype = {
|
||||
* direction depending on the key pressed.
|
||||
*/
|
||||
handleKeyDown(e) {
|
||||
// Bail out early if any unsupported modifier is used, so that we let
|
||||
// keyboard shortcuts through.
|
||||
if (e.metaKey || e.ctrlKey || e.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode === e.DOM_VK_RETURN) {
|
||||
this.selectColor();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode === e.DOM_VK_ESCAPE) {
|
||||
this.emit("canceled");
|
||||
this.hide();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -377,16 +385,14 @@ EyeDropper.prototype = {
|
||||
|
||||
if (e.keyCode === e.DOM_VK_LEFT) {
|
||||
offsetX = -1;
|
||||
}
|
||||
if (e.keyCode === e.DOM_VK_RIGHT) {
|
||||
} else if (e.keyCode === e.DOM_VK_RIGHT) {
|
||||
offsetX = 1;
|
||||
}
|
||||
if (e.keyCode === e.DOM_VK_UP) {
|
||||
} else if (e.keyCode === e.DOM_VK_UP) {
|
||||
offsetY = -1;
|
||||
}
|
||||
if (e.keyCode === e.DOM_VK_DOWN) {
|
||||
} else if (e.keyCode === e.DOM_VK_DOWN) {
|
||||
offsetY = 1;
|
||||
}
|
||||
|
||||
if (e.shiftKey) {
|
||||
modifier = 10;
|
||||
}
|
||||
@ -402,12 +408,7 @@ EyeDropper.prototype = {
|
||||
|
||||
this.moveTo(this.magnifiedArea.x / this.pageZoom,
|
||||
this.magnifiedArea.y / this.pageZoom);
|
||||
}
|
||||
|
||||
// Prevent all keyboard interaction with the page, except if a modifier is used to let
|
||||
// keyboard shortcuts through.
|
||||
let hasModifier = e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
|
||||
if (!hasModifier) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
@ -1511,15 +1511,13 @@ WebConsoleActor.prototype =
|
||||
*
|
||||
* @param object aEvent
|
||||
* The initial network request event information.
|
||||
* @param nsIHttpChannel aChannel
|
||||
* The network request nsIHttpChannel object.
|
||||
* @return object
|
||||
* A new NetworkEventActor is returned. This is used for tracking the
|
||||
* network request and response.
|
||||
*/
|
||||
onNetworkEvent: function WCA_onNetworkEvent(aEvent, aChannel)
|
||||
onNetworkEvent: function WCA_onNetworkEvent(aEvent)
|
||||
{
|
||||
let actor = this.getNetworkEventActor(aChannel);
|
||||
let actor = this.getNetworkEventActor(aEvent.channelId);
|
||||
actor.init(aEvent);
|
||||
|
||||
let packet = {
|
||||
@ -1534,24 +1532,23 @@ WebConsoleActor.prototype =
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the NetworkEventActor for a nsIChannel, if it exists,
|
||||
* Get the NetworkEventActor for a nsIHttpChannel, if it exists,
|
||||
* otherwise create a new one.
|
||||
*
|
||||
* @param nsIHttpChannel aChannel
|
||||
* The channel for the network event.
|
||||
* @param string channelId
|
||||
* The id of the channel for the network event.
|
||||
* @return object
|
||||
* The NetworkEventActor for the given channel.
|
||||
*/
|
||||
getNetworkEventActor: function WCA_getNetworkEventActor(aChannel) {
|
||||
let actor = this._netEvents.get(aChannel);
|
||||
getNetworkEventActor: function WCA_getNetworkEventActor(channelId) {
|
||||
let actor = this._netEvents.get(channelId);
|
||||
if (actor) {
|
||||
// delete from map as we should only need to do this check once
|
||||
this._netEvents.delete(aChannel);
|
||||
actor.channel = null;
|
||||
this._netEvents.delete(channelId);
|
||||
return actor;
|
||||
}
|
||||
|
||||
actor = new NetworkEventActor(aChannel, this);
|
||||
actor = new NetworkEventActor(this);
|
||||
this._actorPool.addActor(actor);
|
||||
return actor;
|
||||
},
|
||||
@ -1575,10 +1572,11 @@ WebConsoleActor.prototype =
|
||||
}
|
||||
request.send(details.body);
|
||||
|
||||
let actor = this.getNetworkEventActor(request.channel);
|
||||
let channel = request.channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
let actor = this.getNetworkEventActor(channel.channelId);
|
||||
|
||||
// map channel to actor so we can associate future events with it
|
||||
this._netEvents.set(request.channel, actor);
|
||||
this._netEvents.set(channel.channelId, actor);
|
||||
|
||||
return {
|
||||
from: this.actorID,
|
||||
@ -1802,16 +1800,12 @@ exports.WebConsoleActor = WebConsoleActor;
|
||||
* Creates an actor for a network event.
|
||||
*
|
||||
* @constructor
|
||||
* @param object aChannel
|
||||
* The nsIChannel associated with this event.
|
||||
* @param object aWebConsoleActor
|
||||
* @param object webConsoleActor
|
||||
* The parent WebConsoleActor instance for this object.
|
||||
*/
|
||||
function NetworkEventActor(aChannel, aWebConsoleActor)
|
||||
{
|
||||
this.parent = aWebConsoleActor;
|
||||
function NetworkEventActor(webConsoleActor) {
|
||||
this.parent = webConsoleActor;
|
||||
this.conn = this.parent.conn;
|
||||
this.channel = aChannel;
|
||||
|
||||
this._request = {
|
||||
method: null,
|
||||
|
@ -29,7 +29,6 @@ using namespace testing;
|
||||
// GTest fixture class that all of our tests derive from.
|
||||
struct DevTools : public ::testing::Test {
|
||||
bool _initialized;
|
||||
JSRuntime* rt;
|
||||
JSContext* cx;
|
||||
JSCompartment* compartment;
|
||||
JS::Zone* zone;
|
||||
@ -37,23 +36,19 @@ struct DevTools : public ::testing::Test {
|
||||
|
||||
DevTools()
|
||||
: _initialized(false),
|
||||
rt(nullptr),
|
||||
cx(nullptr)
|
||||
{ }
|
||||
|
||||
virtual void SetUp() {
|
||||
MOZ_ASSERT(!_initialized);
|
||||
|
||||
rt = getRuntime();
|
||||
if (!rt)
|
||||
cx = getContext();
|
||||
if (!cx)
|
||||
return;
|
||||
|
||||
MOZ_RELEASE_ASSERT(!cx);
|
||||
cx = JS_GetContext(rt);
|
||||
|
||||
JS_BeginRequest(cx);
|
||||
|
||||
global.init(rt, createGlobal());
|
||||
global.init(cx, createGlobal());
|
||||
if (!global)
|
||||
return;
|
||||
JS_EnterCompartment(cx, global);
|
||||
@ -64,8 +59,8 @@ struct DevTools : public ::testing::Test {
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
JSRuntime* getRuntime() {
|
||||
return CycleCollectedJSRuntime::Get()->Runtime();
|
||||
JSContext* getContext() {
|
||||
return CycleCollectedJSRuntime::Get()->Context();
|
||||
}
|
||||
|
||||
static void reportError(JSContext* cx, const char* message, JSErrorReport* report) {
|
||||
|
@ -722,15 +722,14 @@ NetworkResponseListener.prototype = {
|
||||
* logged.
|
||||
* @param object owner
|
||||
* The network monitor owner. This object needs to hold:
|
||||
* - onNetworkEvent(requestInfo, channel, networkMonitor).
|
||||
* - onNetworkEvent(requestInfo)
|
||||
* This method is invoked once for every new network request and it is
|
||||
* given the following arguments: the initial network request
|
||||
* information, and the channel. The third argument is the NetworkMonitor
|
||||
* instance. onNetworkEvent() must return an object which holds several add*()
|
||||
* methods which are used to add further network request/response
|
||||
* information.
|
||||
* - stackTraceCollector If the owner has this optional property, it will
|
||||
* be used as a StackTraceCollector by the NetworkMonitor.
|
||||
* given the initial network request information as an argument.
|
||||
* onNetworkEvent() must return an object which holds several add*()
|
||||
* methods which are used to add further network request/response information.
|
||||
* - stackTraceCollector
|
||||
* If the owner has this optional property, it will be used as a
|
||||
* StackTraceCollector by the NetworkMonitor.
|
||||
*/
|
||||
function NetworkMonitor(filters, owner) {
|
||||
this.filters = filters;
|
||||
@ -1089,7 +1088,7 @@ NetworkMonitor.prototype = {
|
||||
cookies = NetworkHelper.parseCookieHeader(cookieHeader);
|
||||
}
|
||||
|
||||
httpActivity.owner = this.owner.onNetworkEvent(event, channel);
|
||||
httpActivity.owner = this.owner.onNetworkEvent(event);
|
||||
|
||||
this._setupResponseListener(httpActivity);
|
||||
|
||||
|
@ -9502,7 +9502,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHOD
|
||||
OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen,
|
||||
const uint8_t* aData, const nsACString& aMimeType) override
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ using mozilla::dom::DOMRequestService;
|
||||
using mozilla::dom::DOMCursor;
|
||||
using mozilla::dom::Promise;
|
||||
using mozilla::dom::AutoJSAPI;
|
||||
using mozilla::dom::GetJSRuntime;
|
||||
using mozilla::dom::RootingCx;
|
||||
|
||||
DOMRequest::DOMRequest(nsPIDOMWindowInner* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
@ -302,7 +302,7 @@ class FireSuccessAsyncTask : public mozilla::Runnable
|
||||
FireSuccessAsyncTask(DOMRequest* aRequest,
|
||||
const JS::Value& aResult) :
|
||||
mReq(aRequest),
|
||||
mResult(GetJSRuntime(), aResult)
|
||||
mResult(RootingCx(), aResult)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -511,6 +511,12 @@ private:
|
||||
oldTextNode);
|
||||
}
|
||||
if (newTextNode) {
|
||||
nsINode* oldDirAutoSetBy =
|
||||
static_cast<nsTextNode*>(rootNode->GetProperty(nsGkAtoms::dirAutoSetBy));
|
||||
if (oldDirAutoSetBy == newTextNode) {
|
||||
// We're already registered.
|
||||
return OpNext;
|
||||
}
|
||||
nsTextNodeDirectionalityMap::AddEntryToMap(newTextNode, rootNode);
|
||||
} else {
|
||||
rootNode->ClearHasDirAutoSet();
|
||||
@ -684,7 +690,9 @@ WalkDescendantsResetAutoDirection(Element* aElement)
|
||||
if (child->NodeType() == nsIDOMNode::TEXT_NODE &&
|
||||
child->HasTextNodeDirectionalityMap()) {
|
||||
nsTextNodeDirectionalityMap::ResetTextNodeDirection(static_cast<nsTextNode*>(child), nullptr);
|
||||
nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child);
|
||||
// Don't call nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child)
|
||||
// since ResetTextNodeDirection may have kept elements in child's
|
||||
// DirectionalityMap.
|
||||
}
|
||||
child = child->GetNextNode(aElement);
|
||||
}
|
||||
|
@ -147,6 +147,7 @@
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsDOMStringMap.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -3862,3 +3863,29 @@ Element::GetReferrerPolicyAsEnum()
|
||||
}
|
||||
return net::RP_Unset;
|
||||
}
|
||||
|
||||
already_AddRefed<nsDOMStringMap>
|
||||
Element::Dataset()
|
||||
{
|
||||
nsDOMSlots *slots = DOMSlots();
|
||||
|
||||
if (!slots->mDataset) {
|
||||
// mDataset is a weak reference so assignment will not AddRef.
|
||||
// AddRef is called before returning the pointer.
|
||||
slots->mDataset = new nsDOMStringMap(this);
|
||||
}
|
||||
|
||||
RefPtr<nsDOMStringMap> ret = slots->mDataset;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Element::ClearDataset()
|
||||
{
|
||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
||||
|
||||
MOZ_ASSERT(slots && slots->mDataset,
|
||||
"Slots should exist and dataset should not be null.");
|
||||
slots->mDataset = nullptr;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ class nsGlobalWindow;
|
||||
class nsICSSDeclaration;
|
||||
class nsISMILAttr;
|
||||
class nsDocument;
|
||||
class nsDOMStringMap;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -1142,6 +1143,16 @@ public:
|
||||
|
||||
net::ReferrerPolicy GetReferrerPolicyAsEnum();
|
||||
|
||||
/*
|
||||
* Helpers for .dataset. This is implemented on Element, though only some
|
||||
* sorts of elements expose it to JS as a .dataset property
|
||||
*/
|
||||
// Getter, to be called from bindings.
|
||||
already_AddRefed<nsDOMStringMap> Dataset();
|
||||
// Callback for destructor of dataset to ensure to null out our weak pointer
|
||||
// to it.
|
||||
void ClearDataset();
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Named-bools for use with SetAttrAndNotify to make call sites easier to
|
||||
|
@ -181,7 +181,7 @@ FileReader::GetResult(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
static NS_IMETHODIMP
|
||||
static NS_METHOD
|
||||
ReadFuncBinaryString(nsIInputStream* in,
|
||||
void* closure,
|
||||
const char* fromRawSegment,
|
||||
|
@ -496,7 +496,7 @@ class EncoderThreadPoolTerminator final : public nsIObserver
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHODIMP Observe(nsISupports *, const char *topic, const char16_t *) override
|
||||
NS_IMETHOD Observe(nsISupports *, const char *topic, const char16_t *) override
|
||||
{
|
||||
NS_ASSERTION(!strcmp(topic, "xpcom-shutdown-threads"),
|
||||
"Unexpected topic");
|
||||
|
@ -293,10 +293,10 @@ GetJSContext()
|
||||
}
|
||||
} // namespace danger
|
||||
|
||||
JSRuntime*
|
||||
GetJSRuntime()
|
||||
JS::RootingContext*
|
||||
RootingCx()
|
||||
{
|
||||
return CycleCollectedJSRuntime::Get()->Runtime();
|
||||
return CycleCollectedJSRuntime::Get()->RootingCx();
|
||||
}
|
||||
|
||||
AutoJSAPI::AutoJSAPI()
|
||||
@ -590,7 +590,8 @@ AutoJSAPI::ReportException()
|
||||
nsContentUtils::IsCallerChrome(),
|
||||
inner ? inner->WindowID() : 0);
|
||||
if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) {
|
||||
DispatchScriptErrorEvent(inner, JS_GetRuntime(cx()), xpcReport, exn);
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(cx());
|
||||
DispatchScriptErrorEvent(inner, rcx, xpcReport, exn);
|
||||
} else {
|
||||
JS::Rooted<JSObject*> stack(cx(),
|
||||
xpc::FindExceptionStackForConsoleReport(inner, exn));
|
||||
|
@ -136,7 +136,7 @@ JSContext* GetJSContext();
|
||||
|
||||
} // namespace danger
|
||||
|
||||
JSRuntime* GetJSRuntime();
|
||||
JS::RootingContext* RootingCx();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
class ScriptSettingsStackEntry {
|
||||
|
@ -79,6 +79,7 @@
|
||||
#include "nsContentDLF.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsCPrefetchService.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
@ -2790,7 +2791,10 @@ nsIPrincipal*
|
||||
nsContentUtils::ObjectPrincipal(JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(JS_GetObjectRuntime(aObj) == CycleCollectedJSRuntime::Get()->Runtime());
|
||||
|
||||
#ifdef DEBUG
|
||||
JS::AssertObjectBelongsToCurrentThread(aObj);
|
||||
#endif
|
||||
|
||||
// This is duplicated from nsScriptSecurityManager. We don't call through there
|
||||
// because the API unnecessarily requires a JSContext for historical reasons.
|
||||
@ -9275,3 +9279,100 @@ nsContentUtils::GetDocShellForEventTarget(EventTarget* aTarget)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: this function only relates to figuring out HTTPS state, which is an
|
||||
* input to the Secure Context algorithm. We are not actually implementing any
|
||||
* part of the Secure Context algorithm itself here.
|
||||
*
|
||||
* This is a bit of a hack. Ideally we'd propagate HTTPS state through
|
||||
* nsIChannel as described in the Fetch and HTML specs, but making channels
|
||||
* know about whether they should inherit HTTPS state, propagating information
|
||||
* about who the channel's "client" is, exposing GetHttpsState API on channels
|
||||
* and modifying the various cache implementations to store and retrieve HTTPS
|
||||
* state involves a huge amount of code (see bug 1220687). We avoid that for
|
||||
* now using this function.
|
||||
*
|
||||
* This function takes advantage of the observation that we can return true if
|
||||
* nsIContentSecurityManager::IsOriginPotentiallyTrustworthy returns true for
|
||||
* the document's origin (e.g. the origin has a scheme of 'https' or host
|
||||
* 'localhost' etc.). Since we generally propagate a creator document's origin
|
||||
* onto data:, blob:, etc. documents, this works for them too.
|
||||
*
|
||||
* The scenario where this observation breaks down is sandboxing without the
|
||||
* 'allow-same-origin' flag, since in this case a document is given a unique
|
||||
* origin (IsOriginPotentiallyTrustworthy would return false). We handle that
|
||||
* by using the origin that the document would have had had it not been
|
||||
* sandboxed.
|
||||
*
|
||||
* DEFICIENCIES: Note that this function uses nsIScriptSecurityManager's
|
||||
* getChannelResultPrincipalIfNotSandboxed, and that method's ignoring of
|
||||
* sandboxing is limited to the immediate sandbox. In the case that aDocument
|
||||
* should inherit its origin (e.g. data: URI) but its parent has ended up
|
||||
* with a unique origin due to sandboxing further up the parent chain we may
|
||||
* end up returning false when we would ideally return true (since we will
|
||||
* examine the parent's origin for 'https' and not finding it.) This means
|
||||
* that we may restrict the privileges of some pages unnecessarily in this
|
||||
* edge case.
|
||||
*/
|
||||
/* static */ bool
|
||||
nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument)
|
||||
{
|
||||
if (!aDocument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
|
||||
|
||||
if (principal->GetIsSystemPrincipal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If aDocument is sandboxed, try and get the principal that it would have
|
||||
// been given had it not been sandboxed:
|
||||
if (principal->GetIsNullPrincipal() &&
|
||||
(aDocument->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
|
||||
nsIChannel* channel = aDocument->GetChannel();
|
||||
if (channel) {
|
||||
nsCOMPtr<nsIScriptSecurityManager> ssm =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
nsresult rv =
|
||||
ssm->GetChannelResultPrincipalIfNotSandboxed(channel,
|
||||
getter_AddRefs(principal));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
if (principal->GetIsSystemPrincipal()) {
|
||||
// If a document with the system principal is sandboxing a subdocument
|
||||
// that would normally inherit the embedding element's principal (e.g.
|
||||
// a srcdoc document) then the embedding document does not trust the
|
||||
// content that is written to the embedded document. Unlike when the
|
||||
// embedding document is https, in this case we have no indication as
|
||||
// to whether the embedded document's contents are delivered securely
|
||||
// or not, and the sandboxing would possibly indicate that they were
|
||||
// not. To play it safe we return false here. (See bug 1162772
|
||||
// comment 73-80.)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (principal->GetIsNullPrincipal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal->GetIsCodebasePrincipal());
|
||||
|
||||
nsCOMPtr<nsIContentSecurityManager> csm =
|
||||
do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
|
||||
NS_WARN_IF(!csm);
|
||||
if (csm) {
|
||||
bool isTrustworthyOrigin = false;
|
||||
csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
|
||||
if (isTrustworthyOrigin) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1739,9 +1739,6 @@ public:
|
||||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
static JSContext *GetCurrentJSContextForThread();
|
||||
inline static JSContext *RootingCx() {
|
||||
return mozilla::dom::danger::GetJSContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive comparison between two strings. However it only ignores
|
||||
@ -2666,6 +2663,14 @@ public:
|
||||
*/
|
||||
static nsIDocShell* GetDocShellForEventTarget(mozilla::dom::EventTarget* aTarget);
|
||||
|
||||
/**
|
||||
* Returns true if the "HTTPS state" of the document should be "modern". See:
|
||||
*
|
||||
* https://html.spec.whatwg.org/#concept-document-https-state
|
||||
* https://fetch.spec.whatwg.org/#concept-response-https-state
|
||||
*/
|
||||
static bool HttpsStateIsModern(nsIDocument* aDocument);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
@ -1535,7 +1535,7 @@ public:
|
||||
explicit nsFrameLoaderDestroyRunnable(nsFrameLoader* aFrameLoader)
|
||||
: mFrameLoader(aFrameLoader), mPhase(eDestroyDocShell) {}
|
||||
|
||||
NS_IMETHODIMP Run() override;
|
||||
NS_IMETHOD Run() override;
|
||||
};
|
||||
|
||||
void
|
||||
@ -2735,8 +2735,10 @@ class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
|
||||
public Runnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToChild(JSContext* aCx, JS::Handle<JSObject*> aCpows, nsFrameLoader* aFrameLoader)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
nsAsyncMessageToChild(JS::RootingContext* aRootingCx,
|
||||
JS::Handle<JSObject*> aCpows,
|
||||
nsFrameLoader* aFrameLoader)
|
||||
: nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
|
||||
, mFrameLoader(aFrameLoader)
|
||||
{
|
||||
}
|
||||
@ -2786,8 +2788,9 @@ nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
|
||||
}
|
||||
|
||||
if (mChildMessageManager) {
|
||||
RefPtr<nsAsyncMessageToChild> ev = new nsAsyncMessageToChild(aCx, aCpows, this);
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(aCx);
|
||||
RefPtr<nsAsyncMessageToChild> ev = new nsAsyncMessageToChild(rcx, aCpows, this);
|
||||
nsresult rv = ev->Init(aMessage, aData, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1711,8 +1711,8 @@ nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
|
||||
return;
|
||||
}
|
||||
|
||||
JSRuntime* rt = CycleCollectedJSRuntime::Get()->Runtime();
|
||||
JS::Rooted<JSScript*> script(rt);
|
||||
JS::RootingContext* rcx = RootingCx();
|
||||
JS::Rooted<JSScript*> script(rcx);
|
||||
|
||||
nsMessageManagerScriptHolder* holder = sCachedScripts->Get(aURL);
|
||||
if (holder && holder->WillRunInGlobalScope() == aRunInGlobalScope) {
|
||||
@ -1725,7 +1725,7 @@ nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
|
||||
shouldCache, &script);
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(rt, mGlobal->GetJSObject());
|
||||
JS::Rooted<JSObject*> global(rcx, mGlobal->GetJSObject());
|
||||
if (global) {
|
||||
AutoEntryScript aes(global, "message manager script load");
|
||||
JSContext* cx = aes.cx();
|
||||
@ -1845,7 +1845,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
const nsAString& aURL,
|
||||
bool aRunInGlobalScope)
|
||||
{
|
||||
JS::Rooted<JSScript*> script(nsContentUtils::RootingCx());
|
||||
JS::Rooted<JSScript*> script(RootingCx());
|
||||
TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
|
||||
}
|
||||
|
||||
@ -1914,8 +1914,9 @@ class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
|
||||
public Runnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessChild(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
nsAsyncMessageToSameProcessChild(JS::RootingContext* aRootingCx,
|
||||
JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
|
||||
{ }
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
@ -1956,10 +1957,11 @@ public:
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override
|
||||
{
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(aCx);
|
||||
RefPtr<nsAsyncMessageToSameProcessChild> ev =
|
||||
new nsAsyncMessageToSameProcessChild(aCx, aCpows);
|
||||
new nsAsyncMessageToSameProcessChild(rcx, aCpows);
|
||||
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
nsresult rv = ev->Init(aMessage, aData, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -2073,8 +2075,9 @@ class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
|
||||
public SameProcessMessageQueue::Runnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessParent(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
nsAsyncMessageToSameProcessParent(JS::RootingContext* aRootingCx,
|
||||
JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
|
||||
{ }
|
||||
virtual nsresult HandleMessage() override
|
||||
{
|
||||
@ -2111,7 +2114,7 @@ public:
|
||||
queue->Flush();
|
||||
|
||||
if (nsFrameMessageManager::sSameProcessParentManager) {
|
||||
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
|
||||
SameProcessCpowHolder cpows(JS::RootingContext::get(aCx), aCpows);
|
||||
RefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, aMessage,
|
||||
true, &aData, &cpows, aPrincipal, aRetVal);
|
||||
@ -2126,9 +2129,10 @@ public:
|
||||
nsIPrincipal* aPrincipal) override
|
||||
{
|
||||
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(aCx);
|
||||
RefPtr<nsAsyncMessageToSameProcessParent> ev =
|
||||
new nsAsyncMessageToSameProcessParent(aCx, aCpows);
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
new nsAsyncMessageToSameProcessParent(rcx, aCpows);
|
||||
nsresult rv = ev->Init(aMessage, aData, aPrincipal);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
@ -2226,15 +2230,18 @@ nsFrameMessageManager::MarkForCC()
|
||||
return true;
|
||||
}
|
||||
|
||||
nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: mRuntime(nullptr)
|
||||
, mCpows(aCx, aCpows)
|
||||
nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
|
||||
JS::Handle<JSObject*> aCpows)
|
||||
: mRootingCx(aRootingCx)
|
||||
, mCpows(aRootingCx, aCpows)
|
||||
#ifdef DEBUG
|
||||
, mCalledInit(false)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
|
||||
nsresult
|
||||
nsSameProcessAsyncMessageBase::Init(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
nsSameProcessAsyncMessageBase::Init(const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
@ -2243,9 +2250,11 @@ nsSameProcessAsyncMessageBase::Init(JSContext* aCx,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mRuntime = js::GetRuntime(aCx);
|
||||
mMessage = aMessage;
|
||||
mPrincipal = aPrincipal;
|
||||
#ifdef DEBUG
|
||||
mCalledInit = true;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2256,9 +2265,9 @@ nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
|
||||
nsFrameMessageManager* aManager)
|
||||
{
|
||||
// Make sure that we have called Init() and it has succeeded.
|
||||
MOZ_ASSERT(mRuntime);
|
||||
MOZ_ASSERT(mCalledInit);
|
||||
if (aManager) {
|
||||
SameProcessCpowHolder cpows(mRuntime, mCpows);
|
||||
SameProcessCpowHolder cpows(mRootingCx, mCpows);
|
||||
|
||||
RefPtr<nsFrameMessageManager> mm = aManager;
|
||||
mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mData,
|
||||
|
@ -145,8 +145,8 @@ struct nsMessageListenerInfo
|
||||
class MOZ_STACK_CLASS SameProcessCpowHolder : public mozilla::jsipc::CpowHolder
|
||||
{
|
||||
public:
|
||||
SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject*> aObj)
|
||||
: mObj(aRuntime, aObj)
|
||||
SameProcessCpowHolder(JS::RootingContext* aRootingCx, JS::Handle<JSObject*> aObj)
|
||||
: mObj(aRootingCx, aObj)
|
||||
{
|
||||
}
|
||||
|
||||
@ -338,9 +338,9 @@ class nsSameProcessAsyncMessageBase
|
||||
public:
|
||||
typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
|
||||
|
||||
nsSameProcessAsyncMessageBase(JSContext* aCx, JS::Handle<JSObject*> aCpows);
|
||||
nsresult Init(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
nsSameProcessAsyncMessageBase(JS::RootingContext* aRootingCx,
|
||||
JS::Handle<JSObject*> aCpows);
|
||||
nsresult Init(const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
@ -349,11 +349,14 @@ public:
|
||||
private:
|
||||
nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
|
||||
|
||||
JSRuntime* mRuntime;
|
||||
JS::RootingContext* mRootingCx;
|
||||
nsString mMessage;
|
||||
StructuredCloneData mData;
|
||||
JS::PersistentRooted<JSObject*> mCpows;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
#ifdef DEBUG
|
||||
bool mCalledInit;
|
||||
#endif
|
||||
};
|
||||
|
||||
class nsScriptCacheCleaner;
|
||||
@ -425,9 +428,9 @@ class nsScriptCacheCleaner final : public nsIObserver
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData) override
|
||||
NS_IMETHOD Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData) override
|
||||
{
|
||||
if (strcmp("message-manager-flush-caches", aTopic) == 0) {
|
||||
nsMessageManagerScriptExecutor::PurgeCache();
|
||||
|