зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
d4554b4873
|
@ -11,15 +11,6 @@
|
||||||
# Exclude expected objdirs.
|
# Exclude expected objdirs.
|
||||||
obj*/**
|
obj*/**
|
||||||
|
|
||||||
# We ignore all these directories by default, until we get them enabled.
|
|
||||||
# If you are enabling a directory, please add directory specific exclusions
|
|
||||||
# below.
|
|
||||||
layout/**
|
|
||||||
netwerk/cookie/test/browser/**
|
|
||||||
netwerk/test/browser/**
|
|
||||||
netwerk/test/mochitests/**
|
|
||||||
netwerk/test/unit*/**
|
|
||||||
|
|
||||||
# We currently have no js files in these directories, so we ignore them by
|
# We currently have no js files in these directories, so we ignore them by
|
||||||
# default to aid ESLint's performance.
|
# default to aid ESLint's performance.
|
||||||
build/**
|
build/**
|
||||||
|
|
144
.eslintrc.js
144
.eslintrc.js
|
@ -193,5 +193,149 @@ module.exports = {
|
||||||
"space-before-function-paren": "off",
|
"space-before-function-paren": "off",
|
||||||
"space-infix-ops": "off",
|
"space-infix-ops": "off",
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"files": [
|
||||||
|
"netwerk/cookie/test/browser/**",
|
||||||
|
"netwerk/test/browser/**",
|
||||||
|
"netwerk/test/mochitests/**",
|
||||||
|
"netwerk/test/unit*/**",
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"object-shorthand": "off",
|
||||||
|
"mozilla/consistent-if-bracing": "off",
|
||||||
|
"mozilla/reject-importGlobalProperties": "off",
|
||||||
|
"mozilla/no-arbitrary-setTimeout": "off",
|
||||||
|
"mozilla/no-define-cc-etc": "off",
|
||||||
|
"mozilla/no-useless-parameters": "off",
|
||||||
|
"mozilla/no-useless-run-test": "off",
|
||||||
|
"mozilla/use-chromeutils-generateqi": "off",
|
||||||
|
"mozilla/use-chromeutils-import": "off",
|
||||||
|
"mozilla/use-default-preference-values": "off",
|
||||||
|
"mozilla/use-services": "off",
|
||||||
|
"consistent-return": "off",
|
||||||
|
"no-array-constructor": "off",
|
||||||
|
"no-extra-boolean-cast": "off",
|
||||||
|
"no-eval": "off",
|
||||||
|
"no-else-return": "off",
|
||||||
|
"no-global-assign": "off",
|
||||||
|
"no-lonely-if": "off",
|
||||||
|
"no-nested-ternary": "off",
|
||||||
|
"no-new-wrappers": "off",
|
||||||
|
"no-redeclare": "off",
|
||||||
|
"no-return-await": "off",
|
||||||
|
"no-sequences": "off",
|
||||||
|
"no-shadow": "off",
|
||||||
|
"no-throw-literal": "off",
|
||||||
|
"no-undef": "off",
|
||||||
|
"no-unreachable": "off",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"no-useless-return": "off",
|
||||||
|
|
||||||
|
// Not enabling the rules below for now pending prettier roll-out.
|
||||||
|
"arrow-spacing": "off",
|
||||||
|
"block-spacing": "off",
|
||||||
|
"brace-style": "off",
|
||||||
|
"comma-dangle": "off",
|
||||||
|
"comma-spacing": "off",
|
||||||
|
"comma-style": "off",
|
||||||
|
"eol-last": "off",
|
||||||
|
"func-call-spacing": "off",
|
||||||
|
"generator-star-spacing": "off",
|
||||||
|
"key-spacing": "off",
|
||||||
|
"keyword-spacing": "off",
|
||||||
|
"no-extra-semi": "off",
|
||||||
|
"no-tabs": "off",
|
||||||
|
"no-mixed-spaces-and-tabs": "off",
|
||||||
|
"no-multi-spaces": "off",
|
||||||
|
"no-trailing-spaces": "off",
|
||||||
|
"no-whitespace-before-property": "off",
|
||||||
|
"padded-blocks": "off",
|
||||||
|
"quotes": "off",
|
||||||
|
"rest-spread-spacing": "off",
|
||||||
|
"semi": "off",
|
||||||
|
"space-before-blocks": "off",
|
||||||
|
"space-before-function-paren": "off",
|
||||||
|
"space-infix-ops": "off",
|
||||||
|
"space-unary-ops": "off",
|
||||||
|
"spaced-comment": "off",
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"files": [
|
||||||
|
"layout/**",
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"object-shorthand": "off",
|
||||||
|
"mozilla/avoid-removeChild": "off",
|
||||||
|
"mozilla/consistent-if-bracing": "off",
|
||||||
|
"mozilla/reject-importGlobalProperties": "off",
|
||||||
|
"mozilla/no-arbitrary-setTimeout": "off",
|
||||||
|
"mozilla/no-define-cc-etc": "off",
|
||||||
|
"mozilla/no-useless-parameters": "off",
|
||||||
|
"mozilla/no-useless-run-test": "off",
|
||||||
|
"mozilla/use-chromeutils-generateqi": "off",
|
||||||
|
"mozilla/use-chromeutils-import": "off",
|
||||||
|
"mozilla/use-default-preference-values": "off",
|
||||||
|
"mozilla/use-includes-instead-of-indexOf": "off",
|
||||||
|
"mozilla/use-services": "off",
|
||||||
|
"mozilla/use-ownerGlobal": "off",
|
||||||
|
"complexity": "off",
|
||||||
|
"consistent-return": "off",
|
||||||
|
"dot-notation": "off",
|
||||||
|
"no-array-constructor": "off",
|
||||||
|
"no-caller": "off",
|
||||||
|
"no-cond-assign": "off",
|
||||||
|
"no-extra-boolean-cast": "off",
|
||||||
|
"no-eval": "off",
|
||||||
|
"no-else-return": "off",
|
||||||
|
"no-func-assign": "off",
|
||||||
|
"no-global-assign": "off",
|
||||||
|
"no-implied-eval": "off",
|
||||||
|
"no-lonely-if": "off",
|
||||||
|
"no-nested-ternary": "off",
|
||||||
|
"no-new-wrappers": "off",
|
||||||
|
"no-redeclare": "off",
|
||||||
|
"no-restricted-globals": "off",
|
||||||
|
"no-return-await": "off",
|
||||||
|
"no-sequences": "off",
|
||||||
|
"no-throw-literal": "off",
|
||||||
|
"no-useless-concat": "off",
|
||||||
|
"no-undef": "off",
|
||||||
|
"no-unreachable": "off",
|
||||||
|
"no-unsanitized/method": "off",
|
||||||
|
"no-unsanitized/property": "off",
|
||||||
|
"no-unsafe-negation": "off",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"no-useless-return": "off",
|
||||||
|
|
||||||
|
// Not enabling the rules below for now pending prettier roll-out.
|
||||||
|
"arrow-spacing": "off",
|
||||||
|
"block-spacing": "off",
|
||||||
|
"brace-style": "off",
|
||||||
|
"comma-dangle": "off",
|
||||||
|
"comma-spacing": "off",
|
||||||
|
"comma-style": "off",
|
||||||
|
"eol-last": "off",
|
||||||
|
"func-call-spacing": "off",
|
||||||
|
"generator-star-spacing": "off",
|
||||||
|
"linebreak-style": "off",
|
||||||
|
"key-spacing": "off",
|
||||||
|
"keyword-spacing": "off",
|
||||||
|
"no-extra-semi": "off",
|
||||||
|
"no-tabs": "off",
|
||||||
|
"no-mixed-spaces-and-tabs": "off",
|
||||||
|
"no-multi-spaces": "off",
|
||||||
|
"no-trailing-spaces": "off",
|
||||||
|
"no-unexpected-multiline": "off",
|
||||||
|
"no-whitespace-before-property": "off",
|
||||||
|
"padded-blocks": "off",
|
||||||
|
"quotes": "off",
|
||||||
|
"rest-spread-spacing": "off",
|
||||||
|
"semi": "off",
|
||||||
|
"space-before-blocks": "off",
|
||||||
|
"space-before-function-paren": "off",
|
||||||
|
"space-infix-ops": "off",
|
||||||
|
"space-unary-ops": "off",
|
||||||
|
"spaced-comment": "off",
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
|
@ -742,8 +742,7 @@ void Accessible::TakeFocus() const {
|
||||||
|
|
||||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
if (fm) {
|
if (fm) {
|
||||||
AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr,
|
AutoHandlingUserInputStatePusher inputStatePusher(true);
|
||||||
focusContent->OwnerDoc());
|
|
||||||
// XXXbz: Can we actually have a non-element content here?
|
// XXXbz: Can we actually have a non-element content here?
|
||||||
RefPtr<Element> element =
|
RefPtr<Element> element =
|
||||||
focusContent->IsElement() ? focusContent->AsElement() : nullptr;
|
focusContent->IsElement() ? focusContent->AsElement() : nullptr;
|
||||||
|
|
|
@ -294,8 +294,7 @@ void DocAccessible::TakeFocus() const {
|
||||||
// Focus the document.
|
// Focus the document.
|
||||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
RefPtr<dom::Element> newFocus;
|
RefPtr<dom::Element> newFocus;
|
||||||
AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr,
|
AutoHandlingUserInputStatePusher inputStatePusher(true);
|
||||||
mDocumentNode);
|
|
||||||
fm->MoveFocus(mDocumentNode->GetWindow(), nullptr,
|
fm->MoveFocus(mDocumentNode->GetWindow(), nullptr,
|
||||||
nsFocusManager::MOVEFOCUS_ROOT, 0, getter_AddRefs(newFocus));
|
nsFocusManager::MOVEFOCUS_ROOT, 0, getter_AddRefs(newFocus));
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,9 +498,16 @@ pref("browser.tabs.showAudioPlayingIcon", true);
|
||||||
// This should match Chromium's audio indicator delay.
|
// This should match Chromium's audio indicator delay.
|
||||||
pref("browser.tabs.delayHidingAudioPlayingIconMS", 3000);
|
pref("browser.tabs.delayHidingAudioPlayingIconMS", 3000);
|
||||||
|
|
||||||
// Pref to control whether we use separate privileged content processes.
|
|
||||||
#if defined(NIGHTLY_BUILD) && !defined(MOZ_ASAN)
|
#if defined(NIGHTLY_BUILD) && !defined(MOZ_ASAN)
|
||||||
|
// Pref to control whether we use a separate privileged content process
|
||||||
|
// for about: pages. This pref name did not age well: we will have multiple
|
||||||
|
// types of privileged content processes, each with different privileges.
|
||||||
|
// types of privleged content processes, each with different privleges.
|
||||||
pref("browser.tabs.remote.separatePrivilegedContentProcess", true);
|
pref("browser.tabs.remote.separatePrivilegedContentProcess", true);
|
||||||
|
// Pref to control whether we use a separate privileged content process
|
||||||
|
// for certain mozilla webpages (which are listed in the pref
|
||||||
|
// browser.tabs.remote.separatedMozillaDomains).
|
||||||
|
pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
|
|
|
@ -977,7 +977,7 @@ var gIdentityHandler = {
|
||||||
let ctx = canvas.getContext("2d");
|
let ctx = canvas.getContext("2d");
|
||||||
ctx.font = `${14 * scale}px sans-serif`;
|
ctx.font = `${14 * scale}px sans-serif`;
|
||||||
ctx.fillText(`${value}`, 20 * scale, 14 * scale);
|
ctx.fillText(`${value}`, 20 * scale, 14 * scale);
|
||||||
let tabIcon = document.getAnonymousElementByAttribute(gBrowser.selectedTab, "anonid", "tab-icon-image");
|
let tabIcon = gBrowser.selectedTab.iconImage;
|
||||||
let image = new Image();
|
let image = new Image();
|
||||||
image.src = tabIcon.src;
|
image.src = tabIcon.src;
|
||||||
ctx.drawImage(image, 0, 0, 16 * scale, 16 * scale);
|
ctx.drawImage(image, 0, 0, 16 * scale, 16 * scale);
|
||||||
|
|
|
@ -158,10 +158,6 @@ panelview[mainview] > .panel-header {
|
||||||
visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
|
visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabbrowser-tab {
|
|
||||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabbrowser-tab:not([pinned]) {
|
.tabbrowser-tab:not([pinned]) {
|
||||||
-moz-box-flex: 100;
|
-moz-box-flex: 100;
|
||||||
max-width: 225px;
|
max-width: 225px;
|
||||||
|
|
|
@ -96,6 +96,7 @@
|
||||||
Services.scriptloader.loadSubScript("chrome://browser/content/browser-sidebar.js", this);
|
Services.scriptloader.loadSubScript("chrome://browser/content/browser-sidebar.js", this);
|
||||||
Services.scriptloader.loadSubScript("chrome://browser/content/browser-tabsintitlebar.js", this);
|
Services.scriptloader.loadSubScript("chrome://browser/content/browser-tabsintitlebar.js", this);
|
||||||
Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser.js", this);
|
Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser.js", this);
|
||||||
|
Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser-tab.js", this);
|
||||||
Services.scriptloader.loadSubScript("chrome://browser/content/search/autocomplete-popup.js", this);
|
Services.scriptloader.loadSubScript("chrome://browser/content/search/autocomplete-popup.js", this);
|
||||||
Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this);
|
Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this);
|
||||||
|
|
||||||
|
@ -728,7 +729,7 @@
|
||||||
setfocus="false"
|
setfocus="false"
|
||||||
tooltip="tabbrowser-tab-tooltip"
|
tooltip="tabbrowser-tab-tooltip"
|
||||||
stopwatchid="FX_TAB_CLICK_MS">
|
stopwatchid="FX_TAB_CLICK_MS">
|
||||||
<tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
|
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
|
||||||
</tabs>
|
</tabs>
|
||||||
|
|
||||||
<toolbarbutton id="new-tab-button"
|
<toolbarbutton id="new-tab-button"
|
||||||
|
|
|
@ -63,12 +63,6 @@ addEventListener("DOMInputPasswordAdded", function(event) {
|
||||||
let formLike = LoginFormFactory.createFromField(event.originalTarget);
|
let formLike = LoginFormFactory.createFromField(event.originalTarget);
|
||||||
InsecurePasswordUtils.reportInsecurePasswords(formLike);
|
InsecurePasswordUtils.reportInsecurePasswords(formLike);
|
||||||
});
|
});
|
||||||
addEventListener("DOMAutoComplete", function(event) {
|
|
||||||
if (shouldIgnoreLoginManagerEvent(event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoginManagerContent.onDOMAutoComplete(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
ContentMetaHandler.init(this);
|
ContentMetaHandler.init(this);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,574 @@
|
||||||
|
/* 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 is loaded into chrome windows with the subscript loader. Wrap in
|
||||||
|
// a block to prevent accidentally leaking globals onto `window`.
|
||||||
|
{
|
||||||
|
class MozTabbrowserTab extends MozElements.MozTab {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.addEventListener("mouseover", (event) => {
|
||||||
|
if (event.originalTarget.classList.contains("tab-close-button")) {
|
||||||
|
this.mOverCloseButton = true;
|
||||||
|
}
|
||||||
|
this._mouseenter();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("mouseout", (event) => {
|
||||||
|
if (event.originalTarget.classList.contains("tab-close-button")) {
|
||||||
|
this.mOverCloseButton = false;
|
||||||
|
}
|
||||||
|
this._mouseleave();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("dragstart", (event) => {
|
||||||
|
this.style.MozUserFocus = "";
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
this.addEventListener("dragstart", (event) => {
|
||||||
|
if (this.mOverCloseButton) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("mousedown", (event) => {
|
||||||
|
let tabContainer = this.parentNode;
|
||||||
|
|
||||||
|
if (tabContainer._closeTabByDblclick &&
|
||||||
|
event.button == 0 &&
|
||||||
|
event.detail == 1) {
|
||||||
|
this._selectedOnFirstMouseDown = this.selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selected) {
|
||||||
|
this.style.MozUserFocus = "ignore";
|
||||||
|
} else if (event.originalTarget.classList.contains("tab-close-button") ||
|
||||||
|
event.originalTarget.classList.contains("tab-icon-sound") ||
|
||||||
|
event.originalTarget.classList.contains("tab-icon-overlay")) {
|
||||||
|
// Prevent tabbox.xml from selecting the tab.
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.button == 1) {
|
||||||
|
gBrowser.warmupTab(gBrowser._findTabToBlurTo(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.button == 0 && tabContainer._multiselectEnabled) {
|
||||||
|
let shiftKey = event.shiftKey;
|
||||||
|
let accelKey = event.getModifierState("Accel");
|
||||||
|
if (shiftKey) {
|
||||||
|
const lastSelectedTab = gBrowser.lastMultiSelectedTab;
|
||||||
|
if (!accelKey) {
|
||||||
|
gBrowser.selectedTab = lastSelectedTab;
|
||||||
|
|
||||||
|
// Make sure selection is cleared when tab-switch doesn't happen.
|
||||||
|
gBrowser.clearMultiSelectedTabs(false);
|
||||||
|
}
|
||||||
|
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
|
||||||
|
|
||||||
|
// Prevent tabbox.xml from selecting the tab.
|
||||||
|
event.stopPropagation();
|
||||||
|
} else if (accelKey) {
|
||||||
|
// Ctrl (Cmd for mac) key is pressed
|
||||||
|
if (this.multiselected) {
|
||||||
|
gBrowser.removeFromMultiSelectedTabs(this, true);
|
||||||
|
} else if (this != gBrowser.selectedTab) {
|
||||||
|
gBrowser.addToMultiSelectedTabs(this, false);
|
||||||
|
gBrowser.lastMultiSelectedTab = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent tabbox.xml from selecting the tab.
|
||||||
|
event.stopPropagation();
|
||||||
|
} else if (!this.selected && this.multiselected) {
|
||||||
|
gBrowser.lockClearMultiSelectionOnce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
this.addEventListener("mouseup", (event) => {
|
||||||
|
// Make sure that clear-selection is released.
|
||||||
|
// Otherwise selection using Shift key may be broken.
|
||||||
|
gBrowser.unlockClearMultiSelection();
|
||||||
|
|
||||||
|
this.style.MozUserFocus = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("click", (event) => {
|
||||||
|
if (event.button != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getModifierState("Accel") || event.shiftKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gBrowser.multiSelectedTabsCount > 0 &&
|
||||||
|
!event.originalTarget.classList.contains("tab-close-button") &&
|
||||||
|
!event.originalTarget.classList.contains("tab-icon-sound") &&
|
||||||
|
!event.originalTarget.classList.contains("tab-icon-overlay")) {
|
||||||
|
// Tabs were previously multi-selected and user clicks on a tab
|
||||||
|
// without holding Ctrl/Cmd Key
|
||||||
|
|
||||||
|
// Force positional attributes to update when the
|
||||||
|
// target (of the click) is the "active" tab.
|
||||||
|
let updatePositionalAttr = gBrowser.selectedTab == this;
|
||||||
|
|
||||||
|
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.originalTarget.classList.contains("tab-icon-sound") ||
|
||||||
|
(event.originalTarget.classList.contains("tab-icon-overlay") &&
|
||||||
|
(event.originalTarget.hasAttribute("soundplaying") ||
|
||||||
|
event.originalTarget.hasAttribute("muted") ||
|
||||||
|
event.originalTarget.hasAttribute("activemedia-blocked")))) {
|
||||||
|
if (this.multiselected) {
|
||||||
|
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
|
||||||
|
} else {
|
||||||
|
this.toggleMuteAudio();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.originalTarget.classList.contains("tab-close-button")) {
|
||||||
|
if (this.multiselected) {
|
||||||
|
gBrowser.removeMultiSelectedTabs();
|
||||||
|
} else {
|
||||||
|
gBrowser.removeTab(this, {
|
||||||
|
animate: true,
|
||||||
|
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// This enables double-click protection for the tab container
|
||||||
|
// (see tabbrowser-tabs 'click' handler).
|
||||||
|
gBrowser.tabContainer._blockDblClick = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("dblclick", (event) => {
|
||||||
|
if (event.button != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for the one-close-button case
|
||||||
|
if (event.originalTarget.classList.contains("tab-close-button")) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabContainer = this.parentNode;
|
||||||
|
if (tabContainer._closeTabByDblclick &&
|
||||||
|
this._selectedOnFirstMouseDown &&
|
||||||
|
this.selected &&
|
||||||
|
!(event.originalTarget.classList.contains("tab-icon-sound") ||
|
||||||
|
event.originalTarget.classList.contains("tab-icon-overlay"))) {
|
||||||
|
gBrowser.removeTab(this, {
|
||||||
|
animate: true,
|
||||||
|
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
this.addEventListener("animationend", (event) => {
|
||||||
|
if (event.originalTarget.classList.contains("tab-loading-burst")) {
|
||||||
|
this.removeAttribute("bursting");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._selectedOnFirstMouseDown = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how the tab ended up in this mute state. May be any of:
|
||||||
|
*
|
||||||
|
* - undefined: The tabs mute state has never changed.
|
||||||
|
* - null: The mute state was last changed through the UI.
|
||||||
|
* - Any string: The ID was changed through an extension API. The string
|
||||||
|
* must be the ID of the extension which changed it.
|
||||||
|
*/
|
||||||
|
this.muteReason = undefined;
|
||||||
|
|
||||||
|
this.mOverCloseButton = false;
|
||||||
|
|
||||||
|
this.mCorrespondingMenuitem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get inheritedAttributes() {
|
||||||
|
return {
|
||||||
|
".tab-background": "selected=visuallyselected,fadein,multiselected",
|
||||||
|
".tab-line": "selected=visuallyselected,multiselected,before-multiselected",
|
||||||
|
".tab-loading-burst": "pinned,bursting,notselectedsinceload",
|
||||||
|
".tab-content": "pinned,selected=visuallyselected,titlechanged,attention",
|
||||||
|
".tab-throbber": "fadein,pinned,busy,progress,selected=visuallyselected",
|
||||||
|
".tab-icon-pending": "fadein,pinned,busy,progress,selected=visuallyselected,pendingicon",
|
||||||
|
".tab-icon-image": "src=image,triggeringprincipal=iconloadingprincipal,requestcontextid,fadein,pinned,selected=visuallyselected,busy,crashed,sharing",
|
||||||
|
".tab-sharing-icon-overlay": "sharing,selected=visuallyselected,pinned",
|
||||||
|
".tab-icon-overlay": "crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked",
|
||||||
|
".tab-label-container": "pinned,selected=visuallyselected,labeldirection",
|
||||||
|
".tab-label": "text=label,accesskey,fadein,pinned,selected=visuallyselected,attention",
|
||||||
|
".tab-icon-pip": "pictureinpicture",
|
||||||
|
".tab-icon-sound": "soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked,pictureinpicture",
|
||||||
|
".tab-close-button": "fadein,pinned,selected=visuallyselected",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get fragment() {
|
||||||
|
if (!this._fragment) {
|
||||||
|
this._fragment = MozXULElement.parseXULToFragment(`
|
||||||
|
<stack class="tab-stack" flex="1">
|
||||||
|
<vbox class="tab-background">
|
||||||
|
<hbox class="tab-line"></hbox>
|
||||||
|
<spacer flex="1" class="tab-background-inner"></spacer>
|
||||||
|
<hbox class="tab-bottom-line"></hbox>
|
||||||
|
</vbox>
|
||||||
|
<hbox class="tab-loading-burst"></hbox>
|
||||||
|
<hbox class="tab-content" align="center">
|
||||||
|
<hbox class="tab-throbber" layer="true"></hbox>
|
||||||
|
<hbox class="tab-icon-pending"></hbox>
|
||||||
|
<image class="tab-icon-image" validate="never" role="presentation"></image>
|
||||||
|
<image class="tab-sharing-icon-overlay" role="presentation"></image>
|
||||||
|
<image class="tab-icon-overlay" role="presentation"></image>
|
||||||
|
<hbox class="tab-label-container"
|
||||||
|
onoverflow="this.setAttribute('textoverflow', 'true');"
|
||||||
|
onunderflow="this.removeAttribute('textoverflow');"
|
||||||
|
flex="1">
|
||||||
|
<label class="tab-text tab-label" role="presentation"></label>
|
||||||
|
</hbox>
|
||||||
|
<image class="tab-icon-pip"
|
||||||
|
role="presentation"></image>
|
||||||
|
<image class="tab-icon-sound" role="presentation"></image>
|
||||||
|
<image class="tab-close-button close-icon" role="presentation"></image>
|
||||||
|
</hbox>
|
||||||
|
</stack>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
return this.ownerDocument.importNode(this._fragment, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
if (this._initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textContent = "";
|
||||||
|
this.appendChild(this.fragment);
|
||||||
|
this.initializeAttributeInheritance();
|
||||||
|
this.setAttribute("context", "tabContextMenu");
|
||||||
|
this._initialized = true;
|
||||||
|
|
||||||
|
if (!("_lastAccessed" in this)) {
|
||||||
|
this.updateLastAccessed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set _visuallySelected(val) {
|
||||||
|
if (val == (this.getAttribute("visuallyselected") == "true")) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
this.setAttribute("visuallyselected", "true");
|
||||||
|
} else {
|
||||||
|
this.removeAttribute("visuallyselected");
|
||||||
|
}
|
||||||
|
gBrowser._tabAttrModified(this, ["visuallyselected"]);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
set _selected(val) {
|
||||||
|
// in e10s we want to only pseudo-select a tab before its rendering is done, so that
|
||||||
|
// the rest of the system knows that the tab is selected, but we don't want to update its
|
||||||
|
// visual status to selected until after we receive confirmation that its content has painted.
|
||||||
|
if (val)
|
||||||
|
this.setAttribute("selected", "true");
|
||||||
|
else
|
||||||
|
this.removeAttribute("selected");
|
||||||
|
|
||||||
|
// If we're non-e10s we should update the visual selection as well at the same time,
|
||||||
|
// *or* if we're e10s and the visually selected tab isn't changing, in which case the
|
||||||
|
// tab switcher code won't run and update anything else (like the before- and after-
|
||||||
|
// selected attributes).
|
||||||
|
if (!gMultiProcessBrowser || (val && this.hasAttribute("visuallyselected"))) {
|
||||||
|
this._visuallySelected = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
get pinned() {
|
||||||
|
return this.getAttribute("pinned") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get hidden() {
|
||||||
|
return this.getAttribute("hidden") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get muted() {
|
||||||
|
return this.getAttribute("muted") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get multiselected() {
|
||||||
|
return this.getAttribute("multiselected") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get beforeMultiselected() {
|
||||||
|
return this.getAttribute("before-multiselected") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get userContextId() {
|
||||||
|
return this.hasAttribute("usercontextid") ?
|
||||||
|
parseInt(this.getAttribute("usercontextid")) :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get soundPlaying() {
|
||||||
|
return this.getAttribute("soundplaying") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get pictureinpicture() {
|
||||||
|
return this.getAttribute("pictureinpicture") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeMediaBlocked() {
|
||||||
|
return this.getAttribute("activemedia-blocked") == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
get isEmpty() {
|
||||||
|
// Determines if a tab is "empty", usually used in the context of determining
|
||||||
|
// if it's ok to close the tab.
|
||||||
|
if (this.hasAttribute("busy"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.hasAttribute("customizemode"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let browser = this.linkedBrowser;
|
||||||
|
if (!isBlankPageURL(browser.currentURI.spec))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!checkEmptyPageOrigin(browser))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (browser.canGoForward || browser.canGoBack)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastAccessed() {
|
||||||
|
return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _overPlayingIcon() {
|
||||||
|
let iconVisible = this.hasAttribute("soundplaying") ||
|
||||||
|
this.hasAttribute("muted") ||
|
||||||
|
this.hasAttribute("activemedia-blocked");
|
||||||
|
|
||||||
|
let soundPlayingIcon = this.soundPlayingIcon;
|
||||||
|
let overlayIcon = this.overlayIcon;
|
||||||
|
return soundPlayingIcon && soundPlayingIcon.matches(":hover") ||
|
||||||
|
(overlayIcon && overlayIcon.matches(":hover") && iconVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
get soundPlayingIcon() {
|
||||||
|
return this.querySelector(".tab-icon-sound");
|
||||||
|
}
|
||||||
|
|
||||||
|
get overlayIcon() {
|
||||||
|
return this.querySelector(".tab-icon-overlay");
|
||||||
|
}
|
||||||
|
|
||||||
|
get throbber() {
|
||||||
|
return this.querySelector(".tab-throbber");
|
||||||
|
}
|
||||||
|
|
||||||
|
get iconImage() {
|
||||||
|
return this.querySelector(".tab-icon-image");
|
||||||
|
}
|
||||||
|
|
||||||
|
get sharingIcon() {
|
||||||
|
return this.querySelector(".tab-sharing-icon-overlay");
|
||||||
|
}
|
||||||
|
|
||||||
|
get textLabel() {
|
||||||
|
return this.querySelector(".tab-label");
|
||||||
|
}
|
||||||
|
|
||||||
|
get closeButton() {
|
||||||
|
return this.querySelector(".tab-close-button");
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLastAccessed(aDate) {
|
||||||
|
this._lastAccessed = this.selected ? Infinity : (aDate || Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While it would make sense to track this in a field, the field will get nuked
|
||||||
|
* once the node is gone from the DOM, which causes us to think the tab is not
|
||||||
|
* closed, which causes us to make wrong decisions. So we use an expando instead.
|
||||||
|
* <field name="closing">false</field>
|
||||||
|
*/
|
||||||
|
_mouseenter() {
|
||||||
|
if (this.hidden || this.closing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabContainer = this.parentNode;
|
||||||
|
let visibleTabs = tabContainer._getVisibleTabs();
|
||||||
|
let tabIndex = visibleTabs.indexOf(this);
|
||||||
|
|
||||||
|
if (this.selected)
|
||||||
|
tabContainer._handleTabSelect();
|
||||||
|
|
||||||
|
if (tabIndex == 0) {
|
||||||
|
tabContainer._beforeHoveredTab = null;
|
||||||
|
} else {
|
||||||
|
let candidate = visibleTabs[tabIndex - 1];
|
||||||
|
let separatedByScrollButton =
|
||||||
|
tabContainer.getAttribute("overflow") == "true" &&
|
||||||
|
candidate.pinned && !this.pinned;
|
||||||
|
if (!candidate.selected && !separatedByScrollButton) {
|
||||||
|
tabContainer._beforeHoveredTab = candidate;
|
||||||
|
candidate.setAttribute("beforehovered", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tabIndex == visibleTabs.length - 1) {
|
||||||
|
tabContainer._afterHoveredTab = null;
|
||||||
|
} else {
|
||||||
|
let candidate = visibleTabs[tabIndex + 1];
|
||||||
|
if (!candidate.selected) {
|
||||||
|
tabContainer._afterHoveredTab = candidate;
|
||||||
|
candidate.setAttribute("afterhovered", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tabContainer._hoveredTab = this;
|
||||||
|
if (this.linkedPanel && !this.selected) {
|
||||||
|
this.linkedBrowser.unselectedTabHover(true);
|
||||||
|
this.startUnselectedTabHoverTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare connection to host beforehand.
|
||||||
|
SessionStore.speculativeConnectOnTabHover(this);
|
||||||
|
|
||||||
|
let tabToWarm = this;
|
||||||
|
if (this.mOverCloseButton) {
|
||||||
|
tabToWarm = gBrowser._findTabToBlurTo(this);
|
||||||
|
}
|
||||||
|
gBrowser.warmupTab(tabToWarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
_mouseleave() {
|
||||||
|
let tabContainer = this.parentNode;
|
||||||
|
if (tabContainer._beforeHoveredTab) {
|
||||||
|
tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
|
||||||
|
tabContainer._beforeHoveredTab = null;
|
||||||
|
}
|
||||||
|
if (tabContainer._afterHoveredTab) {
|
||||||
|
tabContainer._afterHoveredTab.removeAttribute("afterhovered");
|
||||||
|
tabContainer._afterHoveredTab = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabContainer._hoveredTab = null;
|
||||||
|
if (this.linkedPanel && !this.selected) {
|
||||||
|
this.linkedBrowser.unselectedTabHover(false);
|
||||||
|
this.cancelUnselectedTabHoverTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startUnselectedTabHoverTimer() {
|
||||||
|
// Only record data when we need to.
|
||||||
|
if (!this.linkedBrowser.shouldHandleUnselectedTabHover) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
||||||
|
TelemetryStopwatch.start("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._hoverTabTimer) {
|
||||||
|
clearTimeout(this._hoverTabTimer);
|
||||||
|
this._hoverTabTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelUnselectedTabHoverTimer() {
|
||||||
|
// Since we're listening "mouseout" event, instead of "mouseleave".
|
||||||
|
// Every time the cursor is moving from the tab to its child node (icon),
|
||||||
|
// it would dispatch "mouseout"(for tab) first and then dispatch
|
||||||
|
// "mouseover" (for icon, eg: close button, speaker icon) soon.
|
||||||
|
// It causes we would cancel present TelemetryStopwatch immediately
|
||||||
|
// when cursor is moving on the icon, and then start a new one.
|
||||||
|
// In order to avoid this situation, we could delay cancellation and
|
||||||
|
// remove it if we get "mouseover" within very short period.
|
||||||
|
this._hoverTabTimer = setTimeout(() => {
|
||||||
|
if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
||||||
|
TelemetryStopwatch.cancel("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
finishUnselectedTabHoverTimer() {
|
||||||
|
// Stop timer when the tab is opened.
|
||||||
|
if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
||||||
|
TelemetryStopwatch.finish("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMuteAudio(aMuteReason) {
|
||||||
|
let browser = this.linkedBrowser;
|
||||||
|
let modifiedAttrs = [];
|
||||||
|
let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
|
||||||
|
|
||||||
|
if (this.hasAttribute("activemedia-blocked")) {
|
||||||
|
this.removeAttribute("activemedia-blocked");
|
||||||
|
modifiedAttrs.push("activemedia-blocked");
|
||||||
|
|
||||||
|
browser.resumeMedia();
|
||||||
|
hist.add(3 /* unblockByClickingIcon */ );
|
||||||
|
} else {
|
||||||
|
if (browser.audioMuted) {
|
||||||
|
if (this.linkedPanel) {
|
||||||
|
// "Lazy Browser" should not invoke its unmute method
|
||||||
|
browser.unmute();
|
||||||
|
}
|
||||||
|
this.removeAttribute("muted");
|
||||||
|
hist.add(1 /* unmute */ );
|
||||||
|
} else {
|
||||||
|
if (this.linkedPanel) {
|
||||||
|
// "Lazy Browser" should not invoke its mute method
|
||||||
|
browser.mute();
|
||||||
|
}
|
||||||
|
this.setAttribute("muted", "true");
|
||||||
|
hist.add(0 /* mute */ );
|
||||||
|
}
|
||||||
|
this.muteReason = aMuteReason || null;
|
||||||
|
modifiedAttrs.push("muted");
|
||||||
|
}
|
||||||
|
gBrowser._tabAttrModified(this, modifiedAttrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserContextId(aUserContextId) {
|
||||||
|
if (aUserContextId) {
|
||||||
|
if (this.linkedBrowser) {
|
||||||
|
this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
|
||||||
|
}
|
||||||
|
this.setAttribute("usercontextid", aUserContextId);
|
||||||
|
} else {
|
||||||
|
if (this.linkedBrowser) {
|
||||||
|
this.linkedBrowser.removeAttribute("usercontextid");
|
||||||
|
}
|
||||||
|
this.removeAttribute("usercontextid");
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextualIdentityService.setTabStyle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("tabbrowser-tab", MozTabbrowserTab, {
|
||||||
|
extends: "tab",
|
||||||
|
});
|
||||||
|
}
|
|
@ -655,8 +655,7 @@ window._gBrowser = {
|
||||||
const animations =
|
const animations =
|
||||||
Array.from(aTab.parentNode.getElementsByTagName("tab"))
|
Array.from(aTab.parentNode.getElementsByTagName("tab"))
|
||||||
.map(tab => {
|
.map(tab => {
|
||||||
const throbber =
|
const throbber = tab.throbber;
|
||||||
document.getAnonymousElementByAttribute(tab, "anonid", "tab-throbber");
|
|
||||||
return throbber ? throbber.getAnimations({ subtree: true }) : [];
|
return throbber ? throbber.getAnimations({ subtree: true }) : [];
|
||||||
})
|
})
|
||||||
.reduce((a, b) => a.concat(b))
|
.reduce((a, b) => a.concat(b))
|
||||||
|
@ -2319,8 +2318,7 @@ window._gBrowser = {
|
||||||
let openerTab = ((openerBrowser && this.getTabForBrowser(openerBrowser)) ||
|
let openerTab = ((openerBrowser && this.getTabForBrowser(openerBrowser)) ||
|
||||||
(relatedToCurrent && this.selectedTab));
|
(relatedToCurrent && this.selectedTab));
|
||||||
|
|
||||||
var t = document.createXULElement("tab");
|
var t = document.createXULElement("tab", { is: "tabbrowser-tab" });
|
||||||
|
|
||||||
t.openerTab = openerTab;
|
t.openerTab = openerTab;
|
||||||
|
|
||||||
aURI = aURI || "about:blank";
|
aURI = aURI || "about:blank";
|
||||||
|
@ -4228,8 +4226,8 @@ window._gBrowser = {
|
||||||
|
|
||||||
createTooltip(event) {
|
createTooltip(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
var tab = document.tooltipNode;
|
let tab = document.tooltipNode ? document.tooltipNode.closest("tab") : null;
|
||||||
if (!tab || tab.localName != "tab") {
|
if (!tab) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5410,8 +5408,9 @@ var TabContextMenu = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateContextMenu(aPopupMenu) {
|
updateContextMenu(aPopupMenu) {
|
||||||
this.contextTab = aPopupMenu.triggerNode.localName == "tab" ?
|
let tab = aPopupMenu.triggerNode && aPopupMenu.triggerNode.closest("tab");
|
||||||
aPopupMenu.triggerNode : gBrowser.selectedTab;
|
this.contextTab = tab || gBrowser.selectedTab;
|
||||||
|
|
||||||
let disabled = gBrowser.tabs.length == 1;
|
let disabled = gBrowser.tabs.length == 1;
|
||||||
let multiselectionContext = this.contextTab.multiselected;
|
let multiselectionContext = this.contextTab.multiselected;
|
||||||
|
|
||||||
|
|
|
@ -991,7 +991,10 @@
|
||||||
<parameter name="event"/>
|
<parameter name="event"/>
|
||||||
<parameter name="isLink"/>
|
<parameter name="isLink"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
let tab = event.target.localName == "tab" ? event.target : null;
|
let tab = event.target;
|
||||||
|
while (tab && tab.localName != "tab") {
|
||||||
|
tab = tab.parentNode;
|
||||||
|
}
|
||||||
if (tab && isLink) {
|
if (tab && isLink) {
|
||||||
let {width} = tab.getBoundingClientRect();
|
let {width} = tab.getBoundingClientRect();
|
||||||
if (event.screenX < tab.screenX + width * .25 ||
|
if (event.screenX < tab.screenX + width * .25 ||
|
||||||
|
@ -1238,8 +1241,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tab = event.target;
|
let tab = event.target ? event.target.closest("tab") : null;
|
||||||
|
|
||||||
if (tab.getAttribute("fadein") == "true") {
|
if (tab.getAttribute("fadein") == "true") {
|
||||||
if (tab._fullyOpen) {
|
if (tab._fullyOpen) {
|
||||||
this._updateCloseButtons();
|
this._updateCloseButtons();
|
||||||
|
@ -1330,8 +1332,9 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.target.localName == "tab") {
|
let tab = event.target ? event.target.closest("tab") : null;
|
||||||
gBrowser.removeTab(event.target, {
|
if (tab) {
|
||||||
|
gBrowser.removeTab(tab, {
|
||||||
animate: true,
|
animate: true,
|
||||||
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
||||||
});
|
});
|
||||||
|
@ -1905,579 +1908,4 @@
|
||||||
]]></handler>
|
]]></handler>
|
||||||
</handlers>
|
</handlers>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
<binding id="tabbrowser-tab"
|
|
||||||
extends="chrome://global/content/bindings/tabbox.xml#tab">
|
|
||||||
<content context="tabContextMenu">
|
|
||||||
<xul:stack class="tab-stack" flex="1">
|
|
||||||
<xul:vbox xbl:inherits="selected=visuallyselected,fadein,multiselected"
|
|
||||||
class="tab-background">
|
|
||||||
<xul:hbox xbl:inherits="selected=visuallyselected,multiselected,before-multiselected"
|
|
||||||
class="tab-line"/>
|
|
||||||
<xul:spacer flex="1" class="tab-background-inner"/>
|
|
||||||
<xul:hbox class="tab-bottom-line"/>
|
|
||||||
</xul:vbox>
|
|
||||||
<xul:hbox xbl:inherits="pinned,bursting,notselectedsinceload"
|
|
||||||
anonid="tab-loading-burst"
|
|
||||||
class="tab-loading-burst"/>
|
|
||||||
<xul:hbox xbl:inherits="pinned,selected=visuallyselected,titlechanged,attention"
|
|
||||||
class="tab-content" align="center">
|
|
||||||
<xul:hbox xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected"
|
|
||||||
anonid="tab-throbber"
|
|
||||||
class="tab-throbber"
|
|
||||||
layer="true"/>
|
|
||||||
<xul:hbox xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected,pendingicon"
|
|
||||||
anonid="tab-icon-pending"
|
|
||||||
class="tab-icon-pending"/>
|
|
||||||
<xul:image xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,requestcontextid,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
|
|
||||||
anonid="tab-icon-image"
|
|
||||||
class="tab-icon-image"
|
|
||||||
validate="never"
|
|
||||||
role="presentation"/>
|
|
||||||
<xul:image xbl:inherits="sharing,selected=visuallyselected,pinned"
|
|
||||||
anonid="sharing-icon"
|
|
||||||
class="tab-sharing-icon-overlay"
|
|
||||||
role="presentation"/>
|
|
||||||
<xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked"
|
|
||||||
anonid="overlay-icon"
|
|
||||||
class="tab-icon-overlay"
|
|
||||||
role="presentation"/>
|
|
||||||
<xul:hbox class="tab-label-container"
|
|
||||||
xbl:inherits="pinned,selected=visuallyselected,labeldirection"
|
|
||||||
onoverflow="this.setAttribute('textoverflow', 'true');"
|
|
||||||
onunderflow="this.removeAttribute('textoverflow');"
|
|
||||||
flex="1">
|
|
||||||
<xul:label class="tab-text tab-label" anonid="tab-label"
|
|
||||||
xbl:inherits="xbl:text=label,accesskey,fadein,pinned,selected=visuallyselected,attention"
|
|
||||||
role="presentation"/>
|
|
||||||
</xul:hbox>
|
|
||||||
<xul:image xbl:inherits="pictureinpicture"
|
|
||||||
class="tab-icon-pip"
|
|
||||||
role="presentation"/>
|
|
||||||
<xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked,pictureinpicture"
|
|
||||||
anonid="soundplaying-icon"
|
|
||||||
class="tab-icon-sound"
|
|
||||||
role="presentation"/>
|
|
||||||
<xul:image anonid="close-button"
|
|
||||||
xbl:inherits="fadein,pinned,selected=visuallyselected"
|
|
||||||
class="tab-close-button close-icon"
|
|
||||||
role="presentation"/>
|
|
||||||
</xul:hbox>
|
|
||||||
</xul:stack>
|
|
||||||
</content>
|
|
||||||
|
|
||||||
<implementation>
|
|
||||||
<constructor><![CDATA[
|
|
||||||
if (!("_lastAccessed" in this)) {
|
|
||||||
this.updateLastAccessed();
|
|
||||||
}
|
|
||||||
]]></constructor>
|
|
||||||
|
|
||||||
<property name="_visuallySelected">
|
|
||||||
<setter>
|
|
||||||
<![CDATA[
|
|
||||||
if (val == (this.getAttribute("visuallyselected") == "true")) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val) {
|
|
||||||
this.setAttribute("visuallyselected", "true");
|
|
||||||
} else {
|
|
||||||
this.removeAttribute("visuallyselected");
|
|
||||||
}
|
|
||||||
gBrowser._tabAttrModified(this, ["visuallyselected"]);
|
|
||||||
|
|
||||||
return val;
|
|
||||||
]]>
|
|
||||||
</setter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="_selected">
|
|
||||||
<setter>
|
|
||||||
<![CDATA[
|
|
||||||
// in e10s we want to only pseudo-select a tab before its rendering is done, so that
|
|
||||||
// the rest of the system knows that the tab is selected, but we don't want to update its
|
|
||||||
// visual status to selected until after we receive confirmation that its content has painted.
|
|
||||||
if (val)
|
|
||||||
this.setAttribute("selected", "true");
|
|
||||||
else
|
|
||||||
this.removeAttribute("selected");
|
|
||||||
|
|
||||||
// If we're non-e10s we should update the visual selection as well at the same time,
|
|
||||||
// *or* if we're e10s and the visually selected tab isn't changing, in which case the
|
|
||||||
// tab switcher code won't run and update anything else (like the before- and after-
|
|
||||||
// selected attributes).
|
|
||||||
if (!gMultiProcessBrowser || (val && this.hasAttribute("visuallyselected"))) {
|
|
||||||
this._visuallySelected = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
]]>
|
|
||||||
</setter>
|
|
||||||
</property>
|
|
||||||
<field name="_selectedOnFirstMouseDown">false</field>
|
|
||||||
|
|
||||||
<property name="pinned" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("pinned") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<property name="hidden" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("hidden") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<property name="muted" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("muted") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<property name="multiselected" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("multiselected") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<property name="beforeMultiselected" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("before-multiselected") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<!--
|
|
||||||
Describes how the tab ended up in this mute state. May be any of:
|
|
||||||
|
|
||||||
- undefined: The tabs mute state has never changed.
|
|
||||||
- null: The mute state was last changed through the UI.
|
|
||||||
- Any string: The ID was changed through an extension API. The string
|
|
||||||
must be the ID of the extension which changed it.
|
|
||||||
-->
|
|
||||||
<field name="muteReason">undefined</field>
|
|
||||||
|
|
||||||
<property name="userContextId" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.hasAttribute("usercontextid")
|
|
||||||
? parseInt(this.getAttribute("usercontextid"))
|
|
||||||
: 0;
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="soundPlaying" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("soundplaying") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="pictureinpicture" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("pictureinpicture") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="activeMediaBlocked" readonly="true">
|
|
||||||
<getter>
|
|
||||||
return this.getAttribute("activemedia-blocked") == "true";
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="isEmpty" readonly="true">
|
|
||||||
<getter>
|
|
||||||
// Determines if a tab is "empty", usually used in the context of determining
|
|
||||||
// if it's ok to close the tab.
|
|
||||||
if (this.hasAttribute("busy"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (this.hasAttribute("customizemode"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let browser = this.linkedBrowser;
|
|
||||||
if (!isBlankPageURL(browser.currentURI.spec))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!checkEmptyPageOrigin(browser))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (browser.canGoForward || browser.canGoBack)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="lastAccessed">
|
|
||||||
<getter>
|
|
||||||
return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed;
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
<method name="updateLastAccessed">
|
|
||||||
<parameter name="aDate"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
this._lastAccessed = this.selected ? Infinity : (aDate || Date.now());
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<field name="mOverCloseButton">false</field>
|
|
||||||
<property name="_overPlayingIcon" readonly="true">
|
|
||||||
<getter><![CDATA[
|
|
||||||
let iconVisible = this.hasAttribute("soundplaying") ||
|
|
||||||
this.hasAttribute("muted") ||
|
|
||||||
this.hasAttribute("activemedia-blocked");
|
|
||||||
let soundPlayingIcon =
|
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon");
|
|
||||||
let overlayIcon =
|
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "overlay-icon");
|
|
||||||
|
|
||||||
return soundPlayingIcon && soundPlayingIcon.matches(":hover") ||
|
|
||||||
(overlayIcon && overlayIcon.matches(":hover") && iconVisible);
|
|
||||||
]]></getter>
|
|
||||||
</property>
|
|
||||||
<field name="mCorrespondingMenuitem">null</field>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
While it would make sense to track this in a field, the field will get nuked
|
|
||||||
once the node is gone from the DOM, which causes us to think the tab is not
|
|
||||||
closed, which causes us to make wrong decisions. So we use an expando instead.
|
|
||||||
<field name="closing">false</field>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<method name="_mouseenter">
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this.hidden || this.closing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tabContainer = this.parentNode;
|
|
||||||
let visibleTabs = tabContainer._getVisibleTabs();
|
|
||||||
let tabIndex = visibleTabs.indexOf(this);
|
|
||||||
|
|
||||||
if (this.selected)
|
|
||||||
tabContainer._handleTabSelect();
|
|
||||||
|
|
||||||
if (tabIndex == 0) {
|
|
||||||
tabContainer._beforeHoveredTab = null;
|
|
||||||
} else {
|
|
||||||
let candidate = visibleTabs[tabIndex - 1];
|
|
||||||
let separatedByScrollButton =
|
|
||||||
tabContainer.getAttribute("overflow") == "true" &&
|
|
||||||
candidate.pinned && !this.pinned;
|
|
||||||
if (!candidate.selected && !separatedByScrollButton) {
|
|
||||||
tabContainer._beforeHoveredTab = candidate;
|
|
||||||
candidate.setAttribute("beforehovered", "true");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tabIndex == visibleTabs.length - 1) {
|
|
||||||
tabContainer._afterHoveredTab = null;
|
|
||||||
} else {
|
|
||||||
let candidate = visibleTabs[tabIndex + 1];
|
|
||||||
if (!candidate.selected) {
|
|
||||||
tabContainer._afterHoveredTab = candidate;
|
|
||||||
candidate.setAttribute("afterhovered", "true");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tabContainer._hoveredTab = this;
|
|
||||||
if (this.linkedPanel && !this.selected) {
|
|
||||||
this.linkedBrowser.unselectedTabHover(true);
|
|
||||||
this.startUnselectedTabHoverTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare connection to host beforehand.
|
|
||||||
SessionStore.speculativeConnectOnTabHover(this);
|
|
||||||
|
|
||||||
let tabToWarm = this;
|
|
||||||
if (this.mOverCloseButton) {
|
|
||||||
tabToWarm = gBrowser._findTabToBlurTo(this);
|
|
||||||
}
|
|
||||||
gBrowser.warmupTab(tabToWarm);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_mouseleave">
|
|
||||||
<body><![CDATA[
|
|
||||||
let tabContainer = this.parentNode;
|
|
||||||
if (tabContainer._beforeHoveredTab) {
|
|
||||||
tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
|
|
||||||
tabContainer._beforeHoveredTab = null;
|
|
||||||
}
|
|
||||||
if (tabContainer._afterHoveredTab) {
|
|
||||||
tabContainer._afterHoveredTab.removeAttribute("afterhovered");
|
|
||||||
tabContainer._afterHoveredTab = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabContainer._hoveredTab = null;
|
|
||||||
if (this.linkedPanel && !this.selected) {
|
|
||||||
this.linkedBrowser.unselectedTabHover(false);
|
|
||||||
this.cancelUnselectedTabHoverTimer();
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="startUnselectedTabHoverTimer">
|
|
||||||
<body><![CDATA[
|
|
||||||
// Only record data when we need to.
|
|
||||||
if (!this.linkedBrowser.shouldHandleUnselectedTabHover) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
|
||||||
TelemetryStopwatch.start("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._hoverTabTimer) {
|
|
||||||
clearTimeout(this._hoverTabTimer);
|
|
||||||
this._hoverTabTimer = null;
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="cancelUnselectedTabHoverTimer">
|
|
||||||
<body><![CDATA[
|
|
||||||
// Since we're listening "mouseout" event, instead of "mouseleave".
|
|
||||||
// Every time the cursor is moving from the tab to its child node (icon),
|
|
||||||
// it would dispatch "mouseout"(for tab) first and then dispatch
|
|
||||||
// "mouseover" (for icon, eg: close button, speaker icon) soon.
|
|
||||||
// It causes we would cancel present TelemetryStopwatch immediately
|
|
||||||
// when cursor is moving on the icon, and then start a new one.
|
|
||||||
// In order to avoid this situation, we could delay cancellation and
|
|
||||||
// remove it if we get "mouseover" within very short period.
|
|
||||||
this._hoverTabTimer = setTimeout(() => {
|
|
||||||
if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
|
||||||
TelemetryStopwatch.cancel("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="finishUnselectedTabHoverTimer">
|
|
||||||
<body><![CDATA[
|
|
||||||
// Stop timer when the tab is opened.
|
|
||||||
if (TelemetryStopwatch.running("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this)) {
|
|
||||||
TelemetryStopwatch.finish("HOVER_UNTIL_UNSELECTED_TAB_OPENED", this);
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="toggleMuteAudio">
|
|
||||||
<parameter name="aMuteReason"/>
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
let browser = this.linkedBrowser;
|
|
||||||
let modifiedAttrs = [];
|
|
||||||
let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
|
|
||||||
|
|
||||||
if (this.hasAttribute("activemedia-blocked")) {
|
|
||||||
this.removeAttribute("activemedia-blocked");
|
|
||||||
modifiedAttrs.push("activemedia-blocked");
|
|
||||||
|
|
||||||
browser.resumeMedia();
|
|
||||||
hist.add(3 /* unblockByClickingIcon */);
|
|
||||||
} else {
|
|
||||||
if (browser.audioMuted) {
|
|
||||||
if (this.linkedPanel) {
|
|
||||||
// "Lazy Browser" should not invoke its unmute method
|
|
||||||
browser.unmute();
|
|
||||||
}
|
|
||||||
this.removeAttribute("muted");
|
|
||||||
hist.add(1 /* unmute */);
|
|
||||||
} else {
|
|
||||||
if (this.linkedPanel) {
|
|
||||||
// "Lazy Browser" should not invoke its mute method
|
|
||||||
browser.mute();
|
|
||||||
}
|
|
||||||
this.setAttribute("muted", "true");
|
|
||||||
hist.add(0 /* mute */);
|
|
||||||
}
|
|
||||||
this.muteReason = aMuteReason || null;
|
|
||||||
modifiedAttrs.push("muted");
|
|
||||||
}
|
|
||||||
gBrowser._tabAttrModified(this, modifiedAttrs);
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="setUserContextId">
|
|
||||||
<parameter name="aUserContextId"/>
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
if (aUserContextId) {
|
|
||||||
if (this.linkedBrowser) {
|
|
||||||
this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
|
|
||||||
}
|
|
||||||
this.setAttribute("usercontextid", aUserContextId);
|
|
||||||
} else {
|
|
||||||
if (this.linkedBrowser) {
|
|
||||||
this.linkedBrowser.removeAttribute("usercontextid");
|
|
||||||
}
|
|
||||||
this.removeAttribute("usercontextid");
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextualIdentityService.setTabStyle(this);
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
</implementation>
|
|
||||||
|
|
||||||
<handlers>
|
|
||||||
<handler event="mouseover"><![CDATA[
|
|
||||||
if (event.originalTarget.getAttribute("anonid") == "close-button") {
|
|
||||||
this.mOverCloseButton = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._mouseenter();
|
|
||||||
]]></handler>
|
|
||||||
<handler event="mouseout"><![CDATA[
|
|
||||||
if (event.originalTarget.getAttribute("anonid") == "close-button") {
|
|
||||||
this.mOverCloseButton = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._mouseleave();
|
|
||||||
]]></handler>
|
|
||||||
|
|
||||||
<handler event="dragstart" phase="capturing">
|
|
||||||
this.style.MozUserFocus = "";
|
|
||||||
</handler>
|
|
||||||
|
|
||||||
<handler event="dragstart"><![CDATA[
|
|
||||||
if (this.mOverCloseButton) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
]]></handler>
|
|
||||||
|
|
||||||
<handler event="mousedown" phase="capturing">
|
|
||||||
<![CDATA[
|
|
||||||
let tabContainer = this.parentNode;
|
|
||||||
|
|
||||||
if (tabContainer._closeTabByDblclick &&
|
|
||||||
event.button == 0 &&
|
|
||||||
event.detail == 1) {
|
|
||||||
this._selectedOnFirstMouseDown = this.selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.selected) {
|
|
||||||
this.style.MozUserFocus = "ignore";
|
|
||||||
} else if (event.originalTarget.classList.contains("tab-close-button") ||
|
|
||||||
event.originalTarget.classList.contains("tab-icon-sound") ||
|
|
||||||
event.originalTarget.classList.contains("tab-icon-overlay")) {
|
|
||||||
// Prevent tabbox.xml from selecting the tab.
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.button == 1) {
|
|
||||||
gBrowser.warmupTab(gBrowser._findTabToBlurTo(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.button == 0 && tabContainer._multiselectEnabled) {
|
|
||||||
let shiftKey = event.shiftKey;
|
|
||||||
let accelKey = event.getModifierState("Accel");
|
|
||||||
if (shiftKey) {
|
|
||||||
const lastSelectedTab = gBrowser.lastMultiSelectedTab;
|
|
||||||
if (!accelKey) {
|
|
||||||
gBrowser.selectedTab = lastSelectedTab;
|
|
||||||
|
|
||||||
// Make sure selection is cleared when tab-switch doesn't happen.
|
|
||||||
gBrowser.clearMultiSelectedTabs(false);
|
|
||||||
}
|
|
||||||
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
|
|
||||||
|
|
||||||
// Prevent tabbox.xml from selecting the tab.
|
|
||||||
event.stopPropagation();
|
|
||||||
} else if (accelKey) {
|
|
||||||
// Ctrl (Cmd for mac) key is pressed
|
|
||||||
if (this.multiselected) {
|
|
||||||
gBrowser.removeFromMultiSelectedTabs(this, true);
|
|
||||||
} else if (this != gBrowser.selectedTab) {
|
|
||||||
gBrowser.addToMultiSelectedTabs(this, false);
|
|
||||||
gBrowser.lastMultiSelectedTab = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent tabbox.xml from selecting the tab.
|
|
||||||
event.stopPropagation();
|
|
||||||
} else if (!this.selected && this.multiselected) {
|
|
||||||
gBrowser.lockClearMultiSelectionOnce();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</handler>
|
|
||||||
<handler event="mouseup">
|
|
||||||
// Make sure that clear-selection is released.
|
|
||||||
// Otherwise selection using Shift key may be broken.
|
|
||||||
gBrowser.unlockClearMultiSelection();
|
|
||||||
|
|
||||||
this.style.MozUserFocus = "";
|
|
||||||
</handler>
|
|
||||||
|
|
||||||
<handler event="click" button="0"><![CDATA[
|
|
||||||
if (event.getModifierState("Accel") || event.shiftKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gBrowser.multiSelectedTabsCount > 0 &&
|
|
||||||
!event.originalTarget.classList.contains("tab-close-button") &&
|
|
||||||
!event.originalTarget.classList.contains("tab-icon-sound") &&
|
|
||||||
!event.originalTarget.classList.contains("tab-icon-overlay")) {
|
|
||||||
// Tabs were previously multi-selected and user clicks on a tab
|
|
||||||
// without holding Ctrl/Cmd Key
|
|
||||||
|
|
||||||
// Force positional attributes to update when the
|
|
||||||
// target (of the click) is the "active" tab.
|
|
||||||
let updatePositionalAttr = gBrowser.selectedTab == this;
|
|
||||||
|
|
||||||
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.originalTarget.classList.contains("tab-icon-sound") ||
|
|
||||||
(event.originalTarget.classList.contains("tab-icon-overlay") &&
|
|
||||||
(event.originalTarget.hasAttribute("soundplaying") ||
|
|
||||||
event.originalTarget.hasAttribute("muted") ||
|
|
||||||
event.originalTarget.hasAttribute("activemedia-blocked")))) {
|
|
||||||
if (this.multiselected) {
|
|
||||||
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
|
|
||||||
} else {
|
|
||||||
this.toggleMuteAudio();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.originalTarget.getAttribute("anonid") == "close-button") {
|
|
||||||
if (this.multiselected) {
|
|
||||||
gBrowser.removeMultiSelectedTabs();
|
|
||||||
} else {
|
|
||||||
gBrowser.removeTab(this, {
|
|
||||||
animate: true,
|
|
||||||
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// This enables double-click protection for the tab container
|
|
||||||
// (see tabbrowser-tabs 'click' handler).
|
|
||||||
gBrowser.tabContainer._blockDblClick = true;
|
|
||||||
}
|
|
||||||
]]></handler>
|
|
||||||
|
|
||||||
<handler event="dblclick" button="0" phase="capturing"><![CDATA[
|
|
||||||
// for the one-close-button case
|
|
||||||
if (event.originalTarget.getAttribute("anonid") == "close-button") {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
let tabContainer = this.parentNode;
|
|
||||||
if (tabContainer._closeTabByDblclick &&
|
|
||||||
this._selectedOnFirstMouseDown &&
|
|
||||||
this.selected &&
|
|
||||||
!(event.originalTarget.classList.contains("tab-icon-sound") ||
|
|
||||||
event.originalTarget.classList.contains("tab-icon-overlay"))) {
|
|
||||||
gBrowser.removeTab(this, {
|
|
||||||
animate: true,
|
|
||||||
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
]]></handler>
|
|
||||||
|
|
||||||
<handler event="animationend">
|
|
||||||
<![CDATA[
|
|
||||||
if (event.originalTarget.getAttribute("anonid") == "tab-loading-burst") {
|
|
||||||
this.removeAttribute("bursting");
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</handler>
|
|
||||||
</handlers>
|
|
||||||
</binding>
|
|
||||||
</bindings>
|
</bindings>
|
||||||
|
|
|
@ -38,7 +38,7 @@ add_task(async () => {
|
||||||
|
|
||||||
await waitForAttributeChange(tab, "label");
|
await waitForAttributeChange(tab, "label");
|
||||||
ok(tab.hasAttribute("busy"), "Should have seen the busy attribute");
|
ok(tab.hasAttribute("busy"), "Should have seen the busy attribute");
|
||||||
let label = document.getAnonymousElementByAttribute(tab, "anonid", "tab-label");
|
let label = tab.textLabel;
|
||||||
let bounds = label.getBoundingClientRect();
|
let bounds = label.getBoundingClientRect();
|
||||||
|
|
||||||
await waitForAttributeChange(tab, "busy");
|
await waitForAttributeChange(tab, "busy");
|
||||||
|
@ -60,7 +60,7 @@ add_task(async () => {
|
||||||
is(icon.iconURL, "http://example.com/favicon.ico");
|
is(icon.iconURL, "http://example.com/favicon.ico");
|
||||||
|
|
||||||
let tab = gBrowser.getTabForBrowser(browser);
|
let tab = gBrowser.getTabForBrowser(browser);
|
||||||
let label = document.getAnonymousElementByAttribute(tab, "anonid", "tab-label");
|
let label = tab.textLabel;
|
||||||
let bounds = label.getBoundingClientRect();
|
let bounds = label.getBoundingClientRect();
|
||||||
|
|
||||||
await ContentTask.spawn(browser, null, () => {
|
await ContentTask.spawn(browser, null, () => {
|
||||||
|
|
|
@ -794,3 +794,47 @@ add_task(async function test_blur_hides_popup() {
|
||||||
|
|
||||||
BrowserTestUtils.removeTab(tab);
|
BrowserTestUtils.removeTab(tab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getIsHandlingUserInput(browser, elementId, eventName) {
|
||||||
|
return ContentTask.spawn(browser, [elementId, eventName],
|
||||||
|
async function([contentElementId, contentEventName]) {
|
||||||
|
let element = content.document.getElementById(contentElementId);
|
||||||
|
let isHandlingUserInput = false;
|
||||||
|
await ContentTaskUtils.waitForEvent(element, contentEventName, false, e => {
|
||||||
|
isHandlingUserInput = content.window.windowUtils.isHandlingUserInput;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return isHandlingUserInput;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test checks if the change/click event is considered as user input event.
|
||||||
|
add_task(async function test_handling_user_input() {
|
||||||
|
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
|
||||||
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||||
|
|
||||||
|
let menulist = document.getElementById("ContentSelectDropdown");
|
||||||
|
let selectPopup = menulist.menupopup;
|
||||||
|
|
||||||
|
// Test onchange event when changing value via keyboard.
|
||||||
|
await openSelectPopup(selectPopup, "click", "#one");
|
||||||
|
let getPromise = getIsHandlingUserInput(tab.linkedBrowser, "one", "change");
|
||||||
|
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||||
|
await hideSelectPopup(selectPopup);
|
||||||
|
is(await getPromise, true, "isHandlingUserInput should be true");
|
||||||
|
|
||||||
|
// Test onchange event when changing value via mouse click
|
||||||
|
await openSelectPopup(selectPopup, "click", "#two");
|
||||||
|
getPromise = getIsHandlingUserInput(tab.linkedBrowser, "two", "change");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(selectPopup.lastElementChild, {});
|
||||||
|
is(await getPromise, true, "isHandlingUserInput should be true");
|
||||||
|
|
||||||
|
// Test onclick event fired from clicking select popup.
|
||||||
|
await openSelectPopup(selectPopup, "click", "#three");
|
||||||
|
getPromise = getIsHandlingUserInput(tab.linkedBrowser, "three", "click");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(selectPopup.firstElementChild, {});
|
||||||
|
is(await getPromise, true, "isHandlingUserInput should be true");
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
|
@ -47,7 +47,6 @@ support-files =
|
||||||
test_bug462673.html
|
test_bug462673.html
|
||||||
test_bug628179.html
|
test_bug628179.html
|
||||||
test_bug839103.html
|
test_bug839103.html
|
||||||
test_process_flags_chrome.html
|
|
||||||
title_test.svg
|
title_test.svg
|
||||||
unknownContentType_file.pif
|
unknownContentType_file.pif
|
||||||
unknownContentType_file.pif^headers^
|
unknownContentType_file.pif^headers^
|
||||||
|
@ -414,21 +413,6 @@ skip-if = e10s || debug # Bug 1094240 - has findbar-related failures
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||||
[browser_addCertException.js]
|
[browser_addCertException.js]
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||||
[browser_e10s_about_page_triggeringprincipal.js]
|
|
||||||
skip-if = verify
|
|
||||||
support-files =
|
|
||||||
file_about_child.html
|
|
||||||
file_about_parent.html
|
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
|
||||||
[browser_e10s_switchbrowser.js]
|
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
|
||||||
[browser_e10s_about_process.js]
|
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
|
||||||
[browser_e10s_chrome_process.js]
|
|
||||||
skip-if = debug # Bug 1444565, Bug 1457887
|
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
|
||||||
[browser_e10s_javascript.js]
|
|
||||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
|
||||||
[browser_blockHPKP.js]
|
[browser_blockHPKP.js]
|
||||||
skip-if = verify && !debug
|
skip-if = verify && !debug
|
||||||
uses-unsafe-cpows = true
|
uses-unsafe-cpows = true
|
||||||
|
|
|
@ -34,7 +34,7 @@ add_task(async function closeLastTabInWindow() {
|
||||||
let windowClosedPromise = BrowserTestUtils.domWindowClosed(newWin);
|
let windowClosedPromise = BrowserTestUtils.domWindowClosed(newWin);
|
||||||
expectingDialog = true;
|
expectingDialog = true;
|
||||||
// close tab:
|
// close tab:
|
||||||
document.getAnonymousElementByAttribute(firstTab, "anonid", "close-button").click();
|
firstTab.closeButton.click();
|
||||||
await windowClosedPromise;
|
await windowClosedPromise;
|
||||||
ok(!expectingDialog, "There should have been a dialog.");
|
ok(!expectingDialog, "There should have been a dialog.");
|
||||||
ok(newWin.closed, "Window should be closed.");
|
ok(newWin.closed, "Window should be closed.");
|
||||||
|
@ -63,13 +63,13 @@ add_task(async function closeWindoWithSingleTabTwice() {
|
||||||
expectingDialog = true;
|
expectingDialog = true;
|
||||||
wantToClose = false;
|
wantToClose = false;
|
||||||
let firstDialogShownPromise = new Promise((resolve, reject) => { resolveDialogPromise = resolve; });
|
let firstDialogShownPromise = new Promise((resolve, reject) => { resolveDialogPromise = resolve; });
|
||||||
document.getAnonymousElementByAttribute(firstTab, "anonid", "close-button").click();
|
firstTab.closeButton.click();
|
||||||
await firstDialogShownPromise;
|
await firstDialogShownPromise;
|
||||||
info("Got initial dialog, now trying again");
|
info("Got initial dialog, now trying again");
|
||||||
expectingDialog = true;
|
expectingDialog = true;
|
||||||
wantToClose = true;
|
wantToClose = true;
|
||||||
resolveDialogPromise = null;
|
resolveDialogPromise = null;
|
||||||
document.getAnonymousElementByAttribute(firstTab, "anonid", "close-button").click();
|
firstTab.closeButton.click();
|
||||||
await windowClosedPromise;
|
await windowClosedPromise;
|
||||||
ok(!expectingDialog, "There should have been a dialog.");
|
ok(!expectingDialog, "There should have been a dialog.");
|
||||||
ok(newWin.closed, "Window should be closed.");
|
ok(newWin.closed, "Window should be closed.");
|
||||||
|
|
|
@ -61,10 +61,10 @@ add_task(async function() {
|
||||||
doCompletion();
|
doCompletion();
|
||||||
});
|
});
|
||||||
// Click again:
|
// Click again:
|
||||||
document.getAnonymousElementByAttribute(testTab, "anonid", "close-button").click();
|
testTab.closeButton.click();
|
||||||
});
|
});
|
||||||
// Click once:
|
// Click once:
|
||||||
document.getAnonymousElementByAttribute(testTab, "anonid", "close-button").click();
|
testTab.closeButton.click();
|
||||||
});
|
});
|
||||||
await TestUtils.waitForCondition(() => !testTab.parentNode);
|
await TestUtils.waitForCondition(() => !testTab.parentNode);
|
||||||
ok(!testTab.parentNode, "Tab should be closed completely");
|
ok(!testTab.parentNode, "Tab should be closed completely");
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
const CHROME_PROCESS = E10SUtils.NOT_REMOTE;
|
|
||||||
const WEB_CONTENT_PROCESS = E10SUtils.WEB_REMOTE_TYPE;
|
|
||||||
const PRIVILEGED_CONTENT_PROCESS = E10SUtils.PRIVILEGED_REMOTE_TYPE;
|
|
||||||
const EXTENSION_PROCESS = E10SUtils.EXTENSION_REMOTE_TYPE;
|
|
||||||
|
|
||||||
const CHROME = {
|
|
||||||
id: "cb34538a-d9da-40f3-b61a-069f0b2cb9fb",
|
|
||||||
path: "test-chrome",
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
const CANREMOTE = {
|
|
||||||
id: "2480d3e1-9ce4-4b84-8ae3-910b9a95cbb3",
|
|
||||||
path: "test-allowremote",
|
|
||||||
flags: Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD,
|
|
||||||
};
|
|
||||||
const MUSTREMOTE = {
|
|
||||||
id: "f849cee5-e13e-44d2-981d-0fb3884aaead",
|
|
||||||
path: "test-mustremote",
|
|
||||||
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD,
|
|
||||||
};
|
|
||||||
const CANPRIVILEGEDREMOTE = {
|
|
||||||
id: "a04ffafe-6c63-4266-acae-0f4b093165aa",
|
|
||||||
path: "test-canprivilegedremote",
|
|
||||||
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
|
|
||||||
Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGED_CHILD,
|
|
||||||
};
|
|
||||||
const MUSTEXTENSION = {
|
|
||||||
id: "f7a1798f-965b-49e9-be83-ec6ee4d7d675",
|
|
||||||
path: "test-mustextension",
|
|
||||||
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_EXTENSION_PROCESS,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const TEST_MODULES = [
|
|
||||||
CHROME,
|
|
||||||
CANREMOTE,
|
|
||||||
MUSTREMOTE,
|
|
||||||
CANPRIVILEGEDREMOTE,
|
|
||||||
MUSTEXTENSION,
|
|
||||||
];
|
|
||||||
|
|
||||||
function AboutModule() {
|
|
||||||
}
|
|
||||||
|
|
||||||
AboutModule.prototype = {
|
|
||||||
newChannel(aURI, aLoadInfo) {
|
|
||||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
},
|
|
||||||
|
|
||||||
getURIFlags(aURI) {
|
|
||||||
for (let module of TEST_MODULES) {
|
|
||||||
if (aURI.pathQueryRef.startsWith(module.path)) {
|
|
||||||
return module.flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ok(false, "Called getURIFlags for an unknown page " + aURI.spec);
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
getIndexedDBOriginPostfix(aURI) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
|
|
||||||
};
|
|
||||||
|
|
||||||
var AboutModuleFactory = {
|
|
||||||
createInstance(aOuter, aIID) {
|
|
||||||
if (aOuter)
|
|
||||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
|
||||||
return new AboutModule().QueryInterface(aIID);
|
|
||||||
},
|
|
||||||
|
|
||||||
lockFactory(aLock) {
|
|
||||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
},
|
|
||||||
|
|
||||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory]),
|
|
||||||
};
|
|
||||||
|
|
||||||
add_task(async function init() {
|
|
||||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
|
||||||
for (let module of TEST_MODULES) {
|
|
||||||
registrar.registerFactory(Components.ID(module.id), "",
|
|
||||||
"@mozilla.org/network/protocol/about;1?what=" + module.path,
|
|
||||||
AboutModuleFactory);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
|
||||||
for (let module of TEST_MODULES) {
|
|
||||||
registrar.unregisterFactory(Components.ID(module.id), AboutModuleFactory);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function test_url(url, chromeResult, webContentResult, privilegedContentResult, extensionProcessResult) {
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
webContentResult, "Check URL in web content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, PRIVILEGED_CONTENT_PROCESS),
|
|
||||||
privilegedContentResult, "Check URL in privileged content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, EXTENSION_PROCESS),
|
|
||||||
extensionProcessResult, "Check URL in extension process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with ref in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
webContentResult, "Check URL with ref in web content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, PRIVILEGED_CONTENT_PROCESS),
|
|
||||||
privilegedContentResult, "Check URL with ref in privileged content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, EXTENSION_PROCESS),
|
|
||||||
extensionProcessResult, "Check URL with ref in extension process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with query in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
webContentResult, "Check URL with query in web content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, PRIVILEGED_CONTENT_PROCESS),
|
|
||||||
privilegedContentResult, "Check URL with query in privileged content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, EXTENSION_PROCESS),
|
|
||||||
extensionProcessResult, "Check URL with query in extension process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with query and ref in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
webContentResult, "Check URL with query and ref in web content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, PRIVILEGED_CONTENT_PROCESS),
|
|
||||||
privilegedContentResult, "Check URL with query and ref in privileged content process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, EXTENSION_PROCESS),
|
|
||||||
extensionProcessResult, "Check URL with query and ref in extension process.");
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_chrome() {
|
|
||||||
test_url("about:" + CHROME.path, true, false, false, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_any() {
|
|
||||||
test_url("about:" + CANREMOTE.path, true, true, false, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_remote() {
|
|
||||||
test_url("about:" + MUSTREMOTE.path, false, true, false, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_privileged_remote_true() {
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [
|
|
||||||
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// This shouldn't be taken literally. We will always use the privileged
|
|
||||||
// content type if the URI_CAN_LOAD_IN_PRIVILEGED_CHILD flag is enabled and
|
|
||||||
// the pref is turned on.
|
|
||||||
test_url("about:" + CANPRIVILEGEDREMOTE.path, false, false, true, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_privileged_remote_false() {
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [
|
|
||||||
["browser.tabs.remote.separatePrivilegedContentProcess", false],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// This shouldn't be taken literally. We will always use the privileged
|
|
||||||
// content type if the URI_CAN_LOAD_IN_PRIVILEGED_CHILD flag is enabled and
|
|
||||||
// the pref is turned on.
|
|
||||||
test_url("about:" + CANPRIVILEGEDREMOTE.path, false, true, false, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_extension() {
|
|
||||||
test_url("about:" + MUSTEXTENSION.path, false, false, false, true);
|
|
||||||
});
|
|
|
@ -31,7 +31,7 @@ add_task(async function() {
|
||||||
info("Waiting for the load in that tab to finish");
|
info("Waiting for the load in that tab to finish");
|
||||||
await secondTabLoadedPromise;
|
await secondTabLoadedPromise;
|
||||||
|
|
||||||
let closeBtn = document.getAnonymousElementByAttribute(secondTab, "anonid", "close-button");
|
let closeBtn = secondTab.closeButton;
|
||||||
info("closing second tab (which will self-close in beforeunload)");
|
info("closing second tab (which will self-close in beforeunload)");
|
||||||
closeBtn.click();
|
closeBtn.click();
|
||||||
ok(secondTab.closing, "Second tab should be marked as closing synchronously.");
|
ok(secondTab.closing, "Second tab should be marked as closing synchronously.");
|
||||||
|
|
|
@ -46,6 +46,7 @@ add_task(async function() {
|
||||||
"anonid", "moz-input-box").getBoundingClientRect();
|
"anonid", "moz-input-box").getBoundingClientRect();
|
||||||
let menuButtonRect =
|
let menuButtonRect =
|
||||||
document.getElementById("PanelUI-menu-button").getBoundingClientRect();
|
document.getElementById("PanelUI-menu-button").getBoundingClientRect();
|
||||||
|
let firstTabRect = gBrowser.selectedTab.getBoundingClientRect();
|
||||||
let frameExpectations = {
|
let frameExpectations = {
|
||||||
filter: rects => rects.filter(r => !(
|
filter: rects => rects.filter(r => !(
|
||||||
// We expect the menu button to get into the active state.
|
// We expect the menu button to get into the active state.
|
||||||
|
@ -60,6 +61,11 @@ add_task(async function() {
|
||||||
r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
|
r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
|
||||||
r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom,
|
r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom,
|
||||||
},
|
},
|
||||||
|
{name: "bug 1547341 - a first tab gets drawn early",
|
||||||
|
condition: r =>
|
||||||
|
r.x1 >= firstTabRect.left && r.x2 <= firstTabRect.right &&
|
||||||
|
r.y1 >= firstTabRect.top && r.y2 <= firstTabRect.bottom,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ add_task(async function open_10_tabs() {
|
||||||
max: 20,
|
max: 20,
|
||||||
},
|
},
|
||||||
"browser.tabs.remote.logSwitchTiming": {
|
"browser.tabs.remote.logSwitchTiming": {
|
||||||
max: 25,
|
max: 35,
|
||||||
},
|
},
|
||||||
"network.loadinfo.skip_type_assertion": {
|
"network.loadinfo.skip_type_assertion": {
|
||||||
// This is accessed in debug only.
|
// This is accessed in debug only.
|
||||||
|
|
|
@ -31,11 +31,12 @@ add_task(async function() {
|
||||||
|
|
||||||
let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
|
let tabStripRect = gBrowser.tabContainer.arrowScrollbox.getBoundingClientRect();
|
||||||
let firstTabRect = gBrowser.selectedTab.getBoundingClientRect();
|
let firstTabRect = gBrowser.selectedTab.getBoundingClientRect();
|
||||||
let firstTabLabelRect =
|
let firstTabLabelRect = gBrowser.selectedTab.textLabel.getBoundingClientRect();
|
||||||
document.getAnonymousElementByAttribute(gBrowser.selectedTab, "anonid", "tab-label")
|
|
||||||
.getBoundingClientRect();
|
|
||||||
let textBoxRect = document.getAnonymousElementByAttribute(gURLBar.textbox,
|
let textBoxRect = document.getAnonymousElementByAttribute(gURLBar.textbox,
|
||||||
"anonid", "moz-input-box").getBoundingClientRect();
|
"anonid", "moz-input-box").getBoundingClientRect();
|
||||||
|
let historyDropmarkerRect = document.getAnonymousElementByAttribute(
|
||||||
|
gURLBar.textbox, "anonid", "historydropmarker").getBoundingClientRect();
|
||||||
|
|
||||||
let inRange = (val, min, max) => min <= val && val <= max;
|
let inRange = (val, min, max) => min <= val && val <= max;
|
||||||
|
|
||||||
// Add a reflow observer and open a new tab.
|
// Add a reflow observer and open a new tab.
|
||||||
|
@ -93,6 +94,12 @@ add_task(async function() {
|
||||||
r.y1 >= firstTabLabelRect.y &&
|
r.y1 >= firstTabLabelRect.y &&
|
||||||
r.y2 <= firstTabLabelRect.bottom,
|
r.y2 <= firstTabLabelRect.bottom,
|
||||||
},
|
},
|
||||||
|
{name: "bug 1547341 - addressbar history dropmarker is shown",
|
||||||
|
condition: r => r.x1 >= historyDropmarkerRect.x &&
|
||||||
|
r.x2 <= historyDropmarkerRect.right &&
|
||||||
|
r.y1 >= historyDropmarkerRect.y &&
|
||||||
|
r.y2 <= historyDropmarkerRect.bottom,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -191,8 +191,14 @@ function makeObserver(aObserveTopic, aObserveFunc) {
|
||||||
return removeMe;
|
return removeMe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerCleanupFunction(function() {
|
||||||
|
Services.prefs.clearUserPref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
Services.prefs.setBoolPref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false);
|
||||||
|
|
||||||
(async function() {
|
(async function() {
|
||||||
for (let testCase of gTests) {
|
for (let testCase of gTests) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ support-files =
|
||||||
dummy_page.html
|
dummy_page.html
|
||||||
../general/audio.ogg
|
../general/audio.ogg
|
||||||
file_mediaPlayback.html
|
file_mediaPlayback.html
|
||||||
|
test_process_flags_chrome.html
|
||||||
|
|
||||||
[browser_accessibility_indicator.js]
|
[browser_accessibility_indicator.js]
|
||||||
skip-if = (verify && debug && (os == 'linux')) || (os == 'win' && processor == 'aarch64')
|
skip-if = (verify && debug && (os == 'linux')) || (os == 'win' && processor == 'aarch64')
|
||||||
|
@ -19,6 +20,17 @@ skip-if = (verify && debug && (os == 'linux'))
|
||||||
support-files =
|
support-files =
|
||||||
test_bug1358314.html
|
test_bug1358314.html
|
||||||
[browser_isLocalAboutURI.js]
|
[browser_isLocalAboutURI.js]
|
||||||
|
[browser_e10s_about_page_triggeringprincipal.js]
|
||||||
|
skip-if = verify
|
||||||
|
support-files =
|
||||||
|
file_about_child.html
|
||||||
|
file_about_parent.html
|
||||||
|
[browser_e10s_switchbrowser.js]
|
||||||
|
[browser_e10s_about_process.js]
|
||||||
|
[browser_e10s_mozillaweb_process.js]
|
||||||
|
[browser_e10s_chrome_process.js]
|
||||||
|
skip-if = debug # Bug 1444565, Bug 1457887
|
||||||
|
[browser_e10s_javascript.js]
|
||||||
[browser_multiselect_tabs_active_tab_selected_by_default.js]
|
[browser_multiselect_tabs_active_tab_selected_by_default.js]
|
||||||
[browser_multiselect_tabs_bookmark.js]
|
[browser_multiselect_tabs_bookmark.js]
|
||||||
[browser_multiselect_tabs_clear_selection_when_tab_switch.js]
|
[browser_multiselect_tabs_clear_selection_when_tab_switch.js]
|
||||||
|
@ -52,7 +64,9 @@ skip-if = !e10s # Test only relevant for e10s.
|
||||||
[browser_new_tab_insert_position.js]
|
[browser_new_tab_insert_position.js]
|
||||||
skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
|
skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
|
||||||
support-files = file_new_tab_page.html
|
support-files = file_new_tab_page.html
|
||||||
[browser_new_tab_in_privileged_process_pref.js]
|
[browser_new_tab_in_privilegedabout_process_pref.js]
|
||||||
|
skip-if = !e10s # Pref and test only relevant for e10s.
|
||||||
|
[browser_privilegedmozilla_process_pref.js]
|
||||||
skip-if = !e10s # Pref and test only relevant for e10s.
|
skip-if = !e10s # Pref and test only relevant for e10s.
|
||||||
[browser_new_web_tab_in_file_process_pref.js]
|
[browser_new_web_tab_in_file_process_pref.js]
|
||||||
skip-if = !e10s # Pref and test only relevant for e10s.
|
skip-if = !e10s # Pref and test only relevant for e10s.
|
||||||
|
|
|
@ -111,8 +111,7 @@ async function test_muting_using_menu(tab, expectMuted) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function test_playing_icon_on_tab(tab, browser, isPinned) {
|
async function test_playing_icon_on_tab(tab, browser, isPinned) {
|
||||||
let icon = document.getAnonymousElementByAttribute(tab, "anonid",
|
let icon = isPinned ? tab.overlayIcon : tab.soundPlayingIcon;
|
||||||
isPinned ? "overlay-icon" : "soundplaying-icon");
|
|
||||||
let isActiveTab = tab === gBrowser.selectedTab;
|
let isActiveTab = tab === gBrowser.selectedTab;
|
||||||
|
|
||||||
await play(tab);
|
await play(tab);
|
||||||
|
@ -241,9 +240,7 @@ async function test_swapped_browser_while_playing(oldTab, newBrowser) {
|
||||||
is(newTab.muteReason, null, "Expected the correct muteReason property on the new tab");
|
is(newTab.muteReason, null, "Expected the correct muteReason property on the new tab");
|
||||||
ok(!newTab.hasAttribute("soundplaying"), "Expected the correct soundplaying attribute on the new tab");
|
ok(!newTab.hasAttribute("soundplaying"), "Expected the correct soundplaying attribute on the new tab");
|
||||||
|
|
||||||
let icon = document.getAnonymousElementByAttribute(newTab, "anonid",
|
await test_tooltip(newTab.soundPlayingIcon, "Unmute tab", true);
|
||||||
"soundplaying-icon");
|
|
||||||
await test_tooltip(icon, "Unmute tab", true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function test_swapped_browser_while_not_playing(oldTab, newBrowser) {
|
async function test_swapped_browser_while_not_playing(oldTab, newBrowser) {
|
||||||
|
@ -281,18 +278,14 @@ async function test_swapped_browser_while_not_playing(oldTab, newBrowser) {
|
||||||
is(newTab.muteReason, null, "Expected the correct muteReason property on the new tab");
|
is(newTab.muteReason, null, "Expected the correct muteReason property on the new tab");
|
||||||
ok(!newTab.hasAttribute("soundplaying"), "Expected the correct soundplaying attribute on the new tab");
|
ok(!newTab.hasAttribute("soundplaying"), "Expected the correct soundplaying attribute on the new tab");
|
||||||
|
|
||||||
let icon = document.getAnonymousElementByAttribute(newTab, "anonid",
|
await test_tooltip(newTab.soundPlayingIcon, "Unmute tab", true);
|
||||||
"soundplaying-icon");
|
|
||||||
await test_tooltip(icon, "Unmute tab", true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function test_browser_swapping(tab, browser) {
|
async function test_browser_swapping(tab, browser) {
|
||||||
// First, test swapping with a playing but muted tab.
|
// First, test swapping with a playing but muted tab.
|
||||||
await play(tab);
|
await play(tab);
|
||||||
|
|
||||||
let icon = document.getAnonymousElementByAttribute(tab, "anonid",
|
await test_mute_tab(tab, tab.soundPlayingIcon, true);
|
||||||
"soundplaying-icon");
|
|
||||||
await test_mute_tab(tab, icon, true);
|
|
||||||
|
|
||||||
await BrowserTestUtils.withNewTab({
|
await BrowserTestUtils.withNewTab({
|
||||||
gBrowser,
|
gBrowser,
|
||||||
|
@ -327,7 +320,7 @@ async function test_click_on_pinned_tab_after_mute() {
|
||||||
await play(tab);
|
await play(tab);
|
||||||
|
|
||||||
// Mute the tab.
|
// Mute the tab.
|
||||||
let icon = document.getAnonymousElementByAttribute(tab, "anonid", "overlay-icon");
|
let icon = tab.overlayIcon;
|
||||||
await test_mute_tab(tab, icon, true);
|
await test_mute_tab(tab, icon, true);
|
||||||
|
|
||||||
// Pause playback and wait for it to finish.
|
// Pause playback and wait for it to finish.
|
||||||
|
@ -337,8 +330,7 @@ async function test_click_on_pinned_tab_after_mute() {
|
||||||
await test_mute_tab(tab, icon, false);
|
await test_mute_tab(tab, icon, false);
|
||||||
|
|
||||||
// Now click on the tab.
|
// Now click on the tab.
|
||||||
let image = document.getAnonymousElementByAttribute(tab, "anonid", "tab-icon-image");
|
EventUtils.synthesizeMouseAtCenter(tab.iconImage, {button: 0});
|
||||||
EventUtils.synthesizeMouseAtCenter(image, {button: 0});
|
|
||||||
|
|
||||||
is(tab, gBrowser.selectedTab, "Tab switch should be successful");
|
is(tab, gBrowser.selectedTab, "Tab switch should be successful");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
const CHROME = {
|
||||||
|
id: "cb34538a-d9da-40f3-b61a-069f0b2cb9fb",
|
||||||
|
path: "test-chrome",
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
const CANREMOTE = {
|
||||||
|
id: "2480d3e1-9ce4-4b84-8ae3-910b9a95cbb3",
|
||||||
|
path: "test-allowremote",
|
||||||
|
flags: Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD,
|
||||||
|
};
|
||||||
|
const MUSTREMOTE = {
|
||||||
|
id: "f849cee5-e13e-44d2-981d-0fb3884aaead",
|
||||||
|
path: "test-mustremote",
|
||||||
|
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD,
|
||||||
|
};
|
||||||
|
const CANPRIVILEGEDREMOTE = {
|
||||||
|
id: "a04ffafe-6c63-4266-acae-0f4b093165aa",
|
||||||
|
path: "test-canprivilegedremote",
|
||||||
|
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
|
||||||
|
Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS,
|
||||||
|
};
|
||||||
|
const MUSTEXTENSION = {
|
||||||
|
id: "f7a1798f-965b-49e9-be83-ec6ee4d7d675",
|
||||||
|
path: "test-mustextension",
|
||||||
|
flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_EXTENSION_PROCESS,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const TEST_MODULES = [
|
||||||
|
CHROME,
|
||||||
|
CANREMOTE,
|
||||||
|
MUSTREMOTE,
|
||||||
|
CANPRIVILEGEDREMOTE,
|
||||||
|
MUSTEXTENSION,
|
||||||
|
];
|
||||||
|
|
||||||
|
function AboutModule() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AboutModule.prototype = {
|
||||||
|
newChannel(aURI, aLoadInfo) {
|
||||||
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
},
|
||||||
|
|
||||||
|
getURIFlags(aURI) {
|
||||||
|
for (let module of TEST_MODULES) {
|
||||||
|
if (aURI.pathQueryRef.startsWith(module.path)) {
|
||||||
|
return module.flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(false, "Called getURIFlags for an unknown page " + aURI.spec);
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
getIndexedDBOriginPostfix(aURI) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
|
||||||
|
};
|
||||||
|
|
||||||
|
var AboutModuleFactory = {
|
||||||
|
createInstance(aOuter, aIID) {
|
||||||
|
if (aOuter)
|
||||||
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||||
|
return new AboutModule().QueryInterface(aIID);
|
||||||
|
},
|
||||||
|
|
||||||
|
lockFactory(aLock) {
|
||||||
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
},
|
||||||
|
|
||||||
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory]),
|
||||||
|
};
|
||||||
|
|
||||||
|
add_task(async function init() {
|
||||||
|
SpecialPowers.setBoolPref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", true);
|
||||||
|
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||||
|
for (let module of TEST_MODULES) {
|
||||||
|
registrar.registerFactory(Components.ID(module.id), "",
|
||||||
|
"@mozilla.org/network/protocol/about;1?what=" + module.path,
|
||||||
|
AboutModuleFactory);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerCleanupFunction(() => {
|
||||||
|
SpecialPowers.clearUserPref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess");
|
||||||
|
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||||
|
for (let module of TEST_MODULES) {
|
||||||
|
registrar.unregisterFactory(Components.ID(module.id), AboutModuleFactory);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_chrome() {
|
||||||
|
test_url_for_process_types("about:" + CHROME.path, true, false, false, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_any() {
|
||||||
|
test_url_for_process_types("about:" + CANREMOTE.path, true, true, false, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_remote() {
|
||||||
|
test_url_for_process_types("about:" + MUSTREMOTE.path, false, true, false, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_privileged_remote_true() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// This shouldn't be taken literally. We will always use the privleged about
|
||||||
|
// content type if the URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS flag is enabled and
|
||||||
|
// the pref is turned on.
|
||||||
|
test_url_for_process_types("about:" + CANPRIVILEGEDREMOTE.path, false, false, true, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_privileged_remote_false() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.tabs.remote.separatePrivilegedContentProcess", false],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// This shouldn't be taken literally. We will always use the privleged about
|
||||||
|
// content type if the URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS flag is enabled and
|
||||||
|
// the pref is turned on.
|
||||||
|
test_url_for_process_types("about:" + CANPRIVILEGEDREMOTE.path, false, true, false, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_extension() {
|
||||||
|
test_url_for_process_types("about:" + MUSTEXTENSION.path, false, false, false, false, true);
|
||||||
|
});
|
|
@ -32,8 +32,6 @@ function makeTest(name, startURL, startProcessIsRemote, endURL, endProcessIsRemo
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHROME_PROCESS = E10SUtils.NOT_REMOTE;
|
|
||||||
const WEB_CONTENT_PROCESS = E10SUtils.WEB_REMOTE_TYPE;
|
|
||||||
const PATH = (getRootDirectory(gTestPath) + "test_process_flags_chrome.html").replace("chrome://mochitests", "");
|
const PATH = (getRootDirectory(gTestPath) + "test_process_flags_chrome.html").replace("chrome://mochitests", "");
|
||||||
|
|
||||||
const CHROME = "chrome://mochitests" + PATH;
|
const CHROME = "chrome://mochitests" + PATH;
|
||||||
|
@ -48,38 +46,16 @@ registerCleanupFunction(() => {
|
||||||
gBrowser.removeCurrentTab();
|
gBrowser.removeCurrentTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
function test_url(url, chromeResult, contentResult) {
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
contentResult, "Check URL in web content process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with ref in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
contentResult, "Check URL with ref in web content process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with query in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
contentResult, "Check URL with query in web content process.");
|
|
||||||
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, CHROME_PROCESS),
|
|
||||||
chromeResult, "Check URL with query and ref in chrome process.");
|
|
||||||
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, WEB_CONTENT_PROCESS),
|
|
||||||
contentResult, "Check URL with query and ref in web content process.");
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_chrome() {
|
add_task(async function test_chrome() {
|
||||||
test_url(CHROME, true, false);
|
test_url_for_process_types(CHROME, true, false, false, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_any() {
|
add_task(async function test_any() {
|
||||||
test_url(CANREMOTE, true, true);
|
test_url_for_process_types(CANREMOTE, true, true, false, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_remote() {
|
add_task(async function test_remote() {
|
||||||
test_url(MUSTREMOTE, false, true);
|
test_url_for_process_types(MUSTREMOTE, false, true, false, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The set of page transitions
|
// The set of page transitions
|
|
@ -0,0 +1,24 @@
|
||||||
|
add_task(async function test_privileged_remote_true() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
||||||
|
["browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", true],
|
||||||
|
["browser.tabs.remote.separatedMozillaDomains", "example.org"],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test_url_for_process_types("https://example.com", false, true, false, false, false);
|
||||||
|
test_url_for_process_types("https://example.org", false, false, false, true, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_privileged_remote_false() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
||||||
|
["browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test_url_for_process_types("https://example.com", false, true, false, false, false);
|
||||||
|
test_url_for_process_types("https://example.org", false, true, false, false, false);
|
||||||
|
});
|
|
@ -29,7 +29,7 @@ add_task(async function usingTabCloseButton() {
|
||||||
is(gBrowser.selectedTab, tab1, "Tab1 is active");
|
is(gBrowser.selectedTab, tab1, "Tab1 is active");
|
||||||
|
|
||||||
// Closing a tab which is not multiselected
|
// Closing a tab which is not multiselected
|
||||||
let tab4CloseBtn = document.getAnonymousElementByAttribute(tab4, "anonid", "close-button");
|
let tab4CloseBtn = tab4.closeButton;
|
||||||
let tab4Closing = BrowserTestUtils.waitForTabClosing(tab4);
|
let tab4Closing = BrowserTestUtils.waitForTabClosing(tab4);
|
||||||
|
|
||||||
tab4.mOverCloseButton = true;
|
tab4.mOverCloseButton = true;
|
||||||
|
@ -48,7 +48,7 @@ add_task(async function usingTabCloseButton() {
|
||||||
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
|
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
|
||||||
|
|
||||||
// Closing a selected tab
|
// Closing a selected tab
|
||||||
let tab2CloseBtn = document.getAnonymousElementByAttribute(tab2, "anonid", "close-button");
|
let tab2CloseBtn = tab2.closeButton;
|
||||||
tab2.mOverCloseButton = true;
|
tab2.mOverCloseButton = true;
|
||||||
let tab1Closing = BrowserTestUtils.waitForTabClosing(tab1);
|
let tab1Closing = BrowserTestUtils.waitForTabClosing(tab1);
|
||||||
let tab2Closing = BrowserTestUtils.waitForTabClosing(tab2);
|
let tab2Closing = BrowserTestUtils.waitForTabClosing(tab2);
|
||||||
|
|
|
@ -55,7 +55,7 @@ add_task(async function muteTabs_usingButton() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mute tab0 which is not multiselected, thus other tabs muted state should not be affected
|
// Mute tab0 which is not multiselected, thus other tabs muted state should not be affected
|
||||||
let tab0MuteAudioBtn = document.getAnonymousElementByAttribute(tab0, "anonid", "soundplaying-icon");
|
let tab0MuteAudioBtn = tab0.soundPlayingIcon;
|
||||||
await test_mute_tab(tab0, tab0MuteAudioBtn, true);
|
await test_mute_tab(tab0, tab0MuteAudioBtn, true);
|
||||||
|
|
||||||
ok(muted(tab0), "Tab0 is muted");
|
ok(muted(tab0), "Tab0 is muted");
|
||||||
|
@ -85,7 +85,7 @@ add_task(async function muteTabs_usingButton() {
|
||||||
// b) unmuted tabs (tab1, tab3) will become muted.
|
// b) unmuted tabs (tab1, tab3) will become muted.
|
||||||
// b) media-blocked tabs (tab2) will remain media-blocked.
|
// b) media-blocked tabs (tab2) will remain media-blocked.
|
||||||
// However tab4 (unmuted) which is not multiselected should not be affected.
|
// However tab4 (unmuted) which is not multiselected should not be affected.
|
||||||
let tab1MuteAudioBtn = document.getAnonymousElementByAttribute(tab1, "anonid", "soundplaying-icon");
|
let tab1MuteAudioBtn = tab1.soundPlayingIcon;
|
||||||
await test_mute_tab(tab1, tab1MuteAudioBtn, true);
|
await test_mute_tab(tab1, tab1MuteAudioBtn, true);
|
||||||
|
|
||||||
// Check mute state
|
// Check mute state
|
||||||
|
@ -141,7 +141,7 @@ add_task(async function unmuteTabs_usingButton() {
|
||||||
// b) unmuted tabs (tab0) will remain unmuted.
|
// b) unmuted tabs (tab0) will remain unmuted.
|
||||||
// b) media-blocked tabs (tab1, tab2) will get playing. (media not blocked anymore)
|
// b) media-blocked tabs (tab1, tab2) will get playing. (media not blocked anymore)
|
||||||
// However tab4 (muted) which is not multiselected should not be affected.
|
// However tab4 (muted) which is not multiselected should not be affected.
|
||||||
let tab3MuteAudioBtn = document.getAnonymousElementByAttribute(tab3, "anonid", "soundplaying-icon");
|
let tab3MuteAudioBtn = tab3.soundPlayingIcon;
|
||||||
await test_mute_tab(tab3, tab3MuteAudioBtn, false);
|
await test_mute_tab(tab3, tab3MuteAudioBtn, false);
|
||||||
|
|
||||||
ok(!muted(tab0) && !activeMediaBlocked(tab0), "Tab0 is unmuted and not media-blocked");
|
ok(!muted(tab0) && !activeMediaBlocked(tab0), "Tab0 is unmuted and not media-blocked");
|
||||||
|
@ -249,7 +249,7 @@ add_task(async function playTabs_usingButton() {
|
||||||
// b) unmuted tabs (tab3) will remain unmuted.
|
// b) unmuted tabs (tab3) will remain unmuted.
|
||||||
// b) media-blocked tabs (tab1, tab2) will get playing. (media not blocked anymore)
|
// b) media-blocked tabs (tab1, tab2) will get playing. (media not blocked anymore)
|
||||||
// However tab4 (muted) which is not multiselected should not be affected.
|
// However tab4 (muted) which is not multiselected should not be affected.
|
||||||
let tab2MuteAudioBtn = document.getAnonymousElementByAttribute(tab2, "anonid", "soundplaying-icon");
|
let tab2MuteAudioBtn = tab2.soundPlayingIcon;
|
||||||
await test_mute_tab(tab2, tab2MuteAudioBtn, false);
|
await test_mute_tab(tab2, tab2MuteAudioBtn, false);
|
||||||
|
|
||||||
ok(!muted(tab0) && !activeMediaBlocked(tab0), "Tab0 is unmuted and not activemedia-blocked");
|
ok(!muted(tab0) && !activeMediaBlocked(tab0), "Tab0 is unmuted and not activemedia-blocked");
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to ensure that Activity Stream loads in the privileged content process.
|
* Tests to ensure that Activity Stream loads in the privileged about:
|
||||||
* Normal http web pages should load in the web content process.
|
* content process. Normal http web pages should load in the web content
|
||||||
|
* process.
|
||||||
* Ref: Bug 1469072.
|
* Ref: Bug 1469072.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -16,54 +17,29 @@ const ABOUT_NEWTAB = "about:newtab";
|
||||||
const ABOUT_WELCOME = "about:welcome";
|
const ABOUT_WELCOME = "about:welcome";
|
||||||
const TEST_HTTP = "http://example.org/";
|
const TEST_HTTP = "http://example.org/";
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a xul:browser and makes sure that the remoteTypes for the browser in
|
|
||||||
* both the parent and the child processes are the same.
|
|
||||||
*
|
|
||||||
* @param {xul:browser} browser
|
|
||||||
* A xul:browser.
|
|
||||||
* @param {string} expectedRemoteType
|
|
||||||
* The expected remoteType value for the browser in both the parent
|
|
||||||
* and child processes.
|
|
||||||
* @param {optional string} message
|
|
||||||
* If provided, shows this string as the message when remoteType values
|
|
||||||
* do not match. If not present, it uses the default message defined
|
|
||||||
* in the function parameters.
|
|
||||||
*/
|
|
||||||
function checkBrowserRemoteType(
|
|
||||||
browser,
|
|
||||||
expectedRemoteType,
|
|
||||||
message = `Ensures that tab runs in the ${expectedRemoteType} content process.`
|
|
||||||
) {
|
|
||||||
// Check both parent and child to ensure that they have the correct remoteType.
|
|
||||||
is(browser.remoteType, expectedRemoteType, message);
|
|
||||||
is(browser.messageManager.remoteType, expectedRemoteType,
|
|
||||||
"Parent and child process should agree on the remote type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function setup() {
|
add_task(async function setup() {
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["browser.newtab.preload", false],
|
["browser.newtab.preload", false],
|
||||||
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
["browser.tabs.remote.separatePrivilegedContentProcess", true],
|
||||||
["dom.ipc.processCount.privileged", 1],
|
["dom.ipc.processCount.privilegedabout", 1],
|
||||||
["dom.ipc.keepProcessesAlive.privileged", 1],
|
["dom.ipc.keepProcessesAlive.privilegedabout", 1],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test to ensure that the Activity Stream tabs open in privileged content
|
* Test to ensure that the Activity Stream tabs open in privileged about: content
|
||||||
* process. We will first open an about:newtab page that acts as a reference to
|
* process. We will first open an about:newtab page that acts as a reference to
|
||||||
* the privileged content process. With the reference, we can then open Activity
|
* the privileged about: content process. With the reference, we can then open
|
||||||
* Stream links in a new tab and ensure that the new tab opens in the same
|
* Activity Stream links in a new tab and ensure that the new tab opens in the same
|
||||||
* privileged content process as our reference.
|
* privileged about: content process as our reference.
|
||||||
*/
|
*/
|
||||||
add_task(async function activity_stream_in_privileged_content_process() {
|
add_task(async function activity_stream_in_privileged_content_process() {
|
||||||
Services.ppmm.releaseCachedProcesses();
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
|
||||||
await BrowserTestUtils.withNewTab(ABOUT_NEWTAB, async function(browser1) {
|
await BrowserTestUtils.withNewTab(ABOUT_NEWTAB, async function(browser1) {
|
||||||
checkBrowserRemoteType(browser1, E10SUtils.PRIVILEGED_REMOTE_TYPE);
|
checkBrowserRemoteType(browser1, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE);
|
||||||
|
|
||||||
// Note the processID for about:newtab for comparison later.
|
// Note the processID for about:newtab for comparison later.
|
||||||
let privilegedPid = browser1.frameLoader.remoteTab.osPid;
|
let privilegedPid = browser1.frameLoader.remoteTab.osPid;
|
||||||
|
@ -81,7 +57,7 @@ add_task(async function activity_stream_in_privileged_content_process() {
|
||||||
]) {
|
]) {
|
||||||
await BrowserTestUtils.withNewTab(url, async function(browser2) {
|
await BrowserTestUtils.withNewTab(url, async function(browser2) {
|
||||||
is(browser2.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser2.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that about:newtab tabs are in the same privileged content process.");
|
"Check that about:newtab tabs are in the same privileged about: content process.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -100,25 +76,25 @@ add_task(async function process_switching_through_loading_in_the_same_tab() {
|
||||||
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
||||||
|
|
||||||
for (let [url, remoteType] of [
|
for (let [url, remoteType] of [
|
||||||
[ABOUT_NEWTAB, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[ABOUT_NEWTAB, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[ABOUT_BLANK, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[ABOUT_BLANK, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[ABOUT_HOME, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[ABOUT_HOME, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[ABOUT_WELCOME, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[ABOUT_WELCOME, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[ABOUT_BLANK, E10SUtils.WEB_REMOTE_TYPE],
|
[ABOUT_BLANK, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_NEWTAB}#foo`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_NEWTAB}#foo`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_WELCOME}#bar`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_WELCOME}#bar`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_HOME}#baz`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_HOME}#baz`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_NEWTAB}?q=foo`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_NEWTAB}?q=foo`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_WELCOME}?q=bar`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_WELCOME}?q=bar`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
[`${ABOUT_HOME}?q=baz`, E10SUtils.PRIVILEGED_REMOTE_TYPE],
|
[`${ABOUT_HOME}?q=baz`, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE],
|
||||||
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
[TEST_HTTP, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
]) {
|
]) {
|
||||||
BrowserTestUtils.loadURI(browser, url);
|
BrowserTestUtils.loadURI(browser, url);
|
||||||
|
@ -139,7 +115,7 @@ add_task(async function process_switching_through_navigation_features() {
|
||||||
Services.ppmm.releaseCachedProcesses();
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
|
||||||
await BrowserTestUtils.withNewTab(ABOUT_NEWTAB, async function(browser) {
|
await BrowserTestUtils.withNewTab(ABOUT_NEWTAB, async function(browser) {
|
||||||
checkBrowserRemoteType(browser, E10SUtils.PRIVILEGED_REMOTE_TYPE);
|
checkBrowserRemoteType(browser, E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE);
|
||||||
|
|
||||||
// Note the processID for about:newtab for comparison later.
|
// Note the processID for about:newtab for comparison later.
|
||||||
let privilegedPid = browser.frameLoader.remoteTab.osPid;
|
let privilegedPid = browser.frameLoader.remoteTab.osPid;
|
||||||
|
@ -155,20 +131,20 @@ add_task(async function process_switching_through_navigation_features() {
|
||||||
});
|
});
|
||||||
browser = newTab.linkedBrowser;
|
browser = newTab.linkedBrowser;
|
||||||
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that new tab opened from about:newtab is loaded in privileged content process.");
|
"Check that new tab opened from about:newtab is loaded in privileged about: content process.");
|
||||||
|
|
||||||
// Check that reload does not break the privileged content process affinity.
|
// Check that reload does not break the privileged about: content process affinity.
|
||||||
BrowserReload();
|
BrowserReload();
|
||||||
await BrowserTestUtils.browserLoaded(browser, false, ABOUT_NEWTAB);
|
await BrowserTestUtils.browserLoaded(browser, false, ABOUT_NEWTAB);
|
||||||
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that about:newtab is still in privileged content process after reload.");
|
"Check that about:newtab is still in privileged about: content process after reload.");
|
||||||
|
|
||||||
// Load http webpage
|
// Load http webpage
|
||||||
BrowserTestUtils.loadURI(browser, TEST_HTTP);
|
BrowserTestUtils.loadURI(browser, TEST_HTTP);
|
||||||
await BrowserTestUtils.browserLoaded(browser, false, TEST_HTTP);
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_HTTP);
|
||||||
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
||||||
|
|
||||||
// Check that using the history back feature switches back to privileged content process.
|
// Check that using the history back feature switches back to privileged about: content process.
|
||||||
let promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, ABOUT_NEWTAB);
|
let promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, ABOUT_NEWTAB);
|
||||||
browser.goBack();
|
browser.goBack();
|
||||||
await promiseLocation;
|
await promiseLocation;
|
||||||
|
@ -176,7 +152,7 @@ add_task(async function process_switching_through_navigation_features() {
|
||||||
// the navigation history data will be available when we do browser.goForward();
|
// the navigation history data will be available when we do browser.goForward();
|
||||||
await BrowserTestUtils.waitForEvent(newTab, "SSTabRestored");
|
await BrowserTestUtils.waitForEvent(newTab, "SSTabRestored");
|
||||||
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that about:newtab is still in privileged content process after history goBack.");
|
"Check that about:newtab is still in privileged about: content process after history goBack.");
|
||||||
|
|
||||||
// Check that using the history forward feature switches back to the web content process.
|
// Check that using the history forward feature switches back to the web content process.
|
||||||
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP);
|
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP);
|
||||||
|
@ -193,7 +169,7 @@ add_task(async function process_switching_through_navigation_features() {
|
||||||
browser.gotoIndex(0);
|
browser.gotoIndex(0);
|
||||||
await promiseLocation;
|
await promiseLocation;
|
||||||
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that about:newtab is in privileged content process after history gotoIndex.");
|
"Check that about:newtab is in privileged about: content process after history gotoIndex.");
|
||||||
|
|
||||||
BrowserTestUtils.loadURI(browser, TEST_HTTP);
|
BrowserTestUtils.loadURI(browser, TEST_HTTP);
|
||||||
await BrowserTestUtils.browserLoaded(browser, false, TEST_HTTP);
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_HTTP);
|
||||||
|
@ -205,7 +181,7 @@ add_task(async function process_switching_through_navigation_features() {
|
||||||
});
|
});
|
||||||
await BrowserTestUtils.browserLoaded(browser, false, ABOUT_NEWTAB);
|
await BrowserTestUtils.browserLoaded(browser, false, ABOUT_NEWTAB);
|
||||||
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
"Check that about:newtab is in privileged content process after location change.");
|
"Check that about:newtab is in privileged about: content process after location change.");
|
||||||
});
|
});
|
||||||
|
|
||||||
Services.ppmm.releaseCachedProcesses();
|
Services.ppmm.releaseCachedProcesses();
|
|
@ -0,0 +1,183 @@
|
||||||
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to ensure that Mozilla Privileged Webpages load in the privileged
|
||||||
|
* mozilla web content process. Normal http web pages should load in the web
|
||||||
|
* content process.
|
||||||
|
* Ref: Bug 1539595.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// High and Low Privilege
|
||||||
|
const TEST_HIGH1 = "https://example.org/";
|
||||||
|
const TEST_HIGH2 = "https://test1.example.org/";
|
||||||
|
const TEST_LOW1 = "http://example.org/";
|
||||||
|
const TEST_LOW2 = "https://example.com/";
|
||||||
|
|
||||||
|
add_task(async function setup() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [
|
||||||
|
["browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", true],
|
||||||
|
["browser.tabs.remote.separatedMozillaDomains", "example.org"],
|
||||||
|
["dom.ipc.processCount.privilegedmozilla", 1],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test to ensure that the tabs open in privileged mozilla content process. We
|
||||||
|
* will first open a page that acts as a reference to the privileged mozilla web
|
||||||
|
* content process. With the reference, we can then open other links in a new tab
|
||||||
|
* and ensure that the new tab opens in the same privileged mozilla content process
|
||||||
|
* as our reference.
|
||||||
|
*/
|
||||||
|
add_task(async function webpages_in_privileged_content_process() {
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
|
||||||
|
await BrowserTestUtils.withNewTab(TEST_HIGH1, async function(browser1) {
|
||||||
|
checkBrowserRemoteType(browser1, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE);
|
||||||
|
|
||||||
|
// Note the processID for about:newtab for comparison later.
|
||||||
|
let privilegedPid = browser1.frameLoader.remoteTab.osPid;
|
||||||
|
|
||||||
|
for (let url of [
|
||||||
|
TEST_HIGH1,
|
||||||
|
`${TEST_HIGH1}#foo`,
|
||||||
|
`${TEST_HIGH1}?q=foo`,
|
||||||
|
TEST_HIGH2,
|
||||||
|
`${TEST_HIGH2}#foo`,
|
||||||
|
`${TEST_HIGH2}?q=foo`,
|
||||||
|
]) {
|
||||||
|
await BrowserTestUtils.withNewTab(url, async function(browser2) {
|
||||||
|
is(browser2.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that privileged pages are in the same privileged mozilla content process.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test to ensure that a process switch occurs when navigating between normal
|
||||||
|
* web pages and unprivileged pages in the same tab.
|
||||||
|
*/
|
||||||
|
add_task(async function process_switching_through_loading_in_the_same_tab() {
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
|
||||||
|
await BrowserTestUtils.withNewTab(TEST_LOW1, async function(browser) {
|
||||||
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
||||||
|
|
||||||
|
for (let [url, remoteType] of [
|
||||||
|
[TEST_HIGH1, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW1, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[TEST_HIGH1, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW2, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[TEST_HIGH1, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW1, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[TEST_LOW2, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}#foo`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW1, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}#bar`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW2, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}#baz`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW1, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}?q=foo`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW2, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}?q=bar`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW1, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
[`${TEST_HIGH1}?q=baz`, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE],
|
||||||
|
[TEST_LOW2, E10SUtils.WEB_REMOTE_TYPE],
|
||||||
|
]) {
|
||||||
|
BrowserTestUtils.loadURI(browser, url);
|
||||||
|
await BrowserTestUtils.browserLoaded(browser, false, url);
|
||||||
|
checkBrowserRemoteType(browser, remoteType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test to ensure that a process switch occurs when navigating between normal
|
||||||
|
* web pages and privileged pages using the browser's navigation features
|
||||||
|
* such as history and location change.
|
||||||
|
*/
|
||||||
|
add_task(async function process_switching_through_navigation_features() {
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
|
||||||
|
await BrowserTestUtils.withNewTab(TEST_HIGH1, async function(browser) {
|
||||||
|
checkBrowserRemoteType(browser, E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE);
|
||||||
|
|
||||||
|
// Note the processID for about:newtab for comparison later.
|
||||||
|
let privilegedPid = browser.frameLoader.remoteTab.osPid;
|
||||||
|
|
||||||
|
// Check that about:newtab opened from JS in about:newtab page is in the same process.
|
||||||
|
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, TEST_HIGH1, true);
|
||||||
|
await ContentTask.spawn(browser, TEST_HIGH1, uri => {
|
||||||
|
content.open(uri, "_blank");
|
||||||
|
});
|
||||||
|
let newTab = await promiseTabOpened;
|
||||||
|
registerCleanupFunction(async function() {
|
||||||
|
BrowserTestUtils.removeTab(newTab);
|
||||||
|
});
|
||||||
|
browser = newTab.linkedBrowser;
|
||||||
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that new tab opened from privileged page is loaded in privileged mozilla content process.");
|
||||||
|
|
||||||
|
// Check that reload does not break the privileged mozilla content process affinity.
|
||||||
|
BrowserReload();
|
||||||
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_HIGH1);
|
||||||
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that privileged page is still in privileged mozilla content process after reload.");
|
||||||
|
|
||||||
|
// Load http webpage
|
||||||
|
BrowserTestUtils.loadURI(browser, TEST_LOW1);
|
||||||
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_LOW1);
|
||||||
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
||||||
|
|
||||||
|
// Check that using the history back feature switches back to privileged mozilla content process.
|
||||||
|
let promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HIGH1);
|
||||||
|
browser.goBack();
|
||||||
|
await promiseLocation;
|
||||||
|
// We will need to ensure that the process flip has fully completed so that
|
||||||
|
// the navigation history data will be available when we do browser.goForward();
|
||||||
|
await BrowserTestUtils.waitForEvent(newTab, "SSTabRestored");
|
||||||
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that privileged page is still in privileged mozilla content process after history goBack.");
|
||||||
|
|
||||||
|
// Check that using the history forward feature switches back to the web content process.
|
||||||
|
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_LOW1);
|
||||||
|
browser.goForward();
|
||||||
|
await promiseLocation;
|
||||||
|
// We will need to ensure that the process flip has fully completed so that
|
||||||
|
// the navigation history data will be available when we do browser.gotoIndex(0);
|
||||||
|
await BrowserTestUtils.waitForEvent(newTab, "SSTabRestored");
|
||||||
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE,
|
||||||
|
"Check that tab runs in the web content process after using history goForward.");
|
||||||
|
|
||||||
|
// Check that goto history index does not break the affinity.
|
||||||
|
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HIGH1);
|
||||||
|
browser.gotoIndex(0);
|
||||||
|
await promiseLocation;
|
||||||
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that privileged page is in privileged mozilla content process after history gotoIndex.");
|
||||||
|
|
||||||
|
BrowserTestUtils.loadURI(browser, TEST_LOW2);
|
||||||
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_LOW2);
|
||||||
|
checkBrowserRemoteType(browser, E10SUtils.WEB_REMOTE_TYPE);
|
||||||
|
|
||||||
|
// Check that location change causes a change in process type as well.
|
||||||
|
await ContentTask.spawn(browser, TEST_HIGH1, uri => {
|
||||||
|
content.location = uri;
|
||||||
|
});
|
||||||
|
await BrowserTestUtils.browserLoaded(browser, false, TEST_HIGH1);
|
||||||
|
is(browser.frameLoader.remoteTab.osPid, privilegedPid,
|
||||||
|
"Check that privileged page is in privileged mozilla content process after location change.");
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.ppmm.releaseCachedProcesses();
|
||||||
|
});
|
|
@ -53,7 +53,7 @@ async function overflowTabs() {
|
||||||
|
|
||||||
function getLastCloseButton() {
|
function getLastCloseButton() {
|
||||||
let lastTab = gBrowser.tabs[gBrowser.tabs.length - 1];
|
let lastTab = gBrowser.tabs[gBrowser.tabs.length - 1];
|
||||||
return document.getAnonymousElementByAttribute(lastTab, "anonid", "close-button");
|
return lastTab.closeButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLastCloseButtonLocation() {
|
function getLastCloseButtonLocation() {
|
||||||
|
|
|
@ -189,3 +189,80 @@ async function dragAndDrop(tab1, tab2, copy, destWindow = window) {
|
||||||
function getUrl(tab) {
|
function getUrl(tab) {
|
||||||
return tab.linkedBrowser.currentURI.spec;
|
return tab.linkedBrowser.currentURI.spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a xul:browser and makes sure that the remoteTypes for the browser in
|
||||||
|
* both the parent and the child processes are the same.
|
||||||
|
*
|
||||||
|
* @param {xul:browser} browser
|
||||||
|
* A xul:browser.
|
||||||
|
* @param {string} expectedRemoteType
|
||||||
|
* The expected remoteType value for the browser in both the parent
|
||||||
|
* and child processes.
|
||||||
|
* @param {optional string} message
|
||||||
|
* If provided, shows this string as the message when remoteType values
|
||||||
|
* do not match. If not present, it uses the default message defined
|
||||||
|
* in the function parameters.
|
||||||
|
*/
|
||||||
|
function checkBrowserRemoteType(
|
||||||
|
browser,
|
||||||
|
expectedRemoteType,
|
||||||
|
message = `Ensures that tab runs in the ${expectedRemoteType} content process.`
|
||||||
|
) {
|
||||||
|
// Check both parent and child to ensure that they have the correct remoteType.
|
||||||
|
is(browser.remoteType, expectedRemoteType, message);
|
||||||
|
is(browser.messageManager.remoteType, expectedRemoteType,
|
||||||
|
"Parent and child process should agree on the remote type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_url_for_process_types(url, chromeResult, webContentResult, privilegedAboutContentResult, privilegedMozillaContentResult, extensionProcessResult) {
|
||||||
|
const CHROME_PROCESS = E10SUtils.NOT_REMOTE;
|
||||||
|
const WEB_CONTENT_PROCESS = E10SUtils.WEB_REMOTE_TYPE;
|
||||||
|
const PRIVILEGEDABOUT_CONTENT_PROCESS = E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE;
|
||||||
|
const PRIVILEGEDMOZILLA_CONTENT_PROCESS = E10SUtils.PRIVILEGEDMOZILLA_REMOTE_TYPE;
|
||||||
|
const EXTENSION_PROCESS = E10SUtils.EXTENSION_REMOTE_TYPE;
|
||||||
|
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, CHROME_PROCESS),
|
||||||
|
chromeResult, "Check URL in chrome process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, WEB_CONTENT_PROCESS),
|
||||||
|
webContentResult, "Check URL in web content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, PRIVILEGEDABOUT_CONTENT_PROCESS),
|
||||||
|
privilegedAboutContentResult, "Check URL in privileged about content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, PRIVILEGEDMOZILLA_CONTENT_PROCESS),
|
||||||
|
privilegedMozillaContentResult, "Check URL in privileged mozilla content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url, /* fission */ false, EXTENSION_PROCESS),
|
||||||
|
extensionProcessResult, "Check URL in extension process.");
|
||||||
|
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, CHROME_PROCESS),
|
||||||
|
chromeResult, "Check URL with ref in chrome process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
||||||
|
webContentResult, "Check URL with ref in web content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, PRIVILEGEDABOUT_CONTENT_PROCESS),
|
||||||
|
privilegedAboutContentResult, "Check URL with ref in privileged about content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, PRIVILEGEDMOZILLA_CONTENT_PROCESS),
|
||||||
|
privilegedMozillaContentResult, "Check URL with ref in privileged mozilla content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "#foo", /* fission */ false, EXTENSION_PROCESS),
|
||||||
|
extensionProcessResult, "Check URL with ref in extension process.");
|
||||||
|
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, CHROME_PROCESS),
|
||||||
|
chromeResult, "Check URL with query in chrome process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, WEB_CONTENT_PROCESS),
|
||||||
|
webContentResult, "Check URL with query in web content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, PRIVILEGEDABOUT_CONTENT_PROCESS),
|
||||||
|
privilegedAboutContentResult, "Check URL with query in privileged about content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, PRIVILEGEDMOZILLA_CONTENT_PROCESS),
|
||||||
|
privilegedMozillaContentResult, "Check URL with query in privileged mozilla content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo", /* fission */ false, EXTENSION_PROCESS),
|
||||||
|
extensionProcessResult, "Check URL with query in extension process.");
|
||||||
|
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, CHROME_PROCESS),
|
||||||
|
chromeResult, "Check URL with query and ref in chrome process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, WEB_CONTENT_PROCESS),
|
||||||
|
webContentResult, "Check URL with query and ref in web content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, PRIVILEGEDABOUT_CONTENT_PROCESS),
|
||||||
|
privilegedAboutContentResult, "Check URL with query and ref in privileged about content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, PRIVILEGEDMOZILLA_CONTENT_PROCESS),
|
||||||
|
privilegedMozillaContentResult, "Check URL with query and ref in privileged mozilla content process.");
|
||||||
|
is(E10SUtils.canLoadURIInRemoteType(url + "?foo#bar", /* fission */ false, EXTENSION_PROCESS),
|
||||||
|
extensionProcessResult, "Check URL with query and ref in extension process.");
|
||||||
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<p>chrome: test page</p>
|
<p>chrome: test page</p>
|
||||||
<p><a href="chrome://mochitests/content/browser/browser/base/content/test/general/test_process_flags_chrome.html">chrome</a></p>
|
<p><a href="chrome://mochitests/content/browser/browser/base/content/test/tabs/test_process_flags_chrome.html">chrome</a></p>
|
||||||
<p><a href="chrome://mochitests-any/content/browser/browser/base/content/test/general/test_process_flags_chrome.html">canremote</a></p>
|
<p><a href="chrome://mochitests-any/content/browser/browser/base/content/test/tabs/test_process_flags_chrome.html">canremote</a></p>
|
||||||
<p><a href="chrome://mochitests-content/content/browser/browser/base/content/test/general/test_process_flags_chrome.html">mustremote</a></p>
|
<p><a href="chrome://mochitests-content/content/browser/browser/base/content/test/tabs/test_process_flags_chrome.html">mustremote</a></p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -33,8 +33,7 @@ var gTests = [
|
||||||
let tab = gBrowser.selectedTab;
|
let tab = gBrowser.selectedTab;
|
||||||
is(tab.getAttribute("sharing"), aSharing,
|
is(tab.getAttribute("sharing"), aSharing,
|
||||||
"the tab has the attribute to show the " + aSharing + " icon");
|
"the tab has the attribute to show the " + aSharing + " icon");
|
||||||
let icon =
|
let icon = tab.sharingIcon;
|
||||||
document.getAnonymousElementByAttribute(tab, "anonid", "sharing-icon");
|
|
||||||
is(window.getComputedStyle(icon).display, "none",
|
is(window.getComputedStyle(icon).display, "none",
|
||||||
"the animated sharing icon of the tab is hidden");
|
"the animated sharing icon of the tab is hidden");
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ browser.jar:
|
||||||
content/browser/contentSearchUI.css (content/contentSearchUI.css)
|
content/browser/contentSearchUI.css (content/contentSearchUI.css)
|
||||||
content/browser/tabbrowser.css (content/tabbrowser.css)
|
content/browser/tabbrowser.css (content/tabbrowser.css)
|
||||||
content/browser/tabbrowser.js (content/tabbrowser.js)
|
content/browser/tabbrowser.js (content/tabbrowser.js)
|
||||||
|
content/browser/tabbrowser-tab.js (content/tabbrowser-tab.js)
|
||||||
content/browser/tabbrowser.xml (content/tabbrowser.xml)
|
content/browser/tabbrowser.xml (content/tabbrowser.xml)
|
||||||
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)
|
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)
|
||||||
content/browser/utilityOverlay.js (content/utilityOverlay.js)
|
content/browser/utilityOverlay.js (content/utilityOverlay.js)
|
||||||
|
|
|
@ -27,7 +27,7 @@ bool AboutRedirector::sAboutLoginsEnabled = false;
|
||||||
static const uint32_t ACTIVITY_STREAM_FLAGS =
|
static const uint32_t ACTIVITY_STREAM_FLAGS =
|
||||||
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::ENABLE_INDEXED_DB |
|
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::ENABLE_INDEXED_DB |
|
||||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD |
|
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT;
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT;
|
||||||
|
|
||||||
struct RedirEntry {
|
struct RedirEntry {
|
||||||
|
@ -59,7 +59,7 @@ static const RedirEntry kRedirMap[] = {
|
||||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
|
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
|
||||||
{"logins", "chrome://browser/content/aboutlogins/aboutLogins.html",
|
{"logins", "chrome://browser/content/aboutlogins/aboutLogins.html",
|
||||||
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD |
|
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
|
||||||
{"tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml",
|
{"tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml",
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
|
@ -85,7 +85,7 @@ static const RedirEntry kRedirMap[] = {
|
||||||
{"newtab", "about:blank", ACTIVITY_STREAM_FLAGS},
|
{"newtab", "about:blank", ACTIVITY_STREAM_FLAGS},
|
||||||
{"welcome", "about:blank",
|
{"welcome", "about:blank",
|
||||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD |
|
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
nsIAboutModule::ALLOW_SCRIPT},
|
nsIAboutModule::ALLOW_SCRIPT},
|
||||||
{"library", "chrome://browser/content/aboutLibrary.xhtml",
|
{"library", "chrome://browser/content/aboutLibrary.xhtml",
|
||||||
|
@ -118,7 +118,7 @@ static const RedirEntry kRedirMap[] = {
|
||||||
{"protections", "chrome://browser/content/protections.html",
|
{"protections", "chrome://browser/content/protections.html",
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
|
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
|
||||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD},
|
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS},
|
||||||
};
|
};
|
||||||
|
|
||||||
static nsAutoCString GetAboutModuleName(nsIURI* aURI) {
|
static nsAutoCString GetAboutModuleName(nsIURI* aURI) {
|
||||||
|
|
|
@ -23,16 +23,16 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||||
const ABOUT_LOGINS_ORIGIN = "about:logins";
|
const ABOUT_LOGINS_ORIGIN = "about:logins";
|
||||||
const MASTER_PASSWORD_NOTIFICATION_ID = "master-password-login-required";
|
const MASTER_PASSWORD_NOTIFICATION_ID = "master-password-login-required";
|
||||||
|
|
||||||
const PRIVILEGED_PROCESS_PREF =
|
const PRIVILEGEDABOUT_PROCESS_PREF =
|
||||||
"browser.tabs.remote.separatePrivilegedContentProcess";
|
"browser.tabs.remote.separatePrivilegedContentProcess";
|
||||||
const PRIVILEGED_PROCESS_ENABLED =
|
const PRIVILEGEDABOUT_PROCESS_ENABLED =
|
||||||
Services.prefs.getBoolPref(PRIVILEGED_PROCESS_PREF, false);
|
Services.prefs.getBoolPref(PRIVILEGEDABOUT_PROCESS_PREF, false);
|
||||||
|
|
||||||
// When the privileged content process is enabled, we expect about:logins
|
// When the privileged content process is enabled, we expect about:logins
|
||||||
// to load in it. Otherwise, it's in a normal web content process.
|
// to load in it. Otherwise, it's in a normal web content process.
|
||||||
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE =
|
const EXPECTED_ABOUTLOGINS_REMOTE_TYPE =
|
||||||
PRIVILEGED_PROCESS_ENABLED ? E10SUtils.PRIVILEGED_REMOTE_TYPE
|
PRIVILEGEDABOUT_PROCESS_ENABLED ? E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
|
||||||
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
||||||
|
|
||||||
const isValidLogin = login => {
|
const isValidLogin = login => {
|
||||||
return !(login.hostname || "").startsWith("chrome://");
|
return !(login.hostname || "").startsWith("chrome://");
|
||||||
|
|
|
@ -1065,8 +1065,11 @@ const menuTracker = {
|
||||||
gMenuBuilder.build({menu, tab, pageUrl, inToolsMenu: true});
|
gMenuBuilder.build({menu, tab, pageUrl, inToolsMenu: true});
|
||||||
}
|
}
|
||||||
if (menu.id === "tabContextMenu") {
|
if (menu.id === "tabContextMenu") {
|
||||||
const trigger = menu.triggerNode;
|
let trigger = menu.triggerNode;
|
||||||
const tab = trigger.localName === "tab" ? trigger : tabTracker.activeTab;
|
while (trigger && trigger.localName != "tab") {
|
||||||
|
trigger = trigger.parentNode;
|
||||||
|
}
|
||||||
|
const tab = trigger || tabTracker.activeTab;
|
||||||
const pageUrl = tab.linkedBrowser.currentURI.spec;
|
const pageUrl = tab.linkedBrowser.currentURI.spec;
|
||||||
gMenuBuilder.build({menu, tab, pageUrl, onTab: true});
|
gMenuBuilder.build({menu, tab, pageUrl, onTab: true});
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,18 +26,18 @@ const BASE_URL = "resource://activity-stream/";
|
||||||
const ACTIVITY_STREAM_PAGES = new Set(["home", "newtab", "welcome"]);
|
const ACTIVITY_STREAM_PAGES = new Set(["home", "newtab", "welcome"]);
|
||||||
|
|
||||||
const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
|
const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
|
||||||
const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEGED_REMOTE_TYPE;
|
const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE;
|
||||||
|
|
||||||
const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
|
const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
|
||||||
|
|
||||||
const PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess";
|
const PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess";
|
||||||
const PREF_ACTIVITY_STREAM_PRERENDER_ENABLED = "browser.newtabpage.activity-stream.prerender";
|
const PREF_ACTIVITY_STREAM_PRERENDER_ENABLED = "browser.newtabpage.activity-stream.prerender";
|
||||||
const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
|
const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
|
||||||
|
|
||||||
function AboutNewTabService() {
|
function AboutNewTabService() {
|
||||||
Services.obs.addObserver(this, TOPIC_APP_QUIT);
|
Services.obs.addObserver(this, TOPIC_APP_QUIT);
|
||||||
Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
|
Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
|
||||||
Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS, this);
|
Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
|
||||||
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
||||||
if (!IS_RELEASE_OR_BETA) {
|
if (!IS_RELEASE_OR_BETA) {
|
||||||
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
||||||
|
@ -93,7 +93,7 @@ AboutNewTabService.prototype = {
|
||||||
_activityStreamPrerender: false,
|
_activityStreamPrerender: false,
|
||||||
_activityStreamPath: "",
|
_activityStreamPath: "",
|
||||||
_activityStreamDebug: false,
|
_activityStreamDebug: false,
|
||||||
_privilegedContentProcess: false,
|
_privilegedAboutContentProcess: false,
|
||||||
_overridden: false,
|
_overridden: false,
|
||||||
willNotifyUser: false,
|
willNotifyUser: false,
|
||||||
|
|
||||||
|
@ -106,8 +106,8 @@ AboutNewTabService.prototype = {
|
||||||
observe(subject, topic, data) {
|
observe(subject, topic, data) {
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
case "nsPref:changed":
|
case "nsPref:changed":
|
||||||
if (data === PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS) {
|
if (data === PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS) {
|
||||||
this._privilegedContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS);
|
this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
|
||||||
this.updatePrerenderedPath();
|
this.updatePrerenderedPath();
|
||||||
this.notifyChange();
|
this.notifyChange();
|
||||||
} else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
|
} else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
|
||||||
|
@ -216,7 +216,7 @@ AboutNewTabService.prototype = {
|
||||||
} else {
|
} else {
|
||||||
this._activityStreamEnabled = false;
|
this._activityStreamEnabled = false;
|
||||||
}
|
}
|
||||||
this._privilegedContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS);
|
this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
|
||||||
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
|
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
|
||||||
if (!IS_RELEASE_OR_BETA) {
|
if (!IS_RELEASE_OR_BETA) {
|
||||||
this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
|
this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
|
||||||
|
@ -233,7 +233,7 @@ AboutNewTabService.prototype = {
|
||||||
// Debug files are specially packaged in a non-localized directory, but with
|
// Debug files are specially packaged in a non-localized directory, but with
|
||||||
// dynamic script loading, localized debug is supported.
|
// dynamic script loading, localized debug is supported.
|
||||||
this._activityStreamPath = `${this._activityStreamDebug &&
|
this._activityStreamPath = `${this._activityStreamDebug &&
|
||||||
!this._privilegedContentProcess ? "static" : this.activityStreamLocale}/`;
|
!this._privilegedAboutContentProcess ? "static" : this.activityStreamLocale}/`;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -253,8 +253,8 @@ AboutNewTabService.prototype = {
|
||||||
"activity-stream",
|
"activity-stream",
|
||||||
this._activityStreamPrerender ? "-prerendered" : "",
|
this._activityStreamPrerender ? "-prerendered" : "",
|
||||||
// Debug version loads dev scripts but noscripts separately loads scripts
|
// Debug version loads dev scripts but noscripts separately loads scripts
|
||||||
this._activityStreamDebug && !this._privilegedContentProcess ? "-debug" : "",
|
this._activityStreamDebug && !this._privilegedAboutContentProcess ? "-debug" : "",
|
||||||
this._privilegedContentProcess ? "-noscripts" : "",
|
this._privilegedAboutContentProcess ? "-noscripts" : "",
|
||||||
".html",
|
".html",
|
||||||
].join("");
|
].join("");
|
||||||
},
|
},
|
||||||
|
@ -351,7 +351,7 @@ AboutNewTabService.prototype = {
|
||||||
}
|
}
|
||||||
Services.obs.removeObserver(this, TOPIC_APP_QUIT);
|
Services.obs.removeObserver(this, TOPIC_APP_QUIT);
|
||||||
Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE);
|
Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE);
|
||||||
Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS, this);
|
Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
|
||||||
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
||||||
if (!IS_RELEASE_OR_BETA) {
|
if (!IS_RELEASE_OR_BETA) {
|
||||||
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
||||||
|
|
|
@ -192,5 +192,15 @@ var TabStateInternal = {
|
||||||
tabData[key] = value;
|
tabData[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [Bug 1554512]
|
||||||
|
// If the latest scroll position is on the top, we will delete scroll entry.
|
||||||
|
// When scroll entry is deleted in TabStateCache, it cannot be updated.
|
||||||
|
// To prevent losing the scroll position, we need to add a handing here.
|
||||||
|
if (tabData.scroll) {
|
||||||
|
if (!data.scroll) {
|
||||||
|
delete tabData.scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,17 +9,17 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const PRIVILEGED_PROCESS_PREF =
|
const PRIVILEGEDABOUT_PROCESS_PREF =
|
||||||
"browser.tabs.remote.separatePrivilegedContentProcess";
|
"browser.tabs.remote.separatePrivilegedContentProcess";
|
||||||
const PRIVILEGED_PROCESS_ENABLED =
|
const PRIVILEGEDABOUT_PROCESS_ENABLED =
|
||||||
Services.prefs.getBoolPref(PRIVILEGED_PROCESS_PREF);
|
Services.prefs.getBoolPref(PRIVILEGEDABOUT_PROCESS_PREF);
|
||||||
|
|
||||||
const REMOTE_BROWSER_SHOWN = "remote-browser-shown";
|
const REMOTE_BROWSER_SHOWN = "remote-browser-shown";
|
||||||
|
|
||||||
// When the privileged content process is enabled, we expect about:home
|
// When the privileged content process is enabled, we expect about:home
|
||||||
// to load in it. Otherwise, it's in a normal web content process.
|
// to load in it. Otherwise, it's in a normal web content process.
|
||||||
const EXPECTED_ABOUTHOME_REMOTE_TYPE =
|
const EXPECTED_ABOUTHOME_REMOTE_TYPE =
|
||||||
PRIVILEGED_PROCESS_ENABLED ? E10SUtils.PRIVILEGED_REMOTE_TYPE
|
PRIVILEGEDABOUT_PROCESS_ENABLED ? E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
|
||||||
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
: E10SUtils.DEFAULT_REMOTE_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -172,9 +172,7 @@ var UITour = {
|
||||||
["selectedTabIcon", {
|
["selectedTabIcon", {
|
||||||
query: (aDocument) => {
|
query: (aDocument) => {
|
||||||
let selectedtab = aDocument.defaultView.gBrowser.selectedTab;
|
let selectedtab = aDocument.defaultView.gBrowser.selectedTab;
|
||||||
let element = aDocument.getAnonymousElementByAttribute(selectedtab,
|
let element = selectedtab.iconImage;
|
||||||
"anonid",
|
|
||||||
"tab-icon-image");
|
|
||||||
if (!element || !UITour.isElementVisible(element)) {
|
if (!element || !UITour.isElementVisible(element)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,6 +388,9 @@ class ImportHook(object):
|
||||||
|
|
||||||
def __call__(self, name, globals=None, locals=None, fromlist=None,
|
def __call__(self, name, globals=None, locals=None, fromlist=None,
|
||||||
level=-1):
|
level=-1):
|
||||||
|
if sys.version_info[0] >= 3 and level < 0:
|
||||||
|
level = 0
|
||||||
|
|
||||||
# name might be a relative import. Instead of figuring out what that
|
# name might be a relative import. Instead of figuring out what that
|
||||||
# resolves to, which is complex, just rely on the real import.
|
# resolves to, which is complex, just rely on the real import.
|
||||||
# Since we don't know the full module name, we can't check sys.modules,
|
# Since we don't know the full module name, we can't check sys.modules,
|
||||||
|
|
|
@ -288,55 +288,10 @@ class ElementStyle {
|
||||||
* Optional pseudo-element for which to restrict marking CSS declarations as
|
* Optional pseudo-element for which to restrict marking CSS declarations as
|
||||||
* overridden.
|
* overridden.
|
||||||
*/
|
*/
|
||||||
/* eslint-disable complexity */
|
|
||||||
updateDeclarations(pseudo = "") {
|
updateDeclarations(pseudo = "") {
|
||||||
// Gather all the text properties applied by these rules, ordered
|
// Gather all text properties applicable to the selected element or pseudo-element.
|
||||||
// from more- to less-specific. Text properties from keyframes rule are
|
const textProps = this._getDeclarations(pseudo);
|
||||||
// excluded from being marked as overridden since a number of criteria such
|
// Gather all the computed properties applied by those text properties.
|
||||||
// as time, and animation overlay are required to be check in order to
|
|
||||||
// determine if the property is overridden.
|
|
||||||
const textProps = [];
|
|
||||||
|
|
||||||
for (const rule of this.rules) {
|
|
||||||
// Skip @keyframes rules
|
|
||||||
if (rule.keyframes) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Style rules must be considered only when they have selectors that match the node.
|
|
||||||
// When renaming a selector, the unmatched rule lingers in the Rule view, but it no
|
|
||||||
// longer matches the node. This strict check avoids accidentally causing
|
|
||||||
// declarations to be overridden in the remaining matching rules.
|
|
||||||
const isStyleRule = rule.pseudoElement === "" && rule.matchedSelectors.length > 0;
|
|
||||||
|
|
||||||
// Style rules for pseudo-elements must always be considered, regardless if their
|
|
||||||
// selector matches the node. As a convenience, declarations in rules for
|
|
||||||
// pseudo-elements show up in a separate Pseudo-elements accordion when selecting
|
|
||||||
// the host node (instead of the pseudo-element node directly, which is sometimes
|
|
||||||
// impossible, for example with ::selection or ::first-line).
|
|
||||||
// Loosening the strict check on matched selectors ensures these declarations
|
|
||||||
// participate in the algorithm below to mark them as overridden.
|
|
||||||
const isPseudoElementRule = rule.pseudoElement !== "" &&
|
|
||||||
rule.pseudoElement === pseudo;
|
|
||||||
|
|
||||||
const isElementStyle = rule.domRule.type === ELEMENT_STYLE;
|
|
||||||
|
|
||||||
const filterCondition = pseudo === ""
|
|
||||||
? (isStyleRule || isElementStyle)
|
|
||||||
: isPseudoElementRule;
|
|
||||||
|
|
||||||
// First, gather all relevant CSS declarations (aka TextProperty instances).
|
|
||||||
if (filterCondition) {
|
|
||||||
for (const textProp of rule.textProps.slice(0).reverse()) {
|
|
||||||
if (textProp.enabled) {
|
|
||||||
textProps.push(textProp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gather all the computed properties applied by those text
|
|
||||||
// properties.
|
|
||||||
let computedProps = [];
|
let computedProps = [];
|
||||||
for (const textProp of textProps) {
|
for (const textProp of textProps) {
|
||||||
computedProps = computedProps.concat(textProp.computed);
|
computedProps = computedProps.concat(textProp.computed);
|
||||||
|
@ -418,7 +373,71 @@ class ElementStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* eslint-enable complexity */
|
|
||||||
|
/**
|
||||||
|
* Helper for |this.updateDeclarations()| to mark CSS declarations as overridden.
|
||||||
|
*
|
||||||
|
* Returns an array of CSS declarations (aka TextProperty instances) from all rules
|
||||||
|
* applicable to the selected element ordered from more- to less-specific.
|
||||||
|
*
|
||||||
|
* If a pseudo-element type is given, restrict the result only to declarations
|
||||||
|
* applicable to that pseudo-element.
|
||||||
|
*
|
||||||
|
* NOTE: this method skips CSS declarations in @keyframes rules because a number of
|
||||||
|
* criteria such as time and animation delay need to be checked in order to determine
|
||||||
|
* if the property is overridden at runtime.
|
||||||
|
*
|
||||||
|
* @param {String} pseudo
|
||||||
|
* Optional pseudo-element for which to restrict marking CSS declarations as
|
||||||
|
* overridden. If omitted, only declarations for regular style rules are
|
||||||
|
* returned (no pseudo-element style rules).
|
||||||
|
*
|
||||||
|
* @return {Array}
|
||||||
|
* Array of TextProperty instances.
|
||||||
|
*/
|
||||||
|
_getDeclarations(pseudo = "") {
|
||||||
|
const textProps = [];
|
||||||
|
|
||||||
|
for (const rule of this.rules) {
|
||||||
|
// Skip @keyframes rules
|
||||||
|
if (rule.keyframes) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style rules must be considered only when they have selectors that match the node.
|
||||||
|
// When renaming a selector, the unmatched rule lingers in the Rule view, but it no
|
||||||
|
// longer matches the node. This strict check avoids accidentally causing
|
||||||
|
// declarations to be overridden in the remaining matching rules.
|
||||||
|
const isStyleRule = rule.pseudoElement === "" && rule.matchedSelectors.length > 0;
|
||||||
|
|
||||||
|
// Style rules for pseudo-elements must always be considered, regardless if their
|
||||||
|
// selector matches the node. As a convenience, declarations in rules for
|
||||||
|
// pseudo-elements show up in a separate Pseudo-elements accordion when selecting
|
||||||
|
// the host node (instead of the pseudo-element node directly, which is sometimes
|
||||||
|
// impossible, for example with ::selection or ::first-line).
|
||||||
|
// Loosening the strict check on matched selectors ensures these declarations
|
||||||
|
// participate in the algorithm below to mark them as overridden.
|
||||||
|
const isPseudoElementRule = rule.pseudoElement !== "" &&
|
||||||
|
rule.pseudoElement === pseudo;
|
||||||
|
|
||||||
|
const isElementStyle = rule.domRule.type === ELEMENT_STYLE;
|
||||||
|
|
||||||
|
const filterCondition = pseudo === ""
|
||||||
|
? (isStyleRule || isElementStyle)
|
||||||
|
: isPseudoElementRule;
|
||||||
|
|
||||||
|
// Collect all relevant CSS declarations (aka TextProperty instances).
|
||||||
|
if (filterCondition) {
|
||||||
|
for (const textProp of rule.textProps.slice(0).reverse()) {
|
||||||
|
if (textProp.enabled) {
|
||||||
|
textProps.push(textProp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return textProps;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new declaration to the rule.
|
* Adds a new declaration to the rule.
|
||||||
|
|
|
@ -199,6 +199,7 @@ skip-if = os == 'linux' # focusEditableField times out consistently on linux.
|
||||||
[browser_rules_highlight-used-fonts.js]
|
[browser_rules_highlight-used-fonts.js]
|
||||||
[browser_rules_inactive_css_flexbox.js]
|
[browser_rules_inactive_css_flexbox.js]
|
||||||
[browser_rules_inactive_css_grid.js]
|
[browser_rules_inactive_css_grid.js]
|
||||||
|
[browser_rules_inactive_css_inline.js]
|
||||||
[browser_rules_inherited-properties_01.js]
|
[browser_rules_inherited-properties_01.js]
|
||||||
[browser_rules_inherited-properties_02.js]
|
[browser_rules_inherited-properties_02.js]
|
||||||
[browser_rules_inherited-properties_03.js]
|
[browser_rules_inherited-properties_03.js]
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test css properties that are inactive on block-level elements.
|
||||||
|
|
||||||
|
const TEST_URI = `
|
||||||
|
<style>
|
||||||
|
#block {
|
||||||
|
border: 1px solid #000;
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
#flex {
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1 style="vertical-align:text-bottom;">browser_rules_inactive_css_inline.js</h1>
|
||||||
|
<div id="block">Block</div>
|
||||||
|
<table>
|
||||||
|
<tr><td>A table cell</td></tr>
|
||||||
|
</table>
|
||||||
|
<div id="flex">Inline flex element</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TEST_DATA = [
|
||||||
|
{
|
||||||
|
selector: "h1",
|
||||||
|
inactiveDeclarations: [
|
||||||
|
{
|
||||||
|
declaration: { "vertical-align": "text-bottom" },
|
||||||
|
ruleIndex: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "#block",
|
||||||
|
inactiveDeclarations: [
|
||||||
|
{
|
||||||
|
declaration: { "vertical-align": "sub" },
|
||||||
|
ruleIndex: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "td",
|
||||||
|
activeDeclarations: [
|
||||||
|
{
|
||||||
|
declarations: { "vertical-align": "super" },
|
||||||
|
ruleIndex: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: "#flex",
|
||||||
|
activeDeclarations: [
|
||||||
|
{
|
||||||
|
declarations: { "vertical-align": "text-bottom" },
|
||||||
|
ruleIndex: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
await pushPref("devtools.inspector.inactive.css.enabled", true);
|
||||||
|
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||||
|
const { inspector, view } = await openRuleView();
|
||||||
|
|
||||||
|
await runInactiveCSSTests(view, inspector, TEST_DATA);
|
||||||
|
});
|
|
@ -35,6 +35,7 @@ loader.lazyRequireGetter(this, "setVariableTooltip",
|
||||||
"devtools/client/shared/widgets/tooltip/VariableTooltipHelper", true);
|
"devtools/client/shared/widgets/tooltip/VariableTooltipHelper", true);
|
||||||
loader.lazyRequireGetter(this, "InactiveCssTooltipHelper",
|
loader.lazyRequireGetter(this, "InactiveCssTooltipHelper",
|
||||||
"devtools/client/shared/widgets/tooltip/inactive-css-tooltip-helper", false);
|
"devtools/client/shared/widgets/tooltip/inactive-css-tooltip-helper", false);
|
||||||
|
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry", false);
|
||||||
|
|
||||||
const PREF_IMAGE_TOOLTIP_SIZE = "devtools.inspector.imagePreviewTooltipSize";
|
const PREF_IMAGE_TOOLTIP_SIZE = "devtools.inspector.imagePreviewTooltipSize";
|
||||||
|
|
||||||
|
@ -44,6 +45,9 @@ const TOOLTIP_FONTFAMILY_TYPE = "font-family";
|
||||||
const TOOLTIP_INACTIVE_CSS = "inactive-css";
|
const TOOLTIP_INACTIVE_CSS = "inactive-css";
|
||||||
const TOOLTIP_VARIABLE_TYPE = "variable";
|
const TOOLTIP_VARIABLE_TYPE = "variable";
|
||||||
|
|
||||||
|
// Telemetry
|
||||||
|
const TOOLTIP_SHOWN_SCALAR = "devtools.tooltip.shown";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages all tooltips in the style-inspector.
|
* Manages all tooltips in the style-inspector.
|
||||||
*
|
*
|
||||||
|
@ -53,6 +57,7 @@ const TOOLTIP_VARIABLE_TYPE = "variable";
|
||||||
function TooltipsOverlay(view) {
|
function TooltipsOverlay(view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this._instances = new Map();
|
this._instances = new Map();
|
||||||
|
this.telemetry = new Telemetry();
|
||||||
|
|
||||||
this._onNewSelection = this._onNewSelection.bind(this);
|
this._onNewSelection = this._onNewSelection.bind(this);
|
||||||
this.view.inspector.selection.on("new-node-front", this._onNewSelection);
|
this.view.inspector.selection.on("new-node-front", this._onNewSelection);
|
||||||
|
@ -253,6 +258,9 @@ TooltipsOverlay.prototype = {
|
||||||
await setBrokenImageTooltip(this.getTooltip("previewTooltip"),
|
await setBrokenImageTooltip(this.getTooltip("previewTooltip"),
|
||||||
this.view.inspector.panelDoc);
|
this.view.inspector.panelDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.sendOpenScalarToTelemetry(type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,6 +269,8 @@ TooltipsOverlay.prototype = {
|
||||||
const nodeFront = inspector.selection.nodeFront;
|
const nodeFront = inspector.selection.nodeFront;
|
||||||
await this._setFontPreviewTooltip(font, nodeFront);
|
await this._setFontPreviewTooltip(font, nodeFront);
|
||||||
|
|
||||||
|
this.sendOpenScalarToTelemetry(type);
|
||||||
|
|
||||||
if (nodeInfo.type === VIEW_NODE_FONT_TYPE) {
|
if (nodeInfo.type === VIEW_NODE_FONT_TYPE) {
|
||||||
// If the hovered element is on the font family span, anchor
|
// If the hovered element is on the font family span, anchor
|
||||||
// the tooltip on the whole property value instead.
|
// the tooltip on the whole property value instead.
|
||||||
|
@ -272,6 +282,9 @@ TooltipsOverlay.prototype = {
|
||||||
if (type === TOOLTIP_VARIABLE_TYPE && nodeInfo.value.value.startsWith("--")) {
|
if (type === TOOLTIP_VARIABLE_TYPE && nodeInfo.value.value.startsWith("--")) {
|
||||||
const variable = nodeInfo.value.variable;
|
const variable = nodeInfo.value.variable;
|
||||||
await this._setVariablePreviewTooltip(variable);
|
await this._setVariablePreviewTooltip(variable);
|
||||||
|
|
||||||
|
this.sendOpenScalarToTelemetry(type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,12 +333,25 @@ TooltipsOverlay.prototype = {
|
||||||
|
|
||||||
await this.inactiveCssTooltipHelper.setContent(
|
await this.inactiveCssTooltipHelper.setContent(
|
||||||
nodeInfo.value, this.getTooltip("interactiveTooltip"));
|
nodeInfo.value, this.getTooltip("interactiveTooltip"));
|
||||||
|
|
||||||
|
this.sendOpenScalarToTelemetry(type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a telemetry Scalar showing that a tooltip of `type` has been opened.
|
||||||
|
*
|
||||||
|
* @param {String} type
|
||||||
|
* The node type from `devtools/client/inspector/shared/node-types`.
|
||||||
|
*/
|
||||||
|
sendOpenScalarToTelemetry(type) {
|
||||||
|
this.telemetry.keyedScalarAdd(TOOLTIP_SHOWN_SCALAR, type, 1);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the content of the preview tooltip to display an image preview. The image URL can
|
* Set the content of the preview tooltip to display an image preview. The image URL can
|
||||||
* be relative, a call will be made to the debuggee to retrieve the image content as an
|
* be relative, a call will be made to the debuggee to retrieve the image content as an
|
||||||
|
@ -414,6 +440,7 @@ TooltipsOverlay.prototype = {
|
||||||
|
|
||||||
this.view.inspector.selection.off("new-node-front", this._onNewSelection);
|
this.view.inspector.selection.off("new-node-front", this._onNewSelection);
|
||||||
this.view = null;
|
this.view = null;
|
||||||
|
this.telemetry = null;
|
||||||
|
|
||||||
this._isDestroyed = true;
|
this._isDestroyed = true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -141,7 +141,7 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
|
||||||
// Bug 1510806 has been filed to fix this properly, by making RDM resilient
|
// Bug 1510806 has been filed to fix this properly, by making RDM resilient
|
||||||
// to process flips.
|
// to process flips.
|
||||||
if (mustChangeProcess &&
|
if (mustChangeProcess &&
|
||||||
tab.linkedBrowser.remoteType == "privileged") {
|
tab.linkedBrowser.remoteType == "privilegedabout") {
|
||||||
debug(`Tab must flip away from the privileged content process ` +
|
debug(`Tab must flip away from the privileged content process ` +
|
||||||
`on navigation`);
|
`on navigation`);
|
||||||
gBrowser.updateBrowserRemoteness(tab.linkedBrowser, {
|
gBrowser.updateBrowserRemoteness(tab.linkedBrowser, {
|
||||||
|
|
|
@ -43,43 +43,45 @@ class InactiveCssTooltipHelper {
|
||||||
// Size the content.
|
// Size the content.
|
||||||
tooltip.setContentSize({width: 275, height: Infinity});
|
tooltip.setContentSize({width: 275, height: Infinity});
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Get the template that the Fluent string will be merged with. This template
|
/**
|
||||||
* looks something like this but there is a variable amount of properties in the
|
* Get the template that the Fluent string will be merged with. This template
|
||||||
* fix section:
|
* looks something like this but there is a variable amount of properties in the
|
||||||
*
|
* fix section:
|
||||||
* <div class="devtools-tooltip-inactive-css">
|
*
|
||||||
* <p data-l10n-id="inactive-css-not-grid-or-flex-container"
|
* <div class="devtools-tooltip-inactive-css">
|
||||||
* data-l10n-args="{"property":"align-content"}">
|
* <p data-l10n-id="inactive-css-not-grid-or-flex-container"
|
||||||
* <strong></strong>
|
* data-l10n-args="{"property":"align-content"}">
|
||||||
* </p>
|
* <strong></strong>
|
||||||
* <p data-l10n-id="inactive-css-not-grid-or-flex-container-fix">
|
* </p>
|
||||||
* <strong></strong>
|
* <p data-l10n-id="inactive-css-not-grid-or-flex-container-fix">
|
||||||
* <strong></strong>
|
* <strong></strong>
|
||||||
* <span data-l10n-name="link" class="link"></span>
|
* <strong></strong>
|
||||||
* </p>
|
* <span data-l10n-name="link" class="link"></span>
|
||||||
* </div>
|
* </p>
|
||||||
*
|
* </div>
|
||||||
* @param {Object} data
|
*
|
||||||
* An object in the following format: {
|
* @param {Object} data
|
||||||
* fixId: "inactive-css-not-grid-item-fix", // Fluent id containing the
|
* An object in the following format: {
|
||||||
* // Inactive CSS fix.
|
* fixId: "inactive-css-not-grid-item-fix", // Fluent id containing the
|
||||||
* msgId: "inactive-css-not-grid-item", // Fluent id containing the
|
* // Inactive CSS fix.
|
||||||
* // Inactive CSS message.
|
* msgId: "inactive-css-not-grid-item", // Fluent id containing the
|
||||||
* numFixProps: 2, // Number of properties in the fix section of the
|
* // Inactive CSS message.
|
||||||
* // tooltip.
|
* numFixProps: 2, // Number of properties in the fix section of the
|
||||||
* property: "color", // Property name
|
* // tooltip.
|
||||||
* }
|
* property: "color", // Property name
|
||||||
* @param {HTMLTooltip} tooltip
|
* }
|
||||||
* The tooltip we are targetting.
|
* @param {HTMLTooltip} tooltip
|
||||||
*/
|
* The tooltip we are targetting.
|
||||||
|
*/
|
||||||
getTemplate(data, tooltip) {
|
getTemplate(data, tooltip) {
|
||||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
const { fixId, msgId, numFixProps, property } = data;
|
const { fixId, msgId, numFixProps, property } = data;
|
||||||
const { doc } = tooltip;
|
const { doc } = tooltip;
|
||||||
|
|
||||||
this._currentTooltip = tooltip;
|
this._currentTooltip = tooltip;
|
||||||
this._currentUrl = `https://developer.mozilla.org/docs/Web/CSS/${property}`;
|
this._currentUrl = `https://developer.mozilla.org/docs/Web/CSS/${property}` +
|
||||||
|
`?utm_source=devtools&utm_medium=inspector-inactive-css`;
|
||||||
|
|
||||||
const templateNode = doc.createElementNS(XHTML_NS, "template");
|
const templateNode = doc.createElementNS(XHTML_NS, "template");
|
||||||
|
|
||||||
|
|
|
@ -143,9 +143,7 @@ class InactivePropertyHelper {
|
||||||
const isFirstLetter = selectorText && selectorText.includes("::first-letter");
|
const isFirstLetter = selectorText && selectorText.includes("::first-letter");
|
||||||
const isFirstLine = selectorText && selectorText.includes("::first-line");
|
const isFirstLine = selectorText && selectorText.includes("::first-line");
|
||||||
|
|
||||||
const isInlineLevel = this.checkStyle("display", ["inline", "table-cell"]);
|
return !this.isInlineLevel() && !isFirstLetter && !isFirstLine;
|
||||||
|
|
||||||
return !isInlineLevel && !isFirstLetter && !isFirstLine;
|
|
||||||
},
|
},
|
||||||
fixId: "inactive-css-not-inline-or-tablecell-fix",
|
fixId: "inactive-css-not-inline-or-tablecell-fix",
|
||||||
msgId: "inactive-css-not-inline-or-tablecell",
|
msgId: "inactive-css-not-inline-or-tablecell",
|
||||||
|
@ -299,6 +297,24 @@ class InactivePropertyHelper {
|
||||||
return values.some(value => this.style[propName] === value);
|
return values.some(value => this.style[propName] === value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current node is an inline-level box.
|
||||||
|
*/
|
||||||
|
isInlineLevel() {
|
||||||
|
return this.checkStyle("display", [
|
||||||
|
"inline",
|
||||||
|
"inline-block",
|
||||||
|
"inline-table",
|
||||||
|
"inline-flex",
|
||||||
|
"inline-grid",
|
||||||
|
"table-cell",
|
||||||
|
"table-row",
|
||||||
|
"table-row-group",
|
||||||
|
"table-header-group",
|
||||||
|
"table-footer-group",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current node is a flex container i.e. a node that has a style
|
* Check if the current node is a flex container i.e. a node that has a style
|
||||||
* of `display:flex` or `display:inline-flex`.
|
* of `display:flex` or `display:inline-flex`.
|
||||||
|
|
|
@ -91,7 +91,7 @@ static const RedirEntry kRedirMap[] = {
|
||||||
nsIAboutModule::ALLOW_SCRIPT |
|
nsIAboutModule::ALLOW_SCRIPT |
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD},
|
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS},
|
||||||
{"mozilla", "chrome://global/content/mozilla.xhtml",
|
{"mozilla", "chrome://global/content/mozilla.xhtml",
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
|
||||||
{"neterror", "chrome://global/content/netError.xhtml",
|
{"neterror", "chrome://global/content/netError.xhtml",
|
||||||
|
|
|
@ -710,8 +710,9 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
|
||||||
type = mozilla::ProcType::File;
|
type = mozilla::ProcType::File;
|
||||||
} else if (processType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
} else if (processType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
||||||
type = mozilla::ProcType::Extension;
|
type = mozilla::ProcType::Extension;
|
||||||
} else if (processType.EqualsLiteral(PRIVILEGED_REMOTE_TYPE)) {
|
} else if (processType.EqualsLiteral(
|
||||||
type = mozilla::ProcType::Privileged;
|
PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
||||||
|
type = mozilla::ProcType::PrivilegedAbout;
|
||||||
} else if (processType.EqualsLiteral(
|
} else if (processType.EqualsLiteral(
|
||||||
LARGE_ALLOCATION_REMOTE_TYPE)) {
|
LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||||
type = mozilla::ProcType::WebLargeAllocation;
|
type = mozilla::ProcType::WebLargeAllocation;
|
||||||
|
|
|
@ -185,7 +185,7 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
||||||
case eBasicEventClass:
|
case eBasicEventClass:
|
||||||
// For these following events only allow popups if they're
|
// For these following events only allow popups if they're
|
||||||
// triggered while handling user input. See
|
// triggered while handling user input. See
|
||||||
// PresShell::EventHandler::PrepareToDispatchEvent() for details.
|
// EventStateManager::IsUserInteractionEvent() for details.
|
||||||
if (EventStateManager::IsHandlingUserInput()) {
|
if (EventStateManager::IsHandlingUserInput()) {
|
||||||
abuse = PopupBlocker::openBlocked;
|
abuse = PopupBlocker::openBlocked;
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
|
@ -207,7 +207,7 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
||||||
case eEditorInputEventClass:
|
case eEditorInputEventClass:
|
||||||
// For this following event only allow popups if it's triggered
|
// For this following event only allow popups if it's triggered
|
||||||
// while handling user input. See
|
// while handling user input. See
|
||||||
// PresShell::EventHandler::PrepareToDispatchEvent() for details.
|
// EventStateManager::IsUserInteractionEvent() for details.
|
||||||
if (EventStateManager::IsHandlingUserInput()) {
|
if (EventStateManager::IsHandlingUserInput()) {
|
||||||
abuse = PopupBlocker::openBlocked;
|
abuse = PopupBlocker::openBlocked;
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
|
@ -224,7 +224,7 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
||||||
case eInputEventClass:
|
case eInputEventClass:
|
||||||
// For this following event only allow popups if it's triggered
|
// For this following event only allow popups if it's triggered
|
||||||
// while handling user input. See
|
// while handling user input. See
|
||||||
// PresShell::EventHandler::PrepareToDispatchEvent() for details.
|
// EventStateManager::IsUserInteractionEvent() for details.
|
||||||
if (EventStateManager::IsHandlingUserInput()) {
|
if (EventStateManager::IsHandlingUserInput()) {
|
||||||
abuse = PopupBlocker::openBlocked;
|
abuse = PopupBlocker::openBlocked;
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
|
@ -370,7 +370,7 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
||||||
case eFormEventClass:
|
case eFormEventClass:
|
||||||
// For these following events only allow popups if they're
|
// For these following events only allow popups if they're
|
||||||
// triggered while handling user input. See
|
// triggered while handling user input. See
|
||||||
// PresShell::EventHandler::PrepareToDispatchEvent() for details.
|
// EventStateManager::IsUserInteractionEvent() for details.
|
||||||
if (EventStateManager::IsHandlingUserInput()) {
|
if (EventStateManager::IsHandlingUserInput()) {
|
||||||
abuse = PopupBlocker::openBlocked;
|
abuse = PopupBlocker::openBlocked;
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
|
|
|
@ -415,7 +415,7 @@ enum ProcType {
|
||||||
"web",
|
"web",
|
||||||
"file",
|
"file",
|
||||||
"extension",
|
"extension",
|
||||||
"privileged",
|
"privilegedabout",
|
||||||
"webLargeAllocation",
|
"webLargeAllocation",
|
||||||
"gpu",
|
"gpu",
|
||||||
"rdd",
|
"rdd",
|
||||||
|
|
|
@ -1141,8 +1141,11 @@ void EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||||
aEvent->PreventDefault();
|
aEvent->PreventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<AutoHandlingUserInputStatePusher> userInputStatePusher;
|
||||||
Maybe<AutoPopupStatePusher> popupStatePusher;
|
Maybe<AutoPopupStatePusher> popupStatePusher;
|
||||||
if (mIsMainThreadELM) {
|
if (mIsMainThreadELM) {
|
||||||
|
userInputStatePusher.emplace(
|
||||||
|
EventStateManager::IsUserInteractionEvent(aEvent), aEvent);
|
||||||
popupStatePusher.emplace(
|
popupStatePusher.emplace(
|
||||||
PopupBlocker::GetEventPopupControlState(aEvent, *aDOMEvent));
|
PopupBlocker::GetEventPopupControlState(aEvent, *aDOMEvent));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1558,8 +1558,7 @@ void EventStateManager::FireContextClick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Document* doc = mGestureDownContent->GetComposedDoc();
|
AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
|
||||||
AutoHandlingUserInputStatePusher userInpStatePusher(true, &event, doc);
|
|
||||||
|
|
||||||
// dispatch to DOM
|
// dispatch to DOM
|
||||||
EventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event,
|
EventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event,
|
||||||
|
@ -4042,6 +4041,39 @@ class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
|
||||||
nsCOMPtr<nsIContent> mTarget;
|
nsCOMPtr<nsIContent> mTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*static*/
|
||||||
|
bool EventStateManager::IsUserInteractionEvent(const WidgetEvent* aEvent) {
|
||||||
|
if (!aEvent->IsTrusted()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (aEvent->mMessage) {
|
||||||
|
// eKeyboardEventClass
|
||||||
|
case eKeyPress:
|
||||||
|
case eKeyDown:
|
||||||
|
case eKeyUp:
|
||||||
|
// Not all keyboard events are treated as user input, so that popups
|
||||||
|
// can't be opened, fullscreen mode can't be started, etc at
|
||||||
|
// unexpected time.
|
||||||
|
return aEvent->AsKeyboardEvent()->CanTreatAsUserInput();
|
||||||
|
// eBasicEventClass
|
||||||
|
case eFormChange:
|
||||||
|
// eMouseEventClass
|
||||||
|
case eMouseClick:
|
||||||
|
case eMouseDown:
|
||||||
|
case eMouseUp:
|
||||||
|
// ePointerEventClass
|
||||||
|
case ePointerDown:
|
||||||
|
case ePointerUp:
|
||||||
|
// eTouchEventClass
|
||||||
|
case eTouchStart:
|
||||||
|
case eTouchEnd:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
bool EventStateManager::IsHandlingUserInput() {
|
bool EventStateManager::IsHandlingUserInput() {
|
||||||
return sUserInputEventDepth > 0;
|
return sUserInputEventDepth > 0;
|
||||||
|
@ -6257,36 +6289,13 @@ void EventStateManager::Prefs::Init() {
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
|
AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
|
||||||
bool aIsHandlingUserInput, WidgetEvent* aEvent, Document* aDocument)
|
bool aIsHandlingUserInput, WidgetEvent* aEvent)
|
||||||
: mMessage(aEvent ? aEvent->mMessage : eVoidEvent),
|
: mMessage(aEvent ? aEvent->mMessage : eVoidEvent),
|
||||||
mIsHandlingUserInput(aIsHandlingUserInput) {
|
mIsHandlingUserInput(aIsHandlingUserInput) {
|
||||||
if (!aIsHandlingUserInput) {
|
if (!aIsHandlingUserInput) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EventStateManager::StartHandlingUserInput(mMessage);
|
EventStateManager::StartHandlingUserInput(mMessage);
|
||||||
if (mMessage == eMouseDown) {
|
|
||||||
PresShell::ReleaseCapturingContent();
|
|
||||||
PresShell::AllowMouseCapture(true);
|
|
||||||
}
|
|
||||||
if (!aDocument || !aEvent || !aEvent->IsTrusted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (NeedsToResetFocusManagerMouseButtonHandlingState()) {
|
|
||||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
||||||
NS_ENSURE_TRUE_VOID(fm);
|
|
||||||
// If it's in modal state, mouse button event handling may be nested.
|
|
||||||
// E.g., a modal dialog is opened at mousedown or mouseup event handler
|
|
||||||
// and the dialog is clicked. Therefore, we should store current
|
|
||||||
// mouse button event handling document if nsFocusManager already has it.
|
|
||||||
mMouseButtonEventHandlingDocument =
|
|
||||||
fm->SetMouseButtonHandlingDocument(aDocument);
|
|
||||||
}
|
|
||||||
if (NeedsToUpdateCurrentMouseBtnState()) {
|
|
||||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
|
||||||
if (mouseEvent) {
|
|
||||||
EventStateManager::sCurrentMouseBtn = mouseEvent->mButton;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
|
AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
|
||||||
|
@ -6294,18 +6303,6 @@ AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EventStateManager::StopHandlingUserInput(mMessage);
|
EventStateManager::StopHandlingUserInput(mMessage);
|
||||||
if (mMessage == eMouseDown) {
|
|
||||||
PresShell::AllowMouseCapture(false);
|
|
||||||
}
|
|
||||||
if (NeedsToResetFocusManagerMouseButtonHandlingState()) {
|
|
||||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
||||||
NS_ENSURE_TRUE_VOID(fm);
|
|
||||||
nsCOMPtr<Document> handlingDocument =
|
|
||||||
fm->SetMouseButtonHandlingDocument(mMouseButtonEventHandlingDocument);
|
|
||||||
}
|
|
||||||
if (NeedsToUpdateCurrentMouseBtnState()) {
|
|
||||||
EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -243,6 +243,12 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
||||||
const Maybe<gfx::IntPoint>& aHotspot, nsIWidget* aWidget,
|
const Maybe<gfx::IntPoint>& aHotspot, nsIWidget* aWidget,
|
||||||
bool aLockCursor);
|
bool aLockCursor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the event is considered as user interaction event. I.e.,
|
||||||
|
* enough obvious input to allow to open popup, etc. Otherwise, returns false.
|
||||||
|
*/
|
||||||
|
static bool IsUserInteractionEvent(const WidgetEvent* aEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StartHandlingUserInput() is called when we start to handle a user input.
|
* StartHandlingUserInput() is called when we start to handle a user input.
|
||||||
* StopHandlingUserInput() is called when we finish handling a user input.
|
* StopHandlingUserInput() is called when we finish handling a user input.
|
||||||
|
@ -1286,24 +1292,13 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
||||||
*/
|
*/
|
||||||
class MOZ_RAII AutoHandlingUserInputStatePusher final {
|
class MOZ_RAII AutoHandlingUserInputStatePusher final {
|
||||||
public:
|
public:
|
||||||
AutoHandlingUserInputStatePusher(bool aIsHandlingUserInput,
|
explicit AutoHandlingUserInputStatePusher(bool aIsHandlingUserInput,
|
||||||
WidgetEvent* aEvent,
|
WidgetEvent* aEvent = nullptr);
|
||||||
dom::Document* aDocument);
|
|
||||||
~AutoHandlingUserInputStatePusher();
|
~AutoHandlingUserInputStatePusher();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefPtr<dom::Document> mMouseButtonEventHandlingDocument;
|
|
||||||
EventMessage mMessage;
|
EventMessage mMessage;
|
||||||
bool mIsHandlingUserInput;
|
bool mIsHandlingUserInput;
|
||||||
|
|
||||||
bool NeedsToResetFocusManagerMouseButtonHandlingState() const {
|
|
||||||
return mMessage == eMouseDown || mMessage == eMouseUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NeedsToUpdateCurrentMouseBtnState() const {
|
|
||||||
return mMessage == eMouseDown || mMessage == eMouseUp ||
|
|
||||||
mMessage == ePointerDown || mMessage == ePointerUp;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -698,7 +698,7 @@ nsresult HTMLFormElement::SubmitSubmission(
|
||||||
AutoPopupStatePusher popupStatePusher(mSubmitPopupState);
|
AutoPopupStatePusher popupStatePusher(mSubmitPopupState);
|
||||||
|
|
||||||
AutoHandlingUserInputStatePusher userInpStatePusher(
|
AutoHandlingUserInputStatePusher userInpStatePusher(
|
||||||
aFormSubmission->IsInitiatedFromUserInput(), nullptr, doc);
|
aFormSubmission->IsInitiatedFromUserInput());
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> postDataStream;
|
nsCOMPtr<nsIInputStream> postDataStream;
|
||||||
rv = aFormSubmission->GetEncodedSubmission(
|
rv = aFormSubmission->GetEncodedSubmission(
|
||||||
|
|
|
@ -2285,7 +2285,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvReplyKeyEvent(
|
||||||
NS_ENSURE_TRUE(presContext, IPC_OK());
|
NS_ENSURE_TRUE(presContext, IPC_OK());
|
||||||
|
|
||||||
AutoHandlingUserInputStatePusher userInpStatePusher(localEvent.IsTrusted(),
|
AutoHandlingUserInputStatePusher userInpStatePusher(localEvent.IsTrusted(),
|
||||||
&localEvent, doc);
|
&localEvent);
|
||||||
|
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
|
|
||||||
|
|
|
@ -672,6 +672,11 @@ bool ContentChild::Init(MessageLoop* aIOLoop, base::ProcessId aParentPid,
|
||||||
// their own children.
|
// their own children.
|
||||||
if (recordreplay::IsMiddleman()) {
|
if (recordreplay::IsMiddleman()) {
|
||||||
SetMiddlemanIPCChannel(recordreplay::parent::ChannelToUIProcess());
|
SetMiddlemanIPCChannel(recordreplay::parent::ChannelToUIProcess());
|
||||||
|
|
||||||
|
// Eagerly mark this child as connected, as using another IPC channel will
|
||||||
|
// cause that channel's protocol to be marked as connected instead and
|
||||||
|
// prevent this one from being able to send IPDL messages.
|
||||||
|
ActorConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Open(aChannel, aParentPid, aIOLoop)) {
|
if (!Open(aChannel, aParentPid, aIOLoop)) {
|
||||||
|
@ -2723,7 +2728,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRemoteType(
|
||||||
SetProcessName(NS_LITERAL_STRING("file:// Content"));
|
SetProcessName(NS_LITERAL_STRING("file:// Content"));
|
||||||
} else if (aRemoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
} else if (aRemoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
||||||
SetProcessName(NS_LITERAL_STRING("WebExtensions"));
|
SetProcessName(NS_LITERAL_STRING("WebExtensions"));
|
||||||
} else if (aRemoteType.EqualsLiteral(PRIVILEGED_REMOTE_TYPE)) {
|
} else if (aRemoteType.EqualsLiteral(PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
||||||
SetProcessName(NS_LITERAL_STRING("Privileged Content"));
|
SetProcessName(NS_LITERAL_STRING("Privileged Content"));
|
||||||
} else if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
} else if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||||
SetProcessName(NS_LITERAL_STRING("Large Allocation Web Content"));
|
SetProcessName(NS_LITERAL_STRING("Large Allocation Web Content"));
|
||||||
|
|
|
@ -52,7 +52,8 @@
|
||||||
#define DEFAULT_REMOTE_TYPE "web"
|
#define DEFAULT_REMOTE_TYPE "web"
|
||||||
#define FILE_REMOTE_TYPE "file"
|
#define FILE_REMOTE_TYPE "file"
|
||||||
#define EXTENSION_REMOTE_TYPE "extension"
|
#define EXTENSION_REMOTE_TYPE "extension"
|
||||||
#define PRIVILEGED_REMOTE_TYPE "privileged"
|
#define PRIVILEGEDABOUT_REMOTE_TYPE "privilegedabout"
|
||||||
|
#define PRIVILEGEDMOZILLA_REMOTE_TYPE "privilegedmozilla"
|
||||||
|
|
||||||
// This must start with the DEFAULT_REMOTE_TYPE above.
|
// This must start with the DEFAULT_REMOTE_TYPE above.
|
||||||
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
|
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
|
||||||
|
|
|
@ -92,7 +92,7 @@ declTest("getActor with remoteType match", {
|
||||||
});
|
});
|
||||||
|
|
||||||
declTest("getActor with remoteType mismatch", {
|
declTest("getActor with remoteType mismatch", {
|
||||||
remoteTypes: ["privileged"],
|
remoteTypes: ["privilegedabout"],
|
||||||
url: TEST_URL,
|
url: TEST_URL,
|
||||||
|
|
||||||
async test(browser) {
|
async test(browser) {
|
||||||
|
|
|
@ -800,7 +800,7 @@ static void DebugDoContentSecurityCheck(nsIChannel* aChannel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(FUZZING)
|
#ifdef EARLY_BETA_OR_EARLIER
|
||||||
// Assert that we never use the SystemPrincipal to load remote documents
|
// Assert that we never use the SystemPrincipal to load remote documents
|
||||||
// i.e., HTTP, HTTPS, FTP URLs
|
// i.e., HTTP, HTTPS, FTP URLs
|
||||||
static void AssertSystemPrincipalMustNotLoadRemoteDocuments(
|
static void AssertSystemPrincipalMustNotLoadRemoteDocuments(
|
||||||
|
@ -860,7 +860,7 @@ static void AssertSystemPrincipalMustNotLoadRemoteDocuments(
|
||||||
// but other mochitest are exempt from this
|
// but other mochitest are exempt from this
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(false, "SystemPrincipal must not load remote documents.");
|
MOZ_RELEASE_ASSERT(false, "SystemPrincipal must not load remote documents.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -890,7 +890,7 @@ nsresult nsContentSecurityManager::doContentSecurityCheck(
|
||||||
DebugDoContentSecurityCheck(aChannel, loadInfo);
|
DebugDoContentSecurityCheck(aChannel, loadInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(FUZZING)
|
#ifdef EARLY_BETA_OR_EARLIER
|
||||||
AssertSystemPrincipalMustNotLoadRemoteDocuments(aChannel);
|
AssertSystemPrincipalMustNotLoadRemoteDocuments(aChannel);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ support-files =
|
||||||
support-files =
|
support-files =
|
||||||
file_FTP_console_warning.html
|
file_FTP_console_warning.html
|
||||||
[browser_test_assert_systemprincipal_documents.js]
|
[browser_test_assert_systemprincipal_documents.js]
|
||||||
skip-if = !debug && !fuzzing
|
skip-if = !nightly_build
|
||||||
support-files =
|
support-files =
|
||||||
file_assert_systemprincipal_documents.html
|
file_assert_systemprincipal_documents.html
|
||||||
file_assert_systemprincipal_documents_iframe.html
|
file_assert_systemprincipal_documents_iframe.html
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef jit_shared_IonAssemblerBufferWithConstantPools_h
|
#ifndef jit_shared_IonAssemblerBufferWithConstantPools_h
|
||||||
#define jit_shared_IonAssemblerBufferWithConstantPools_h
|
#define jit_shared_IonAssemblerBufferWithConstantPools_h
|
||||||
|
|
||||||
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/MathAlgorithms.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -783,7 +784,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
id, sizeExcludingCurrentPool());
|
id, sizeExcludingCurrentPool());
|
||||||
}
|
}
|
||||||
|
|
||||||
finishPool();
|
finishPool(numInst * InstSize);
|
||||||
if (this->oom()) {
|
if (this->oom()) {
|
||||||
return OOM_FAIL;
|
return OOM_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -813,7 +814,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
JitSpew(JitSpew_Pools,
|
JitSpew(JitSpew_Pools,
|
||||||
"[%d] nextInstrOffset @ %d caused a constant pool spill", id,
|
"[%d] nextInstrOffset @ %d caused a constant pool spill", id,
|
||||||
this->nextOffset().getOffset());
|
this->nextOffset().getOffset());
|
||||||
finishPool();
|
finishPool(ShortRangeBranchHysteresis);
|
||||||
}
|
}
|
||||||
return this->nextOffset();
|
return this->nextOffset();
|
||||||
}
|
}
|
||||||
|
@ -944,27 +945,38 @@ struct AssemblerBufferWithConstantPools
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Are any short-range branches about to expire?
|
// Are any short-range branches about to expire?
|
||||||
bool hasExpirableShortRangeBranches() const {
|
bool hasExpirableShortRangeBranches(size_t reservedBytes) const {
|
||||||
if (branchDeadlines_.empty()) {
|
if (branchDeadlines_.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include branches that would expire in the next N bytes.
|
// Include branches that would expire in the next N bytes. The reservedBytes
|
||||||
// The hysteresis avoids the needless creation of many tiny constant
|
// argument avoids the needless creation of many tiny constant pools.
|
||||||
// pools.
|
//
|
||||||
return this->nextOffset().getOffset() + ShortRangeBranchHysteresis >
|
// As the reservedBytes could be of any sizes such as SIZE_MAX, in the case
|
||||||
size_t(branchDeadlines_.earliestDeadline().getOffset());
|
// of flushPool, we have to check for overflow when comparing the deadline
|
||||||
|
// with our expected reserved bytes.
|
||||||
|
size_t deadline = branchDeadlines_.earliestDeadline().getOffset();
|
||||||
|
using CheckedSize = mozilla::CheckedInt<size_t>;
|
||||||
|
CheckedSize current(this->nextOffset().getOffset());
|
||||||
|
CheckedSize poolFreeSpace(reservedBytes);
|
||||||
|
auto future = current + poolFreeSpace;
|
||||||
|
return !future.isValid() || deadline < future.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPoolEmpty() const {
|
bool isPoolEmptyFor(size_t bytes) const {
|
||||||
return pool_.numEntries() == 0 && !hasExpirableShortRangeBranches();
|
return pool_.numEntries() == 0 && !hasExpirableShortRangeBranches(bytes);
|
||||||
}
|
}
|
||||||
void finishPool() {
|
void finishPool(size_t reservedBytes) {
|
||||||
JitSpew(JitSpew_Pools,
|
JitSpew(JitSpew_Pools,
|
||||||
"[%d] Attempting to finish pool %zu with %u entries.", id,
|
"[%d] Attempting to finish pool %zu with %u entries.", id,
|
||||||
poolInfo_.length(), pool_.numEntries());
|
poolInfo_.length(), pool_.numEntries());
|
||||||
|
|
||||||
if (isPoolEmpty()) {
|
if (reservedBytes < ShortRangeBranchHysteresis) {
|
||||||
|
reservedBytes = ShortRangeBranchHysteresis;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPoolEmptyFor(reservedBytes)) {
|
||||||
// If there is no data in the pool being dumped, don't dump anything.
|
// If there is no data in the pool being dumped, don't dump anything.
|
||||||
JitSpew(JitSpew_Pools, "[%d] Aborting because the pool is empty", id);
|
JitSpew(JitSpew_Pools, "[%d] Aborting because the pool is empty", id);
|
||||||
return;
|
return;
|
||||||
|
@ -984,7 +996,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
|
|
||||||
// Now generate branch veneers for any short-range branches that are
|
// Now generate branch veneers for any short-range branches that are
|
||||||
// about to expire.
|
// about to expire.
|
||||||
while (hasExpirableShortRangeBranches()) {
|
while (hasExpirableShortRangeBranches(reservedBytes)) {
|
||||||
unsigned rangeIdx = branchDeadlines_.earliestDeadlineRange();
|
unsigned rangeIdx = branchDeadlines_.earliestDeadlineRange();
|
||||||
BufferOffset deadline = branchDeadlines_.earliestDeadline();
|
BufferOffset deadline = branchDeadlines_.earliestDeadline();
|
||||||
|
|
||||||
|
@ -1052,7 +1064,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
JitSpew(JitSpew_Pools, "[%d] Requesting a pool flush", id);
|
JitSpew(JitSpew_Pools, "[%d] Requesting a pool flush", id);
|
||||||
finishPool();
|
finishPool(SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enterNoPool(size_t maxInst) {
|
void enterNoPool(size_t maxInst) {
|
||||||
|
@ -1070,7 +1082,8 @@ struct AssemblerBufferWithConstantPools
|
||||||
if (!hasSpaceForInsts(maxInst, 0)) {
|
if (!hasSpaceForInsts(maxInst, 0)) {
|
||||||
JitSpew(JitSpew_Pools, "[%d] No-Pool instruction(%zu) caused a spill.",
|
JitSpew(JitSpew_Pools, "[%d] No-Pool instruction(%zu) caused a spill.",
|
||||||
id, sizeExcludingCurrentPool());
|
id, sizeExcludingCurrentPool());
|
||||||
finishPool();
|
finishPool(maxInst * InstSize);
|
||||||
|
MOZ_ASSERT(hasSpaceForInsts(maxInst, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -1105,7 +1118,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
inhibitNops_ = false;
|
inhibitNops_ = false;
|
||||||
}
|
}
|
||||||
void assertNoPoolAndNoNops() {
|
void assertNoPoolAndNoNops() {
|
||||||
MOZ_ASSERT(inhibitNops_ && (isPoolEmpty() || canNotPlacePool_));
|
MOZ_ASSERT(inhibitNops_ && (isPoolEmptyFor(InstSize) || canNotPlacePool_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void align(unsigned alignment) { align(alignment, alignFillInst_); }
|
void align(unsigned alignment) { align(alignment, alignFillInst_); }
|
||||||
|
@ -1130,7 +1143,7 @@ struct AssemblerBufferWithConstantPools
|
||||||
// Alignment would cause a pool dump, so dump the pool now.
|
// Alignment would cause a pool dump, so dump the pool now.
|
||||||
JitSpew(JitSpew_Pools, "[%d] Alignment of %d at %zu caused a spill.", id,
|
JitSpew(JitSpew_Pools, "[%d] Alignment of %d at %zu caused a spill.", id,
|
||||||
alignment, sizeExcludingCurrentPool());
|
alignment, sizeExcludingCurrentPool());
|
||||||
finishPool();
|
finishPool(requiredFill);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool prevInhibitNops = inhibitNops_;
|
bool prevInhibitNops = inhibitNops_;
|
||||||
|
|
|
@ -435,12 +435,14 @@ MSG_DEF(JSMSG_PROXY_DELETE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "can't delete prope
|
||||||
MSG_DEF(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions handler returned false")
|
MSG_DEF(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions handler returned false")
|
||||||
MSG_DEF(JSMSG_PROXY_SET_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy set handler returned false for property '{0}'")
|
MSG_DEF(JSMSG_PROXY_SET_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy set handler returned false for property '{0}'")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
|
MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
|
||||||
|
MSG_DEF(JSMSG_CANT_DELETE_NON_EXTENSIBLE, 1, JSEXN_TYPEERR, "proxy can't delete property '{0}' on a non-extensible object")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report existing configurable property '{0}' as non-configurable")
|
MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report existing configurable property '{0}' as non-configurable")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report an existing own property '{0}' as non-existent on a non-extensible object")
|
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report an existing own property '{0}' as non-existent on a non-extensible object")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 2, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor ('{0}', {1})")
|
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 2, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor ('{0}', {1})")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report a non-configurable own property '{0}' as non-existent")
|
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report a non-configurable own property '{0}' as non-existent")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_NEW, 1, JSEXN_TYPEERR, "proxy can't report a new property '{0}' on a non-extensible object")
|
MSG_DEF(JSMSG_CANT_REPORT_NEW, 1, JSEXN_TYPEERR, "proxy can't report a new property '{0}' on a non-extensible object")
|
||||||
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report a non-existent property '{0}' as non-configurable")
|
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report a non-existent property '{0}' as non-configurable")
|
||||||
|
MSG_DEF(JSMSG_CANT_REPORT_W_AS_NW, 1, JSEXN_TYPEERR, "proxy can't report existing writable property '{0}' as non-writable")
|
||||||
MSG_DEF(JSMSG_CANT_SET_NW_NC, 1, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property '{0}'")
|
MSG_DEF(JSMSG_CANT_SET_NW_NC, 1, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property '{0}'")
|
||||||
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 1, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property '{0}' without a setter")
|
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 1, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property '{0}' without a setter")
|
||||||
MSG_DEF(JSMSG_CANT_SKIP_NC, 1, JSEXN_TYPEERR, "proxy can't skip a non-configurable property '{0}'")
|
MSG_DEF(JSMSG_CANT_SKIP_NC, 1, JSEXN_TYPEERR, "proxy can't skip a non-configurable property '{0}'")
|
||||||
|
|
|
@ -620,6 +620,12 @@ bool ScriptedProxyHandler::getOwnPropertyDescriptor(
|
||||||
if (targetDesc.configurable()) {
|
if (targetDesc.configurable()) {
|
||||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_C_AS_NC);
|
return js::Throw(cx, id, JSMSG_CANT_REPORT_C_AS_NC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resultDesc.hasWritable() && !resultDesc.writable()) {
|
||||||
|
if (targetDesc.writable()) {
|
||||||
|
return js::Throw(cx, id, JSMSG_CANT_REPORT_W_AS_NW);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 18.
|
// Step 18.
|
||||||
|
@ -733,6 +739,17 @@ bool ScriptedProxyHandler::defineProperty(JSContext* cx, HandleObject proxy,
|
||||||
return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID,
|
return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID,
|
||||||
DETAILS_CANT_REPORT_C_AS_NC);
|
DETAILS_CANT_REPORT_C_AS_NC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetDesc.isDataDescriptor() && !targetDesc.configurable() &&
|
||||||
|
targetDesc.writable()) {
|
||||||
|
if (desc.hasWritable() && !desc.writable()) {
|
||||||
|
static const char DETAILS_CANT_DEFINE_NW[] =
|
||||||
|
"proxy can't define an existing non-configurable writable property "
|
||||||
|
"as non-writable";
|
||||||
|
return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID,
|
||||||
|
DETAILS_CANT_DEFINE_NW);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 17.
|
// Step 17.
|
||||||
|
@ -992,12 +1009,26 @@ bool ScriptedProxyHandler::delete_(JSContext* cx, HandleObject proxy,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 11.
|
||||||
|
if (!desc.object()) {
|
||||||
|
return result.succeed();
|
||||||
|
}
|
||||||
|
|
||||||
// Step 12.
|
// Step 12.
|
||||||
if (desc.object() && !desc.configurable()) {
|
if (!desc.configurable()) {
|
||||||
return Throw(cx, id, JSMSG_CANT_DELETE);
|
return Throw(cx, id, JSMSG_CANT_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 11,13.
|
bool extensible;
|
||||||
|
if (!IsExtensible(cx, target, &extensible)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extensible) {
|
||||||
|
return Throw(cx, id, JSMSG_CANT_DELETE_NON_EXTENSIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
return result.succeed();
|
return result.succeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var target = {};
|
||||||
|
Object.defineProperty(target, "test", {configurable: false, writable: true, value: 5});
|
||||||
|
|
||||||
|
var proxy = new Proxy(target, {
|
||||||
|
defineProperty(target, property) {
|
||||||
|
assertEq(property, "test");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(
|
||||||
|
() => Object.defineProperty(proxy, "test", {writable: false}), TypeError);
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(
|
||||||
|
() => Reflect.defineProperty(proxy, "test", {writable: false}), TypeError);
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,18 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var target = { test: true };
|
||||||
|
Object.preventExtensions(target);
|
||||||
|
|
||||||
|
var proxy = new Proxy(target, {
|
||||||
|
deleteProperty(target, property) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEq(delete proxy.missing, true);
|
||||||
|
assertEq(Reflect.deleteProperty(proxy, "missing"), true);
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => { delete proxy.test; }, TypeError);
|
||||||
|
assertThrowsInstanceOf(() => Reflect.deleteProperty(proxy, "test"), TypeError);
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -0,0 +1,20 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var target = {};
|
||||||
|
Object.defineProperty(target, "test",
|
||||||
|
{configurable: false, writable: true, value: 1});
|
||||||
|
|
||||||
|
var proxy = new Proxy(target, {
|
||||||
|
getOwnPropertyDescriptor(target, property) {
|
||||||
|
assertEq(property, "test");
|
||||||
|
return {configurable: false, writable: false, value: 1};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(proxy, "test"),
|
||||||
|
TypeError);
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => Reflect.getOwnPropertyDescriptor(proxy, "test"),
|
||||||
|
TypeError);
|
||||||
|
|
||||||
|
reportCompare(0, 0);
|
|
@ -188,8 +188,8 @@ ProcessType ScriptPreloader::GetChildProcessType(const nsAString& remoteType) {
|
||||||
if (remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
if (remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
|
||||||
return ProcessType::Extension;
|
return ProcessType::Extension;
|
||||||
}
|
}
|
||||||
if (remoteType.EqualsLiteral(PRIVILEGED_REMOTE_TYPE)) {
|
if (remoteType.EqualsLiteral(PRIVILEGEDABOUT_REMOTE_TYPE)) {
|
||||||
return ProcessType::Privileged;
|
return ProcessType::PrivilegedAbout;
|
||||||
}
|
}
|
||||||
return ProcessType::Web;
|
return ProcessType::Web;
|
||||||
}
|
}
|
||||||
|
@ -346,9 +346,9 @@ void ScriptPreloader::FinishContentStartup() {
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mContentStartupFinishedTopic.Equals(CONTENT_DOCUMENT_LOADED_TOPIC)) {
|
if (mContentStartupFinishedTopic.Equals(CONTENT_DOCUMENT_LOADED_TOPIC)) {
|
||||||
MOZ_ASSERT(sProcessType == ProcessType::Privileged);
|
MOZ_ASSERT(sProcessType == ProcessType::PrivilegedAbout);
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(sProcessType != ProcessType::Privileged);
|
MOZ_ASSERT(sProcessType != ProcessType::PrivilegedAbout);
|
||||||
}
|
}
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ Result<Ok, nsresult> ScriptPreloader::InitCache(
|
||||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||||
MOZ_RELEASE_ASSERT(obs);
|
MOZ_RELEASE_ASSERT(obs);
|
||||||
|
|
||||||
if (sProcessType == ProcessType::Privileged) {
|
if (sProcessType == ProcessType::PrivilegedAbout) {
|
||||||
// Since we control all of the documents loaded in the privileged
|
// Since we control all of the documents loaded in the privileged
|
||||||
// content process, we can increase the window of active time for the
|
// content process, we can increase the window of active time for the
|
||||||
// ScriptPreloader to include the scripts that are loaded until the
|
// ScriptPreloader to include the scripts that are loaded until the
|
||||||
|
|
|
@ -46,7 +46,7 @@ enum class ProcessType : uint8_t {
|
||||||
Parent,
|
Parent,
|
||||||
Web,
|
Web,
|
||||||
Extension,
|
Extension,
|
||||||
Privileged,
|
PrivilegedAbout,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -7730,6 +7730,67 @@ nsresult PresShell::EventHandler::HandleEventWithTarget(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class MOZ_RAII AutoEventHandler final {
|
||||||
|
public:
|
||||||
|
AutoEventHandler(WidgetEvent* aEvent, Document* aDocument) : mEvent(aEvent) {
|
||||||
|
MOZ_ASSERT(mEvent);
|
||||||
|
MOZ_ASSERT(mEvent->IsTrusted());
|
||||||
|
|
||||||
|
if (mEvent->mMessage == eMouseDown) {
|
||||||
|
PresShell::ReleaseCapturingContent();
|
||||||
|
PresShell::AllowMouseCapture(true);
|
||||||
|
}
|
||||||
|
if (aDocument && NeedsToResetFocusManagerMouseButtonHandlingState()) {
|
||||||
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
|
NS_ENSURE_TRUE_VOID(fm);
|
||||||
|
// If it's in modal state, mouse button event handling may be nested.
|
||||||
|
// E.g., a modal dialog is opened at mousedown or mouseup event handler
|
||||||
|
// and the dialog is clicked. Therefore, we should store current
|
||||||
|
// mouse button event handling document if nsFocusManager already has it.
|
||||||
|
mMouseButtonEventHandlingDocument =
|
||||||
|
fm->SetMouseButtonHandlingDocument(aDocument);
|
||||||
|
}
|
||||||
|
if (NeedsToUpdateCurrentMouseBtnState()) {
|
||||||
|
WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
|
||||||
|
if (mouseEvent) {
|
||||||
|
EventStateManager::sCurrentMouseBtn = mouseEvent->mButton;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~AutoEventHandler() {
|
||||||
|
if (mEvent->mMessage == eMouseDown) {
|
||||||
|
PresShell::AllowMouseCapture(false);
|
||||||
|
}
|
||||||
|
if (NeedsToResetFocusManagerMouseButtonHandlingState()) {
|
||||||
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
|
NS_ENSURE_TRUE_VOID(fm);
|
||||||
|
RefPtr<Document> document =
|
||||||
|
fm->SetMouseButtonHandlingDocument(mMouseButtonEventHandlingDocument);
|
||||||
|
}
|
||||||
|
if (NeedsToUpdateCurrentMouseBtnState()) {
|
||||||
|
EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool NeedsToResetFocusManagerMouseButtonHandlingState() const {
|
||||||
|
return mEvent->mMessage == eMouseDown || mEvent->mMessage == eMouseUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeedsToUpdateCurrentMouseBtnState() const {
|
||||||
|
return mEvent->mMessage == eMouseDown || mEvent->mMessage == eMouseUp ||
|
||||||
|
mEvent->mMessage == ePointerDown || mEvent->mMessage == ePointerUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<Document> mMouseButtonEventHandlingDocument;
|
||||||
|
WidgetEvent* mEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
nsresult PresShell::EventHandler::HandleEventWithCurrentEventInfo(
|
nsresult PresShell::EventHandler::HandleEventWithCurrentEventInfo(
|
||||||
WidgetEvent* aEvent, nsEventStatus* aEventStatus,
|
WidgetEvent* aEvent, nsEventStatus* aEventStatus,
|
||||||
bool aIsHandlingNativeEvent, nsIContent* aOverrideClickTarget) {
|
bool aIsHandlingNativeEvent, nsIContent* aOverrideClickTarget) {
|
||||||
|
@ -7756,10 +7817,8 @@ nsresult PresShell::EventHandler::HandleEventWithCurrentEventInfo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isHandlingUserInput = false;
|
|
||||||
bool touchIsNew = false;
|
bool touchIsNew = false;
|
||||||
if (!PrepareToDispatchEvent(aEvent, aEventStatus, &isHandlingUserInput,
|
if (!PrepareToDispatchEvent(aEvent, aEventStatus, &touchIsNew)) {
|
||||||
&touchIsNew)) {
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7767,9 +7826,9 @@ nsresult PresShell::EventHandler::HandleEventWithCurrentEventInfo(
|
||||||
// performance.
|
// performance.
|
||||||
RecordEventPreparationPerformance(aEvent);
|
RecordEventPreparationPerformance(aEvent);
|
||||||
|
|
||||||
AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
|
AutoHandlingUserInputStatePusher userInpStatePusher(
|
||||||
aEvent, GetDocument());
|
EventStateManager::IsUserInteractionEvent(aEvent), aEvent);
|
||||||
|
AutoEventHandler eventHandler(aEvent, GetDocument());
|
||||||
AutoPopupStatePusher popupStatePusher(
|
AutoPopupStatePusher popupStatePusher(
|
||||||
PopupBlocker::GetEventPopupControlState(aEvent));
|
PopupBlocker::GetEventPopupControlState(aEvent));
|
||||||
|
|
||||||
|
@ -7877,11 +7936,9 @@ nsresult PresShell::EventHandler::DispatchEvent(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PresShell::EventHandler::PrepareToDispatchEvent(
|
bool PresShell::EventHandler::PrepareToDispatchEvent(
|
||||||
WidgetEvent* aEvent, nsEventStatus* aEventStatus, bool* aIsUserInteraction,
|
WidgetEvent* aEvent, nsEventStatus* aEventStatus, bool* aTouchIsNew) {
|
||||||
bool* aTouchIsNew) {
|
|
||||||
MOZ_ASSERT(aEvent->IsTrusted());
|
MOZ_ASSERT(aEvent->IsTrusted());
|
||||||
MOZ_ASSERT(aEventStatus);
|
MOZ_ASSERT(aEventStatus);
|
||||||
MOZ_ASSERT(aIsUserInteraction);
|
|
||||||
MOZ_ASSERT(aTouchIsNew);
|
MOZ_ASSERT(aTouchIsNew);
|
||||||
|
|
||||||
*aTouchIsNew = false;
|
*aTouchIsNew = false;
|
||||||
|
@ -7895,26 +7952,14 @@ bool PresShell::EventHandler::PrepareToDispatchEvent(
|
||||||
case eKeyUp: {
|
case eKeyUp: {
|
||||||
WidgetKeyboardEvent* keyboardEvent = aEvent->AsKeyboardEvent();
|
WidgetKeyboardEvent* keyboardEvent = aEvent->AsKeyboardEvent();
|
||||||
MaybeHandleKeyboardEventBeforeDispatch(keyboardEvent);
|
MaybeHandleKeyboardEventBeforeDispatch(keyboardEvent);
|
||||||
// Not all keyboard events are treated as user input, so that popups
|
|
||||||
// can't be opened, fullscreen mode can't be started, etc at unexpected
|
|
||||||
// time.
|
|
||||||
*aIsUserInteraction = keyboardEvent->CanTreatAsUserInput();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case eMouseDown:
|
|
||||||
case eMouseUp:
|
|
||||||
case ePointerDown:
|
|
||||||
case ePointerUp:
|
|
||||||
*aIsUserInteraction = true;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case eMouseMove: {
|
case eMouseMove: {
|
||||||
bool allowCapture = EventStateManager::GetActiveEventStateManager() &&
|
bool allowCapture = EventStateManager::GetActiveEventStateManager() &&
|
||||||
GetPresContext() &&
|
GetPresContext() &&
|
||||||
GetPresContext()->EventStateManager() ==
|
GetPresContext()->EventStateManager() ==
|
||||||
EventStateManager::GetActiveEventStateManager();
|
EventStateManager::GetActiveEventStateManager();
|
||||||
PresShell::AllowMouseCapture(allowCapture);
|
PresShell::AllowMouseCapture(allowCapture);
|
||||||
*aIsUserInteraction = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case eDrop: {
|
case eDrop: {
|
||||||
|
@ -7926,12 +7971,9 @@ bool PresShell::EventHandler::PrepareToDispatchEvent(
|
||||||
aEvent->mFlags.mOnlyChromeDispatch = true;
|
aEvent->mFlags.mOnlyChromeDispatch = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*aIsUserInteraction = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case eContextMenu: {
|
case eContextMenu: {
|
||||||
*aIsUserInteraction = false;
|
|
||||||
|
|
||||||
// If we cannot open context menu even though eContextMenu is fired, we
|
// If we cannot open context menu even though eContextMenu is fired, we
|
||||||
// should stop dispatching it into the DOM.
|
// should stop dispatching it into the DOM.
|
||||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||||
|
@ -7956,10 +7998,8 @@ bool PresShell::EventHandler::PrepareToDispatchEvent(
|
||||||
case eTouchCancel:
|
case eTouchCancel:
|
||||||
case eTouchPointerCancel:
|
case eTouchPointerCancel:
|
||||||
return mPresShell->mTouchManager.PreHandleEvent(
|
return mPresShell->mTouchManager.PreHandleEvent(
|
||||||
aEvent, aEventStatus, *aTouchIsNew, *aIsUserInteraction,
|
aEvent, aEventStatus, *aTouchIsNew, mPresShell->mCurrentEventContent);
|
||||||
mPresShell->mCurrentEventContent);
|
|
||||||
default:
|
default:
|
||||||
*aIsUserInteraction = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2563,10 +2563,6 @@ class PresShell final : public nsStubDocumentObserver,
|
||||||
*
|
*
|
||||||
* @param aEvent The handling event.
|
* @param aEvent The handling event.
|
||||||
* @param aEventStatus [in/out] The status of aEvent.
|
* @param aEventStatus [in/out] The status of aEvent.
|
||||||
* @param aIsUserInteraction [out] Set to true if the event is user
|
|
||||||
* interaction. I.e., enough obvious input
|
|
||||||
* to allow to open popup, etc. Otherwise,
|
|
||||||
* set to false.
|
|
||||||
* @param aTouchIsNew [out] Set to true if the event is an
|
* @param aTouchIsNew [out] Set to true if the event is an
|
||||||
* eTouchMove event and it represents new
|
* eTouchMove event and it represents new
|
||||||
* touch. Otherwise, set to false.
|
* touch. Otherwise, set to false.
|
||||||
|
@ -2575,8 +2571,7 @@ class PresShell final : public nsStubDocumentObserver,
|
||||||
*/
|
*/
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
bool PrepareToDispatchEvent(WidgetEvent* aEvent,
|
bool PrepareToDispatchEvent(WidgetEvent* aEvent,
|
||||||
nsEventStatus* aEventStatus,
|
nsEventStatus* aEventStatus, bool* aTouchIsNew);
|
||||||
bool* aIsUserInteraction, bool* aTouchIsNew);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaybeHandleKeyboardEventBeforeDispatch() may handle aKeyboardEvent
|
* MaybeHandleKeyboardEventBeforeDispatch() may handle aKeyboardEvent
|
||||||
|
|
|
@ -220,7 +220,7 @@ nsIFrame* TouchManager::SuppressInvalidPointsAndGetTargetedFrame(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TouchManager::PreHandleEvent(WidgetEvent* aEvent, nsEventStatus* aStatus,
|
bool TouchManager::PreHandleEvent(WidgetEvent* aEvent, nsEventStatus* aStatus,
|
||||||
bool& aTouchIsNew, bool& aIsHandlingUserInput,
|
bool& aTouchIsNew,
|
||||||
nsCOMPtr<nsIContent>& aCurrentEventContent) {
|
nsCOMPtr<nsIContent>& aCurrentEventContent) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aEvent->IsTrusted());
|
MOZ_DIAGNOSTIC_ASSERT(aEvent->IsTrusted());
|
||||||
|
|
||||||
|
@ -228,7 +228,6 @@ bool TouchManager::PreHandleEvent(WidgetEvent* aEvent, nsEventStatus* aStatus,
|
||||||
// cases in PresShell::EventHandler::PrepareToDispatchEvent().
|
// cases in PresShell::EventHandler::PrepareToDispatchEvent().
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
case eTouchStart: {
|
case eTouchStart: {
|
||||||
aIsHandlingUserInput = true;
|
|
||||||
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
||||||
// if there is only one touch in this touchstart event, assume that it is
|
// if there is only one touch in this touchstart event, assume that it is
|
||||||
// the start of a new touch session and evict any old touches in the
|
// the start of a new touch session and evict any old touches in the
|
||||||
|
@ -335,9 +334,6 @@ bool TouchManager::PreHandleEvent(WidgetEvent* aEvent, nsEventStatus* aStatus,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eTouchEnd:
|
case eTouchEnd:
|
||||||
aIsHandlingUserInput = true;
|
|
||||||
// Fall through to touchcancel code
|
|
||||||
MOZ_FALLTHROUGH;
|
|
||||||
case eTouchCancel: {
|
case eTouchCancel: {
|
||||||
// Remove the changed touches
|
// Remove the changed touches
|
||||||
// need to make sure we only remove touches that are ending here
|
// need to make sure we only remove touches that are ending here
|
||||||
|
|
|
@ -49,7 +49,7 @@ class TouchManager {
|
||||||
WidgetTouchEvent* aEvent);
|
WidgetTouchEvent* aEvent);
|
||||||
|
|
||||||
bool PreHandleEvent(mozilla::WidgetEvent* aEvent, nsEventStatus* aStatus,
|
bool PreHandleEvent(mozilla::WidgetEvent* aEvent, nsEventStatus* aStatus,
|
||||||
bool& aTouchIsNew, bool& aIsHandlingUserInput,
|
bool& aTouchIsNew,
|
||||||
nsCOMPtr<nsIContent>& aCurrentEventContent);
|
nsCOMPtr<nsIContent>& aCurrentEventContent);
|
||||||
|
|
||||||
static already_AddRefed<nsIContent> GetAnyCapturedTouchTarget();
|
static already_AddRefed<nsIContent> GetAnyCapturedTouchTarget();
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
var SimpleTest = window.opener.SimpleTest;
|
var SimpleTest = window.opener.SimpleTest;
|
||||||
var SpecialPowers = window.opener.SpecialPowers;
|
var SpecialPowers = window.opener.SpecialPowers;
|
||||||
var is = window.opener.is;
|
var is = window.opener.is;
|
||||||
var t, e, utils, iterations;
|
|
||||||
var smoothScrollPref = "general.smoothScroll";
|
var smoothScrollPref = "general.smoothScroll";
|
||||||
|
|
||||||
function startTest() {
|
function startTest() {
|
||||||
|
|
|
@ -30,12 +30,12 @@ function newDir() {
|
||||||
var dir = tmpDir.clone();
|
var dir = tmpDir.clone();
|
||||||
dir.append("testdir" + Math.floor(Math.random() * 10000));
|
dir.append("testdir" + Math.floor(Math.random() * 10000));
|
||||||
dir.QueryInterface(Ci.nsIFile);
|
dir.QueryInterface(Ci.nsIFile);
|
||||||
dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
|
dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o700);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirs = [];
|
var dirs = [];
|
||||||
for(var i = 0; i < 6; i++) {
|
for(let i = 0; i < 6; i++) {
|
||||||
dirs.push(newDir());
|
dirs.push(newDir());
|
||||||
}
|
}
|
||||||
dirs.push(homeDir);
|
dirs.push(homeDir);
|
||||||
|
@ -119,7 +119,7 @@ function runTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function endTest() {
|
function endTest() {
|
||||||
for(var i = 0; i < dirs.length - 1; i++) {
|
for(let i = 0; i < dirs.length - 1; i++) {
|
||||||
dirs[i].remove(true);
|
dirs[i].remove(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ function testOnWindow(aIsPrivate, aCallback) {
|
||||||
MockFilePicker.showCallback = function(filepicker) {
|
MockFilePicker.showCallback = function(filepicker) {
|
||||||
var test = tests[testIndex];
|
var test = tests[testIndex];
|
||||||
var returned = -1;
|
var returned = -1;
|
||||||
for (var i = 0; i < dirs.length; i++) {
|
for (let i = 0; i < dirs.length; i++) {
|
||||||
var dir = MockFilePicker.displayDirectory
|
var dir = MockFilePicker.displayDirectory
|
||||||
? MockFilePicker.displayDirectory
|
? MockFilePicker.displayDirectory
|
||||||
: Services.dirsvc.get(MockFilePicker.displaySpecialDirectory, Ci.nsIFile);
|
: Services.dirsvc.get(MockFilePicker.displaySpecialDirectory, Ci.nsIFile);
|
||||||
|
|
|
@ -59,7 +59,7 @@ function runTests()
|
||||||
select.addEventListener("popupshowing", function (aEvent) {
|
select.addEventListener("popupshowing", function (aEvent) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
synthesizeKey("KEY_ArrowDown");
|
synthesizeKey("KEY_ArrowDown");
|
||||||
select.addEventListener("popuphiding", function (aEvent) {
|
select.addEventListener("popuphiding", function (aEventInner) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
// Enter key should cause closing the dropdown of the select element
|
// Enter key should cause closing the dropdown of the select element
|
||||||
// and keypress event shouldn't be fired on the input element because
|
// and keypress event shouldn't be fired on the input element because
|
||||||
|
|
|
@ -114,17 +114,17 @@ function checkClipRegionWithDoc(doc, offsetX, offsetY, id, rects, checkBounds) {
|
||||||
"': expected " + dumpRegion(rects) + ", got " + dumpRegion(clipRects));
|
"': expected " + dumpRegion(rects) + ", got " + dumpRegion(clipRects));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkClipRegion = function checkClipRegion(id, rects) {
|
checkClipRegion = function(id, rects) {
|
||||||
checkClipRegionWithDoc(document, 0, 0, id, rects, true);
|
checkClipRegionWithDoc(document, 0, 0, id, rects, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkClipRegionForFrame = function checkClipRegionForFrame(fid, id, rects) {
|
checkClipRegionForFrame = function(fid, id, rects) {
|
||||||
var f = document.getElementById(fid);
|
var f = document.getElementById(fid);
|
||||||
var bounds = f.getBoundingClientRect();
|
var bounds = f.getBoundingClientRect();
|
||||||
checkClipRegionWithDoc(f.contentDocument, bounds.left, bounds.top, id, rects, true);
|
checkClipRegionWithDoc(f.contentDocument, bounds.left, bounds.top, id, rects, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkClipRegionNoBounds = function checkClipRegionNoBounds(id, rects) {
|
checkClipRegionNoBounds = function(id, rects) {
|
||||||
checkClipRegionWithDoc(document, 0, 0, id, rects, false);
|
checkClipRegionWithDoc(document, 0, 0, id, rects, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ limitations under the License.
|
||||||
<p id="display"></p>
|
<p id="display"></p>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
/* eslint-disable no-shadow */
|
||||||
var tests = [];
|
var tests = [];
|
||||||
var curDescribeMsg = '';
|
var curDescribeMsg = '';
|
||||||
var curItMsg = '';
|
var curItMsg = '';
|
||||||
|
|
|
@ -5,7 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=507902
|
||||||
-->
|
-->
|
||||||
<head>
|
<head>
|
||||||
<title>Test for Bug 507902</title>
|
<title>Test for Bug 507902</title>
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -60,7 +60,7 @@ var canvasNames = [ "brokenIconTest", "brokenIconReference",
|
||||||
"loadingIconTest", "loadingIconReference",
|
"loadingIconTest", "loadingIconReference",
|
||||||
"loadedTest", "loadedReference" ];
|
"loadedTest", "loadedReference" ];
|
||||||
var windowElem = document.documentElement;
|
var windowElem = document.documentElement;
|
||||||
for (var i in canvasNames) {
|
for (let i in canvasNames) {
|
||||||
var can = document.createElement("canvas");
|
var can = document.createElement("canvas");
|
||||||
can.setAttribute("width", windowElem.getAttribute("width"));
|
can.setAttribute("width", windowElem.getAttribute("width"));
|
||||||
can.setAttribute("height", windowElem.getAttribute("height"));
|
can.setAttribute("height", windowElem.getAttribute("height"));
|
||||||
|
@ -81,7 +81,7 @@ for (var i in canvasNames) {
|
||||||
// with the image, but not the bottom and right borders.
|
// with the image, but not the bottom and right borders.
|
||||||
|
|
||||||
if ((i > 1) && (i < 4)) {
|
if ((i > 1) && (i < 4)) {
|
||||||
var ctx = can.getContext("2d");
|
let ctx = can.getContext("2d");
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.rect(0,0, 30, 30);
|
ctx.rect(0,0, 30, 30);
|
||||||
ctx.clip();
|
ctx.clip();
|
||||||
|
@ -327,7 +327,7 @@ function resetImage() {
|
||||||
// debugging.
|
// debugging.
|
||||||
//
|
//
|
||||||
function makeCanvasesVisible() {
|
function makeCanvasesVisible() {
|
||||||
for (var i = 0; i < canvasNames.length - 1; i += 2) {
|
for (let i = 0; i < canvasNames.length - 1; i += 2) {
|
||||||
var title = document.createElement("h3");
|
var title = document.createElement("h3");
|
||||||
title.innerHTML = canvasNames[i] + ", " + canvasNames[i+1] + ":";
|
title.innerHTML = canvasNames[i] + ", " + canvasNames[i+1] + ":";
|
||||||
document.body.appendChild(title);
|
document.body.appendChild(title);
|
||||||
|
@ -359,7 +359,7 @@ function disableBorderAndPad() {
|
||||||
|
|
||||||
function drawWindowToCanvas(canvasName) {
|
function drawWindowToCanvas(canvasName) {
|
||||||
var win = testFrameElem.contentWindow;
|
var win = testFrameElem.contentWindow;
|
||||||
var ctx = canvases[canvasName].getContext("2d");
|
let ctx = canvases[canvasName].getContext("2d");
|
||||||
// drawWindow always draws one canvas pixel for each CSS pixel in the source
|
// drawWindow always draws one canvas pixel for each CSS pixel in the source
|
||||||
// window, so scale the drawing to show the zoom (making each canvas pixel be one
|
// window, so scale the drawing to show the zoom (making each canvas pixel be one
|
||||||
// device pixel instead)
|
// device pixel instead)
|
||||||
|
|
|
@ -23,7 +23,7 @@ extracted from the test framework there and put into Mochitest.
|
||||||
<body>
|
<body>
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=156716">Mozilla Bug 156716</a>
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=156716">Mozilla Bug 156716</a>
|
||||||
<div id="content" style="display: none">
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
@ -78,14 +78,14 @@ function runTest() {
|
||||||
doc.getElementsByTagName('head')[0].appendChild(style);
|
doc.getElementsByTagName('head')[0].appendChild(style);
|
||||||
var names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y1', 'y2', 'y3', 'y4'];
|
var names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y1', 'y2', 'y3', 'y4'];
|
||||||
for (var i in names) {
|
for (var i in names) {
|
||||||
var p = doc.createElement('p');
|
let p = doc.createElement('p');
|
||||||
p.id = names[i];
|
p.id = names[i];
|
||||||
doc.body.appendChild(p);
|
doc.body.appendChild(p);
|
||||||
}
|
}
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var check = function (c, e) {
|
var check = function (c, e) {
|
||||||
count += 1;
|
count += 1;
|
||||||
var p = doc.getElementById(c);
|
let p = doc.getElementById(c);
|
||||||
is(doc.defaultView.getComputedStyle(p).textTransform, e ? 'uppercase' : 'none', "case " + c + " failed (index " + count + ")");
|
is(doc.defaultView.getComputedStyle(p).textTransform, e ? 'uppercase' : 'none', "case " + c + " failed (index " + count + ")");
|
||||||
}
|
}
|
||||||
check('a', true); // 1
|
check('a', true); // 1
|
||||||
|
@ -138,4 +138,3 @@ function runTest() {
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=696253
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Utility function for getting computed style of "align-self":
|
* Utility function for getting computed style of "align-self":
|
||||||
*/
|
*/
|
||||||
|
@ -156,27 +155,27 @@ function main() {
|
||||||
testGeneralNode(body);
|
testGeneralNode(body);
|
||||||
testNodeThatHasParent(body);
|
testNodeThatHasParent(body);
|
||||||
|
|
||||||
//
|
//
|
||||||
// align-items/self tests:
|
// align-items/self tests:
|
||||||
//
|
//
|
||||||
//// Block tests
|
//// Block tests
|
||||||
var elem = document.body;
|
var element = document.body;
|
||||||
var child = document.getElementById("display");
|
var child = document.getElementById("display");
|
||||||
var abs = document.getElementById("absChild");
|
var absChild = document.getElementById("absChild");
|
||||||
is(getComputedAlignItems(elem), 'normal', "default align-items value for block container");
|
is(getComputedAlignItems(element), 'normal', "default align-items value for block container");
|
||||||
is(getComputedAlignSelf(child), 'auto', "default align-self value for block child");
|
is(getComputedAlignSelf(child), 'auto', "default align-self value for block child");
|
||||||
is(getComputedAlignSelf(abs), 'auto', "default align-self value for block container abs.pos. child");
|
is(getComputedAlignSelf(absChild), 'auto', "default align-self value for block container abs.pos. child");
|
||||||
elem.style.alignItems = "end";
|
element.style.alignItems = "end";
|
||||||
is(getComputedAlignSelf(child), 'auto', "align-self:auto value persists for block child");
|
is(getComputedAlignSelf(child), 'auto', "align-self:auto value persists for block child");
|
||||||
is(getComputedAlignSelf(abs), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
is(getComputedAlignSelf(absChild), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
||||||
elem.style.alignItems = "left";
|
element.style.alignItems = "left";
|
||||||
is(getComputedAlignItems(elem), 'end', "align-items:left is an invalid declaration");
|
is(getComputedAlignItems(element), 'end', "align-items:left is an invalid declaration");
|
||||||
is(getComputedAlignSelf(child), 'auto', "align-self:auto persists for block child");
|
is(getComputedAlignSelf(child), 'auto', "align-self:auto persists for block child");
|
||||||
is(getComputedAlignSelf(abs), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
is(getComputedAlignSelf(absChild), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
||||||
elem.style.alignItems = "right";
|
element.style.alignItems = "right";
|
||||||
is(getComputedAlignItems(elem), 'end', "align-items:right is an invalid declaration");
|
is(getComputedAlignItems(element), 'end', "align-items:right is an invalid declaration");
|
||||||
is(getComputedAlignSelf(child), 'auto', "align-self:auto value persists for block child");
|
is(getComputedAlignSelf(child), 'auto', "align-self:auto value persists for block child");
|
||||||
is(getComputedAlignSelf(abs), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
is(getComputedAlignSelf(absChild), 'auto', "align-self:auto value persists for block container abs.pos. child");
|
||||||
|
|
||||||
//// Flexbox tests
|
//// Flexbox tests
|
||||||
function testFlexAlignItemsSelf(elem) {
|
function testFlexAlignItemsSelf(elem) {
|
||||||
|
@ -227,32 +226,32 @@ function main() {
|
||||||
// justify-items/self tests:
|
// justify-items/self tests:
|
||||||
//
|
//
|
||||||
//// Block tests
|
//// Block tests
|
||||||
var elem = document.body;
|
element = document.body;
|
||||||
var child = document.getElementById("display");
|
child = document.getElementById("display");
|
||||||
var abs = document.getElementById("absChild");
|
absChild = document.getElementById("absChild");
|
||||||
is(getComputedJustifyItems(elem), 'normal', "default justify-items value for block container");
|
is(getComputedJustifyItems(element), 'normal', "default justify-items value for block container");
|
||||||
is(getComputedJustifySelf(child), 'auto', "default justify-self value for block container child");
|
is(getComputedJustifySelf(child), 'auto', "default justify-self value for block container child");
|
||||||
is(getComputedJustifySelf(abs), 'auto', "default justify-self value for block container abs.pos. child");
|
is(getComputedJustifySelf(absChild), 'auto', "default justify-self value for block container abs.pos. child");
|
||||||
elem.style.justifyItems = "end";
|
element.style.justifyItems = "end";
|
||||||
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
||||||
is(getComputedJustifySelf(abs), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
is(getComputedJustifySelf(absChild), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
||||||
elem.style.justifyItems = "left";
|
element.style.justifyItems = "left";
|
||||||
is(getComputedJustifyItems(elem), 'left', "justify-items:left computes to itself on a block");
|
is(getComputedJustifyItems(element), 'left', "justify-items:left computes to itself on a block");
|
||||||
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
||||||
is(getComputedJustifySelf(abs), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
is(getComputedJustifySelf(absChild), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
||||||
elem.style.justifyItems = "right";
|
element.style.justifyItems = "right";
|
||||||
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
||||||
is(getComputedJustifySelf(abs), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
is(getComputedJustifySelf(absChild), 'auto', "justify-self:auto value persists for block container abs.pos. child");
|
||||||
elem.style.justifyItems = "safe right";
|
element.style.justifyItems = "safe right";
|
||||||
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
is(getComputedJustifySelf(child), 'auto', "justify-self:auto value persists for block child");
|
||||||
elem.style.justifyItems = "";
|
element.style.justifyItems = "";
|
||||||
child.style.justifySelf = "left";
|
child.style.justifySelf = "left";
|
||||||
is(getComputedJustifySelf(child), 'left', "justify-self:left computes to left on block child");
|
is(getComputedJustifySelf(child), 'left', "justify-self:left computes to left on block child");
|
||||||
child.style.justifySelf = "right";
|
child.style.justifySelf = "right";
|
||||||
is(getComputedJustifySelf(child), 'right', "justify-self:right computes to right on block child");
|
is(getComputedJustifySelf(child), 'right', "justify-self:right computes to right on block child");
|
||||||
child.style.justifySelf = "";
|
child.style.justifySelf = "";
|
||||||
abs.style.justifySelf = "right";
|
absChild.style.justifySelf = "right";
|
||||||
is(getComputedJustifySelf(abs), 'right', "justify-self:right computes to right on block container abs.pos. child");
|
is(getComputedJustifySelf(absChild), 'right', "justify-self:right computes to right on block container abs.pos. child");
|
||||||
|
|
||||||
//// Flexbox tests
|
//// Flexbox tests
|
||||||
function testFlexJustifyItemsSelf(elem) {
|
function testFlexJustifyItemsSelf(elem) {
|
||||||
|
@ -324,26 +323,26 @@ function main() {
|
||||||
testGridJustifyItemsSelf(document.getElementById("gridContainer"));
|
testGridJustifyItemsSelf(document.getElementById("gridContainer"));
|
||||||
testGridJustifyItemsSelf(document.getElementById("gridContainerFlex"));
|
testGridJustifyItemsSelf(document.getElementById("gridContainerFlex"));
|
||||||
|
|
||||||
//
|
//
|
||||||
// align-content tests:
|
// align-content tests:
|
||||||
//
|
//
|
||||||
//// Block tests
|
//// Block tests
|
||||||
var elem = document.body;
|
element = document.body;
|
||||||
var child = document.getElementById("display");
|
child = document.getElementById("display");
|
||||||
var abs = document.getElementById("absChild");
|
absChild = document.getElementById("absChild");
|
||||||
is(getComputedAlignContent(elem), 'normal', "default align-content value for block container");
|
is(getComputedAlignContent(element), 'normal', "default align-content value for block container");
|
||||||
is(getComputedAlignContent(child), 'normal', "default align-content value for block child");
|
is(getComputedAlignContent(child), 'normal', "default align-content value for block child");
|
||||||
is(getComputedAlignContent(abs), 'normal', "default align-content value for block container abs.pos. child");
|
is(getComputedAlignContent(absChild), 'normal', "default align-content value for block container abs.pos. child");
|
||||||
elem.style.alignContent = "end";
|
element.style.alignContent = "end";
|
||||||
is(getComputedAlignContent(child), 'normal', "default align-content isn't affected by parent align-content value for in-flow child");
|
is(getComputedAlignContent(child), 'normal', "default align-content isn't affected by parent align-content value for in-flow child");
|
||||||
is(getComputedAlignContent(abs), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
is(getComputedAlignContent(absChild), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
||||||
elem.style.alignContent = "left";
|
element.style.alignContent = "left";
|
||||||
is(getComputedAlignContent(elem), 'end', "align-content:left isn't a valid declaration");
|
is(getComputedAlignContent(element), 'end', "align-content:left isn't a valid declaration");
|
||||||
is(getComputedAlignContent(abs), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
is(getComputedAlignContent(absChild), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
||||||
elem.style.alignContent = "right";
|
element.style.alignContent = "right";
|
||||||
is(getComputedAlignContent(elem), 'end', "align-content:right isn't a valid declaration");
|
is(getComputedAlignContent(element), 'end', "align-content:right isn't a valid declaration");
|
||||||
is(getComputedAlignContent(abs), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
is(getComputedAlignContent(absChild), 'normal', "default align-content isn't affected by parent align-content value for block container abs.pos. child");
|
||||||
elem.style.alignContent = "";
|
element.style.alignContent = "";
|
||||||
|
|
||||||
//// Flexbox tests
|
//// Flexbox tests
|
||||||
function testFlexAlignContent(elem) {
|
function testFlexAlignContent(elem) {
|
||||||
|
@ -387,28 +386,28 @@ function main() {
|
||||||
testGridAlignContent(document.getElementById("gridContainerFlex"));
|
testGridAlignContent(document.getElementById("gridContainerFlex"));
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// justify-content tests:
|
// justify-content tests:
|
||||||
//
|
//
|
||||||
//// Block tests
|
//// Block tests
|
||||||
var elem = document.body;
|
element = document.body;
|
||||||
var child = document.getElementById("display");
|
child = document.getElementById("display");
|
||||||
var abs = document.getElementById("absChild");
|
absChild = document.getElementById("absChild");
|
||||||
is(getComputedJustifyContent(elem), 'normal', "default justify-content value for block container");
|
is(getComputedJustifyContent(element), 'normal', "default justify-content value for block container");
|
||||||
is(getComputedJustifyContent(child), 'normal', "default justify-content value for block child");
|
is(getComputedJustifyContent(child), 'normal', "default justify-content value for block child");
|
||||||
is(getComputedJustifyContent(abs), 'normal', "default justify-content value for block container abs.pos. child");
|
is(getComputedJustifyContent(absChild), 'normal', "default justify-content value for block container abs.pos. child");
|
||||||
elem.style.justifyContent = "end";
|
element.style.justifyContent = "end";
|
||||||
is(getComputedJustifyContent(child), 'normal', "default justify-content isn't affected by parent justify-content value for in-flow child");
|
is(getComputedJustifyContent(child), 'normal', "default justify-content isn't affected by parent justify-content value for in-flow child");
|
||||||
is(getComputedJustifyContent(abs), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
is(getComputedJustifyContent(absChild), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
||||||
elem.style.justifyContent = "left";
|
element.style.justifyContent = "left";
|
||||||
is(getComputedJustifyContent(elem), 'left', "justify-content:left computes to left on block child");
|
is(getComputedJustifyContent(element), 'left', "justify-content:left computes to left on block child");
|
||||||
is(getComputedJustifyContent(abs), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
is(getComputedJustifyContent(absChild), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
||||||
elem.style.justifyContent = "right";
|
element.style.justifyContent = "right";
|
||||||
is(getComputedJustifyContent(elem), 'right', "justify-content:right computes to right on block child");
|
is(getComputedJustifyContent(element), 'right', "justify-content:right computes to right on block child");
|
||||||
is(getComputedJustifyContent(abs), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
is(getComputedJustifyContent(absChild), 'normal', "default justify-content isn't affected by parent justify-content value for block container abs.pos. child");
|
||||||
elem.style.justifyContent = "safe right";
|
element.style.justifyContent = "safe right";
|
||||||
is(getComputedJustifyContent(elem), 'safe right', "justify-content:'safe right' computes to 'justify-content:safe right'");
|
is(getComputedJustifyContent(element), 'safe right', "justify-content:'safe right' computes to 'justify-content:safe right'");
|
||||||
elem.style.justifyContent = "";
|
element.style.justifyContent = "";
|
||||||
child.style.justifyContent = "left";
|
child.style.justifyContent = "left";
|
||||||
is(getComputedJustifyContent(child), 'left', "justify-content:left computes to left on block child");
|
is(getComputedJustifyContent(child), 'left', "justify-content:left computes to left on block child");
|
||||||
child.style.justifyContent = "right";
|
child.style.justifyContent = "right";
|
||||||
|
@ -416,9 +415,9 @@ function main() {
|
||||||
child.style.justifyContent = "safe left";
|
child.style.justifyContent = "safe left";
|
||||||
is(getComputedJustifyContent(child), 'safe left', "justify-content:safe left computes to 'safe left' on block child");
|
is(getComputedJustifyContent(child), 'safe left', "justify-content:safe left computes to 'safe left' on block child");
|
||||||
child.style.justifyContent = "";
|
child.style.justifyContent = "";
|
||||||
abs.style.justifyContent = "right";
|
absChild.style.justifyContent = "right";
|
||||||
is(getComputedJustifyContent(abs), 'right', "justify-content:right computes to right on block container abs.pos. child");
|
is(getComputedJustifyContent(absChild), 'right', "justify-content:right computes to right on block container abs.pos. child");
|
||||||
abs.style.justifyContent = "";
|
absChild.style.justifyContent = "";
|
||||||
|
|
||||||
//// Flexbox tests
|
//// Flexbox tests
|
||||||
function testFlexJustifyContent(elem) {
|
function testFlexJustifyContent(elem) {
|
||||||
|
|
|
@ -34,6 +34,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1183461
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/* eslint-disable no-shadow */
|
||||||
|
|
||||||
// Take over the refresh driver right from the start.
|
// Take over the refresh driver right from the start.
|
||||||
advance_clock(0);
|
advance_clock(0);
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ function testTransitionTakingOver() {
|
||||||
getComputedStyle(child).opacity;
|
getComputedStyle(child).opacity;
|
||||||
gUtils.advanceTimeAndRefresh(0);
|
gUtils.advanceTimeAndRefresh(0);
|
||||||
waitForAllPaints(function() {
|
waitForAllPaints(function() {
|
||||||
var opacity = gUtils.getOMTAStyle(child, "opacity");
|
opacity = gUtils.getOMTAStyle(child, "opacity");
|
||||||
is(opacity, "0.4",
|
is(opacity, "0.4",
|
||||||
"transition that interrupted animation is correct");
|
"transition that interrupted animation is correct");
|
||||||
gUtils.advanceTimeAndRefresh(5000);
|
gUtils.advanceTimeAndRefresh(5000);
|
||||||
|
|
|
@ -18,7 +18,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=73586
|
||||||
<div id="display"></div>
|
<div id="display"></div>
|
||||||
|
|
||||||
<div id="content" style="display: none">
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
@ -51,8 +51,6 @@ function check_children(p, check_cb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var display = document.getElementById("display");
|
|
||||||
|
|
||||||
function run_series(check_cb) {
|
function run_series(check_cb) {
|
||||||
var display = document.getElementById("display");
|
var display = document.getElementById("display");
|
||||||
// Use a new parent node every time since the optimizations cause
|
// Use a new parent node every time since the optimizations cause
|
||||||
|
@ -189,4 +187,3 @@ run_series(function(child, elt, elts, node, nodes) {
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=98997
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="content" style="display: none">
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
|
@ -102,7 +102,7 @@ for (i = 0; i < cnodes.length; ++i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in divs) {
|
for (i in divs) {
|
||||||
var div = divs[i];
|
let div = divs[i];
|
||||||
if (div.className.match(/makeemptytext/))
|
if (div.className.match(/makeemptytext/))
|
||||||
div.insertBefore(document.createTextNode(""), div.firstChild);
|
div.insertBefore(document.createTextNode(""), div.firstChild);
|
||||||
}
|
}
|
||||||
|
@ -120,20 +120,20 @@ function bg(div) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in divs) {
|
for (i in divs) {
|
||||||
var div = divs[i];
|
let div = divs[i];
|
||||||
is(bg(div), ORANGE, "should be orange");
|
is(bg(div), ORANGE, "should be orange");
|
||||||
is(color(div), MAROON, "should be maroon");
|
is(color(div), MAROON, "should be maroon");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in divs) {
|
for (i in divs) {
|
||||||
var div = divs[i];
|
let div = divs[i];
|
||||||
var e = document.createEvent("MouseEvents");
|
var e = document.createEvent("MouseEvents");
|
||||||
e.initEvent("click", true, true);
|
e.initEvent("click", true, true);
|
||||||
div.dispatchEvent(e);
|
div.dispatchEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in divs) {
|
for (i in divs) {
|
||||||
var div = divs[i];
|
let div = divs[i];
|
||||||
is(bg(div), GREEN, "should be green");
|
is(bg(div), GREEN, "should be green");
|
||||||
is(color(div), NAVY, "should be navy");
|
is(color(div), NAVY, "should be navy");
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,6 @@ function is_pending(aPromise, aDescription, aTestID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchAsArrayBuffer(aURL) {
|
function fetchAsArrayBuffer(aURL) {
|
||||||
var xhr;
|
|
||||||
return new Promise(function(aResolve, aReject) {
|
return new Promise(function(aResolve, aReject) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", aURL);
|
xhr.open("GET", aURL);
|
||||||
|
@ -1818,10 +1817,9 @@ function runTest() {
|
||||||
expected.vdocument.push(all[0]);
|
expected.vdocument.push(all[0]);
|
||||||
|
|
||||||
// Create a FontFace in each window and add it to each document's FontFaceSet.
|
// Create a FontFace in each window and add it to each document's FontFaceSet.
|
||||||
var i = 0;
|
|
||||||
var faces = [];
|
var faces = [];
|
||||||
sourceWindows.forEach(function({ win, what: whatWin }) {
|
sourceWindows.forEach(function({ win, what: whatWin }, index) {
|
||||||
var f = new win.FontFace("test" + ++i, "url(x)");
|
var f = new win.FontFace("test" + index, "url(x)");
|
||||||
sourceDocuments.forEach(function({ doc, what: whatDoc }) {
|
sourceDocuments.forEach(function({ doc, what: whatDoc }) {
|
||||||
doc.fonts.add(f);
|
doc.fonts.add(f);
|
||||||
expected[whatDoc].push(f);
|
expected[whatDoc].push(f);
|
||||||
|
@ -1830,10 +1828,10 @@ function runTest() {
|
||||||
});
|
});
|
||||||
|
|
||||||
sourceDocuments.forEach(function({ doc, what }) {
|
sourceDocuments.forEach(function({ doc, what }) {
|
||||||
var all = Array.from(doc.fonts);
|
let allFonts = Array.from(doc.fonts);
|
||||||
is(expected[what].length, all.length, "expected FontFaceSet size (TEST 48) (" + what + ")");
|
is(expected[what].length, allFonts.length, "expected FontFaceSet size (TEST 48) (" + what + ")");
|
||||||
for (var i = 0; i < expected[what].length; i++) {
|
for (let i = 0; i < expected[what].length; i++) {
|
||||||
is(expected[what][i], all[i], "expected FontFace (" + expected[what][i]._description + ") at index " + i + " (TEST 48) (" + what + ")");
|
is(expected[what][i], allFonts[i], "expected FontFace (" + expected[what][i]._description + ") at index " + i + " (TEST 48) (" + what + ")");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -87,11 +87,11 @@ function test_property(property)
|
||||||
check_final(info.subproperties[idx]);
|
check_final(info.subproperties[idx]);
|
||||||
|
|
||||||
// can all properties be removed from the style?
|
// can all properties be removed from the style?
|
||||||
function test_remove_all_properties(property, value) {
|
function test_remove_all_properties(propName, value) {
|
||||||
var i, p = [];
|
var i, p = [];
|
||||||
for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
|
for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
|
||||||
for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
|
for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
|
||||||
var errstr = "when setting property " + property + " to " + value;
|
var errstr = "when setting property " + propName + " to " + value;
|
||||||
is(gDeclaration.length, 0, "unremovable properties " + errstr);
|
is(gDeclaration.length, 0, "unremovable properties " + errstr);
|
||||||
is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
|
is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,11 +101,11 @@ function test_property(property)
|
||||||
check_final(info.subproperties[idx]);
|
check_final(info.subproperties[idx]);
|
||||||
|
|
||||||
// can all properties be removed from the style?
|
// can all properties be removed from the style?
|
||||||
function test_remove_all_properties(property, value) {
|
function test_remove_all_properties(propName, value) {
|
||||||
var i, p = [];
|
var i, p = [];
|
||||||
for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
|
for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
|
||||||
for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
|
for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
|
||||||
var errstr = "when setting property " + property + " to " + value;
|
var errstr = "when setting property " + propName + " to " + value;
|
||||||
is(gDeclaration.length, 0, "unremovable properties " + errstr);
|
is(gDeclaration.length, 0, "unremovable properties " + errstr);
|
||||||
is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
|
is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ function run() {
|
||||||
expression_should_not_be_parseable(max_name);
|
expression_should_not_be_parseable(max_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_serialization(q, test_application, should_apply) {
|
function test_serialization(q, test_application, expected_to_apply) {
|
||||||
style.setAttribute("media", q);
|
style.setAttribute("media", q);
|
||||||
var ser1 = style.sheet.media.mediaText;
|
var ser1 = style.sheet.media.mediaText;
|
||||||
isnot(ser1, "", "serialization of '" + q + "' should not be empty");
|
isnot(ser1, "", "serialization of '" + q + "' should not be empty");
|
||||||
|
@ -145,9 +145,9 @@ function run() {
|
||||||
var ser2 = style.sheet.media.mediaText;
|
var ser2 = style.sheet.media.mediaText;
|
||||||
is(ser2, ser1, "parse+serialize of '" + q + "' should be idempotent");
|
is(ser2, ser1, "parse+serialize of '" + q + "' should be idempotent");
|
||||||
if (test_application) {
|
if (test_application) {
|
||||||
var applies = body_cs.getPropertyValue("text-decoration") == "underline";
|
let applies = body_cs.getPropertyValue("text-decoration") == "underline";
|
||||||
is(applies, should_apply,
|
is(applies, expected_to_apply,
|
||||||
"Media query '" + q + "' should " + (should_apply ? "" : "NOT ") +
|
"Media query '" + q + "' should " + (expected_to_apply ? "" : "NOT ") +
|
||||||
"apply after serialize + reparse");
|
"apply after serialize + reparse");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,10 +170,10 @@ function run() {
|
||||||
is(ser3, ser1, "cloning query '" + q + "' should not change " +
|
is(ser3, ser1, "cloning query '" + q + "' should not change " +
|
||||||
"serialization");
|
"serialization");
|
||||||
if (test_application) {
|
if (test_application) {
|
||||||
var applies = clonewin.getComputedStyle(clonedoc.body).
|
let applies = clonewin.getComputedStyle(clonedoc.body).
|
||||||
textDecoration == "underline";
|
textDecoration == "underline";
|
||||||
is(applies, should_apply,
|
is(applies, expected_to_apply,
|
||||||
"Media query '" + q + "' should " + (should_apply ? "" : "NOT ") +
|
"Media query '" + q + "' should " + (expected_to_apply ? "" : "NOT ") +
|
||||||
"apply after cloning");
|
"apply after cloning");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -927,5 +927,3 @@ function handle_iframe_onload(event)
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -266,20 +266,20 @@ function run() {
|
||||||
|
|
||||||
/* Bug 753777: test that things work in a freshly-created iframe */
|
/* Bug 753777: test that things work in a freshly-created iframe */
|
||||||
(function() {
|
(function() {
|
||||||
var iframe = document.createElement("iframe");
|
let newIframe = document.createElement("iframe");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(newIframe);
|
||||||
|
|
||||||
is(iframe.contentWindow.matchMedia("all").matches, true,
|
is(newIframe.contentWindow.matchMedia("all").matches, true,
|
||||||
"matchMedia should work in newly-created iframe");
|
"matchMedia should work in newly-created iframe");
|
||||||
// FIXME(emilio): All browsers fail this test right now. Probably should
|
// FIXME(emilio): All browsers fail this test right now. Probably should
|
||||||
// pass, see https://github.com/w3c/csswg-drafts/issues/3101, bug 1458816,
|
// pass, see https://github.com/w3c/csswg-drafts/issues/3101, bug 1458816,
|
||||||
// and bug 1011468.
|
// and bug 1011468.
|
||||||
todo_is(iframe.contentWindow.matchMedia("(min-width: 1px)").matches, true,
|
todo_is(newIframe.contentWindow.matchMedia("(min-width: 1px)").matches, true,
|
||||||
"(min-width: 1px) should match in newly-created iframe");
|
"(min-width: 1px) should match in newly-created iframe");
|
||||||
todo_is(iframe.contentWindow.matchMedia("(max-width: 1px)").matches, false,
|
todo_is(newIframe.contentWindow.matchMedia("(max-width: 1px)").matches, false,
|
||||||
"(max-width: 1px) should not match in newly-created iframe");
|
"(max-width: 1px) should not match in newly-created iframe");
|
||||||
|
|
||||||
document.body.removeChild(iframe);
|
document.body.removeChild(newIframe);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/* Bug 716751: listeners lost due to GC */
|
/* Bug 716751: listeners lost due to GC */
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче