зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
--HG-- extra : rebase_source : 4502430f7e773b654c4557946c39000735b14bb3
This commit is contained in:
Коммит
c6c323a9e4
|
@ -1,5 +1,3 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.2"
|
||||
|
@ -3089,6 +3087,7 @@ dependencies = [
|
|||
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -1814,3 +1814,5 @@ pref("browser.aboutConfig.showWarning", true);
|
|||
// Launcher process is disabled by default, will be selectively enabled via SHIELD
|
||||
pref("browser.launcherProcess.enabled", false);
|
||||
#endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
|
||||
|
||||
pref("browser.toolbars.keyboard_navigation", false);
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file is loaded into the browser window scope.
|
||||
/* eslint-env mozilla/browser-window */
|
||||
|
||||
/**
|
||||
* Handle keyboard navigation for toolbars.
|
||||
* Having separate tab stops for every toolbar control results in an
|
||||
* unmanageable number of tab stops. Therefore, we group buttons under a single
|
||||
* tab stop and allow movement between them using left/right arrows.
|
||||
* However, text inputs use the arrow keys for their own purposes, so they need
|
||||
* their own tab stop. There are also groups of buttons before and after the
|
||||
* URL bar input which should get their own tab stop. The subsequent buttons on
|
||||
* the toolbar are then another tab stop after that.
|
||||
* Tab stops for groups of buttons are set using the <toolbartabstop/> element.
|
||||
* This element is invisible, but gets included in the tab order. When one of
|
||||
* these gets focus, it redirects focus to the appropriate button. This avoids
|
||||
* the need to continually manage the tabindex of toolbar buttons in response to
|
||||
* toolbarchanges.
|
||||
*/
|
||||
|
||||
ToolbarKeyboardNavigator = {
|
||||
// Toolbars we want to be keyboard navigable.
|
||||
kToolbars: [CustomizableUI.AREA_NAVBAR, CustomizableUI.AREA_BOOKMARKS],
|
||||
|
||||
_isButton(aElem) {
|
||||
return aElem.tagName == "toolbarbutton" ||
|
||||
aElem.getAttribute("role") == "button";
|
||||
},
|
||||
|
||||
// Get a TreeWalker which includes only controls which should be keyboard
|
||||
// navigable.
|
||||
_getWalker(aRoot) {
|
||||
if (aRoot._toolbarKeyNavWalker) {
|
||||
return aRoot._toolbarKeyNavWalker;
|
||||
}
|
||||
|
||||
let filter = (aNode) => {
|
||||
if (aNode.tagName == "toolbartabstop") {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
// Special case for the "View site information" button, which isn't
|
||||
// actionable in some cases but is still visible.
|
||||
if (aNode.id == "identity-box" &&
|
||||
document.getElementById("urlbar").getAttribute("pageproxystate") ==
|
||||
"invalid") {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
|
||||
// Skip invisible or disabled elements.
|
||||
if (aNode.hidden || aNode.disabled) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
// This width check excludes the overflow button when there's no overflow.
|
||||
let bounds = window.windowUtils.getBoundsWithoutFlushing(aNode);
|
||||
if (bounds.width == 0) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
|
||||
if (this._isButton(aNode)) {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
};
|
||||
aRoot._toolbarKeyNavWalker = document.createTreeWalker(aRoot,
|
||||
NodeFilter.SHOW_ELEMENT, filter);
|
||||
return aRoot._toolbarKeyNavWalker;
|
||||
},
|
||||
|
||||
init() {
|
||||
for (let id of this.kToolbars) {
|
||||
let toolbar = document.getElementById(id);
|
||||
// When enabled, no toolbar buttons should themselves be tabbable.
|
||||
// We manage toolbar focus completely. This attribute ensures that CSS
|
||||
// doesn't set -moz-user-focus: normal.
|
||||
toolbar.setAttribute("keyNav", "true");
|
||||
for (let stop of toolbar.getElementsByTagName("toolbartabstop")) {
|
||||
// These are invisible, but because they need to be in the tab order,
|
||||
// they can't get display: none or similar. They must therefore be
|
||||
// explicitly hidden for accessibility.
|
||||
stop.setAttribute("aria-hidden", "true");
|
||||
stop.addEventListener("focus", this);
|
||||
}
|
||||
toolbar.addEventListener("keydown", this);
|
||||
toolbar.addEventListener("keypress", this);
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
for (let id of this.kToolbars) {
|
||||
let toolbar = document.getElementById(id);
|
||||
for (let stop of toolbar.getElementsByTagName("toolbartabstop")) {
|
||||
stop.removeEventListener("focus", this);
|
||||
}
|
||||
toolbar.removeEventListener("keydown", this);
|
||||
toolbar.removeEventListener("keypress", this);
|
||||
toolbar.removeAttribute("keyNav");
|
||||
}
|
||||
},
|
||||
|
||||
_focusButton(aButton) {
|
||||
// Toolbar buttons aren't focusable because if they were, clicking them
|
||||
// would focus them, which is undesirable. Therefore, we must make a
|
||||
// button focusable only when we want to focus it.
|
||||
aButton.setAttribute("tabindex", "-1");
|
||||
aButton.focus();
|
||||
// We could remove tabindex now, but even though the button keeps DOM
|
||||
// focus, a11y gets confused because the button reports as not being
|
||||
// focusable. This results in weirdness if the user switches windows and
|
||||
// then switches back. Instead, remove tabindex when the button loses
|
||||
// focus.
|
||||
aButton.addEventListener("blur", this);
|
||||
},
|
||||
|
||||
_onButtonBlur(aEvent) {
|
||||
if (document.activeElement == aEvent.target) {
|
||||
// This event was fired because the user switched windows. This button
|
||||
// will get focus again when the user returns.
|
||||
return;
|
||||
}
|
||||
aEvent.target.removeEventListener("blur", this);
|
||||
aEvent.target.removeAttribute("tabindex");
|
||||
},
|
||||
|
||||
_onTabStopFocus(aEvent) {
|
||||
let toolbar = aEvent.target.closest("toolbar");
|
||||
let walker = this._getWalker(toolbar);
|
||||
|
||||
let oldFocus = aEvent.relatedTarget;
|
||||
if (oldFocus) {
|
||||
// Save this because we might rewind focus and the subsequent focus event
|
||||
// won't get a relatedTarget.
|
||||
this._isFocusMovingBackward =
|
||||
oldFocus.compareDocumentPosition(aEvent.target) &
|
||||
Node.DOCUMENT_POSITION_PRECEDING;
|
||||
if (this._isFocusMovingBackward && oldFocus && this._isButton(oldFocus)) {
|
||||
// Shift+tabbing from a button will land on its toolbartabstop. Skip it.
|
||||
document.commandDispatcher.rewindFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
walker.currentNode = aEvent.target;
|
||||
let button = walker.nextNode();
|
||||
if (!button || !this._isButton(button)) {
|
||||
// No navigable buttons for this tab stop. Skip it.
|
||||
if (this._isFocusMovingBackward) {
|
||||
document.commandDispatcher.rewindFocus();
|
||||
} else {
|
||||
document.commandDispatcher.advanceFocus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._focusButton(button);
|
||||
},
|
||||
|
||||
navigateButtons(aToolbar, aPrevious) {
|
||||
let oldFocus = document.activeElement;
|
||||
let walker = this._getWalker(aToolbar);
|
||||
// Start from the current control and walk to the next/previous control.
|
||||
walker.currentNode = oldFocus;
|
||||
let newFocus;
|
||||
if (aPrevious) {
|
||||
newFocus = walker.previousNode();
|
||||
} else {
|
||||
newFocus = walker.nextNode();
|
||||
}
|
||||
if (!newFocus || newFocus.tagName == "toolbartabstop") {
|
||||
// There are no more controls or we hit a tab stop placeholder.
|
||||
return;
|
||||
}
|
||||
this._focusButton(newFocus);
|
||||
},
|
||||
|
||||
_onKeyDown(aEvent) {
|
||||
let focus = document.activeElement;
|
||||
if (aEvent.altKey || aEvent.controlKey || aEvent.metaKey ||
|
||||
aEvent.shiftKey || !this._isButton(focus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.key) {
|
||||
case "ArrowLeft":
|
||||
this.navigateButtons(aEvent.currentTarget, true);
|
||||
break;
|
||||
case "ArrowRight":
|
||||
this.navigateButtons(aEvent.currentTarget, false);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
aEvent.preventDefault();
|
||||
},
|
||||
|
||||
_onKeyPress(aEvent) {
|
||||
let focus = document.activeElement;
|
||||
if ((aEvent.key != "Enter" && aEvent.key != " ") ||
|
||||
!this._isButton(focus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focus.getAttribute("type") == "menu") {
|
||||
focus.open = true;
|
||||
} else {
|
||||
// Several buttons specifically don't use command events; e.g. because
|
||||
// they want to activate for middle click. Therefore, simulate a
|
||||
// click event.
|
||||
// If this button does handle command events, that won't trigger here.
|
||||
// Command events have their own keyboard handling: keypress for enter
|
||||
// and keyup for space. We rely on that behavior, since there's no way
|
||||
// for us to reliably know what events a button handles.
|
||||
focus.dispatchEvent(new MouseEvent("click", {
|
||||
bubbles: true,
|
||||
ctrlKey: aEvent.ctrlKey,
|
||||
altKey: aEvent.altKey,
|
||||
shiftKey: aEvent.shiftKey,
|
||||
metaKey: aEvent.metaKey,
|
||||
}));
|
||||
}
|
||||
// We deliberately don't call aEvent.preventDefault() here so that enter
|
||||
// will trigger a command event handler if appropriate.
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "focus":
|
||||
this._onTabStopFocus(aEvent);
|
||||
break;
|
||||
case "keydown":
|
||||
this._onKeyDown(aEvent);
|
||||
break;
|
||||
case "keypress":
|
||||
this._onKeyPress(aEvent);
|
||||
break;
|
||||
case "blur":
|
||||
this._onButtonBlur(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
};
|
|
@ -778,7 +778,7 @@ html|input.urlbar-input {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#identity-box {
|
||||
#nav-bar:not([keyNav=true]) #identity-box {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
|
@ -981,7 +981,7 @@ html|*#fullscreen-exit-button {
|
|||
|
||||
/* notification anchors should only be visible when their associated
|
||||
notifications are */
|
||||
.notification-anchor-icon {
|
||||
#nav-bar:not([keyNav=true]) .notification-anchor-icon {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
|
@ -1427,4 +1427,8 @@ toolbarpaletteitem > toolbaritem {
|
|||
}
|
||||
}
|
||||
|
||||
toolbar[keyNav=true]:not([collapsed=true]):not([customizing=true]) toolbartabstop {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
%include theme-vars.inc.css
|
||||
|
|
|
@ -148,6 +148,8 @@ if (AppConstants.NIGHTLY_BUILD) {
|
|||
}
|
||||
|
||||
XPCOMUtils.defineLazyScriptGetter(this, "pktUI", "chrome://pocket/content/main.js");
|
||||
XPCOMUtils.defineLazyScriptGetter(this, "ToolbarKeyboardNavigator",
|
||||
"chrome://browser/content/browser-toolbarKeyNav.js");
|
||||
|
||||
// lazy service getters
|
||||
|
||||
|
@ -283,6 +285,16 @@ XPCOMUtils.defineLazyGetter(this, "Win7Features", () => {
|
|||
return null;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gToolbarKeyNavEnabled",
|
||||
"browser.toolbars.keyboard_navigation", false,
|
||||
(aPref, aOldVal, aNewVal) => {
|
||||
if (aNewVal) {
|
||||
ToolbarKeyboardNavigator.init();
|
||||
} else {
|
||||
ToolbarKeyboardNavigator.uninit();
|
||||
}
|
||||
});
|
||||
|
||||
customElements.setElementCreationCallback("translation-notification", () => {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://browser/content/translation-notification.js", window);
|
||||
|
@ -1384,6 +1396,9 @@ var gBrowserInit = {
|
|||
BrowserPageActions.init();
|
||||
gAccessibilityServiceIndicator.init();
|
||||
AccessibilityRefreshBlocker.init();
|
||||
if (gToolbarKeyNavEnabled) {
|
||||
ToolbarKeyboardNavigator.init();
|
||||
}
|
||||
|
||||
gRemoteControl.updateVisualCue(Marionette.running);
|
||||
|
||||
|
@ -1930,6 +1945,10 @@ var gBrowserInit = {
|
|||
|
||||
AccessibilityRefreshBlocker.uninit();
|
||||
|
||||
if (gToolbarKeyNavEnabled) {
|
||||
ToolbarKeyboardNavigator.uninit();
|
||||
}
|
||||
|
||||
LanguagePrompt.uninit();
|
||||
|
||||
BrowserSearch.uninit();
|
||||
|
|
|
@ -835,6 +835,7 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
overflowpanel="widget-overflow"
|
||||
context="toolbar-context-menu">
|
||||
|
||||
<toolbartabstop/>
|
||||
<hbox id="nav-bar-customization-target" flex="1">
|
||||
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
label="&backCmd.label;"
|
||||
|
@ -888,6 +889,7 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
<toolbaritem id="urlbar-container" flex="400" persist="width"
|
||||
removable="false"
|
||||
class="chromeclass-location" overflows="false">
|
||||
<toolbartabstop/>
|
||||
<textbox id="urlbar" flex="1"
|
||||
placeholder="&urlbar.placeholder2;"
|
||||
defaultPlaceholder="&urlbar.placeholder2;"
|
||||
|
@ -1007,6 +1009,7 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
<label id="extension" class="urlbar-display urlbar-display-extension" value="&urlbar.extension.label;"/>
|
||||
</box>
|
||||
<hbox id="page-action-buttons" context="pageActionContextMenu">
|
||||
<toolbartabstop/>
|
||||
<hbox id="contextual-feature-recommendation" role="button" hidden="true">
|
||||
<hbox id="cfr-label-container">
|
||||
<label id="cfr-label"/>
|
||||
|
@ -1064,6 +1067,7 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
</hbox>
|
||||
</hbox>
|
||||
</textbox>
|
||||
<toolbartabstop/>
|
||||
</toolbaritem>
|
||||
|
||||
<toolbarspring cui-areatype="toolbar" class="chromeclass-toolbar-additional"/>
|
||||
|
@ -1159,6 +1163,7 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
|
||||
collapsed="true"
|
||||
customizable="true">
|
||||
<toolbartabstop skipintoolbarset="true"/>
|
||||
<toolbaritem id="personal-bookmarks"
|
||||
title="&bookmarksToolbarItem.label;"
|
||||
cui-areatype="toolbar"
|
||||
|
@ -1328,7 +1333,9 @@ xmlns="http://www.w3.org/1999/xhtml"
|
|||
align="center"
|
||||
flex="100"
|
||||
persist="width">
|
||||
<toolbartabstop/>
|
||||
<searchbar id="searchbar" flex="1"/>
|
||||
<toolbartabstop/>
|
||||
</toolbaritem>
|
||||
</toolbarpalette>
|
||||
</toolbox>
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
[browser_toolbarButtonKeyPress.js]
|
||||
[browser_toolbarKeyNav.js]
|
||||
support-files = !/browser/base/content/test/permissions/permissions.html
|
||||
|
|
|
@ -30,6 +30,12 @@ function waitForLocationChange() {
|
|||
return promise;
|
||||
}
|
||||
|
||||
add_task(async function setPref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.toolbars.keyboard_navigation", true]],
|
||||
});
|
||||
});
|
||||
|
||||
// Test activation of the app menu button from the keyboard.
|
||||
// The app menu should appear and focus should move inside it.
|
||||
add_task(async function testAppMenuButtonPress() {
|
||||
|
@ -86,6 +92,7 @@ add_task(async function testDeveloperButtonPress() {
|
|||
await hidden;
|
||||
CustomizableUI.reset();
|
||||
});
|
||||
|
||||
// Test that the Developer menu doesn't open when a key other than space or
|
||||
// enter is pressed .
|
||||
add_task(async function testDeveloperButtonWrongKey() {
|
||||
|
@ -159,3 +166,80 @@ add_task(async function testSendTabToDeviceButtonPress() {
|
|||
PageActions.actionForID("sendToDevice").pinnedToUrlbar = false;
|
||||
});
|
||||
});
|
||||
|
||||
// Test activation of the Reload button from the keyboard.
|
||||
// This is a toolbarbutton with a click handler and no command handler, but
|
||||
// the toolbar keyboard navigation code should handle keyboard activation.
|
||||
add_task(async function testReloadButtonPress() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async function(aBrowser) {
|
||||
let button = document.getElementById("reload-button");
|
||||
await TestUtils.waitForCondition(() => !button.disabled);
|
||||
forceFocus(button);
|
||||
let loaded = BrowserTestUtils.browserLoaded(aBrowser);
|
||||
EventUtils.synthesizeKey(" ");
|
||||
await loaded;
|
||||
ok(true, "Page loaded after Reload button pressed");
|
||||
});
|
||||
});
|
||||
|
||||
// Test activation of the Sidebars button from the keyboard.
|
||||
// This is a toolbarbutton with a command handler.
|
||||
add_task(async function testSidebarsButtonPress() {
|
||||
let button = document.getElementById("sidebar-button");
|
||||
ok(!button.checked, "Sidebars button not checked at start of test");
|
||||
let sidebarBox = document.getElementById("sidebar-box");
|
||||
ok(sidebarBox.hidden, "Sidebar hidden at start of test");
|
||||
forceFocus(button);
|
||||
EventUtils.synthesizeKey(" ");
|
||||
await TestUtils.waitForCondition(() => button.checked);
|
||||
ok(true, "Sidebars button checked after press");
|
||||
ok(!sidebarBox.hidden, "Sidebar visible after press");
|
||||
// Make sure the sidebar is fully loaded before we hide it.
|
||||
// Otherwise, the unload event might call JS which isn't loaded yet.
|
||||
// We can't use BrowserTestUtils.browserLoaded because it fails on non-tab
|
||||
// docs. Instead, wait for something in the JS script.
|
||||
let sidebarWin = document.getElementById("sidebar").contentWindow;
|
||||
await TestUtils.waitForCondition(() => sidebarWin.PlacesUIUtils);
|
||||
forceFocus(button);
|
||||
EventUtils.synthesizeKey(" ");
|
||||
await TestUtils.waitForCondition(() => !button.checked);
|
||||
ok(true, "Sidebars button not checked after press");
|
||||
ok(sidebarBox.hidden, "Sidebar hidden after press");
|
||||
});
|
||||
|
||||
// Test activation of the Bookmark this page button from the keyboard.
|
||||
// This is an image with a click handler on its parent and no command handler,
|
||||
// but the toolbar keyboard navigation code should handle keyboard activation.
|
||||
add_task(async function testBookmarkButtonPress() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async function(aBrowser) {
|
||||
let button = document.getElementById("star-button");
|
||||
forceFocus(button);
|
||||
let panel = document.getElementById("editBookmarkPanel");
|
||||
let focused = BrowserTestUtils.waitForEvent(panel, "focus", true);
|
||||
EventUtils.synthesizeKey(" ");
|
||||
await focused;
|
||||
ok(true, "Focus inside edit bookmark panel after Bookmark button pressed");
|
||||
let hidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
|
||||
EventUtils.synthesizeKey("KEY_Escape");
|
||||
await hidden;
|
||||
});
|
||||
});
|
||||
|
||||
// Test activation of the Bookmarks Menu button from the keyboard.
|
||||
// This is a button with type="menu".
|
||||
// The Bookmarks Menu should appear.
|
||||
add_task(async function testBookmarksmenuButtonPress() {
|
||||
CustomizableUI.addWidgetToArea("bookmarks-menu-button",
|
||||
CustomizableUI.AREA_NAVBAR);
|
||||
let button = document.getElementById("bookmarks-menu-button");
|
||||
forceFocus(button);
|
||||
let menu = document.getElementById("BMB_bookmarksPopup");
|
||||
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
||||
EventUtils.synthesizeKey(" ");
|
||||
await shown;
|
||||
ok(true, "Bookmarks Menu shown after toolbar button pressed");
|
||||
let hidden = BrowserTestUtils.waitForEvent(menu, "popuphidden");
|
||||
menu.hidePopup();
|
||||
await hidden;
|
||||
CustomizableUI.reset();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test browser toolbar keyboard navigation.
|
||||
* These tests assume the default browser configuration for toolbars unless
|
||||
* otherwise specified.
|
||||
*/
|
||||
|
||||
const PERMISSIONS_PAGE = "https://example.com/browser/browser/base/content/test/permissions/permissions.html";
|
||||
|
||||
async function expectFocusAfterKey(aKey, aFocus, aAncestorOk = false) {
|
||||
let res = aKey.match(/^(Shift\+)?(?:(.)|(.+))$/);
|
||||
let shift = Boolean(res[1]);
|
||||
let key;
|
||||
if (res[2]) {
|
||||
key = res[2]; // Character.
|
||||
} else {
|
||||
key = "KEY_" + res[3]; // Tab, ArrowRight, etc.
|
||||
}
|
||||
let expected;
|
||||
let friendlyExpected;
|
||||
if (typeof aFocus == "string") {
|
||||
expected = document.getElementById(aFocus);
|
||||
friendlyExpected = aFocus;
|
||||
} else {
|
||||
expected = aFocus;
|
||||
if (aFocus == gURLBar.inputField) {
|
||||
friendlyExpected = "URL bar input";
|
||||
} else if (aFocus == gBrowser.selectedBrowser) {
|
||||
friendlyExpected = "Web document";
|
||||
}
|
||||
}
|
||||
let focused = BrowserTestUtils.waitForEvent(expected, "focus", aAncestorOk);
|
||||
EventUtils.synthesizeKey(key, {shiftKey: shift});
|
||||
await focused;
|
||||
ok(true, friendlyExpected + " focused after " + aKey + " pressed");
|
||||
}
|
||||
|
||||
function startFromUrlBar() {
|
||||
gURLBar.focus();
|
||||
is(document.activeElement, gURLBar.inputField,
|
||||
"URL bar focused for start of test");
|
||||
}
|
||||
|
||||
// The Reload button is disabled for a short time even after the page finishes
|
||||
// loading. Wait for it to be enabled.
|
||||
async function waitUntilReloadEnabled() {
|
||||
let button = document.getElementById("reload-button");
|
||||
await TestUtils.waitForCondition(() => !button.disabled);
|
||||
}
|
||||
|
||||
add_task(async function setPref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.toolbars.keyboard_navigation", true],
|
||||
["accessibility.tabfocus", 7],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Test tab stops with no page loaded.
|
||||
add_task(async function testTabStopsNoPage() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function() {
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Shift+Tab", "home-button");
|
||||
await expectFocusAfterKey("Shift+Tab", "tabbrowser-tabs", true);
|
||||
await expectFocusAfterKey("Tab", "home-button");
|
||||
await expectFocusAfterKey("Tab", gURLBar.inputField);
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
|
||||
});
|
||||
});
|
||||
|
||||
// Test tab stops with a page loaded.
|
||||
add_task(async function testTabStopsPageLoaded() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async function() {
|
||||
await waitUntilReloadEnabled();
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Shift+Tab", "identity-box");
|
||||
await expectFocusAfterKey("Shift+Tab", "reload-button");
|
||||
await expectFocusAfterKey("Shift+Tab", "tabbrowser-tabs", true);
|
||||
await expectFocusAfterKey("Tab", "reload-button");
|
||||
await expectFocusAfterKey("Tab", "identity-box");
|
||||
await expectFocusAfterKey("Tab", gURLBar.inputField);
|
||||
await expectFocusAfterKey("Tab", "pageActionButton");
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
|
||||
});
|
||||
});
|
||||
|
||||
// Test tab stops with a notification anchor visible.
|
||||
// The notification anchor should not get its own tab stop.
|
||||
add_task(async function testTabStopsWithNotification() {
|
||||
await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function(aBrowser) {
|
||||
let popupShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
|
||||
// Request a permission.
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("#geo", {}, aBrowser);
|
||||
await popupShown;
|
||||
startFromUrlBar();
|
||||
// If the notification anchor were in the tab order, the next shift+tab
|
||||
// would focus it instead of #identity-box.
|
||||
await expectFocusAfterKey("Shift+Tab", "identity-box");
|
||||
});
|
||||
});
|
||||
|
||||
// Test tab stops with the Bookmarks toolbar visible.
|
||||
add_task(async function testTabStopsWithBookmarksToolbar() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function() {
|
||||
CustomizableUI.setToolbarVisibility("PersonalToolbar", true);
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
await expectFocusAfterKey("Tab", "PersonalToolbar", true);
|
||||
await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
|
||||
|
||||
// Make sure the Bookmarks toolbar is no longer tabbable once hidden.
|
||||
CustomizableUI.setToolbarVisibility("PersonalToolbar", false);
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
await expectFocusAfterKey("Tab", gBrowser.selectedBrowser);
|
||||
});
|
||||
});
|
||||
|
||||
// Test a focusable toolbartabstop which has no navigable buttons.
|
||||
add_task(async function testTabStopNoButtons() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function() {
|
||||
// The Back, Forward and Reload buttons are all currently disabled.
|
||||
// The Home button is the only other button at that tab stop.
|
||||
CustomizableUI.removeWidgetFromArea("home-button");
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Shift+Tab", "tabbrowser-tabs", true);
|
||||
await expectFocusAfterKey("Tab", gURLBar.inputField);
|
||||
CustomizableUI.reset();
|
||||
// Make sure the button is reachable now that it has been re-added.
|
||||
await expectFocusAfterKey("Shift+Tab", "home-button", true);
|
||||
});
|
||||
});
|
||||
|
||||
// Test that right/left arrows move through toolbarbuttons.
|
||||
// This also verifies that:
|
||||
// 1. Right/left arrows do nothing when at the edges; and
|
||||
// 2. The overflow menu button can't be reached by right arrow when it isn't
|
||||
// visible.
|
||||
add_task(async function testArrowsToolbarbuttons() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function() {
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft");
|
||||
is(document.activeElement.id, "library-button",
|
||||
"ArrowLeft at end of button group does nothing");
|
||||
await expectFocusAfterKey("ArrowRight", "sidebar-button");
|
||||
// This next check also confirms that the overflow menu button is skipped,
|
||||
// since it is currently invisible.
|
||||
await expectFocusAfterKey("ArrowRight", "PanelUI-menu-button");
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight");
|
||||
is(document.activeElement.id, "PanelUI-menu-button",
|
||||
"ArrowRight at end of button group does nothing");
|
||||
await expectFocusAfterKey("ArrowLeft", "sidebar-button");
|
||||
await expectFocusAfterKey("ArrowLeft", "library-button");
|
||||
});
|
||||
});
|
||||
|
||||
// Test that right/left arrows move through buttons wihch aren't toolbarbuttons
|
||||
// but have role="button".
|
||||
add_task(async function testArrowsRoleButton() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async function() {
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Tab", "pageActionButton");
|
||||
await expectFocusAfterKey("ArrowRight", "pocket-button");
|
||||
await expectFocusAfterKey("ArrowRight", "star-button");
|
||||
await expectFocusAfterKey("ArrowLeft", "pocket-button");
|
||||
await expectFocusAfterKey("ArrowLeft", "pageActionButton");
|
||||
});
|
||||
});
|
||||
|
||||
// Test that right/left arrows do not land on disabled buttons.
|
||||
add_task(async function testArrowsDisabledButtons() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async function(aBrowser) {
|
||||
await waitUntilReloadEnabled();
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Shift+Tab", "identity-box");
|
||||
// Back and Forward buttons are disabled.
|
||||
await expectFocusAfterKey("Shift+Tab", "reload-button");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft");
|
||||
is(document.activeElement.id, "reload-button",
|
||||
"ArrowLeft on Reload button when prior buttons disabled does nothing");
|
||||
|
||||
BrowserTestUtils.loadURI(aBrowser, "https://example.com/2");
|
||||
await BrowserTestUtils.browserLoaded(aBrowser);
|
||||
await waitUntilReloadEnabled();
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Shift+Tab", "identity-box");
|
||||
await expectFocusAfterKey("Shift+Tab", "back-button");
|
||||
// Forward button is still disabled.
|
||||
await expectFocusAfterKey("ArrowRight", "reload-button");
|
||||
});
|
||||
});
|
||||
|
||||
// Test that right arrow reaches the overflow menu button when it is visible.
|
||||
add_task(async function testArrowsOverflowButton() {
|
||||
await BrowserTestUtils.withNewTab("about:blank", async function() {
|
||||
// Move something to the overflow menu to make the button appear.
|
||||
CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
|
||||
startFromUrlBar();
|
||||
await expectFocusAfterKey("Tab", "library-button");
|
||||
await expectFocusAfterKey("ArrowRight", "sidebar-button");
|
||||
await expectFocusAfterKey("ArrowRight", "nav-bar-overflow-button");
|
||||
await expectFocusAfterKey("ArrowRight", "PanelUI-menu-button");
|
||||
await expectFocusAfterKey("ArrowLeft", "nav-bar-overflow-button");
|
||||
// Make sure the button is not reachable once it is invisible again.
|
||||
await expectFocusAfterKey("ArrowRight", "PanelUI-menu-button");
|
||||
CustomizableUI.reset();
|
||||
// Flush layout so its invisibility can be detected.
|
||||
document.getElementById("nav-bar-overflow-button").clientWidth;
|
||||
await expectFocusAfterKey("ArrowLeft", "sidebar-button");
|
||||
});
|
||||
});
|
|
@ -55,7 +55,8 @@ browser.jar:
|
|||
content/browser/browser-sidebar.js (content/browser-sidebar.js)
|
||||
content/browser/browser-siteIdentity.js (content/browser-siteIdentity.js)
|
||||
content/browser/browser-sync.js (content/browser-sync.js)
|
||||
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js)
|
||||
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js)
|
||||
content/browser/browser-toolbarKeyNav.js (content/browser-toolbarKeyNav.js)
|
||||
content/browser/browser-thumbnails.js (content/browser-thumbnails.js)
|
||||
content/browser/browser-webrender.js (content/browser-webrender.js)
|
||||
content/browser/tab-content.js (content/tab-content.js)
|
||||
|
|
|
@ -126,21 +126,25 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.urlbarView-tags,
|
||||
.urlbarView-secondary {
|
||||
color: var(--urlbar-popup-action-color);
|
||||
font-size: .85em;
|
||||
}
|
||||
|
||||
.urlbarView-url {
|
||||
color: var(--urlbar-popup-url-color);
|
||||
}
|
||||
|
||||
.urlbarView-title > strong,
|
||||
.urlbarView-url > strong,
|
||||
.urlbarView-tag > strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.urlbarView-secondary {
|
||||
color: var(--urlbar-popup-action-color);
|
||||
}
|
||||
|
||||
.urlbarView-url {
|
||||
color: var(--urlbar-popup-url-color);
|
||||
}
|
||||
|
||||
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary::before,
|
||||
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary {
|
||||
color: inherit;
|
||||
|
|
|
@ -20,13 +20,7 @@ export function createFrame(thread: ThreadId, frame: FramePacket): ?Frame {
|
|||
if (!frame) {
|
||||
return null;
|
||||
}
|
||||
let title;
|
||||
if (frame.type == "call") {
|
||||
const c = frame.callee;
|
||||
title = c.name || c.userDisplayName || c.displayName;
|
||||
} else {
|
||||
title = `(${frame.type})`;
|
||||
}
|
||||
|
||||
const location = {
|
||||
sourceId: clientCommands.getSourceForActor(frame.where.actor),
|
||||
line: frame.where.line,
|
||||
|
@ -36,7 +30,7 @@ export function createFrame(thread: ThreadId, frame: FramePacket): ?Frame {
|
|||
return {
|
||||
id: frame.actor,
|
||||
thread,
|
||||
displayName: title,
|
||||
displayName: frame.displayName,
|
||||
location,
|
||||
generatedLocation: location,
|
||||
this: frame.this,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { isDevelopment } from "devtools-environment";
|
|||
import Services from "devtools-services";
|
||||
import { asyncStoreHelper } from "./asyncStoreHelper";
|
||||
|
||||
const prefsSchemaVersion = "1.0.7";
|
||||
const prefsSchemaVersion = "1.0.8";
|
||||
|
||||
const pref = Services.pref;
|
||||
|
||||
|
@ -137,8 +137,8 @@ export const asyncStore = asyncStoreHelper("debugger", {
|
|||
|
||||
if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
|
||||
// clear pending Breakpoints
|
||||
prefs.pendingBreakpoints = {};
|
||||
prefs.tabs = [];
|
||||
prefs.xhrBreakpoints = [];
|
||||
asyncStore.pendingBreakpoints = {};
|
||||
asyncStore.tabs = [];
|
||||
asyncStore.xhrBreakpoints = [];
|
||||
prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,15 @@ const { createValueGrip } = require("devtools/server/actors/object/utils");
|
|||
const { ActorClassWithSpec } = require("devtools/shared/protocol");
|
||||
const { frameSpec } = require("devtools/shared/specs/frame");
|
||||
|
||||
function formatDisplayName(frame) {
|
||||
if (frame.type === "call") {
|
||||
const callee = frame.callee;
|
||||
return callee.name || callee.userDisplayName || callee.displayName;
|
||||
}
|
||||
|
||||
return `(${frame.type})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* An actor for a specified stack frame.
|
||||
*/
|
||||
|
@ -76,10 +85,6 @@ const FrameActor = ActorClassWithSpec(frameSpec, {
|
|||
const threadActor = this.threadActor;
|
||||
const form = { actor: this.actorID,
|
||||
type: this.frame.type };
|
||||
if (this.frame.type === "call") {
|
||||
form.callee = createValueGrip(this.frame.callee, threadActor._pausePool,
|
||||
threadActor.objectGrip);
|
||||
}
|
||||
|
||||
// NOTE: ignoreFrameEnvironment lets the client explicitly avoid
|
||||
// populating form environments on pause.
|
||||
|
@ -95,6 +100,7 @@ const FrameActor = ActorClassWithSpec(frameSpec, {
|
|||
threadActor.objectGrip);
|
||||
}
|
||||
|
||||
form.displayName = formatDisplayName(this.frame);
|
||||
form.arguments = this._args();
|
||||
if (this.frame.script) {
|
||||
const generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
|
||||
|
|
|
@ -33,7 +33,7 @@ function test_pause_frame() {
|
|||
gThreadClient.addOneTimeListener("paused", function(event, packet) {
|
||||
Assert.ok(!!packet.frame);
|
||||
Assert.ok(!!packet.frame.actor);
|
||||
Assert.equal(packet.frame.callee.name, "stopMe");
|
||||
Assert.equal(packet.frame.displayName, "stopMe");
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
|
|
|
@ -29,57 +29,36 @@ function run_test() {
|
|||
do_test_pending();
|
||||
}
|
||||
|
||||
var gFrames = [
|
||||
var frameFixtures = [
|
||||
// Function calls...
|
||||
{ type: "call", callee: { name: "depth3" } },
|
||||
{ type: "call", callee: { name: "depth2" } },
|
||||
{ type: "call", callee: { name: "depth1" } },
|
||||
{ type: "call", displayName: "depth3" },
|
||||
{ type: "call", displayName: "depth2" },
|
||||
{ type: "call", displayName: "depth1" },
|
||||
|
||||
// Anonymous function call in our eval...
|
||||
{ type: "call", callee: { name: undefined } },
|
||||
{ type: "call", displayName: undefined },
|
||||
|
||||
// The eval itself.
|
||||
{ type: "eval", callee: { name: undefined } },
|
||||
{ type: "eval", displayName: "(eval)" },
|
||||
];
|
||||
|
||||
var gSliceTests = [
|
||||
{ start: 0, count: undefined, resetActors: true },
|
||||
{ start: 0, count: 1 },
|
||||
{ start: 2, count: 2 },
|
||||
{ start: 1, count: 15 },
|
||||
{ start: 15, count: undefined },
|
||||
];
|
||||
|
||||
function test_frame_slice() {
|
||||
if (gSliceTests.length == 0) {
|
||||
gThreadClient.resume(() => finishClient(gClient));
|
||||
return;
|
||||
}
|
||||
|
||||
const test = gSliceTests.shift();
|
||||
gThreadClient.getFrames(test.start, test.count, function(response) {
|
||||
const testFrames = gFrames.slice(test.start,
|
||||
test.count ? test.start + test.count : undefined);
|
||||
Assert.equal(testFrames.length, response.frames.length);
|
||||
for (let i = 0; i < testFrames.length; i++) {
|
||||
const expected = testFrames[i];
|
||||
function test_frame_packet() {
|
||||
gThreadClient.getFrames(0, 1000, function(response) {
|
||||
for (let i = 0; i < response.frames.length; i++) {
|
||||
const expected = frameFixtures[i];
|
||||
const actual = response.frames[i];
|
||||
|
||||
if (test.resetActors) {
|
||||
expected.actor = actual.actor;
|
||||
}
|
||||
|
||||
for (const key of ["type", "callee-name"]) {
|
||||
Assert.equal(expected[key] || undefined, actual[key]);
|
||||
}
|
||||
Assert.equal(expected.displayname, actual.displayname, "Frame displayname");
|
||||
Assert.equal(expected.type, actual.type, "Frame displayname");
|
||||
}
|
||||
test_frame_slice();
|
||||
|
||||
gThreadClient.resume(() => finishClient(gClient));
|
||||
});
|
||||
}
|
||||
|
||||
function test_pause_frame() {
|
||||
gThreadClient.addOneTimeListener("paused", function(event, packet) {
|
||||
test_frame_slice();
|
||||
test_frame_packet();
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
|
|
|
@ -64,8 +64,7 @@ static void Sync(BrowsingContext* aBrowsingContext) {
|
|||
MOZ_DIAGNOSTIC_ASSERT(cc);
|
||||
RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
|
||||
BrowsingContext* opener = aBrowsingContext->GetOpener();
|
||||
cc->SendAttachBrowsingContext(BrowsingContextId(parent ? parent->Id() : 0),
|
||||
BrowsingContextId(opener ? opener->Id() : 0),
|
||||
cc->SendAttachBrowsingContext(parent, opener,
|
||||
BrowsingContextId(aBrowsingContext->Id()),
|
||||
aBrowsingContext->Name());
|
||||
}
|
||||
|
@ -103,6 +102,10 @@ BrowsingContext* BrowsingContext::TopLevelBrowsingContext() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext* BrowsingContext::Canonical() {
|
||||
return CanonicalBrowsingContext::Cast(this);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<BrowsingContext> BrowsingContext::Create(
|
||||
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
|
||||
Type aType) {
|
||||
|
@ -238,8 +241,7 @@ void BrowsingContext::Detach() {
|
|||
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
MOZ_DIAGNOSTIC_ASSERT(cc);
|
||||
cc->SendDetachBrowsingContext(BrowsingContextId(Id()),
|
||||
false /* aMoveToBFCache */);
|
||||
cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
|
||||
}
|
||||
|
||||
void BrowsingContext::CacheChildren() {
|
||||
|
@ -264,8 +266,7 @@ void BrowsingContext::CacheChildren() {
|
|||
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
MOZ_DIAGNOSTIC_ASSERT(cc);
|
||||
cc->SendDetachBrowsingContext(BrowsingContextId(Id()),
|
||||
true /* aMoveToBFCache */);
|
||||
cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsCached() { return sCachedBrowsingContexts->has(Id()); }
|
||||
|
@ -288,8 +289,7 @@ void BrowsingContext::SetOpener(BrowsingContext* aOpener) {
|
|||
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
MOZ_DIAGNOSTIC_ASSERT(cc);
|
||||
cc->SendSetOpenerBrowsingContext(
|
||||
BrowsingContextId(Id()), BrowsingContextId(aOpener ? aOpener->Id() : 0));
|
||||
cc->SendSetOpenerBrowsingContext(this, aOpener);
|
||||
}
|
||||
|
||||
BrowsingContext::~BrowsingContext() {
|
||||
|
@ -326,7 +326,7 @@ void BrowsingContext::NotifyUserGestureActivation() {
|
|||
}
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(cc);
|
||||
cc->SendSetUserGestureActivation(BrowsingContextId(topLevelBC->Id()), true);
|
||||
cc->SendSetUserGestureActivation(topLevelBC, true);
|
||||
}
|
||||
|
||||
void BrowsingContext::NotifyResetUserGestureActivation() {
|
||||
|
@ -343,7 +343,7 @@ void BrowsingContext::NotifyResetUserGestureActivation() {
|
|||
}
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(cc);
|
||||
cc->SendSetUserGestureActivation(BrowsingContextId(topLevelBC->Id()), false);
|
||||
cc->SendSetUserGestureActivation(topLevelBC, false);
|
||||
}
|
||||
|
||||
void BrowsingContext::SetUserGestureActivation() {
|
||||
|
@ -397,18 +397,17 @@ void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
|
|||
// document for this browsing context is loaded).
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1516343.
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
cc->SendWindowClose(BrowsingContextId(mBrowsingContextId),
|
||||
aCallerType == CallerType::System);
|
||||
cc->SendWindowClose(this, aCallerType == CallerType::System);
|
||||
}
|
||||
|
||||
void BrowsingContext::Focus(ErrorResult& aError) {
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
cc->SendWindowFocus(BrowsingContextId(mBrowsingContextId));
|
||||
cc->SendWindowFocus(this);
|
||||
}
|
||||
|
||||
void BrowsingContext::Blur(ErrorResult& aError) {
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
cc->SendWindowBlur(BrowsingContextId(mBrowsingContextId));
|
||||
cc->SendWindowBlur(this);
|
||||
}
|
||||
|
||||
Nullable<WindowProxyHolder> BrowsingContext::GetTop(ErrorResult& aError) {
|
||||
|
@ -460,7 +459,7 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
|||
getter_AddRefs(data.callerDocumentURI()), aError)) {
|
||||
return;
|
||||
}
|
||||
data.source() = BrowsingContextId(sourceBc->Id());
|
||||
data.source() = sourceBc;
|
||||
data.isFromPrivateWindow() =
|
||||
callerInnerWindow &&
|
||||
nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow);
|
||||
|
@ -485,8 +484,7 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
|||
return;
|
||||
}
|
||||
|
||||
cc->SendWindowPostMessage(BrowsingContextId(mBrowsingContextId), messageData,
|
||||
data);
|
||||
cc->SendWindowPostMessage(this, messageData, data);
|
||||
}
|
||||
|
||||
void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
||||
|
@ -515,4 +513,46 @@ already_AddRefed<BrowsingContext> BrowsingContext::FindChildWithName(
|
|||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
||||
void IPDLParamTraits<dom::BrowsingContext>::Write(
|
||||
IPC::Message* aMsg, IProtocol* aActor, dom::BrowsingContext* aParam) {
|
||||
uint64_t id = aParam ? aParam->Id() : 0;
|
||||
WriteIPDLParam(aMsg, aActor, id);
|
||||
|
||||
// If his is an in-process send. We want to make sure that our BrowsingContext
|
||||
// object lives long enough to make it to the other side, so we take an extra
|
||||
// reference. This reference is freed in ::Read().
|
||||
if (!aActor->GetIPCChannel()->IsCrossProcess()) {
|
||||
NS_IF_ADDREF(aParam);
|
||||
}
|
||||
}
|
||||
|
||||
bool IPDLParamTraits<dom::BrowsingContext>::Read(
|
||||
const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
|
||||
RefPtr<dom::BrowsingContext>* aResult) {
|
||||
uint64_t id = 0;
|
||||
if (!ReadIPDLParam(aMsg, aIter, aActor, &id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
aResult = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
*aResult = dom::BrowsingContext::Get(id);
|
||||
MOZ_ASSERT(aResult, "Deserialized absent BrowsingContext!");
|
||||
|
||||
// If this is an in-process actor, free the reference taken in ::Write().
|
||||
if (!aActor->GetIPCChannel()->IsCrossProcess()) {
|
||||
dom::BrowsingContext* bc = *aResult;
|
||||
NS_IF_RELEASE(bc);
|
||||
}
|
||||
|
||||
return aResult != nullptr;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
class nsGlobalWindowOuter;
|
||||
class nsOuterWindowProxy;
|
||||
class PickleIterator;
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
} // namespace IPC
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -27,9 +32,17 @@ class ErrorResult;
|
|||
class LogModule;
|
||||
class OOMReporter;
|
||||
|
||||
namespace ipc {
|
||||
class IProtocol;
|
||||
|
||||
template <typename T>
|
||||
struct IPDLParamTraits;
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
|
||||
class BrowsingContextGroup;
|
||||
class CanonicalBrowsingContext;
|
||||
class ContentParent;
|
||||
template <typename>
|
||||
struct Nullable;
|
||||
|
@ -81,6 +94,9 @@ class BrowsingContext : public nsWrapperCache,
|
|||
BrowsingContext* aParent, BrowsingContext* aOpener,
|
||||
const nsAString& aName, uint64_t aId, ContentParent* aOriginProcess);
|
||||
|
||||
// Cast this object to a canonical browsing context, and return it.
|
||||
CanonicalBrowsingContext* Canonical();
|
||||
|
||||
// Get the DocShell for this BrowsingContext if it is in-process, or
|
||||
// null if it's not.
|
||||
nsIDocShell* GetDocShell() { return mDocShell; }
|
||||
|
@ -254,6 +270,17 @@ extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
|
|||
JS::MutableHandle<JSObject*> aRetVal);
|
||||
|
||||
} // namespace dom
|
||||
|
||||
// Allow sending BrowsingContext objects over IPC.
|
||||
namespace ipc {
|
||||
template <>
|
||||
struct IPDLParamTraits<dom::BrowsingContext> {
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
dom::BrowsingContext* aParam);
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, RefPtr<dom::BrowsingContext>* aResult);
|
||||
};
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_BrowsingContext_h)
|
||||
|
|
|
@ -977,7 +977,11 @@ nsRect Element::GetClientAreaRect() {
|
|||
nsIScrollableFrame* sf = GetScrollFrame(&frame);
|
||||
|
||||
if (sf) {
|
||||
return sf->GetScrollPortRect();
|
||||
nsRect scrollPort = sf->GetScrollPortRect();
|
||||
// The scroll port value might be expanded to the minimum scale size, we
|
||||
// should limit the size to the ICB in such cases.
|
||||
scrollPort.SizeTo(sf->GetLayoutSize());
|
||||
return scrollPort;
|
||||
}
|
||||
|
||||
if (frame &&
|
||||
|
|
|
@ -166,9 +166,8 @@ BlobURL::Mutate(nsIURIMutator** aMutator) {
|
|||
|
||||
// nsIClassInfo methods:
|
||||
NS_IMETHODIMP
|
||||
BlobURL::GetInterfaces(uint32_t* count, nsIID*** array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
BlobURL::GetInterfaces(nsTArray<nsIID>& array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,7 +302,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
|||
in nsISupports aContext,
|
||||
in ACString aMimeTypeGuess,
|
||||
in nsIURI aOriginalURIIfRedirect,
|
||||
in bool aSendViolationReports);
|
||||
in bool aSendViolationReports,
|
||||
in AString aNonce);
|
||||
|
||||
%{ C++
|
||||
// nsIObserver topic to fire when the policy encounters a violation.
|
||||
|
|
|
@ -3590,67 +3590,54 @@ PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg,
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvWindowClose(
|
||||
const BrowsingContextId& aContextId, const bool& aTrustedCaller) {
|
||||
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
BrowsingContext* aContext, bool aTrustedCaller) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ChildIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = aContext->GetDOMWindow();
|
||||
nsGlobalWindowOuter::Cast(window)->CloseOuter(aTrustedCaller);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvWindowFocus(
|
||||
const BrowsingContextId& aContextId) {
|
||||
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
mozilla::ipc::IPCResult ContentChild::RecvWindowFocus(BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ChildIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = aContext->GetDOMWindow();
|
||||
nsGlobalWindowOuter::Cast(window)->FocusOuter();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvWindowBlur(
|
||||
const BrowsingContextId& aContextId) {
|
||||
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ChildIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = aContext->GetDOMWindow();
|
||||
nsGlobalWindowOuter::Cast(window)->BlurOuter();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
|
||||
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
|
||||
BrowsingContext* aContext, const ClonedMessageData& aMessage,
|
||||
const PostMessageData& aData) {
|
||||
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ChildIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
RefPtr<nsGlobalWindowOuter> window =
|
||||
nsGlobalWindowOuter::Cast(bc->GetDOMWindow());
|
||||
nsGlobalWindowOuter::Cast(aContext->GetDOMWindow());
|
||||
nsCOMPtr<nsIPrincipal> providedPrincipal;
|
||||
if (!window->GetPrincipalForPostMessage(
|
||||
aData.targetOrigin(), aData.targetOriginURI(),
|
||||
|
@ -3659,11 +3646,10 @@ mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> sourceBc = BrowsingContext::Get(aData.source());
|
||||
RefPtr<BrowsingContext> sourceBc = aData.source();
|
||||
if (!sourceBc) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to use a dead or detached context 0x%08" PRIx64,
|
||||
(uint64_t)aData.source()));
|
||||
("ChildIPC: Trying to use a dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -714,12 +714,12 @@ class ContentChild final : public PContentChild,
|
|||
|
||||
virtual void OnChannelReceivedMessage(const Message& aMsg) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvWindowClose(const BrowsingContextId& aContextId,
|
||||
const bool& aTrustedCaller);
|
||||
mozilla::ipc::IPCResult RecvWindowFocus(const BrowsingContextId& aContextId);
|
||||
mozilla::ipc::IPCResult RecvWindowBlur(const BrowsingContextId& aContextId);
|
||||
mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
|
||||
bool aTrustedCaller);
|
||||
mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
|
||||
mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
|
||||
mozilla::ipc::IPCResult RecvWindowPostMessage(
|
||||
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
|
||||
BrowsingContext* aContext, const ClonedMessageData& aMessage,
|
||||
const PostMessageData& aData);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
|
|
@ -5609,31 +5609,9 @@ mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
|
||||
const BrowsingContextId& aParentId, const BrowsingContextId& aOpenerId,
|
||||
const BrowsingContextId& aChildId, const nsString& aName) {
|
||||
RefPtr<CanonicalBrowsingContext> parent =
|
||||
CanonicalBrowsingContext::Get(aParentId);
|
||||
if (aParentId && !parent) {
|
||||
// Unless 'aParentId' is 0 (which it is when the child is a root
|
||||
// BrowsingContext) there should always be a corresponding
|
||||
// 'parent'. The only reason for there not beeing one is if the
|
||||
// parent has already been detached, in which case the
|
||||
// BrowsingContext that tries to attach itself to the context with
|
||||
// 'aParentId' is surely doomed and we can safely do nothing.
|
||||
|
||||
// TODO(farre): When we start syncing/moving BrowsingContexts to
|
||||
// other child processes is it possible to get into races where
|
||||
// constructive operations on already detached BrowsingContexts
|
||||
// are requested? This needs to be answered/handled, but for now
|
||||
// return early. [Bug 1471598]
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to attach to already detached parent 0x%08" PRIx64,
|
||||
(uint64_t)aParentId));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (parent && !parent->IsOwnedByProcess(ChildID())) {
|
||||
BrowsingContext* aParent, BrowsingContext* aOpener,
|
||||
BrowsingContextId aChildId, const nsString& aName) {
|
||||
if (aParent && !aParent->Canonical()->IsOwnedByProcess(ChildID())) {
|
||||
// Where trying attach a child BrowsingContext to a parent
|
||||
// BrowsingContext in another process. This is illegal since the
|
||||
// only thing that could create that child BrowsingContext is a
|
||||
|
@ -5648,7 +5626,7 @@ mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
|
|||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
|
||||
("ParentIPC: Trying to attach to out of process parent context "
|
||||
"0x%08" PRIx64,
|
||||
parent->Id()));
|
||||
aParent->Id()));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -5663,13 +5641,12 @@ mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
|
|||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
|
||||
("ParentIPC: Trying to attach already attached 0x%08" PRIx64
|
||||
" to 0x%08" PRIx64,
|
||||
child->Id(), (uint64_t)aParentId));
|
||||
child->Id(), aParent ? aParent->Id() : 0));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (!child) {
|
||||
RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerId);
|
||||
child = BrowsingContext::CreateFromIPC(parent, opener, aName,
|
||||
child = BrowsingContext::CreateFromIPC(aParent, aOpener, aName,
|
||||
(uint64_t)aChildId, this);
|
||||
}
|
||||
|
||||
|
@ -5677,18 +5654,14 @@ mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
|
||||
const BrowsingContextId& aContextId, const bool& aMoveToBFCache) {
|
||||
RefPtr<CanonicalBrowsingContext> context =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
|
||||
if (!context) {
|
||||
BrowsingContext* aContext, bool aMoveToBFCache) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to detach already detached 0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ParentIPC: Trying to detach already detached"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (!context->IsOwnedByProcess(ChildID())) {
|
||||
if (!aContext->Canonical()->IsOwnedByProcess(ChildID())) {
|
||||
// Where trying to detach a child BrowsingContext in another child
|
||||
// process. This is illegal since the owner of the BrowsingContext
|
||||
// is the proccess with the in-process docshell, which is tracked
|
||||
|
@ -5698,33 +5671,28 @@ mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
|
|||
// above TODO. [Bug 1471598]
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
|
||||
("ParentIPC: Trying to detach out of process context 0x%08" PRIx64,
|
||||
context->Id()));
|
||||
aContext->Id()));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (aMoveToBFCache) {
|
||||
context->CacheChildren();
|
||||
aContext->CacheChildren();
|
||||
} else {
|
||||
context->Detach();
|
||||
aContext->Detach();
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvSetOpenerBrowsingContext(
|
||||
const BrowsingContextId& aContextId,
|
||||
const BrowsingContextId& aOpenerContextId) {
|
||||
RefPtr<CanonicalBrowsingContext> context =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
|
||||
if (!context) {
|
||||
BrowsingContext* aContext, BrowsingContext* aOpener) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to set opener already detached 0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ParentIPC: Trying to set opener already detached"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (!context->IsOwnedByProcess(ChildID())) {
|
||||
if (!aContext->Canonical()->IsOwnedByProcess(ChildID())) {
|
||||
// Where trying to set opener on a child BrowsingContext in
|
||||
// another child process. This is illegal since the owner of the
|
||||
// BrowsingContext is the proccess with the in-process docshell,
|
||||
|
@ -5735,29 +5703,24 @@ mozilla::ipc::IPCResult ContentParent::RecvSetOpenerBrowsingContext(
|
|||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
|
||||
("ParentIPC: Trying to set opener on out of process context "
|
||||
"0x%08" PRIx64,
|
||||
context->Id()));
|
||||
aContext->Id()));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerContextId);
|
||||
context->SetOpener(opener);
|
||||
aContext->SetOpener(aOpener);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvSetUserGestureActivation(
|
||||
const BrowsingContextId& aContextId, const bool& aNewValue) {
|
||||
RefPtr<CanonicalBrowsingContext> context =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
|
||||
if (!context) {
|
||||
BrowsingContext* aContext, bool aNewValue) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to activate wrong context 0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
("ParentIPC: Trying to activate wrong context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
context->NotifySetUserGestureActivationFromIPC(aNewValue);
|
||||
aContext->Canonical()->NotifySetUserGestureActivationFromIPC(aNewValue);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -5782,14 +5745,11 @@ void ContentParent::UnregisterRemoveWorkerActor() {
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
|
||||
const BrowsingContextId& aContextId, const bool& aTrustedCaller) {
|
||||
RefPtr<CanonicalBrowsingContext> bc =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
BrowsingContext* aContext, bool aTrustedCaller) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -5798,66 +5758,57 @@ mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
|
|||
// browsing contexts of bc.
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp =
|
||||
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
|
||||
Unused << cp->SendWindowClose(aContextId, aTrustedCaller);
|
||||
ContentParent* cp = cpm->GetContentProcessById(
|
||||
ContentParentId(aContext->Canonical()->OwnerProcessId()));
|
||||
Unused << cp->SendWindowClose(aContext, aTrustedCaller);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
|
||||
const BrowsingContextId& aContextId) {
|
||||
RefPtr<CanonicalBrowsingContext> bc =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp =
|
||||
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
|
||||
Unused << cp->SendWindowFocus(aContextId);
|
||||
ContentParent* cp = cpm->GetContentProcessById(
|
||||
ContentParentId(aContext->Canonical()->OwnerProcessId()));
|
||||
Unused << cp->SendWindowFocus(aContext);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
|
||||
const BrowsingContextId& aContextId) {
|
||||
RefPtr<CanonicalBrowsingContext> bc =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp =
|
||||
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
|
||||
Unused << cp->SendWindowBlur(aContextId);
|
||||
ContentParent* cp = cpm->GetContentProcessById(
|
||||
ContentParentId(aContext->Canonical()->OwnerProcessId()));
|
||||
Unused << cp->SendWindowBlur(aContext);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
|
||||
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
|
||||
BrowsingContext* aContext, const ClonedMessageData& aMessage,
|
||||
const PostMessageData& aData) {
|
||||
RefPtr<CanonicalBrowsingContext> bc =
|
||||
CanonicalBrowsingContext::Get(aContextId);
|
||||
if (!bc) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context "
|
||||
"0x%08" PRIx64,
|
||||
(uint64_t)aContextId));
|
||||
if (!aContext) {
|
||||
MOZ_LOG(
|
||||
BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp =
|
||||
cpm->GetContentProcessById(ContentParentId(bc->OwnerProcessId()));
|
||||
ContentParent* cp = cpm->GetContentProcessById(
|
||||
ContentParentId(aContext->Canonical()->OwnerProcessId()));
|
||||
StructuredCloneData messageFromChild;
|
||||
UnpackClonedMessageDataForParent(aMessage, messageFromChild);
|
||||
ClonedMessageData message;
|
||||
|
@ -5865,7 +5816,7 @@ mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
|
|||
// FIXME Logging?
|
||||
return IPC_OK();
|
||||
}
|
||||
Unused << cp->SendWindowPostMessage(aContextId, message, aData);
|
||||
Unused << cp->SendWindowPostMessage(aContext, message, aData);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -618,27 +618,25 @@ class ContentParent final : public PContentParent,
|
|||
static bool IsInputEventQueueSupported();
|
||||
|
||||
mozilla::ipc::IPCResult RecvAttachBrowsingContext(
|
||||
const BrowsingContextId& aParentContextId,
|
||||
const BrowsingContextId& aOpenerId, const BrowsingContextId& aContextId,
|
||||
const nsString& aName);
|
||||
BrowsingContext* aParentContext, BrowsingContext* aOpener,
|
||||
BrowsingContextId aContextId, const nsString& aName);
|
||||
|
||||
mozilla::ipc::IPCResult RecvDetachBrowsingContext(
|
||||
const BrowsingContextId& aContextId, const bool& aMoveToBFCache);
|
||||
mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
|
||||
bool aMoveToBFCache);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetOpenerBrowsingContext(
|
||||
const BrowsingContextId& aContextId,
|
||||
const BrowsingContextId& aOpenerContextId);
|
||||
BrowsingContext* aContext, BrowsingContext* aOpener);
|
||||
|
||||
mozilla::ipc::IPCResult RecvWindowClose(const BrowsingContextId& aContextId,
|
||||
const bool& aTrustedCaller);
|
||||
mozilla::ipc::IPCResult RecvWindowFocus(const BrowsingContextId& aContextId);
|
||||
mozilla::ipc::IPCResult RecvWindowBlur(const BrowsingContextId& aContextId);
|
||||
mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
|
||||
bool aTrustedCaller);
|
||||
mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
|
||||
mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
|
||||
mozilla::ipc::IPCResult RecvWindowPostMessage(
|
||||
const BrowsingContextId& aContextId, const ClonedMessageData& aMessage,
|
||||
BrowsingContext* aContext, const ClonedMessageData& aMessage,
|
||||
const PostMessageData& aData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetUserGestureActivation(
|
||||
const BrowsingContextId& aContextId, const bool& aNewValue);
|
||||
BrowsingContext* aContext, bool aNewValue);
|
||||
|
||||
protected:
|
||||
void OnChannelConnected(int32_t pid) override;
|
||||
|
|
|
@ -27,7 +27,7 @@ using mozilla::LayoutDeviceIntPoint from "Units.h";
|
|||
using hal::ScreenOrientation from "mozilla/HalScreenConfiguration.h";
|
||||
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
|
||||
using refcounted class nsIPrincipal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
using refcounted class nsIURI from "mozilla/ipc/URIUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -189,7 +189,7 @@ struct PerformanceInfo
|
|||
struct WindowGlobalInit
|
||||
{
|
||||
nsIPrincipal principal;
|
||||
BrowsingContextId browsingContextId;
|
||||
BrowsingContext browsingContext;
|
||||
uint64_t innerWindowId;
|
||||
uint64_t outerWindowId;
|
||||
};
|
||||
|
|
|
@ -88,7 +88,7 @@ using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
|
|||
using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
|
||||
using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -621,7 +621,7 @@ parent:
|
|||
sync SetPrefersReducedMotionOverrideForTest(bool aValue);
|
||||
sync ResetPrefersReducedMotionOverrideForTest();
|
||||
|
||||
async RootBrowsingContext(BrowsingContextId aId);
|
||||
async RootBrowsingContext(BrowsingContext aContext);
|
||||
|
||||
child:
|
||||
/**
|
||||
|
|
|
@ -102,6 +102,7 @@ using mozilla::Telemetry::ChildEventData from "mozilla/TelemetryComms.h";
|
|||
using mozilla::Telemetry::DiscardedData from "mozilla/TelemetryComms.h";
|
||||
using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
|
||||
using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
|
||||
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
|
||||
union ChromeRegistryItem
|
||||
|
@ -308,7 +309,7 @@ struct NotificationEventData
|
|||
|
||||
struct PostMessageData
|
||||
{
|
||||
BrowsingContextId source;
|
||||
BrowsingContext source;
|
||||
nsString origin;
|
||||
nsString targetOrigin;
|
||||
nsIURI targetOriginURI;
|
||||
|
@ -1219,47 +1220,44 @@ parent:
|
|||
async StoreUserInteractionAsPermission(Principal aPrincipal);
|
||||
|
||||
/**
|
||||
* Sync the BrowsingContext with id 'aContextId' and name 'aName'
|
||||
* to the parent, and attach it to the BrowsingContext with id
|
||||
* 'aParentContextId'. If 'aParentContextId' is '0' the
|
||||
* BrowsingContext is a root in the BrowsingContext
|
||||
* tree. AttachBrowsingContext must only be called at most once
|
||||
* for any child BrowsingContext, and only for BrowsingContexts
|
||||
* where the parent and the child context contains their
|
||||
* nsDocShell.
|
||||
* Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
|
||||
* parent, and attach it to the BrowsingContext 'aParentContext'. If
|
||||
* 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
|
||||
* BrowsingContext tree. AttachBrowsingContext must only be called at most
|
||||
* once for any child BrowsingContext, and only for BrowsingContexts where
|
||||
* the parent and the child context contains their nsDocShell.
|
||||
*/
|
||||
async AttachBrowsingContext(BrowsingContextId aParentContextId,
|
||||
BrowsingContextId aOpenerId,
|
||||
async AttachBrowsingContext(BrowsingContext aParentContext,
|
||||
BrowsingContext aOpener,
|
||||
BrowsingContextId aContextId,
|
||||
nsString aName);
|
||||
|
||||
/**
|
||||
* Remove the synced BrowsingContext with id 'aContextId' from the
|
||||
* parent. DetachBrowsingContext is only needed to be called once
|
||||
* for any BrowsingContext, since detaching a node in the
|
||||
* BrowsingContext detaches the entire sub-tree rooted at that
|
||||
* node. Calling DetachBrowsingContext with an already detached
|
||||
* BrowsingContext effectively does nothing. Note that it is not
|
||||
* an error to call DetachBrowsingContext on a BrowsingContext
|
||||
* belonging to an already detached subtree. The 'aMoveToBFCache'
|
||||
* paramater controls if detaching a BrowsingContext should move
|
||||
* it to the bfcache allowing it to be re-attached if navigated
|
||||
* Remove the synced BrowsingContext 'aContext' from the parent.
|
||||
* DetachBrowsingContext is only needed to be called once for any
|
||||
* BrowsingContext, since detaching a node in the BrowsingContext detaches
|
||||
* the entire sub-tree rooted at that node. Calling DetachBrowsingContext
|
||||
* with an already detached BrowsingContext effectively does nothing. Note
|
||||
* that it is not an error to call DetachBrowsingContext on a
|
||||
* BrowsingContext belonging to an already detached subtree. The
|
||||
* 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
|
||||
* should move it to the bfcache allowing it to be re-attached if navigated
|
||||
* to.
|
||||
*/
|
||||
async DetachBrowsingContext(BrowsingContextId aContextId,
|
||||
async DetachBrowsingContext(BrowsingContext aContext,
|
||||
bool aMoveToBFCache);
|
||||
|
||||
/**
|
||||
* Set the opener of browsing context with id 'aContextId' to the
|
||||
* browsing context with id 'aOpenerId'.
|
||||
* Set the opener of browsing context 'aContext' to the browsing context
|
||||
* with id 'aOpenerId'.
|
||||
*/
|
||||
async SetOpenerBrowsingContext(BrowsingContextId aContextId,
|
||||
BrowsingContextId aOpenerContextId);
|
||||
async SetOpenerBrowsingContext(BrowsingContext aContext,
|
||||
BrowsingContext aOpenerContext);
|
||||
|
||||
/**
|
||||
* Notify parent to update user gesture activation flag.
|
||||
*/
|
||||
async SetUserGestureActivation(BrowsingContextId aContextId,
|
||||
async SetUserGestureActivation(BrowsingContext aContext,
|
||||
bool aNewValue);
|
||||
|
||||
both:
|
||||
|
@ -1279,11 +1277,10 @@ both:
|
|||
async PushError(nsCString scope, Principal principal, nsString message,
|
||||
uint32_t flags);
|
||||
|
||||
async WindowClose(BrowsingContextId aContextId,
|
||||
bool aTrustedCaller);
|
||||
async WindowFocus(BrowsingContextId aContextId);
|
||||
async WindowBlur(BrowsingContextId aContextId);
|
||||
async WindowPostMessage(BrowsingContextId aContextId, ClonedMessageData aMessage,
|
||||
async WindowClose(BrowsingContext aContext, bool aTrustedCaller);
|
||||
async WindowFocus(BrowsingContext aContext);
|
||||
async WindowBlur(BrowsingContext aContext);
|
||||
async WindowPostMessage(BrowsingContext aContext, ClonedMessageData aMessage,
|
||||
PostMessageData aData);
|
||||
};
|
||||
|
||||
|
|
|
@ -554,7 +554,7 @@ nsresult TabChild::Init(mozIDOMWindowProxy* aParent) {
|
|||
// Send our browsing context to the parent process.
|
||||
RefPtr<BrowsingContext> browsingContext =
|
||||
nsDocShell::Cast(docShell)->GetBrowsingContext();
|
||||
SendRootBrowsingContext(BrowsingContextId(browsingContext->Id()));
|
||||
SendRootBrowsingContext(browsingContext);
|
||||
|
||||
// Few lines before, baseWindow->Create() will end up creating a new
|
||||
// window root in nsGlobalWindow::SetDocShell.
|
||||
|
|
|
@ -3444,9 +3444,9 @@ mozilla::ipc::IPCResult TabParent::RecvGetSystemFont(nsCString* aFontName) {
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult TabParent::RecvRootBrowsingContext(
|
||||
const BrowsingContextId& aId) {
|
||||
BrowsingContext* aBrowsingContext) {
|
||||
MOZ_ASSERT(!mBrowsingContext, "May only set browsing context once!");
|
||||
mBrowsingContext = CanonicalBrowsingContext::Get(aId);
|
||||
mBrowsingContext = CanonicalBrowsingContext::Cast(aBrowsingContext);
|
||||
MOZ_ASSERT(mBrowsingContext, "Invalid ID!");
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -257,11 +257,10 @@ class TabParent final : public PBrowserParent,
|
|||
const nsCursor& aValue, const bool& aHasCustomCursor,
|
||||
const nsCString& aUri, const uint32_t& aWidth, const uint32_t& aHeight,
|
||||
const uint32_t& aStride, const gfx::SurfaceFormat& aFormat,
|
||||
const uint32_t& aHotspotX, const uint32_t& aHotspotY,
|
||||
const bool& aForce);
|
||||
const uint32_t& aHotspotX, const uint32_t& aHotspotY, const bool& aForce);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetStatus(
|
||||
const uint32_t& aType, const nsString& aStatus);
|
||||
mozilla::ipc::IPCResult RecvSetStatus(const uint32_t& aType,
|
||||
const nsString& aStatus);
|
||||
|
||||
mozilla::ipc::IPCResult RecvShowTooltip(const uint32_t& aX,
|
||||
const uint32_t& aY,
|
||||
|
@ -595,7 +594,7 @@ class TabParent final : public PBrowserParent,
|
|||
mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
|
||||
const nsCString& aFirstPartyURI, const bool& aHideDoorHanger);
|
||||
|
||||
mozilla::ipc::IPCResult RecvRootBrowsingContext(const BrowsingContextId& aId);
|
||||
mozilla::ipc::IPCResult RecvRootBrowsingContext(BrowsingContext* aContext);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName);
|
||||
mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName);
|
||||
|
|
|
@ -39,9 +39,8 @@ already_AddRefed<WindowGlobalChild> WindowGlobalChild::Create(
|
|||
RefPtr<dom::BrowsingContext> bc = docshell->GetBrowsingContext();
|
||||
RefPtr<WindowGlobalChild> wgc = new WindowGlobalChild(aWindow, bc);
|
||||
|
||||
WindowGlobalInit init(principal,
|
||||
BrowsingContextId(wgc->BrowsingContext()->Id()),
|
||||
wgc->mInnerWindowId, wgc->mOuterWindowId);
|
||||
WindowGlobalInit init(principal, bc, wgc->mInnerWindowId,
|
||||
wgc->mOuterWindowId);
|
||||
|
||||
// Send the link constructor over PInProcessChild or PBrowser.
|
||||
if (XRE_IsParentProcess()) {
|
||||
|
|
|
@ -37,7 +37,7 @@ WindowGlobalParent::WindowGlobalParent(const WindowGlobalInit& aInit,
|
|||
MOZ_RELEASE_ASSERT(mDocumentPrincipal, "Must have a valid principal");
|
||||
|
||||
// NOTE: mBrowsingContext initialized in Init()
|
||||
MOZ_RELEASE_ASSERT(aInit.browsingContextId() != 0,
|
||||
MOZ_RELEASE_ASSERT(aInit.browsingContext(),
|
||||
"Must be made in BrowsingContext");
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ void WindowGlobalParent::Init(const WindowGlobalInit& aInit) {
|
|||
processId = static_cast<ContentParent*>(Manager()->Manager())->ChildID();
|
||||
}
|
||||
|
||||
mBrowsingContext = CanonicalBrowsingContext::Get(aInit.browsingContextId());
|
||||
mBrowsingContext = CanonicalBrowsingContext::Cast(aInit.browsingContext());
|
||||
MOZ_ASSERT(mBrowsingContext);
|
||||
|
||||
// XXX(nika): This won't be the case soon, but for now this is a good
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace dom {
|
|||
class CanonicalBrowsingContext;
|
||||
class WindowGlobalChild;
|
||||
class JSWindowActorParent;
|
||||
class TabParent;
|
||||
|
||||
/**
|
||||
* A handle in the parent process to a specific nsGlobalWindowInner object.
|
||||
|
|
|
@ -311,6 +311,17 @@ nsresult ScriptLoader::CheckContentPolicy(Document* aDocument,
|
|||
requestingNode, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
|
||||
contentPolicyType);
|
||||
|
||||
// snapshot the nonce at load start time for performing CSP checks
|
||||
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT ||
|
||||
contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_MODULE) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aContext);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
nsAutoString cspNonce;
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
|
||||
secCheckLoadInfo->SetCspNonce(cspNonce);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsresult rv = NS_CheckContentLoadPolicy(
|
||||
aRequest->mURI, secCheckLoadInfo, NS_LossyConvertUTF16toASCII(aType),
|
||||
|
@ -1257,6 +1268,18 @@ nsresult ScriptLoader::StartLoad(ScriptLoadRequest* aRequest) {
|
|||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// snapshot the nonce at load start time for performing CSP checks
|
||||
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT ||
|
||||
contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_MODULE) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(context);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
nsAutoString cspNonce;
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
loadInfo->SetCspNonce(cspNonce);
|
||||
}
|
||||
}
|
||||
|
||||
// To avoid decoding issues, the build-id is part of the JSBytecodeMimeType
|
||||
// constant.
|
||||
aRequest->mCacheInfo = nullptr;
|
||||
|
|
|
@ -121,7 +121,8 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
|||
nsISupports* aRequestContext,
|
||||
const nsACString& aMimeTypeGuess,
|
||||
nsIURI* aOriginalURIIfRedirect,
|
||||
bool aSendViolationReports, int16_t* outDecision) {
|
||||
bool aSendViolationReports, const nsAString& aNonce,
|
||||
int16_t* outDecision) {
|
||||
if (CSPCONTEXTLOGENABLED()) {
|
||||
CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
|
||||
aContentLocation->GetSpecOrDefault().get()));
|
||||
|
@ -155,18 +156,8 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString nonce;
|
||||
bool parserCreated = false;
|
||||
if (!isPreload) {
|
||||
if (aContentType == nsIContentPolicy::TYPE_SCRIPT ||
|
||||
aContentType == nsIContentPolicy::TYPE_STYLESHEET) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aRequestContext);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
// XXXbz What about SVG elements that can have nonce?
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
|
||||
if (script && script->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER) {
|
||||
parserCreated = true;
|
||||
|
@ -177,7 +168,7 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
|||
permitsInternal(dir,
|
||||
nullptr, // aTriggeringElement
|
||||
aCSPEventListener, aContentLocation,
|
||||
aOriginalURIIfRedirect, nonce, isPreload,
|
||||
aOriginalURIIfRedirect, aNonce, isPreload,
|
||||
false, // allow fallback to default-src
|
||||
aSendViolationReports,
|
||||
true, // send blocked URI in violation reports
|
||||
|
|
|
@ -172,6 +172,10 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString cspNonce;
|
||||
rv = aLoadInfo->GetCspNonce(cspNonce);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 1) Apply speculate CSP for preloads
|
||||
bool isPreload = nsContentUtils::IsPreloadType(contentType);
|
||||
|
||||
|
@ -186,7 +190,7 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
|
|||
contentType, cspEventListener, aContentLocation, requestOrigin,
|
||||
requestContext, aMimeTypeGuess,
|
||||
nullptr, // no redirect, aOriginal URL is null.
|
||||
aLoadInfo->GetSendCSPViolationEvents(), aDecision);
|
||||
aLoadInfo->GetSendCSPViolationEvents(), cspNonce, aDecision);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if the preload policy already denied the load, then there
|
||||
|
@ -207,7 +211,8 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
|
|||
rv = csp->ShouldLoad(contentType, cspEventListener, aContentLocation,
|
||||
requestOrigin, requestContext, aMimeTypeGuess,
|
||||
nullptr, // no redirect, aOriginal URL is null.
|
||||
aLoadInfo->GetSendCSPViolationEvents(), aDecision);
|
||||
aLoadInfo->GetSendCSPViolationEvents(), cspNonce,
|
||||
aDecision);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -251,17 +256,6 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
|||
nsIAsyncVerifyRedirectCallback *callback) {
|
||||
net::nsAsyncRedirectAutoCallback autoCallback(callback);
|
||||
|
||||
if (XRE_IsE10sParentProcess()) {
|
||||
nsCOMPtr<nsIParentChannel> parentChannel;
|
||||
NS_QueryNotificationCallbacks(oldChannel, parentChannel);
|
||||
if (parentChannel) {
|
||||
// This is an IPC'd channel. Don't check it here, because we won't have
|
||||
// access to the request context; we'll check them in the content
|
||||
// process instead. Bug 1509738 covers fixing this.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> newUri;
|
||||
nsresult rv = newChannel->GetURI(getter_AddRefs(newUri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -303,6 +297,10 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString cspNonce;
|
||||
rv = loadInfo->GetCspNonce(cspNonce);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isPreload = nsContentUtils::IsPreloadType(policyType);
|
||||
|
||||
/* On redirect, if the content policy is a preload type, rejecting the preload
|
||||
|
@ -330,6 +328,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
|||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // Original nsIURI
|
||||
true, // aSendViolationReports
|
||||
cspNonce, // nonce
|
||||
&aDecision);
|
||||
|
||||
// if the preload policy already denied the load, then there
|
||||
|
@ -356,6 +355,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
|||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // Original nsIURI
|
||||
true, // aSendViolationReports
|
||||
cspNonce, // nonce
|
||||
&aDecision);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_FRAME =
|
||||
`<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<script id='myScript' nonce='123456789' type='application/javascript'></script>
|
||||
<script nonce='123456789'>
|
||||
let myScript = document.getElementById('myScript');
|
||||
// 1) start loading the script using the nonce 123456789
|
||||
myScript.src='file_nonce_snapshot.sjs?redir-script';
|
||||
// 2) dynamically change the nonce, load should use initial nonce
|
||||
myScript.setAttribute('nonce','987654321');
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const SCRIPT = "window.parent.postMessage('script-loaded', '*');";
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
let queryString = request.queryString;
|
||||
|
||||
if (queryString === "load-frame") {
|
||||
response.setHeader("Content-Security-Policy", "script-src 'nonce-123456789'", false);
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(TEST_FRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (queryString === "redir-script") {
|
||||
response.setStatusLine("1.1", 302, "Found");
|
||||
response.setHeader("Location", "file_nonce_snapshot.sjs?load-script", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (queryString === "load-script") {
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write(SCRIPT);
|
||||
return;
|
||||
}
|
||||
|
||||
// we should never get here but just in case return something unexpected
|
||||
response.write("do'h");
|
||||
}
|
|
@ -368,3 +368,6 @@ support-files =
|
|||
worker_helper.js
|
||||
main_csp_worker.html
|
||||
main_csp_worker.html^headers^
|
||||
[test_nonce_snapshot.html]
|
||||
support-files =
|
||||
file_nonce_snapshot.sjs
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 1509738 - Snapshot nonce at load start time</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<iframe style="width:100%;" id="testframe"></iframe>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/* Description of the test:
|
||||
* a) the test starts loading a script using whitelisted nonce
|
||||
* b) the nonce of the script gets modified
|
||||
* c) the script hits a 302 server side redirect
|
||||
* d) we ensure the script still loads and does not use the modified nonce
|
||||
*/
|
||||
|
||||
window.addEventListener("message", receiveMessage);
|
||||
function receiveMessage(event) {
|
||||
is(event.data, "script-loaded", "script loaded even though nonce was dynamically modified");
|
||||
window.removeEventListener("message", receiveMessage);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
let src = "file_nonce_snapshot.sjs?load-frame";
|
||||
document.getElementById("testframe").src = src;
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -153,7 +153,7 @@ function run_test() {
|
|||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
null, // nsICSPEventListener
|
||||
NetUtil.newURI("http://blocked.test/foo.js"),
|
||||
null, null, null, null, true);
|
||||
null, null, null, null, true, null);
|
||||
});
|
||||
|
||||
// test that inline script violations cause a report in report-only policy
|
||||
|
@ -206,7 +206,7 @@ function run_test() {
|
|||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
null, // nsICSPEventListener
|
||||
NetUtil.newURI("data:image/png;base64," + base64data),
|
||||
null, null, null, null, true);
|
||||
null, null, null, null, true, null);
|
||||
});
|
||||
|
||||
// test that only the uri's scheme is reported for globally unique identifiers
|
||||
|
@ -216,7 +216,7 @@ function run_test() {
|
|||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
|
||||
null, // nsICSPEventListener
|
||||
NetUtil.newURI("intent://mymaps.com/maps?um=1&ie=UTF-8&fb=1&sll"),
|
||||
null, null, null, null, true);
|
||||
null, null, null, null, true, null);
|
||||
});
|
||||
|
||||
// test fragment removal
|
||||
|
@ -227,7 +227,7 @@ function run_test() {
|
|||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
null, // nsICSPEventListener
|
||||
NetUtil.newURI(selfSpec + "#bar"),
|
||||
null, null, null, null, true);
|
||||
null, null, null, null, true, null);
|
||||
});
|
||||
|
||||
// test scheme of ftp:
|
||||
|
@ -237,6 +237,6 @@ function run_test() {
|
|||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
null, // nsICSPEventListener
|
||||
NetUtil.newURI("ftp://blocked.test/profile.png"),
|
||||
null, null, null, null, true);
|
||||
null, null, null, null, true, null);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
|
|||
use webrender::DebugFlags;
|
||||
use webrender::{ApiRecordingReceiver, BinaryRecorder};
|
||||
use webrender::{AsyncPropertySampler, PipelineInfo, SceneBuilderHooks};
|
||||
use webrender::{UploadMethod, VertexUsageHint};
|
||||
use webrender::{UploadMethod, VertexUsageHint, ProfilerHooks, set_profiler_hooks};
|
||||
use webrender::{Device, Shaders, WrShaders, ShaderPrecacheFlags};
|
||||
use thread_profiler::register_thread_with_profiler;
|
||||
use moz2d_renderer::Moz2dBlobImageHandler;
|
||||
|
@ -779,6 +779,26 @@ extern "C" {
|
|||
pub fn gecko_profiler_end_marker(name: *const c_char);
|
||||
}
|
||||
|
||||
/// Simple implementation of the WR ProfilerHooks trait to allow profile
|
||||
/// markers to be seen in the Gecko profiler.
|
||||
struct GeckoProfilerHooks;
|
||||
|
||||
impl ProfilerHooks for GeckoProfilerHooks {
|
||||
fn begin_marker(&self, label: &CStr) {
|
||||
unsafe {
|
||||
gecko_profiler_start_marker(label.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
fn end_marker(&self, label: &CStr) {
|
||||
unsafe {
|
||||
gecko_profiler_end_marker(label.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PROFILER_HOOKS: GeckoProfilerHooks = GeckoProfilerHooks {};
|
||||
|
||||
#[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &mut Transaction to an extern function
|
||||
extern "C" {
|
||||
// These callbacks are invoked from the scene builder thread (aka the APZ
|
||||
|
@ -1120,6 +1140,9 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
// Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
|
||||
set_profiler_hooks(Some(&PROFILER_HOOKS));
|
||||
|
||||
let notifier = Box::new(CppNotifier {
|
||||
window_id: window_id,
|
||||
});
|
||||
|
|
|
@ -319,6 +319,24 @@ name = "crossbeam-utils"
|
|||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cstr"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cstr-macros 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cstr-macros"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.7.18"
|
||||
|
@ -1075,6 +1093,11 @@ dependencies = [
|
|||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procedural-masquerade"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.1"
|
||||
|
@ -1607,6 +1630,7 @@ dependencies = [
|
|||
"core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1883,6 +1907,8 @@ dependencies = [
|
|||
"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9"
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
|
||||
"checksum cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ee681252c9c0a6e84bbb53257faa3d88a49ce6fb32148ae1a9dc24b588302a71"
|
||||
"checksum cstr-macros 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5e700cd6ede9b3f81b23ce4cba15f75cc8bf5b5a5dce2db293b1d31f4950ed78"
|
||||
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
|
||||
"checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
|
@ -1969,6 +1995,7 @@ dependencies = [
|
|||
"checksum plane-split 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b84b8cf2daa6a829b3e756fb75e0eab8e0d963754de9bfc83a4373a47121323a"
|
||||
"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"
|
||||
"checksum proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "d3797b7142c9aa74954e351fc089bbee7958cebbff6bf2815e7ffff0b19f547d"
|
||||
"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
|
|
|
@ -28,6 +28,7 @@ bincode = "1.0"
|
|||
bitflags = "1.0"
|
||||
byteorder = "1.0"
|
||||
cfg-if = "0.1.2"
|
||||
cstr = "0.1.2"
|
||||
fxhash = "0.2.1"
|
||||
gleam = "0.6.8"
|
||||
image = { optional = true, version = "0.21" }
|
||||
|
|
|
@ -374,6 +374,8 @@ impl FrameBuilder {
|
|||
);
|
||||
|
||||
{
|
||||
profile_marker!("UpdateVisibility");
|
||||
|
||||
let visibility_context = FrameVisibilityContext {
|
||||
device_pixel_scale,
|
||||
clip_scroll_tree,
|
||||
|
@ -439,15 +441,19 @@ impl FrameBuilder {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
self.prim_store.prepare_primitives(
|
||||
&mut prim_list,
|
||||
&pic_context,
|
||||
&mut pic_state,
|
||||
&frame_context,
|
||||
&mut frame_state,
|
||||
data_stores,
|
||||
scratch,
|
||||
);
|
||||
{
|
||||
profile_marker!("PreparePrims");
|
||||
|
||||
self.prim_store.prepare_primitives(
|
||||
&mut prim_list,
|
||||
&pic_context,
|
||||
&mut pic_state,
|
||||
&frame_context,
|
||||
&mut frame_state,
|
||||
data_stores,
|
||||
scratch,
|
||||
);
|
||||
}
|
||||
|
||||
let pic = &mut self.prim_store.pictures[self.root_pic_index.0];
|
||||
pic.restore_context(
|
||||
|
@ -500,6 +506,7 @@ impl FrameBuilder {
|
|||
debug_flags: DebugFlags,
|
||||
) -> Frame {
|
||||
profile_scope!("build");
|
||||
profile_marker!("BuildFrame");
|
||||
debug_assert!(
|
||||
DeviceIntRect::new(DeviceIntPoint::zero(), self.window_size)
|
||||
.contains_rect(&self.screen_rect)
|
||||
|
@ -546,79 +553,86 @@ impl FrameBuilder {
|
|||
debug_flags,
|
||||
);
|
||||
|
||||
resource_cache.block_until_all_resources_added(gpu_cache,
|
||||
&mut render_tasks,
|
||||
texture_cache_profile);
|
||||
{
|
||||
profile_marker!("BlockOnResources");
|
||||
|
||||
resource_cache.block_until_all_resources_added(gpu_cache,
|
||||
&mut render_tasks,
|
||||
texture_cache_profile);
|
||||
}
|
||||
|
||||
let mut passes = vec![];
|
||||
|
||||
// Add passes as required for our cached render tasks.
|
||||
if !render_tasks.cacheable_render_tasks.is_empty() {
|
||||
passes.push(RenderPass::new_off_screen(screen_size));
|
||||
for cacheable_render_task in &render_tasks.cacheable_render_tasks {
|
||||
render_tasks.assign_to_passes(
|
||||
*cacheable_render_task,
|
||||
0,
|
||||
screen_size,
|
||||
&mut passes,
|
||||
);
|
||||
}
|
||||
passes.reverse();
|
||||
}
|
||||
|
||||
if let Some(main_render_task_id) = main_render_task_id {
|
||||
let passes_start = passes.len();
|
||||
passes.push(RenderPass::new_main_framebuffer(screen_size));
|
||||
render_tasks.assign_to_passes(
|
||||
main_render_task_id,
|
||||
passes_start,
|
||||
screen_size,
|
||||
&mut passes,
|
||||
);
|
||||
passes[passes_start..].reverse();
|
||||
}
|
||||
|
||||
|
||||
let mut deferred_resolves = vec![];
|
||||
let mut has_texture_cache_tasks = false;
|
||||
let mut prim_headers = PrimitiveHeaders::new();
|
||||
// Used to generated a unique z-buffer value per primitive.
|
||||
let mut z_generator = ZBufferIdGenerator::new();
|
||||
let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
|
||||
self.config.dual_source_blending_is_supported;
|
||||
|
||||
for pass in &mut passes {
|
||||
let mut ctx = RenderTargetContext {
|
||||
device_pixel_scale,
|
||||
prim_store: &self.prim_store,
|
||||
resource_cache,
|
||||
use_dual_source_blending,
|
||||
clip_scroll_tree,
|
||||
data_stores,
|
||||
surfaces: &surfaces,
|
||||
scratch,
|
||||
screen_world_rect,
|
||||
globals: &self.globals,
|
||||
};
|
||||
{
|
||||
profile_marker!("Batching");
|
||||
|
||||
pass.build(
|
||||
&mut ctx,
|
||||
gpu_cache,
|
||||
&mut render_tasks,
|
||||
&mut deferred_resolves,
|
||||
&self.clip_store,
|
||||
&mut transform_palette,
|
||||
&mut prim_headers,
|
||||
&mut z_generator,
|
||||
);
|
||||
|
||||
match pass.kind {
|
||||
RenderPassKind::MainFramebuffer(ref color) => {
|
||||
has_texture_cache_tasks |= color.must_be_drawn();
|
||||
// Add passes as required for our cached render tasks.
|
||||
if !render_tasks.cacheable_render_tasks.is_empty() {
|
||||
passes.push(RenderPass::new_off_screen(screen_size));
|
||||
for cacheable_render_task in &render_tasks.cacheable_render_tasks {
|
||||
render_tasks.assign_to_passes(
|
||||
*cacheable_render_task,
|
||||
0,
|
||||
screen_size,
|
||||
&mut passes,
|
||||
);
|
||||
}
|
||||
RenderPassKind::OffScreen { ref texture_cache, ref color, .. } => {
|
||||
has_texture_cache_tasks |= !texture_cache.is_empty();
|
||||
has_texture_cache_tasks |= color.must_be_drawn();
|
||||
passes.reverse();
|
||||
}
|
||||
|
||||
if let Some(main_render_task_id) = main_render_task_id {
|
||||
let passes_start = passes.len();
|
||||
passes.push(RenderPass::new_main_framebuffer(screen_size));
|
||||
render_tasks.assign_to_passes(
|
||||
main_render_task_id,
|
||||
passes_start,
|
||||
screen_size,
|
||||
&mut passes,
|
||||
);
|
||||
passes[passes_start..].reverse();
|
||||
}
|
||||
|
||||
// Used to generated a unique z-buffer value per primitive.
|
||||
let mut z_generator = ZBufferIdGenerator::new();
|
||||
let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
|
||||
self.config.dual_source_blending_is_supported;
|
||||
|
||||
for pass in &mut passes {
|
||||
let mut ctx = RenderTargetContext {
|
||||
device_pixel_scale,
|
||||
prim_store: &self.prim_store,
|
||||
resource_cache,
|
||||
use_dual_source_blending,
|
||||
clip_scroll_tree,
|
||||
data_stores,
|
||||
surfaces: &surfaces,
|
||||
scratch,
|
||||
screen_world_rect,
|
||||
globals: &self.globals,
|
||||
};
|
||||
|
||||
pass.build(
|
||||
&mut ctx,
|
||||
gpu_cache,
|
||||
&mut render_tasks,
|
||||
&mut deferred_resolves,
|
||||
&self.clip_store,
|
||||
&mut transform_palette,
|
||||
&mut prim_headers,
|
||||
&mut z_generator,
|
||||
);
|
||||
|
||||
match pass.kind {
|
||||
RenderPassKind::MainFramebuffer(ref color) => {
|
||||
has_texture_cache_tasks |= color.must_be_drawn();
|
||||
}
|
||||
RenderPassKind::OffScreen { ref texture_cache, ref color, .. } => {
|
||||
has_texture_cache_tasks |= !texture_cache.is_empty();
|
||||
has_texture_cache_tasks |= color.must_be_drawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ extern crate bitflags;
|
|||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
#[macro_use]
|
||||
extern crate cstr;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
@ -70,6 +72,9 @@ extern crate thread_profiler;
|
|||
extern crate wr_malloc_size_of;
|
||||
use wr_malloc_size_of as malloc_size_of;
|
||||
|
||||
#[macro_use]
|
||||
mod profiler;
|
||||
|
||||
mod batch;
|
||||
mod border;
|
||||
mod box_shadow;
|
||||
|
@ -103,7 +108,6 @@ mod internal_types;
|
|||
mod picture;
|
||||
mod prim_store;
|
||||
mod print_tree;
|
||||
mod profiler;
|
||||
mod record;
|
||||
mod render_backend;
|
||||
mod render_task;
|
||||
|
@ -207,6 +211,7 @@ pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver};
|
|||
pub use device::Device;
|
||||
pub use frame_builder::ChasePrimitive;
|
||||
pub use picture::FRAMES_BEFORE_PICTURE_CACHING;
|
||||
pub use profiler::{ProfilerHooks, set_profiler_hooks};
|
||||
pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
|
||||
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
|
||||
pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};
|
||||
|
|
|
@ -1646,6 +1646,8 @@ impl<'a> PictureUpdateState<'a> {
|
|||
clip_store: &ClipStore,
|
||||
clip_data_store: &ClipDataStore,
|
||||
) {
|
||||
profile_marker!("UpdatePictures");
|
||||
|
||||
let mut state = PictureUpdateState {
|
||||
surfaces,
|
||||
surface_stack: vec![SurfaceIndex(0)],
|
||||
|
|
|
@ -7,9 +7,10 @@ use debug_render::DebugRenderer;
|
|||
use device::query::{GpuSampler, GpuTimer, NamedTag};
|
||||
use euclid::{Point2D, Rect, Size2D, vec2};
|
||||
use internal_types::FastHashMap;
|
||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
||||
use renderer::{MAX_VERTEX_TEXTURE_WIDTH, wr_has_been_initialized};
|
||||
use std::collections::vec_deque::VecDeque;
|
||||
use std::{f32, mem};
|
||||
use std::ffi::CStr;
|
||||
use time::precise_time_ns;
|
||||
|
||||
const GRAPH_WIDTH: f32 = 1024.0;
|
||||
|
@ -20,6 +21,68 @@ const PROFILE_PADDING: f32 = 10.0;
|
|||
|
||||
const ONE_SECOND_NS: u64 = 1000000000;
|
||||
|
||||
/// Defines the interface for hooking up an external profiler to WR.
|
||||
pub trait ProfilerHooks : Send + Sync {
|
||||
/// Called at the beginning of a profile scope. The label must
|
||||
/// be a C string (null terminated).
|
||||
fn begin_marker(&self, label: &CStr);
|
||||
|
||||
/// Called at the end of a profile scope. The label must
|
||||
/// be a C string (null terminated).
|
||||
fn end_marker(&self, label: &CStr);
|
||||
}
|
||||
|
||||
/// The current global profiler callbacks, if set by embedder.
|
||||
static mut PROFILER_HOOKS: Option<&'static ProfilerHooks> = None;
|
||||
|
||||
/// Set the profiler callbacks, or None to disable the profiler.
|
||||
/// This function must only ever be called before any WR instances
|
||||
/// have been created, or the hooks will not be set.
|
||||
pub fn set_profiler_hooks(hooks: Option<&'static ProfilerHooks>) {
|
||||
if !wr_has_been_initialized() {
|
||||
unsafe {
|
||||
PROFILER_HOOKS = hooks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple RAII style struct to manage a profile scope.
|
||||
pub struct ProfileScope {
|
||||
name: &'static CStr,
|
||||
}
|
||||
|
||||
impl ProfileScope {
|
||||
/// Begin a new profile scope
|
||||
pub fn new(name: &'static CStr) -> Self {
|
||||
unsafe {
|
||||
if let Some(ref hooks) = PROFILER_HOOKS {
|
||||
hooks.begin_marker(name);
|
||||
}
|
||||
}
|
||||
|
||||
ProfileScope {
|
||||
name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProfileScope {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if let Some(ref hooks) = PROFILER_HOOKS {
|
||||
hooks.end_marker(self.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper macro to define profile scopes.
|
||||
macro_rules! profile_marker {
|
||||
($string:expr) => {
|
||||
let _scope = $crate::profiler::ProfileScope::new(cstr!($string));
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuProfileTag {
|
||||
pub label: &'static str,
|
||||
|
|
|
@ -1252,7 +1252,7 @@ impl RenderTaskCache {
|
|||
// this in the render task. The renderer will draw this
|
||||
// task into the appropriate layer and rect of the texture
|
||||
// cache on this frame.
|
||||
let (texture_id, texture_layer, uv_rect) =
|
||||
let (texture_id, texture_layer, uv_rect, _) =
|
||||
texture_cache.get_cache_location(&entry.handle);
|
||||
|
||||
render_task.location = RenderTaskLocation::TextureCache {
|
||||
|
|
|
@ -84,6 +84,7 @@ use std::os::raw::c_void;
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::thread;
|
||||
use std::cell::RefCell;
|
||||
|
@ -106,6 +107,14 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Is only false if no WR instances have ever been created.
|
||||
static HAS_BEEN_INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Returns true if a WR instance has ever been initialized in this process.
|
||||
pub fn wr_has_been_initialized() -> bool {
|
||||
HAS_BEEN_INITIALIZED.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
|
||||
/// Enabling this toggle would force the GPU cache scattered texture to
|
||||
/// be resized every frame, which enables GPU debuggers to see if this
|
||||
|
@ -1629,6 +1638,8 @@ impl Renderer {
|
|||
mut options: RendererOptions,
|
||||
shaders: Option<&mut WrShaders>
|
||||
) -> Result<(Self, RenderApiSender), RendererError> {
|
||||
HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
|
||||
|
||||
let (api_tx, api_rx) = channel::msg_channel()?;
|
||||
let (payload_tx, payload_rx) = channel::payload_channel()?;
|
||||
let (result_tx, result_rx) = channel();
|
||||
|
|
|
@ -35,9 +35,9 @@ const TEXTURE_REGION_PIXELS: usize =
|
|||
enum EntryDetails {
|
||||
Standalone,
|
||||
Cache {
|
||||
// Origin within the texture layer where this item exists.
|
||||
/// Origin within the texture layer where this item exists.
|
||||
origin: DeviceIntPoint,
|
||||
// The layer index of the texture array.
|
||||
/// The layer index of the texture array.
|
||||
layer_index: usize,
|
||||
},
|
||||
}
|
||||
|
@ -121,12 +121,8 @@ impl CacheEntry {
|
|||
fn update_gpu_cache(&mut self, gpu_cache: &mut GpuCache) {
|
||||
if let Some(mut request) = gpu_cache.request(&mut self.uv_rect_handle) {
|
||||
let (origin, layer_index) = match self.details {
|
||||
EntryDetails::Standalone { .. } => (DeviceIntPoint::zero(), 0.0),
|
||||
EntryDetails::Cache {
|
||||
origin,
|
||||
layer_index,
|
||||
..
|
||||
} => (origin, layer_index as f32),
|
||||
EntryDetails::Standalone => (DeviceIntPoint::zero(), 0.0),
|
||||
EntryDetails::Cache { origin, layer_index } => (origin, layer_index as f32),
|
||||
};
|
||||
let image_source = ImageSource {
|
||||
p0: origin.to_f32(),
|
||||
|
@ -295,10 +291,9 @@ struct EntryHandles {
|
|||
impl EntryHandles {
|
||||
/// Mutably borrows the requested handle list.
|
||||
fn select(&mut self, kind: EntryKind) -> &mut Vec<FreeListHandle<CacheEntryMarker>> {
|
||||
if kind == EntryKind::Standalone {
|
||||
&mut self.standalone
|
||||
} else {
|
||||
&mut self.shared
|
||||
match kind {
|
||||
EntryKind::Standalone => &mut self.standalone,
|
||||
EntryKind::Shared => &mut self.shared,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -811,12 +806,8 @@ impl TextureCache {
|
|||
// in GPU memory.
|
||||
if let Some(data) = data {
|
||||
let (layer_index, origin) = match entry.details {
|
||||
EntryDetails::Standalone { .. } => (0, DeviceIntPoint::zero()),
|
||||
EntryDetails::Cache {
|
||||
layer_index,
|
||||
origin,
|
||||
..
|
||||
} => (layer_index, origin),
|
||||
EntryDetails::Standalone => (0, DeviceIntPoint::zero()),
|
||||
EntryDetails::Cache { layer_index, origin } => (layer_index, origin),
|
||||
};
|
||||
|
||||
let op = TextureCacheUpdate::new_update(
|
||||
|
@ -844,24 +835,11 @@ impl TextureCache {
|
|||
// This function will assert in debug modes if the caller
|
||||
// tries to get a handle that was not requested this frame.
|
||||
pub fn get(&self, handle: &TextureCacheHandle) -> CacheItem {
|
||||
let entry = self.entries
|
||||
.get_opt(handle)
|
||||
.expect("BUG: was dropped from cache or not updated!");
|
||||
debug_assert_eq!(entry.last_access, self.now);
|
||||
let (layer_index, origin) = match entry.details {
|
||||
EntryDetails::Standalone { .. } => {
|
||||
(0, DeviceIntPoint::zero())
|
||||
}
|
||||
EntryDetails::Cache {
|
||||
layer_index,
|
||||
origin,
|
||||
..
|
||||
} => (layer_index, origin),
|
||||
};
|
||||
let (texture_id, layer_index, uv_rect, uv_rect_handle) = self.get_cache_location(handle);
|
||||
CacheItem {
|
||||
uv_rect_handle: entry.uv_rect_handle,
|
||||
texture_id: TextureSource::TextureCache(entry.texture_id),
|
||||
uv_rect: DeviceIntRect::new(origin, entry.size),
|
||||
uv_rect_handle,
|
||||
texture_id: TextureSource::TextureCache(texture_id),
|
||||
uv_rect,
|
||||
texture_layer: layer_index as i32,
|
||||
}
|
||||
}
|
||||
|
@ -869,11 +847,12 @@ impl TextureCache {
|
|||
/// A more detailed version of get(). This allows access to the actual
|
||||
/// device rect of the cache allocation.
|
||||
///
|
||||
/// Returns a tuple identifying the texture, the layer, and the region.
|
||||
/// Returns a tuple identifying the texture, the layer, the region,
|
||||
/// and its GPU handle.
|
||||
pub fn get_cache_location(
|
||||
&self,
|
||||
handle: &TextureCacheHandle,
|
||||
) -> (CacheTextureId, LayerIndex, DeviceIntRect) {
|
||||
) -> (CacheTextureId, LayerIndex, DeviceIntRect, GpuCacheHandle) {
|
||||
let entry = self.entries
|
||||
.get_opt(handle)
|
||||
.expect("BUG: was dropped from cache or not updated!");
|
||||
|
@ -890,7 +869,8 @@ impl TextureCache {
|
|||
};
|
||||
(entry.texture_id,
|
||||
layer_index as usize,
|
||||
DeviceIntRect::new(origin, entry.size))
|
||||
DeviceIntRect::new(origin, entry.size),
|
||||
entry.uv_rect_handle)
|
||||
}
|
||||
|
||||
pub fn mark_unused(&mut self, handle: &TextureCacheHandle) {
|
||||
|
@ -980,14 +960,11 @@ impl TextureCache {
|
|||
// Free a cache entry from the standalone list or shared cache.
|
||||
fn free(&mut self, entry: CacheEntry) {
|
||||
match entry.details {
|
||||
EntryDetails::Standalone { .. } => {
|
||||
EntryDetails::Standalone => {
|
||||
// This is a standalone texture allocation. Free it directly.
|
||||
self.pending_updates.push_free(entry.texture_id);
|
||||
}
|
||||
EntryDetails::Cache {
|
||||
origin,
|
||||
layer_index,
|
||||
} => {
|
||||
EntryDetails::Cache { origin, layer_index } => {
|
||||
// Free the block in the given region.
|
||||
let texture_array = self.shared_textures.select(entry.format, entry.filter);
|
||||
let region = &mut texture_array.regions[layer_index];
|
||||
|
@ -1202,10 +1179,11 @@ impl TextureCache {
|
|||
// Handle the rare case than an update moves an entry from
|
||||
// shared to standalone or vice versa. This involves a linear
|
||||
// search, but should be rare enough not to matter.
|
||||
let (from, to) = if new_kind == EntryKind::Standalone {
|
||||
(&mut self.doc_data.handles.shared, &mut self.doc_data.handles.standalone)
|
||||
} else {
|
||||
(&mut self.doc_data.handles.standalone, &mut self.doc_data.handles.shared)
|
||||
let (from, to) = match new_kind {
|
||||
EntryKind::Standalone =>
|
||||
(&mut self.doc_data.handles.shared, &mut self.doc_data.handles.standalone),
|
||||
EntryKind::Shared =>
|
||||
(&mut self.doc_data.handles.standalone, &mut self.doc_data.handles.shared),
|
||||
};
|
||||
let idx = from.iter().position(|h| h.weak() == *handle).unwrap();
|
||||
to.push(from.remove(idx));
|
||||
|
|
|
@ -457,6 +457,9 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
|
|||
ipcController = controller.ref().ToIPC();
|
||||
}
|
||||
|
||||
nsAutoString cspNonce;
|
||||
Unused << NS_WARN_IF(NS_FAILED(aLoadInfo->GetCspNonce(cspNonce)));
|
||||
|
||||
*aOptionalLoadInfoArgs = LoadInfoArgs(
|
||||
loadingPrincipalInfo, triggeringPrincipalInfo, principalToInheritInfo,
|
||||
sandboxedLoadingPrincipalInfo, topLevelPrincipalInfo,
|
||||
|
@ -484,7 +487,7 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
|
|||
aLoadInfo->GetIsPreflight(), aLoadInfo->GetLoadTriggeredFromExternal(),
|
||||
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
|
||||
aLoadInfo->GetDocumentHasUserInteracted(),
|
||||
aLoadInfo->GetDocumentHasLoaded(),
|
||||
aLoadInfo->GetDocumentHasLoaded(), cspNonce,
|
||||
aLoadInfo->GetIsFromProcessingFrameAttributes());
|
||||
|
||||
return NS_OK;
|
||||
|
@ -640,7 +643,7 @@ nsresult LoadInfoArgsToLoadInfo(
|
|||
loadInfoArgs.isPreflight(), loadInfoArgs.loadTriggeredFromExternal(),
|
||||
loadInfoArgs.serviceWorkerTaintingSynthesized(),
|
||||
loadInfoArgs.documentHasUserInteracted(),
|
||||
loadInfoArgs.documentHasLoaded());
|
||||
loadInfoArgs.documentHasLoaded(), loadInfoArgs.cspNonce());
|
||||
|
||||
if (loadInfoArgs.isFromProcessingFrameAttributes()) {
|
||||
loadInfo->SetIsFromProcessingFrameAttributes();
|
||||
|
|
|
@ -312,6 +312,11 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver {
|
|||
sIsPumpingMessages = aIsPumping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this MessageChannel cross process boundaries?
|
||||
*/
|
||||
bool IsCrossProcess() const { return mIsCrossProcess; }
|
||||
|
||||
#ifdef OS_WIN
|
||||
struct MOZ_STACK_CLASS SyncStackFrame {
|
||||
SyncStackFrame(MessageChannel* channel, bool interrupt);
|
||||
|
|
|
@ -646,17 +646,9 @@ info needed by later passes, along with a basic name for the decl."""
|
|||
self.ipdltype = ipdltype
|
||||
self.name = name
|
||||
|
||||
def isCopyable(self):
|
||||
return not _cxxTypeNeedsMove(self.ipdltype)
|
||||
|
||||
def var(self):
|
||||
return ExprVar(self.name)
|
||||
|
||||
def mayMoveExpr(self):
|
||||
if self.isCopyable():
|
||||
return self.var()
|
||||
return ExprMove(self.var())
|
||||
|
||||
def bareType(self, side, fq=False):
|
||||
"""Return this decl's unqualified C++ type."""
|
||||
return _cxxBareType(self.ipdltype, side, fq=fq)
|
||||
|
@ -1071,7 +1063,13 @@ class MessageDecl(ipdl.ast.MessageDecl):
|
|||
cxxargs = []
|
||||
|
||||
if paramsems == 'move':
|
||||
cxxargs.extend([p.mayMoveExpr() for p in self.params])
|
||||
# We don't std::move() RefPtr<T> types because current Recv*()
|
||||
# implementors take these parameters as T*, and
|
||||
# std::move(RefPtr<T>) doesn't coerce to T*.
|
||||
cxxargs.extend([
|
||||
p.var() if p.ipdltype.isCxx() and p.ipdltype.isRefcounted() else ExprMove(p.var())
|
||||
for p in self.params
|
||||
])
|
||||
elif paramsems == 'in':
|
||||
cxxargs.extend([p.var() for p in self.params])
|
||||
else:
|
||||
|
|
|
@ -118,13 +118,9 @@ class nsXPCComponents_Interfaces final : public nsIXPCComponents_Interfaces,
|
|||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_Interfaces).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_Interfaces::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Interfaces),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -275,13 +271,9 @@ class nsXPCComponents_Classes final : public nsIXPCComponents_Classes,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_Classes).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_Classes::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Classes),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -432,13 +424,9 @@ class nsXPCComponents_Results final : public nsIXPCComponents_Results,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_Results).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_Results::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Results),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -577,13 +565,9 @@ class nsXPCComponents_ID final : public nsIXPCComponents_ID,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_ID).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_ID::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_ID),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -732,13 +716,9 @@ class nsXPCComponents_Exception final : public nsIXPCComponents_Exception,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_Exception).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_Exception::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Exception),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1027,13 +1007,9 @@ class nsXPCComponents_Constructor final : public nsIXPCComponents_Constructor,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCComponents_Constructor).Clone();
|
||||
array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
nsXPCComponents_Constructor::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Constructor),
|
||||
NS_GET_IID(nsIXPCScriptable)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ bool XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
|
||||
return false;
|
||||
|
||||
case nsXPTType::T_IID: {
|
||||
case nsXPTType::T_NSIDPTR: {
|
||||
nsID* iid2 = *static_cast<nsID* const*>(s);
|
||||
if (!iid2) {
|
||||
d.setNull();
|
||||
|
@ -185,6 +185,9 @@ bool XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
return xpc::ID2JSValue(cx, *iid2, d);
|
||||
}
|
||||
|
||||
case nsXPTType::T_NSID:
|
||||
return xpc::ID2JSValue(cx, *static_cast<const nsID*>(s), d);
|
||||
|
||||
case nsXPTType::T_ASTRING: {
|
||||
const nsAString* p = static_cast<const nsAString*>(s);
|
||||
if (!p || p->IsVoid()) {
|
||||
|
@ -542,13 +545,20 @@ bool XPCConvert::JSData2Native(JSContext* cx, void* d, HandleValue s,
|
|||
NS_ERROR("void* params not supported");
|
||||
return false;
|
||||
|
||||
case nsXPTType::T_IID:
|
||||
case nsXPTType::T_NSIDPTR:
|
||||
if (Maybe<nsID> id = xpc::JSValue2ID(cx, s)) {
|
||||
*((const nsID**)d) = id.ref().Clone();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case nsXPTType::T_NSID:
|
||||
if (Maybe<nsID> id = xpc::JSValue2ID(cx, s)) {
|
||||
*((nsID*)d) = id.ref();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case nsXPTType::T_ASTRING: {
|
||||
nsAString* ws = (nsAString*)d;
|
||||
if (s.isUndefined() || s.isNull()) {
|
||||
|
@ -1615,7 +1625,7 @@ void xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue,
|
|||
break;
|
||||
|
||||
// Pointer Types
|
||||
case nsXPTType::T_IID:
|
||||
case nsXPTType::T_NSIDPTR:
|
||||
case nsXPTType::T_CHAR_STR:
|
||||
case nsXPTType::T_WCHAR_STR:
|
||||
case nsXPTType::T_PSTRING_SIZE_IS:
|
||||
|
@ -1647,6 +1657,11 @@ void xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue,
|
|||
break;
|
||||
}
|
||||
|
||||
// Clear nsID& parameters to `0`
|
||||
case nsXPTType::T_NSID:
|
||||
((nsID*)aValue)->Clear();
|
||||
break;
|
||||
|
||||
// Clear the JS::Value to `undefined`
|
||||
case nsXPTType::T_JSVAL:
|
||||
((JS::Value*)aValue)->setUndefined();
|
||||
|
|
|
@ -71,13 +71,9 @@ BackstagePass::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
|
|||
|
||||
/***************************************************************************/
|
||||
NS_IMETHODIMP
|
||||
BackstagePass::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
|
||||
*aCount = 2;
|
||||
nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
|
||||
*aArray = array;
|
||||
|
||||
array[0] = NS_GET_IID(nsIXPCScriptable).Clone();
|
||||
array[1] = NS_GET_IID(nsIScriptObjectPrincipal).Clone();
|
||||
BackstagePass::GetInterfaces(nsTArray<nsIID>& aArray) {
|
||||
aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCScriptable),
|
||||
NS_GET_IID(nsIScriptObjectPrincipal)};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ bool XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
|
|||
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PWSTRING);
|
||||
break;
|
||||
case tID:
|
||||
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PNSIID);
|
||||
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::NSIDPTR);
|
||||
break;
|
||||
case tISup:
|
||||
*resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE);
|
||||
|
@ -466,7 +466,7 @@ bool XPCVariant::VariantDataToJS(nsIVariant* variant, nsresult* pErr,
|
|||
return false;
|
||||
}
|
||||
nsID* v = &iid;
|
||||
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, {TD_PNSIID},
|
||||
return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, {TD_NSIDPTR},
|
||||
&iid, 0, pErr);
|
||||
}
|
||||
case nsIDataType::VTYPE_ASTRING: {
|
||||
|
@ -612,7 +612,7 @@ bool XPCVariant::VariantDataToJS(nsIVariant* variant, nsresult* pErr,
|
|||
xptIndex = nsXPTType::Idx::WCHAR;
|
||||
break;
|
||||
case nsIDataType::VTYPE_ID:
|
||||
xptIndex = nsXPTType::Idx::PNSIID;
|
||||
xptIndex = nsXPTType::Idx::NSIDPTR;
|
||||
break;
|
||||
case nsIDataType::VTYPE_CHAR_STR:
|
||||
xptIndex = nsXPTType::Idx::PSTRING;
|
||||
|
|
|
@ -559,15 +559,17 @@ bool nsXPCWrappedJSClass::GetInterfaceTypeFromParam(
|
|||
} else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
|
||||
// Get IID from a passed parameter.
|
||||
const nsXPTParamInfo& param = method->Param(inner.ArgNum());
|
||||
if (param.Type().Tag() != nsXPTType::T_IID) {
|
||||
if (param.Type().Tag() != nsXPTType::T_NSID &&
|
||||
param.Type().Tag() != nsXPTType::T_NSIDPTR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void* ptr = nativeParams[inner.ArgNum()].val.p;
|
||||
|
||||
// If the IID is passed indirectly (as an outparam), dereference by an
|
||||
// extra level.
|
||||
if (ptr && param.IsIndirect()) {
|
||||
// If our IID is passed as a pointer outparameter, an extra level of
|
||||
// dereferencing is required.
|
||||
if (ptr && param.Type().Tag() == nsXPTType::T_NSIDPTR &&
|
||||
param.IsIndirect()) {
|
||||
ptr = *(nsID**)ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1262,13 +1262,23 @@ bool CallMethodHelper::GetInterfaceTypeFromParam(const nsXPTType& type,
|
|||
|
||||
*result = inner.GetInterface()->IID();
|
||||
} else if (inner.Tag() == nsXPTType::T_INTERFACE_IS) {
|
||||
nsID* id = (nsID*)GetDispatchParam(inner.ArgNum())->val.p;
|
||||
if (!id) {
|
||||
const nsXPTCVariant* param = GetDispatchParam(inner.ArgNum());
|
||||
if (param->type.Tag() != nsXPTType::T_NSID &&
|
||||
param->type.Tag() != nsXPTType::T_NSIDPTR) {
|
||||
return Throw(NS_ERROR_UNEXPECTED, mCallContext);
|
||||
}
|
||||
|
||||
const void* ptr = ¶m->val;
|
||||
if (param->type.Tag() == nsXPTType::T_NSIDPTR) {
|
||||
ptr = *static_cast<nsID* const*>(ptr);
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
return ThrowBadParam(NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO,
|
||||
inner.ArgNum(), mCallContext);
|
||||
}
|
||||
|
||||
*result = *id;
|
||||
*result = *static_cast<const nsID*>(ptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1499,9 +1509,9 @@ bool CallMethodHelper::ConvertIndependentParam(uint8_t i) {
|
|||
// the default value if IsOptional is true.
|
||||
if (i >= mArgc) {
|
||||
MOZ_ASSERT(paramInfo.IsOptional(), "missing non-optional argument!");
|
||||
if (type.Tag() == nsXPTType::T_IID) {
|
||||
// NOTE: 'const nsIID&' is supported, so it must be allocated.
|
||||
dp->val.p = new nsIID();
|
||||
if (type.Tag() == nsXPTType::T_NSID) {
|
||||
// Use a default value of the null ID for optional NSID objects.
|
||||
dp->ext.nsid.Clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -513,71 +513,50 @@ already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(
|
|||
return set.forget();
|
||||
}
|
||||
|
||||
nsIID** iidArray = nullptr;
|
||||
uint32_t iidCount = 0;
|
||||
|
||||
if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) {
|
||||
AutoTArray<nsIID, 4> iids;
|
||||
if (NS_FAILED(classInfo->GetInterfaces(iids))) {
|
||||
// Note: I'm making it OK for this call to fail so that one can add
|
||||
// nsIClassInfo to classes implemented in script without requiring this
|
||||
// method to be implemented.
|
||||
|
||||
// Make sure these are set correctly...
|
||||
iidArray = nullptr;
|
||||
iidCount = 0;
|
||||
iids.Clear();
|
||||
}
|
||||
|
||||
MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray),
|
||||
"GetInterfaces returned bad array");
|
||||
|
||||
// !!! from here on we only exit through the 'out' label !!!
|
||||
|
||||
if (iidCount) {
|
||||
nsTArray<RefPtr<XPCNativeInterface>> interfaceArray(iidCount);
|
||||
nsIID** currentIID = iidArray;
|
||||
|
||||
for (uint32_t i = 0; i < iidCount; i++) {
|
||||
nsIID* iid = *(currentIID++);
|
||||
if (!iid) {
|
||||
NS_ERROR("Null found in classinfo interface list");
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(iid);
|
||||
|
||||
if (!iface) {
|
||||
// XXX warn here
|
||||
continue;
|
||||
}
|
||||
|
||||
interfaceArray.AppendElement(iface.forget());
|
||||
// Try to look up each IID's XPCNativeInterface object.
|
||||
nsTArray<RefPtr<XPCNativeInterface>> interfaces(iids.Length());
|
||||
for (auto& iid : iids) {
|
||||
RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(&iid);
|
||||
if (iface) {
|
||||
interfaces.AppendElement(iface.forget());
|
||||
}
|
||||
}
|
||||
|
||||
if (interfaceArray.Length() > 0) {
|
||||
set = NewInstance(std::move(interfaceArray));
|
||||
if (set) {
|
||||
NativeSetMap* map2 = xpcrt->GetNativeSetMap();
|
||||
if (!map2) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
XPCNativeSetKey key(set);
|
||||
|
||||
XPCNativeSet* set2 = map2->Add(&key, set);
|
||||
if (!set2) {
|
||||
NS_ERROR("failed to add our set!");
|
||||
set = nullptr;
|
||||
goto out;
|
||||
}
|
||||
// It is okay to find an existing entry here because
|
||||
// we did not look for one before we called Add().
|
||||
if (set2 != set) {
|
||||
set = set2;
|
||||
}
|
||||
// Build a set from the interfaces specified here.
|
||||
if (interfaces.Length() > 0) {
|
||||
set = NewInstance(std::move(interfaces));
|
||||
if (set) {
|
||||
NativeSetMap* map2 = xpcrt->GetNativeSetMap();
|
||||
if (!map2) {
|
||||
return set.forget();
|
||||
}
|
||||
} else
|
||||
set = GetNewOrUsed(&NS_GET_IID(nsISupports));
|
||||
} else
|
||||
|
||||
XPCNativeSetKey key(set);
|
||||
XPCNativeSet* set2 = map2->Add(&key, set);
|
||||
if (!set2) {
|
||||
NS_ERROR("failed to add our set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It is okay to find an existing entry here because
|
||||
// we did not look for one before we called Add().
|
||||
if (set2 != set) {
|
||||
set = set2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set = GetNewOrUsed(&NS_GET_IID(nsISupports));
|
||||
}
|
||||
|
||||
if (set) {
|
||||
#ifdef DEBUG
|
||||
|
@ -588,11 +567,6 @@ already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(
|
|||
MOZ_ASSERT(set2 == set, "hashtables inconsistent!");
|
||||
}
|
||||
|
||||
out:
|
||||
if (iidArray) {
|
||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
|
||||
}
|
||||
|
||||
return set.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -2896,7 +2896,7 @@ nsIPrincipal* GetObjectPrincipal(JSObject* obj);
|
|||
// a pointer to a value described by the type `nsXPTType`.
|
||||
//
|
||||
// This method expects a value of the following types:
|
||||
// TD_PNSIID
|
||||
// TD_NSIDPTR
|
||||
// value : nsID* (free)
|
||||
// TD_ASTRING, TD_CSTRING, TD_UTF8STRING
|
||||
// value : ns[C]String* (truncate)
|
||||
|
|
|
@ -59,11 +59,7 @@ BlobComponent.prototype =
|
|||
// nsIClassInfo
|
||||
flags: 0,
|
||||
|
||||
getInterfaces: function getInterfaces(aCount) {
|
||||
var interfaces = [Ci.nsIClassInfo];
|
||||
aCount.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
interfaces: [Ci.nsIClassInfo],
|
||||
|
||||
getScriptableHelper: function getScriptableHelper() {
|
||||
return null;
|
||||
|
|
|
@ -90,11 +90,7 @@ FileComponent.prototype =
|
|||
// nsIClassInfo
|
||||
flags: 0,
|
||||
|
||||
getInterfaces: function getInterfaces(aCount) {
|
||||
var interfaces = [Ci.nsIClassInfo];
|
||||
aCount.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
interfaces: [Ci.nsIClassInfo],
|
||||
|
||||
getScriptableHelper: function getScriptableHelper() {
|
||||
return null;
|
||||
|
|
|
@ -17,9 +17,8 @@ FooComponent.prototype =
|
|||
// nsIClassInfo
|
||||
flags: 0,
|
||||
|
||||
getInterfaces: function getInterfaces(aCount) {
|
||||
get interfaces() {
|
||||
var interfaces = [Ci.nsIClassInfo];
|
||||
aCount.value = interfaces.length;
|
||||
|
||||
// Guerilla test for line numbers hiding in this method
|
||||
var threw = true;
|
||||
|
@ -27,7 +26,7 @@ FooComponent.prototype =
|
|||
thereIsNoSuchIdentifier;
|
||||
threw = false;
|
||||
} catch (ex) {
|
||||
Assert.ok(ex.lineNumber == 27);
|
||||
Assert.ok(ex.lineNumber == 26);
|
||||
}
|
||||
Assert.ok(threw);
|
||||
|
||||
|
@ -60,11 +59,7 @@ BarComponent.prototype =
|
|||
// nsIClassInfo
|
||||
flags: 0,
|
||||
|
||||
getInterfaces: function getInterfaces(aCount) {
|
||||
var interfaces = [Ci.nsIClassInfo];
|
||||
aCount.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
interfaces: [Ci.nsIClassInfo],
|
||||
|
||||
getScriptableHelper: function getScriptableHelper() {
|
||||
return null;
|
||||
|
|
|
@ -75,10 +75,10 @@ function run_test() {
|
|||
|
||||
// Call getInterfaces to test line numbers in JS components. But as long as
|
||||
// we're doing that, why not test what it returns too?
|
||||
// Kind of odd that this is not returning an array containing the
|
||||
// number... Or for that matter not returning an array containing an object?
|
||||
var interfaces = foo.getInterfaces({});
|
||||
Assert.equal(interfaces, Ci.nsIClassInfo.number);
|
||||
var interfaces = foo.interfaces;
|
||||
Assert.ok(Array.isArray(interfaces));
|
||||
Assert.equal(interfaces.length, 1);
|
||||
Assert.ok(interfaces[0].equals(Ci.nsIClassInfo))
|
||||
|
||||
// try to create another component which doesn't directly implement QI
|
||||
Assert.ok((contractID + "2") in Cc);
|
||||
|
|
|
@ -380,9 +380,14 @@ bool nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState,
|
|||
? mHelper.mMinimumScaleSize
|
||||
: aState->mInsideBorderSize;
|
||||
|
||||
nsSize scrollPortSize =
|
||||
const nsSize scrollPortSize =
|
||||
nsSize(std::max(0, layoutSize.width - vScrollbarDesiredWidth),
|
||||
std::max(0, layoutSize.height - hScrollbarDesiredHeight));
|
||||
if (mHelper.mIsUsingMinimumScaleSize) {
|
||||
mHelper.mICBSize =
|
||||
nsSize(std::max(0, aState->mInsideBorderSize.width - vScrollbarDesiredWidth),
|
||||
std::max(0, aState->mInsideBorderSize.height - hScrollbarDesiredHeight));
|
||||
}
|
||||
|
||||
nsSize visualViewportSize = scrollPortSize;
|
||||
nsIPresShell* presShell = PresShell();
|
||||
|
|
|
@ -195,6 +195,12 @@ class ScrollFrameHelper : public nsIReflowCallback {
|
|||
*/
|
||||
void UpdateScrollbarPosition();
|
||||
|
||||
nsSize GetLayoutSize() const {
|
||||
if (mIsUsingMinimumScaleSize) {
|
||||
return mICBSize;
|
||||
}
|
||||
return mScrollPort.Size();
|
||||
}
|
||||
nsRect GetScrollPortRect() const { return mScrollPort; }
|
||||
nsPoint GetScrollPosition() const {
|
||||
return mScrollPort.TopLeft() - mScrolledFrame->GetPosition();
|
||||
|
@ -563,6 +569,10 @@ class ScrollFrameHelper : public nsIReflowCallback {
|
|||
nsRect mScrollPort;
|
||||
nsSize mMinimumScaleSize;
|
||||
|
||||
// Stores the ICB size for the root document if this frame is using the
|
||||
// minimum scale size for |mScrollPort|.
|
||||
nsSize mICBSize;
|
||||
|
||||
// Where we're currently scrolling to, if we're scrolling asynchronously.
|
||||
// If we're not in the middle of an asynchronous scroll then this is
|
||||
// just the current scroll position. ScrollBy will choose its
|
||||
|
@ -888,6 +898,9 @@ class nsHTMLScrollFrame : public nsContainerFrame,
|
|||
nsBoxLayoutState bls(aPresContext, aRC, 0);
|
||||
return mHelper.GetNondisappearingScrollbarWidth(&bls, aWM);
|
||||
}
|
||||
virtual nsSize GetLayoutSize() const override {
|
||||
return mHelper.GetLayoutSize();
|
||||
}
|
||||
virtual nsRect GetScrolledRect() const override {
|
||||
return mHelper.GetScrolledRect();
|
||||
}
|
||||
|
@ -1362,6 +1375,9 @@ class nsXULScrollFrame final : public nsBoxFrame,
|
|||
nsBoxLayoutState bls(aPresContext, aRC, 0);
|
||||
return mHelper.GetNondisappearingScrollbarWidth(&bls, aWM);
|
||||
}
|
||||
virtual nsSize GetLayoutSize() const override {
|
||||
return mHelper.GetLayoutSize();
|
||||
}
|
||||
virtual nsRect GetScrolledRect() const override {
|
||||
return mHelper.GetScrolledRect();
|
||||
}
|
||||
|
|
|
@ -110,6 +110,15 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
|
|||
virtual nscoord GetNondisappearingScrollbarWidth(
|
||||
nsPresContext* aPresContext, gfxContext* aRC,
|
||||
mozilla::WritingMode aWM) = 0;
|
||||
/**
|
||||
* Get the layout size of this frame.
|
||||
* Note that this is a value which is not expanded by the minimum scale size.
|
||||
* For scroll frames other than the root content document's scroll frame, this
|
||||
* value will be the same as GetScrollPortRect().Size().
|
||||
*
|
||||
* This value is used for Element.clientWidth and clientHeight.
|
||||
*/
|
||||
virtual nsSize GetLayoutSize() const = 0;
|
||||
/**
|
||||
* GetScrolledRect is designed to encapsulate deciding which
|
||||
* directions of overflow should be reachable by scrolling and which
|
||||
|
|
|
@ -858,6 +858,16 @@ nsresult Loader::CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
|
|||
aLoadingPrincipal, aTriggeringPrincipal, aRequestingNode,
|
||||
nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, contentPolicyType);
|
||||
|
||||
// snapshot the nonce at load start time for performing CSP checks
|
||||
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aRequestingNode);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
nsAutoString cspNonce;
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
|
||||
secCheckLoadInfo->SetCspNonce(cspNonce);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsresult rv = NS_CheckContentLoadPolicy(
|
||||
aTargetURI, secCheckLoadInfo, NS_LITERAL_CSTRING("text/css"), &shouldLoad,
|
||||
|
@ -1310,6 +1320,18 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// snapshot the nonce at load start time for performing CSP checks
|
||||
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
|
||||
nsCOMPtr<Element> element =
|
||||
do_QueryInterface(aLoadData->mRequestingNode);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
nsAutoString cspNonce;
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
loadInfo->SetCspNonce(cspNonce);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = channel->Open(getter_AddRefs(stream));
|
||||
|
||||
|
@ -1438,6 +1460,17 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// snapshot the nonce at load start time for performing CSP checks
|
||||
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
|
||||
if (element && element->IsHTMLElement()) {
|
||||
nsAutoString cspNonce;
|
||||
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
loadInfo->SetCspNonce(cspNonce);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aLoadData->ShouldDefer()) {
|
||||
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
|
||||
if (cos) {
|
||||
|
|
|
@ -136,9 +136,8 @@ nsJARURI::Write(nsIObjectOutputStream *aOutputStream) {
|
|||
// nsIClassInfo methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetInterfaces(uint32_t *count, nsIID ***array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
nsJARURI::GetInterfaces(nsTArray<nsIID> &array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -478,6 +478,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
|
|||
mServiceWorkerTaintingSynthesized(false),
|
||||
mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted),
|
||||
mDocumentHasLoaded(rhs.mDocumentHasLoaded),
|
||||
mCspNonce(rhs.mCspNonce),
|
||||
mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes) {}
|
||||
|
||||
LoadInfo::LoadInfo(
|
||||
|
@ -510,7 +511,7 @@ LoadInfo::LoadInfo(
|
|||
const nsTArray<nsCString>& aCorsUnsafeHeaders, bool aForcePreflight,
|
||||
bool aIsPreflight, bool aLoadTriggeredFromExternal,
|
||||
bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted,
|
||||
bool aDocumentHasLoaded)
|
||||
bool aDocumentHasLoaded, const nsAString& aCspNonce)
|
||||
: mLoadingPrincipal(aLoadingPrincipal),
|
||||
mTriggeringPrincipal(aTriggeringPrincipal),
|
||||
mPrincipalToInherit(aPrincipalToInherit),
|
||||
|
@ -556,6 +557,7 @@ LoadInfo::LoadInfo(
|
|||
mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized),
|
||||
mDocumentHasUserInteracted(aDocumentHasUserInteracted),
|
||||
mDocumentHasLoaded(aDocumentHasLoaded),
|
||||
mCspNonce(aCspNonce),
|
||||
mIsFromProcessingFrameAttributes(false) {
|
||||
// Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
|
||||
MOZ_ASSERT(mLoadingPrincipal ||
|
||||
|
@ -1254,6 +1256,20 @@ LoadInfo::SetDocumentHasLoaded(bool aDocumentHasLoaded) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetCspNonce(nsAString& aCspNonce) {
|
||||
aCspNonce = mCspNonce;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetCspNonce(const nsAString& aCspNonce) {
|
||||
MOZ_ASSERT(!mInitialSecurityCheckDone,
|
||||
"setting the nonce is only allowed before any sec checks");
|
||||
mCspNonce = aCspNonce;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsTopLevelLoad(bool* aResult) {
|
||||
*aResult = mFrameOuterWindowID ? mFrameOuterWindowID == mOuterWindowID
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
|
||||
#include "nsIURI.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
|
@ -121,7 +122,8 @@ class LoadInfo final : public nsILoadInfo {
|
|||
const nsTArray<nsCString>& aUnsafeHeaders, bool aForcePreflight,
|
||||
bool aIsPreflight, bool aLoadTriggeredFromExternal,
|
||||
bool aServiceWorkerTaintingSynthesized,
|
||||
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded);
|
||||
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded,
|
||||
const nsAString& aCspNonce);
|
||||
LoadInfo(const LoadInfo& rhs);
|
||||
|
||||
NS_IMETHOD GetRedirects(JSContext* aCx,
|
||||
|
@ -198,6 +200,7 @@ class LoadInfo final : public nsILoadInfo {
|
|||
bool mServiceWorkerTaintingSynthesized;
|
||||
bool mDocumentHasUserInteracted;
|
||||
bool mDocumentHasLoaded;
|
||||
nsString mCspNonce;
|
||||
|
||||
// Is true if this load was triggered by processing the attributes of the
|
||||
// browsing context container.
|
||||
|
|
|
@ -1047,6 +1047,14 @@ interface nsILoadInfo : nsISupports
|
|||
*/
|
||||
[infallible] attribute boolean documentHasLoaded;
|
||||
|
||||
/**
|
||||
* A snapshot of the nonce at load start time which is used for CSP
|
||||
* checks and only set for:
|
||||
* * TYPE_SCRIPT and
|
||||
* * TYPE_STYLESHEET
|
||||
*/
|
||||
attribute AString cspNonce;
|
||||
|
||||
/**
|
||||
* The object in charged to receive CSP violation events. It can be null.
|
||||
* This attribute will be merged into the CSP object eventually.
|
||||
|
|
|
@ -607,9 +607,8 @@ nsSimpleURI::GetAsciiHost(nsACString &result) {
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSimpleURI::GetInterfaces(uint32_t *count, nsIID ***array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
nsSimpleURI::GetInterfaces(nsTArray<nsIID> &array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2944,8 +2944,8 @@ nsSocketTransport::GetInterface(const nsIID &iid, void **result) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetInterfaces(uint32_t *count, nsIID ***array) {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsSocketTransport)(count, array);
|
||||
nsSocketTransport::GetInterfaces(nsTArray<nsIID>& array) {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsSocketTransport)(array);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -3447,9 +3447,8 @@ bool nsStandardURL::Deserialize(const URIParams &aParams) {
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStandardURL::GetInterfaces(uint32_t *count, nsIID ***array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
nsStandardURL::GetInterfaces(nsTArray<nsIID> &array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ struct LoadInfoArgs
|
|||
bool serviceWorkerTaintingSynthesized;
|
||||
bool documentHasUserInteracted;
|
||||
bool documentHasLoaded;
|
||||
nsString cspNonce;
|
||||
bool isFromProcessingFrameAttributes;
|
||||
};
|
||||
|
||||
|
|
|
@ -516,9 +516,8 @@ TransportSecurityInfo::Read(nsIObjectInputStream* aStream) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TransportSecurityInfo::GetInterfaces(uint32_t* count, nsIID*** array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
TransportSecurityInfo::GetInterfaces(nsTArray<nsIID>& array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1227,9 +1227,8 @@ nsNSSCertificate::Read(nsIObjectInputStream* aStream) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array) {
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
nsNSSCertificate::GetInterfaces(nsTArray<nsIID>& array) {
|
||||
array.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ class AsyncStatementClassInfo : public nsIClassInfo {
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
GetInterfaces(uint32_t *_count, nsIID ***_array) override {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(AsyncStatement)(_count, _array);
|
||||
GetInterfaces(nsTArray<nsIID> &_array) override {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(AsyncStatement)(_array);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
|
|
@ -47,8 +47,8 @@ class StatementClassInfo : public nsIClassInfo {
|
|||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
GetInterfaces(uint32_t *_count, nsIID ***_array) override {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
|
||||
GetInterfaces(nsTArray<nsIID> &_array) override {
|
||||
return NS_CI_INTERFACE_GETTER_NAME(Statement)(_array);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
|
|
@ -104,6 +104,7 @@ mochitest-browser-chrome:
|
|||
by-test-platform:
|
||||
linux64-.*cov/opt: 7200
|
||||
windows10-64-ccov/debug: 7200
|
||||
windows10-aarch64/*: 7200
|
||||
macosx64-ccov/debug: 10800
|
||||
linux.*/debug: 5400
|
||||
default: 3600
|
||||
|
|
|
@ -291,10 +291,12 @@ talos-xperf:
|
|||
run-as-administrator:
|
||||
by-test-platform:
|
||||
windows7-32.*: false
|
||||
windows10-aarch64.*: false
|
||||
windows10-64.*: true
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows7-32(-pgo)?/.*: ['mozilla-beta', 'trunk', 'try']
|
||||
windows10-aarch64/opt: []
|
||||
windows10-64.*/opt: ['mozilla-beta', 'trunk', 'try']
|
||||
default: []
|
||||
tier:
|
||||
|
|
|
@ -205,6 +205,18 @@ windows10-64/opt:
|
|||
- mochitest-headless
|
||||
- raptor-firefox
|
||||
|
||||
# windows10-aarch64/opt:
|
||||
# build-platform: win64-aarch64/opt
|
||||
# test-sets:
|
||||
# - awsy
|
||||
# - desktop-screenshot-capture
|
||||
# - windows-talos
|
||||
# - marionette-gpu-tests
|
||||
# - windows-tests
|
||||
# - web-platform-tests
|
||||
# - mochitest-headless
|
||||
# - raptor-firefox
|
||||
|
||||
windows10-64-ux/opt:
|
||||
build-platform: win64-nightly/opt
|
||||
test-sets:
|
||||
|
|
|
@ -35,6 +35,7 @@ web-platform-tests:
|
|||
macosx64.*/opt: 8
|
||||
macosx64/debug: 16
|
||||
windows10.*/debug: 18
|
||||
windows10-aarch64/opt: 12
|
||||
macosx64-ccov/debug: 24
|
||||
default: 12
|
||||
max-run-time:
|
||||
|
@ -49,6 +50,7 @@ web-platform-tests:
|
|||
run-on-projects:
|
||||
by-test-platform:
|
||||
android.*: ['mozilla-central', 'try']
|
||||
windows10-aarch64/opt: ['try', 'mozilla-central']
|
||||
.*-qr/.*: ['release', 'try'] # skip on integration branches due to high load
|
||||
default: built-projects
|
||||
tier:
|
||||
|
@ -104,6 +106,7 @@ web-platform-tests-reftests:
|
|||
run-on-projects:
|
||||
by-test-platform:
|
||||
android.*: ['mozilla-central', 'try']
|
||||
windows10-aarch64/opt: ['try', 'mozilla-central']
|
||||
linux64-qr/.*: ['release', 'try'] # skip on integration branches due to high load
|
||||
default: built-projects
|
||||
tier:
|
||||
|
@ -151,6 +154,7 @@ web-platform-tests-wdspec:
|
|||
- --test-type=wdspec
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-aarch64/opt: ['try', 'mozilla-central']
|
||||
android.*: ['mozilla-central', 'try']
|
||||
.*-qr/.*: ['release', 'try'] # skip on integration branches due to high load
|
||||
default: built-projects
|
||||
|
|
|
@ -23,6 +23,7 @@ job-defaults:
|
|||
requires-signed-builds:
|
||||
by-test-platform:
|
||||
windows10-64-asan/opt: false # No XPCShell on ASAN yet
|
||||
windows10-aarch64/*: false # No signing on arm64
|
||||
windows.*: true
|
||||
default: false
|
||||
|
||||
|
@ -33,6 +34,7 @@ xpcshell:
|
|||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-asan/opt: [] # No XPCShell on ASAN yet
|
||||
windows10-aarch64/opt: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
chunks:
|
||||
by-test-platform:
|
||||
|
@ -41,6 +43,7 @@ xpcshell:
|
|||
android-em-4.3-arm7-api-16/debug: 12
|
||||
macosx.*: 1
|
||||
windows.*: 1
|
||||
windows10-aarch64/opt: 8
|
||||
windows10-64-ccov/debug: 8
|
||||
macosx64-ccov/debug: 8
|
||||
default: 8
|
||||
|
|
|
@ -77,6 +77,11 @@ WINDOWS_WORKER_TYPES = {
|
|||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows10-aarch64': {
|
||||
'virtual': 'test-provisioner/bitbar',
|
||||
'virtual-with-gpu': 'test-provisioner/bitbar',
|
||||
'hardware': 'test-provisioner/bitbar',
|
||||
},
|
||||
'windows10-64-ccov': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win10-64',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu',
|
||||
|
@ -583,6 +588,7 @@ def set_treeherder_machine_platform(config, tests):
|
|||
'macosx64/debug': 'osx-10-10/debug',
|
||||
'macosx64/opt': 'osx-10-10/opt',
|
||||
'win64-asan/opt': 'windows10-64/asan',
|
||||
'win64-aarch64/opt': 'windows10-aarch64/opt',
|
||||
'win32-pgo/opt': 'windows7-32/pgo',
|
||||
'win64-pgo/opt': 'windows10-64/pgo',
|
||||
# The build names for Android platforms have partially evolved over the
|
||||
|
@ -644,6 +650,7 @@ def set_tier(config, tests):
|
|||
'windows7-32-pgo/opt',
|
||||
'windows7-32-devedition/opt',
|
||||
'windows7-32-nightly/opt',
|
||||
'windows10-aarch64/opt',
|
||||
'windows10-64/debug',
|
||||
'windows10-64/opt',
|
||||
'windows10-64-pgo/opt',
|
||||
|
|
|
@ -34,6 +34,7 @@ WORKER_TYPES = {
|
|||
'aws-provisioner-v1/gecko-t-win7-32': ('generic-worker', 'windows'),
|
||||
'aws-provisioner-v1/gecko-t-win7-32-gpu': ('generic-worker', 'windows'),
|
||||
'releng-hardware/gecko-t-win7-32-hw': ('generic-worker', 'windows'),
|
||||
'test-provisioner/bitbar': ('generic-worker', 'windows'),
|
||||
'aws-provisioner-v1/taskcluster-generic': ('docker-worker', 'linux'),
|
||||
'invalid/invalid': ('invalid', None),
|
||||
'invalid/always-optimized': ('always-optimized', None),
|
||||
|
|
|
@ -724,7 +724,7 @@ class AndroidEmulator(object):
|
|||
if not self.substs['TARGET_CPU'].startswith('arm'):
|
||||
return 'x86-7.0'
|
||||
else:
|
||||
return '7.0'
|
||||
return '4.3'
|
||||
return 'x86-7.0'
|
||||
|
||||
|
||||
|
|
|
@ -132,10 +132,6 @@ class RaptorRunner(MozbuildObject):
|
|||
'title': socket.gethostname(),
|
||||
'default_actions': default_actions,
|
||||
'raptor_cmd_line_args': self.raptor_args,
|
||||
'python3_manifest': {
|
||||
'win32': 'python3.manifest',
|
||||
'win64': 'python3_x64.manifest',
|
||||
},
|
||||
'host': self.host,
|
||||
'power_test': self.power_test,
|
||||
'is_release_build': self.is_release_build,
|
||||
|
|
|
@ -19,7 +19,7 @@ required_settings = ['apps', 'type', 'page_cycles', 'test_url', 'measure',
|
|||
'unit', 'lower_is_better', 'alert_threshold']
|
||||
|
||||
playback_settings = ['playback_binary_manifest', 'playback_pageset_manifest',
|
||||
'playback_recordings', 'python3_win_manifest']
|
||||
'playback_recordings']
|
||||
|
||||
|
||||
def filter_app(tests, values):
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"size": 13576786,
|
||||
"visibility": "public",
|
||||
"digest": "5d471e470369381f130de28a3c54db27c3724e1e9269c510a593d61c4cf41713c9424da62e46ae98fd1decce00ecca876209ed059487f5a02882ba16a50daed1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "mitmdump-win-2.0.2.zip",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
|
@ -12,6 +12,7 @@ import time
|
|||
import mozinfo
|
||||
|
||||
from mozlog import get_proxy_logger
|
||||
from mozprocess import ProcessHandler
|
||||
|
||||
from .base import Playback
|
||||
|
||||
|
@ -27,11 +28,6 @@ else:
|
|||
mozharness_dir = os.path.join(here, '../../../mozharness')
|
||||
sys.path.insert(0, mozharness_dir)
|
||||
|
||||
# required for using a python3 virtualenv on win for mitmproxy
|
||||
from mozharness.base.python import Python3Virtualenv
|
||||
from mozharness.mozilla.testing.testbase import TestingMixin
|
||||
from mozharness.base.vcs.vcsbase import MercurialScript
|
||||
|
||||
raptor_dir = os.path.join(here, '..')
|
||||
sys.path.insert(0, raptor_dir)
|
||||
|
||||
|
@ -79,7 +75,7 @@ POLICIES_CONTENT_OFF = '''{
|
|||
}'''
|
||||
|
||||
|
||||
class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
||||
class Mitmproxy(Playback):
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
@ -106,10 +102,6 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
|||
# go ahead and download and setup mitmproxy
|
||||
self.download()
|
||||
|
||||
# on windows we must use a python3 virtualen for mitmproxy
|
||||
if 'win' in self.config['platform']:
|
||||
self.setup_py3_virtualenv()
|
||||
|
||||
# mitmproxy must be started before setup, so that the CA cert is available
|
||||
self.start()
|
||||
self.setup()
|
||||
|
@ -119,16 +111,10 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
|||
if not os.path.exists(self.raptor_dir):
|
||||
os.makedirs(self.raptor_dir)
|
||||
|
||||
if 'win' in self.config['platform']:
|
||||
# on windows we need a python3 environment and use our own package from tooltool
|
||||
self.py3_path = self.fetch_python3()
|
||||
LOG.info("python3 path is: %s" % self.py3_path)
|
||||
else:
|
||||
# on osx and linux we use pre-built binaries
|
||||
LOG.info("downloading mitmproxy binary")
|
||||
_manifest = os.path.join(here, self.config['playback_binary_manifest'])
|
||||
transformed_manifest = transform_platform(_manifest, self.config['platform'])
|
||||
tooltool_download(transformed_manifest, self.config['run_local'], self.raptor_dir)
|
||||
LOG.info("downloading mitmproxy binary")
|
||||
_manifest = os.path.join(here, self.config['playback_binary_manifest'])
|
||||
transformed_manifest = transform_platform(_manifest, self.config['platform'])
|
||||
tooltool_download(transformed_manifest, self.config['run_local'], self.raptor_dir)
|
||||
|
||||
# we use one pageset for all platforms
|
||||
LOG.info("downloading mitmproxy pageset")
|
||||
|
@ -137,44 +123,10 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
|||
tooltool_download(transformed_manifest, self.config['run_local'], self.raptor_dir)
|
||||
return
|
||||
|
||||
def fetch_python3(self):
|
||||
"""Mitmproxy on windows needs Python 3.x"""
|
||||
python3_path = os.path.join(self.raptor_dir, 'python3.6', 'python')
|
||||
if not os.path.exists(os.path.dirname(python3_path)):
|
||||
_manifest = os.path.join(here, self.config['python3_win_manifest'])
|
||||
transformed_manifest = transform_platform(_manifest, self.config['platform'],
|
||||
self.config['processor'])
|
||||
LOG.info("downloading py3 package for mitmproxy windows: %s" % transformed_manifest)
|
||||
tooltool_download(transformed_manifest, self.config['run_local'], self.raptor_dir)
|
||||
cmd = [python3_path, '--version']
|
||||
# just want python3 ver printed in production log
|
||||
subprocess.Popen(cmd, env=os.environ.copy())
|
||||
return python3_path
|
||||
|
||||
def setup_py3_virtualenv(self):
|
||||
"""Mitmproxy on windows needs Python 3.x; set up a separate py 3.x env here"""
|
||||
LOG.info("Setting up python 3.x virtualenv, required for mitmproxy on windows")
|
||||
# these next two are required for py3_venv_configuration
|
||||
self.abs_dirs = {'base_work_dir': mozharness_dir}
|
||||
self.log_obj = None
|
||||
# now create the py3 venv
|
||||
venv_path = os.path.join(self.raptor_dir, 'py3venv')
|
||||
self.py3_venv_configuration(python_path=self.py3_path, venv_path=venv_path)
|
||||
self.py3_create_venv()
|
||||
self.py3_install_modules(["cffi==1.10.0"])
|
||||
requirements = [os.path.join(here, "mitmproxy_requirements.txt")]
|
||||
self.py3_install_requirement_files(requirements)
|
||||
# add py3 executables path to system path
|
||||
sys.path.insert(1, self.py3_path_to_executables())
|
||||
# install mitmproxy itself
|
||||
self.py3_install_modules(modules=['mitmproxy'])
|
||||
self.mitmdump_path = os.path.join(self.py3_path_to_executables(), 'mitmdump')
|
||||
|
||||
def start(self):
|
||||
"""Start playing back the mitmproxy recording. If on windows, the mitmdump_path was
|
||||
already set when creating py3 env"""
|
||||
if self.mitmdump_path is None:
|
||||
self.mitmdump_path = os.path.join(self.raptor_dir, 'mitmdump')
|
||||
"""Start playing back the mitmproxy recording."""
|
||||
|
||||
self.mitmdump_path = os.path.join(self.raptor_dir, 'mitmdump')
|
||||
|
||||
recordings_list = self.recordings.split()
|
||||
self.mitmproxy_proc = self.start_mitmproxy_playback(self.mitmdump_path,
|
||||
|
@ -228,7 +180,9 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
|||
LOG.info("Starting mitmproxy playback using command: %s" % ' '.join(command))
|
||||
# to turn off mitmproxy log output, use these params for Popen:
|
||||
# Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
|
||||
mitmproxy_proc = subprocess.Popen(command, env=env)
|
||||
mitmproxy_proc = ProcessHandler(command, env=env)
|
||||
mitmproxy_proc.run()
|
||||
|
||||
time.sleep(MITMDUMP_SLEEP)
|
||||
data = mitmproxy_proc.poll()
|
||||
if data is None: # None value indicates process hasn't terminated
|
||||
|
@ -242,10 +196,8 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
|
|||
"""Stop the mitproxy server playback"""
|
||||
mitmproxy_proc = self.mitmproxy_proc
|
||||
LOG.info("Stopping mitmproxy playback, klling process %d" % mitmproxy_proc.pid)
|
||||
if mozinfo.os == 'win':
|
||||
mitmproxy_proc.kill()
|
||||
else:
|
||||
mitmproxy_proc.terminate()
|
||||
mitmproxy_proc.kill()
|
||||
|
||||
time.sleep(MITMDUMP_SLEEP)
|
||||
status = mitmproxy_proc.poll()
|
||||
if status is None: # None value indicates process hasn't terminated
|
||||
|
@ -334,8 +286,8 @@ class MitmproxyDesktop(Mitmproxy):
|
|||
LOG.info("Firefox policies file contents:")
|
||||
LOG.info(contents)
|
||||
if (POLICIES_CONTENT_ON % {
|
||||
'cert': self.cert_path,
|
||||
'host': self.config['host']}) in contents:
|
||||
'cert': self.cert_path,
|
||||
'host': self.config['host']}) in contents:
|
||||
LOG.info("Verified mitmproxy CA certificate is installed in Firefox")
|
||||
else:
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"size": 15380470,
|
||||
"visibility": "public",
|
||||
"digest": "cd78b88d95b69bef99d7192b71dd34118700f44db0a0069a13bfd4943b131e8d7fdac83859f8ac15d873d4b329eef69d8d75d0a6746d06fdcfc5d06da0c9784c",
|
||||
"algorithm": "sha512",
|
||||
"unpack": true,
|
||||
"filename": "python3.6.zip"
|
||||
}
|
||||
]
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"size": 16026760,
|
||||
"visibility": "public",
|
||||
"digest": "379428e3955671213a245ccd9ccf6f9d17d368db68c02da8baed7be629f2691127cd3e3f86807b25e2098d9840083fdc07946ab1bed0c14db4a5b628a47ed9ef",
|
||||
"algorithm": "sha512",
|
||||
"unpack": true,
|
||||
"filename": "python3.6.amd64.zip"
|
||||
}
|
||||
]
|
|
@ -171,7 +171,6 @@ class Raptor(object):
|
|||
_key = 'playback_pageset_zip_%s' % self.config['platform']
|
||||
self.config['playback_pageset_zip'] = test.get(_key, None)
|
||||
self.config['playback_recordings'] = test.get('playback_recordings', None)
|
||||
self.config['python3_win_manifest'] = test.get('python3_win_manifest', None)
|
||||
|
||||
def run_test(self, test, timeout=None):
|
||||
self.log.info("starting raptor test: %s" % test['name'])
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
type = pageload
|
||||
playback = mitmproxy
|
||||
playback_binary_manifest = mitmproxy-rel-bin-{platform}.manifest
|
||||
python3_win_manifest = python3{x64}.manifest
|
||||
playback_pageset_manifest = mitmproxy-recordings-raptor-tp6-1.manifest
|
||||
page_cycles = 25
|
||||
unit = ms
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
type = pageload
|
||||
playback = mitmproxy
|
||||
playback_binary_manifest = mitmproxy-rel-bin-{platform}.manifest
|
||||
python3_win_manifest = python3{x64}.manifest
|
||||
page_cycles = 25
|
||||
unit = ms
|
||||
lower_is_better = true
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
type = pageload
|
||||
playback = mitmproxy
|
||||
playback_binary_manifest = mitmproxy-rel-bin-{platform}.manifest
|
||||
python3_win_manifest = python3{x64}.manifest
|
||||
playback_pageset_manifest = mitmproxy-recordings-raptor-tp6-2.manifest
|
||||
page_cycles = 25
|
||||
unit = ms
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче