Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Noemi Erli 2019-05-29 19:01:09 +03:00
Родитель dc93158b38 eb09749a72
Коммит d4554b4873
161 изменённых файлов: 3723 добавлений и 2512 удалений

Просмотреть файл

@ -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/**

Просмотреть файл

@ -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="{&quot;property&quot;:&quot;align-content&quot;}"> * <p data-l10n-id="inactive-css-not-grid-or-flex-container"
* <strong></strong> * data-l10n-args="{&quot;property&quot;:&quot;align-content&quot;}">
* </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 */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше