Merge autoland to mozilla-central. a=merge

This commit is contained in:
Daniel Varga 2019-08-14 07:07:09 +03:00
Родитель 2c649ef356 a17323e9d8
Коммит bac38ea0ea
388 изменённых файлов: 5014 добавлений и 4149 удалений

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

@ -252,7 +252,6 @@ modules/libpref/test/unit/*data/**
python/**
# Remote agent
remote/pref/remote.js
remote/Protocol.jsm
remote/server/HTTPD.jsm
remote/server/Packet.jsm

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

@ -28,9 +28,7 @@ modules/libpref/test/unit/data/testParser.js
modules/libpref/test/unit/data/testPrefLocked.js
modules/libpref/test/unit/data/testPrefSticky.js
modules/libpref/test/unit/extdata/testExt.js
remote/pref/remote.js
services/sync/tests/unit/prefs_test_prefs_store.js
testing/marionette/prefs/marionette.js
# Ignore testing pref files which aren't parsed normally.
testing/profiles/**/user.js

6
Cargo.lock сгенерированный
Просмотреть файл

@ -385,7 +385,7 @@ version = "0.1.0"
dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dogear 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dogear 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"moz_task 0.1.0",
@ -956,7 +956,7 @@ dependencies = [
[[package]]
name = "dogear"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3989,7 +3989,7 @@ dependencies = [
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
"checksum dogear 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99e2ed5f8036ceb83d951f769651ff0e2be5ddb0c62da87d50d27c22086db01c"
"checksum dogear 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "251a15c9a597d70eb53cbb0c5473d8d8c6241aef615c092030ebab27fb5b26ef"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"

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

@ -329,6 +329,9 @@ pref("browser.urlbar.openintab", false);
pref("browser.urlbar.usepreloadedtopurls.enabled", false);
pref("browser.urlbar.usepreloadedtopurls.expire_days", 14);
// Whether the quantum bar displays the major design update.
pref("browser.urlbar.megabar", false);
pref("browser.urlbar.openViewOnFocus", false);
pref("browser.altClickSave", false);

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

@ -982,8 +982,10 @@ var SocialTracking = {
this,
"enabled",
this.PREF_ENABLED,
false
false,
this.updateCategoryItem.bind(this)
);
this.updateCategoryItem();
XPCOMUtils.defineLazyPreferenceGetter(
this,
"uiEnabled",
@ -1019,6 +1021,10 @@ var SocialTracking = {
);
},
updateCategoryItem() {
this.categoryItem.classList.toggle("blocked", this.enabled);
},
isBlocking(state) {
let cookieTrackerBlocked =
(state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER) != 0;

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

@ -48,6 +48,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PanelMultiView: "resource:///modules/PanelMultiView.jsm",
PanelView: "resource:///modules/PanelMultiView.jsm",
PermitUnloader: "resource://gre/actors/BrowserElementParent.jsm",
PictureInPicture: "resource://gre/modules/PictureInPicture.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
PlacesTransactions: "resource://gre/modules/PlacesTransactions.jsm",

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

@ -506,6 +506,12 @@
#include browser-context.inc
</menupopup>
<menupopup id="pictureInPictureToggleContextMenu">
<menuitem label="&pictureInPictureHideToggle.label;"
accesskey="&pictureInPictureHideToggle.accesskey;"
oncommand="PictureInPicture.hideToggle();" />
</menupopup>
#include ../../components/places/content/placesContextMenu.inc.xul
<panel id="ctrlTab-panel" hidden="true" norestorefocus="true" level="top">

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

@ -222,6 +222,7 @@ uses-unsafe-cpows = true
[browser_bug767836_perwindowpb.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug817947.js]
skip-if = os == 'linux' && !debug && bits == 64 # Bug 1556066
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug832435.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.

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

@ -121,7 +121,11 @@ async function testSubview(hasException) {
let categoryItem = document.getElementById(
"protections-popup-category-socialblock"
);
ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
ok(BrowserTestUtils.is_visible(categoryItem), "STP category item is visible");
ok(
categoryItem.classList.contains("blocked"),
"STP category item is blocked"
);
let subview = document.getElementById("protections-popup-socialblockView");
let viewShown = BrowserTestUtils.waitForEvent(subview, "ViewShown");
categoryItem.click();

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

@ -653,6 +653,7 @@ const listeners = {
"PictureInPicture:Close": ["PictureInPicture"],
"PictureInPicture:Playing": ["PictureInPicture"],
"PictureInPicture:Paused": ["PictureInPicture"],
"PictureInPicture:OpenToggleContextMenu": ["PictureInPicture"],
"Reader:FaviconRequest": ["ReaderParent"],
"Reader:UpdateReaderButton": ["ReaderParent"],
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js

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

@ -102,10 +102,11 @@ export default class LoginList extends HTMLElement {
listItem.hidden = !visibleLoginGuids.has(listItem.dataset.guid);
}
this.classList.toggle(
"create-login-selected",
this._selectedGuid == null && Object.keys(this._logins).length > 0
);
let createLoginSelected =
this._selectedGuid == null && Object.keys(this._logins).length > 0;
this.classList.toggle("create-login-selected", createLoginSelected);
this._createLoginButton.disabled = createLoginSelected;
// Re-arrange the login-list-items according to their sort
for (let i = this._loginGuidsSortedOrder.length - 1; i >= 0; i--) {
@ -475,6 +476,7 @@ export default class LoginList extends HTMLElement {
oldSelectedItem.removeAttribute("aria-selected");
}
this.classList.toggle("create-login-selected", !listItem.dataset.guid);
this._createLoginButton.disabled = !listItem.dataset.guid;
listItem.classList.add("selected");
listItem.setAttribute("aria-selected", "true");
listItem.scrollIntoView();

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

@ -50,20 +50,28 @@ add_task(async function test_create_login() {
let loginList = Cu.waiveXrays(
content.document.querySelector("login-list")
);
let createButton = loginList.shadowRoot.querySelector(
".create-login-button"
);
let createButton = loginList._createLoginButton;
is(
content.getComputedStyle(loginList._blankLoginListItem).display,
"none",
"the blank login list item should be hidden initially"
);
ok(
!createButton.disabled,
"Create button should not be disabled initially"
);
createButton.click();
isnot(
content.getComputedStyle(loginList._blankLoginListItem).display,
"none",
"the blank login list item should be visible after clicking on the create button"
);
ok(
createButton.disabled,
"Create button should be disabled after being clicked"
);
let loginItem = Cu.waiveXrays(
content.document.querySelector("login-item")
@ -118,6 +126,11 @@ add_task(async function test_create_login() {
"none",
"the blank login list item should be hidden after adding new login"
);
ok(
!loginList._createLoginButton.disabled,
"Create button shouldn't be disabled after exiting create login view"
);
let loginGuid = await ContentTaskUtils.waitForCondition(() => {
return loginList._loginGuidsSortedOrder.find(
guid => loginList._logins[guid].login.origin == aOriginTuple[1]

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

@ -153,11 +153,16 @@ a.hidden,
cursor: default;
}
#protection-details,
.inline-text-icon {
padding: 4px;
padding-inline-start: 24px;
}
#protection-details {
-moz-context-properties: fill;
fill: currentColor;
background: url("chrome://browser/skin/settings.svg") no-repeat 3px 3px;
padding: 4px 4px 4px 24px;
font-size: 0.75em;
display: inline;
cursor: default;
@ -297,11 +302,15 @@ a.hidden,
z-index: -1;
}
input {
input[type="radio"] {
position: absolute;
left: -100px;
}
[dir="rtl"] input[type="radio"] {
right: -100px;
}
#legend input:focus + label {
outline: solid 1px;
outline-offset: -1px;
@ -347,6 +356,10 @@ input {
background-size: 16px;
}
[dir="rtl"] #legend label {
background-position: right center;
}
#legend label:-moz-focusring {
outline: none;
}
@ -485,6 +498,7 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
padding-inline-start: 24px;
}
[dir="rtl"] #protection-details,
[dir="rtl"] .inline-text-icon {
background-position-x: 100%;
}

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

@ -137,13 +137,45 @@ go-to-privacy-settings = Go to Privacy Settings
# This is the title attribute describing the Lockwise card's link to about:logins
go-to-saved-logins = Go to Saved Logins
## The title attribute is used to display the type of protection.
## The aria-label is spoken by screen readers to make the visual graph accessible to blind users.
##
## Variables:
## $count (Number) - Number of specific trackers
## $percentage (Number) - Percentage this type of tracker contributes to the whole graph
bar-tooltip-social =
.title = Social Media Trackers
.aria-label =
{ $count ->
[one] { $count } social media tracker ({ $percentage }%)
*[other] { $count } social media trackers ({ $percentage }%)
}
bar-tooltip-cookie =
.title = Cross-Site Tracking Cookies
.aria-label =
{ $count ->
[one] { $count } cross-site tracking cookie ({ $percentage }%)
*[other] { $count } cross-site tracking cookies ({ $percentage }%)
}
bar-tooltip-tracker =
.title = Tracking Content
.aria-label =
{ $count ->
[one] { $count } tracking content ({ $percentage }%)
*[other] { $count } tracking content ({ $percentage }%)
}
bar-tooltip-fingerprinter =
.title = Fingerprinters
.aria-label =
{ $count ->
[one] { $count } fingerprinter ({ $percentage }%)
*[other] { $count } fingerprinters ({ $percentage }%)
}
bar-tooltip-cryptominer =
.title = Cryptominers
.aria-label =
{ $count ->
[one] { $count } cryptominer ({ $percentage }%)
*[other] { $count } cryptominers ({ $percentage }%)
}

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

@ -37,7 +37,7 @@
<div class="body-wrapper">
<p id="graph-week-summary"></p>
<div id="graph-wrapper">
<div id="graph"></div>
<div id="graph" role="table"></div>
<div id="legend">
<label id="graphLegendDescription" data-l10n-id="graph-legend-description"></label>
<input id="tab-social" data-type="social" type="radio" name="tabs" aria-describedby="socialTitle" checked>

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

@ -99,36 +99,66 @@ document.addEventListener("DOMContentLoaded", e => {
cryptominer: 0,
};
// For accessibility clients, we turn the graph into a fake table with annotated text.
// We use WAI-ARIA roles, properties, and states to mark up the table, rows and cells.
// Each day becomes one row in the table.
// Each row contains the day, total, and then one cell for each bar that we display.
// At most, a row can contain seven cells.
// But we need to caclulate the actual number of the most cells in a row to give accurate information.
let maxColumnCount = 0;
let date = new Date();
// The graph is already a role "table" from the HTML file.
let graph = document.getElementById("graph");
for (let i = 0; i <= 6; i++) {
let dateString = date.toISOString().split("T")[0];
let ariaOwnsString = ""; // Get the row's colummns in order
let currentColumnCount = 0;
let bar = document.createElement("div");
bar.className = "graph-bar";
bar.setAttribute("role", "row");
let innerBar = document.createElement("div");
innerBar.className = "graph-wrapper-bar";
if (data[dateString]) {
let content = data[dateString];
let count = document.createElement("div");
count.className = "bar-count";
count.id = "count" + i;
count.setAttribute("role", "cell");
count.textContent = content.total;
bar.appendChild(count);
ariaOwnsString = count.id;
currentColumnCount += 1;
let barHeight = (content.total / largest) * 100;
weekCount += content.total;
bar.style.height = `${barHeight}%`;
for (let type of dataTypes) {
if (content[type]) {
let dataHeight = (content[type] / content.total) * 100;
// Since we are dealing with non-visual content, screen readers need a parent container to get the text
let cellSpan = document.createElement("span");
cellSpan.id = type + i;
cellSpan.setAttribute("role", "cell");
let div = document.createElement("div");
div.className = `${type}-bar inner-bar`;
div.setAttribute("data-type", type);
div.style.height = `${dataHeight}%`;
div.setAttribute(
"data-l10n-args",
JSON.stringify({ count: content[type], percentage: dataHeight })
);
div.setAttribute("data-l10n-id", `bar-tooltip-${type}`);
weekTypeCounts[type] += content[type];
innerBar.appendChild(div);
cellSpan.appendChild(div);
innerBar.appendChild(cellSpan);
ariaOwnsString = ariaOwnsString + " " + cellSpan.id;
currentColumnCount += 1;
}
}
if (currentColumnCount > maxColumnCount) {
// The current row has more than any previous rows
maxColumnCount = currentColumnCount;
}
} else {
// There were no content blocking events on this day.
bar.classList.add("empty");
@ -144,14 +174,21 @@ document.addEventListener("DOMContentLoaded", e => {
let label = document.createElement("span");
label.className = "column-label";
// While the graphs fill up from the right, the days fill up from the left, so match the IDs
label.id = "day" + (6 - i);
label.setAttribute("role", "rowheader");
if (i == 6) {
label.setAttribute("data-l10n-id", "graph-today");
} else {
label.textContent = data.weekdays[(i + 1 + new Date().getDay()) % 7];
}
graph.append(label);
// Make the day the first column in a row, making it the row header.
bar.setAttribute("aria-owns", "day" + i + " " + ariaOwnsString);
date.setDate(date.getDate() - 1);
}
maxColumnCount += 1; // Add the day column in the fake table
graph.setAttribute("aria-colCount", maxColumnCount);
// Set the total number of each type of tracker on the tabs as well as their
// "Learn More" links
for (let type of dataTypes) {

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

@ -193,6 +193,19 @@ add_task(async function test_graph_display() {
is(allBars.length, 7, "7 bars have been found on the graph");
// For accessibility, test if the graph is a table
// and has a correct column count (number of data types + total + day)
is(
content.document.getElementById("graph").getAttribute("role"),
"table",
"Graph is an accessible table"
);
is(
content.document.getElementById("graph").getAttribute("aria-colcount"),
DATA_TYPES.length + 2,
"Table has the right number of columns"
);
// today has each type
// yesterday will have no tracking cookies
// 2 days ago will have no fingerprinters
@ -205,31 +218,91 @@ add_task(async function test_graph_display() {
DATA_TYPES.length,
"today has all of the data types shown"
);
is(allBars[6].getAttribute("role"), "row", "Today has the correct role");
is(
allBars[6].getAttribute("aria-owns"),
"day0 count0 cryptominer0 fingerprinter0 tracker0 cookie0 social0",
"Row has the columns in the right order"
);
is(
allBars[6].querySelector(".tracker-bar").style.height,
"10%",
"trackers take 10%"
);
is(
allBars[6].querySelector(".tracker-bar").parentNode.getAttribute("role"),
"cell",
"Trackers have the correct role"
);
is(
allBars[6].querySelector(".tracker-bar").getAttribute("aria-label"),
"1 tracking content (10%)",
"Trackers have the correct accessible text"
);
is(
allBars[6].querySelector(".cryptominer-bar").style.height,
"20%",
"cryptominers take 20%"
);
is(
allBars[6]
.querySelector(".cryptominer-bar")
.parentNode.getAttribute("role"),
"cell",
"Cryptominers have the correct role"
);
is(
allBars[6].querySelector(".cryptominer-bar").getAttribute("aria-label"),
"2 cryptominers (20%)",
"Cryptominers have the correct accessible label"
);
is(
allBars[6].querySelector(".fingerprinter-bar").style.height,
"20%",
"fingerprinters take 20%"
);
is(
allBars[6]
.querySelector(".fingerprinter-bar")
.parentNode.getAttribute("role"),
"cell",
"Fingerprinters have the correct role"
);
is(
allBars[6].querySelector(".fingerprinter-bar").getAttribute("aria-label"),
"2 fingerprinters (20%)",
"Fingerprinters have the correct accessible label"
);
is(
allBars[6].querySelector(".cookie-bar").style.height,
"40%",
"cross site tracking cookies take 40%"
);
is(
allBars[6].querySelector(".cookie-bar").parentNode.getAttribute("role"),
"cell",
"cross site tracking cookies have the correct role"
);
is(
allBars[6].querySelector(".cookie-bar").getAttribute("aria-label"),
"4 cross-site tracking cookies (40%)",
"cross site tracking cookies have the correct accessible label"
);
is(
allBars[6].querySelector(".social-bar").style.height,
"10%",
"social trackers take 10%"
);
is(
allBars[6].querySelector(".social-bar").parentNode.getAttribute("role"),
"cell",
"social trackers have the correct role"
);
is(
allBars[6].querySelector(".social-bar").getAttribute("aria-label"),
"1 social media tracker (10%)",
"social trackers have the correct accessible text"
);
is(
allBars[5].querySelectorAll(".inner-bar").length,
@ -240,6 +313,11 @@ add_task(async function test_graph_display() {
!allBars[5].querySelector(".cookie-bar"),
"there is no cross site tracking cookie section 1 day ago."
);
is(
allBars[5].getAttribute("aria-owns"),
"day1 count1 cryptominer1 fingerprinter1 tracker1 social1",
"Row has the columns in the right order"
);
is(
allBars[4].querySelectorAll(".inner-bar").length,
@ -250,6 +328,11 @@ add_task(async function test_graph_display() {
!allBars[4].querySelector(".fingerprinter-bar"),
"there is no fingerprinter section 1 day ago."
);
is(
allBars[4].getAttribute("aria-owns"),
"day2 count2 cryptominer2 tracker2 cookie2 social2",
"Row has the columns in the right order"
);
is(
allBars[3].querySelectorAll(".inner-bar").length,
@ -260,6 +343,11 @@ add_task(async function test_graph_display() {
!allBars[3].querySelector(".cryptominer-bar"),
"there is no cryptominer section 1 day ago."
);
is(
allBars[3].getAttribute("aria-owns"),
"day3 count3 fingerprinter3 tracker3 cookie3 social3",
"Row has the columns in the right order"
);
is(
allBars[2].querySelectorAll(".inner-bar").length,
@ -270,6 +358,11 @@ add_task(async function test_graph_display() {
!allBars[2].querySelector(".tracker-bar"),
"there is no tracker section 1 day ago."
);
is(
allBars[2].getAttribute("aria-owns"),
"day4 count4 cryptominer4 fingerprinter4 cookie4 social4",
"Row has the columns in the right order"
);
is(
allBars[1].querySelectorAll(".inner-bar").length,
@ -280,6 +373,11 @@ add_task(async function test_graph_display() {
!allBars[1].querySelector(".social-bar"),
"there is no social section 1 day ago."
);
is(
allBars[1].getAttribute("aria-owns"),
"day5 count5 cryptominer5 fingerprinter5 tracker5 cookie5",
"Row has the columns in the right order"
);
is(
allBars[0].querySelectorAll(".inner-bar").length,
@ -287,6 +385,11 @@ add_task(async function test_graph_display() {
"6 days ago has no content"
);
ok(allBars[0].classList.contains("empty"), "6 days ago is an empty bar");
is(
allBars[0].getAttribute("aria-owns"),
"day6 ",
"Row has the columns in the right order"
);
// Check that each tab has the correct aria-describedby value. This helps screen readers
// know what type of tracker the reported tab number is referencing.

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

@ -18,24 +18,13 @@ class SearchOneOffs {
this.container.appendChild(
MozXULElement.parseXULToFragment(
`
<deck class="search-panel-one-offs-header search-panel-header search-panel-current-input">
<label class="searchbar-oneoffheader-search" value="&searchWithHeader.label;"/>
<hbox class="search-panel-searchforwith search-panel-current-input">
<label value="&searchFor.label;"/>
<label class="searchbar-oneoffheader-searchtext search-panel-input-value" flex="1" crop="end"/>
<label flex="10000" value="&searchWith.label;"/>
</hbox>
<hbox class="search-panel-searchonengine search-panel-current-input">
<label value="&search.label;"/>
<label class="searchbar-oneoffheader-engine search-panel-input-value" flex="1" crop="end"/>
<label flex="10000" value="&searchAfter.label;"/>
</hbox>
</deck>
<description role="group" class="search-panel-one-offs">
<button class="searchbar-engine-one-off-item search-setting-button-compact" tooltiptext="&changeSearchSettings.tooltip;"/>
</description>
<div class="search-panel-one-offs-header search-panel-header search-panel-current-input">
<label class="searchbar-oneoffheader-search" value="&searchWithDesc.label;"/>
</div>
<div class="search-panel-one-offs"/>
<vbox class="search-add-engines"/>
<button class="search-setting-button search-panel-header" label="&changeSearchSettings.button;"/>
<button class="searchbar-engine-one-off-item search-setting-button-compact" tooltiptext="&changeSearchSettings.tooltip;"/>
<button class="search-setting-button" label="&changeSearchSettings.button;"/>
<menupopup class="search-one-offs-context-menu">
<menuitem class="search-one-offs-context-open-in-new-tab" label="&searchInNewTab.label;" accesskey="&searchInNewTab.accesskey;"/>
<menuitem class="search-one-offs-context-set-default" label="&searchSetAsDefault.label;" accesskey="&searchSetAsDefault.accesskey;"/>
@ -179,12 +168,17 @@ class SearchOneOffs {
}
/**
* Width in pixels of the one-off buttons. 49px is the min-width of
* each search engine button, adapt this const when changing the css.
* It's actually 48px + 1px of right border.
* Width in pixels of the one-off buttons.
*/
get buttonWidth() {
return 49;
return this.compact ? 40 : 48;
}
/**
* Height in pixels of the one-off buttons.
*/
get buttonHeight() {
return 32;
}
/**
@ -274,7 +268,14 @@ class SearchOneOffs {
(this._view && this._view.isOpen) ||
(this.popup && this.popup.popupOpen)
) {
this._updateAfterQueryChanged();
let isOneOffSelected =
this.selectedButton &&
this.selectedButton.classList.contains("searchbar-engine-one-off-item");
// Typing de-selects the settings or opensearch buttons at the bottom
// of the search panel, as typing shows the user intends to search.
if (this.selectedButton && !isOneOffSelected) {
this.selectedButton = null;
}
}
return val;
}
@ -291,10 +292,6 @@ class SearchOneOffs {
* The selected one-off button. Null if no one-off is selected.
*/
set selectedButton(val) {
if (val && val.classList.contains("dummy")) {
// Never select dummy buttons.
val = null;
}
let previousButton = this._selectedButton;
if (previousButton) {
previousButton.removeAttribute("selected");
@ -392,43 +389,6 @@ class SearchOneOffs {
this._engines = null;
}
/**
* Updates the parts of the UI that show the query string.
*/
_updateAfterQueryChanged() {
let headerSearchText = this.querySelector(
".searchbar-oneoffheader-searchtext"
);
headerSearchText.setAttribute("value", this.query);
let groupText;
let isOneOffSelected =
this.selectedButton &&
this.selectedButton.classList.contains("searchbar-engine-one-off-item");
// Typing de-selects the settings or opensearch buttons at the bottom
// of the search panel, as typing shows the user intends to search.
if (this.selectedButton && !isOneOffSelected) {
this.selectedButton = null;
}
if (this.query) {
groupText =
headerSearchText.previousElementSibling.value +
'"' +
headerSearchText.value +
'"' +
headerSearchText.nextElementSibling.value;
if (!isOneOffSelected) {
this.header.selectedIndex = 1;
}
} else {
let noSearchHeader = this.querySelector(".searchbar-oneoffheader-search");
groupText = noSearchHeader.value;
if (!isOneOffSelected) {
this.header.selectedIndex = 0;
}
}
this.buttons.setAttribute("aria-label", groupText);
}
/**
* Infallible, non-re-entrant version of `__rebuild()`.
*/
@ -454,9 +414,6 @@ class SearchOneOffs {
this.selectedButton = null;
this._contextEngine = null;
// Update the 'Search for <keywords> with:" header.
this._updateAfterQueryChanged();
// Handle opensearch items. This needs to be done before building the
// list of one off providers, as that code will return early if all the
// alternative engines are hidden.
@ -480,15 +437,14 @@ class SearchOneOffs {
}
// Finally, build the list of one-off buttons.
while (this.buttons.firstElementChild != this.settingsButtonCompact) {
while (this.buttons.firstElementChild) {
this.buttons.firstElementChild.remove();
}
// Remove the trailing empty text node introduced by the binding's
// content markup above.
if (this.settingsButtonCompact.nextElementSibling) {
this.settingsButtonCompact.nextElementSibling.remove();
}
let headerText = this.header.querySelector(
".searchbar-oneoffheader-search"
);
this.buttons.setAttribute("aria-label", headerText.value);
let engines = await this.getEngines();
let defaultEngine = await Services.search.getDefault();
@ -508,7 +464,10 @@ class SearchOneOffs {
return;
}
let panelWidth = parseInt((this.popup || this._view.panel).clientWidth);
// this.buttonWidth is for the compact settings button.
let buttonsWidth = this.compact
? this._textboxWidth - this.buttonWidth - this.header.clientWidth
: this.popup.clientWidth;
// There's one weird thing to guard against: when layout pixels
// aren't an integral multiple of device pixels, the last button
@ -519,33 +478,41 @@ class SearchOneOffs {
// As a workaround, decrement the width if the scale is not an integer.
let scale = window.windowUtils.screenPixelsPerCSSPixel;
if (Math.floor(scale) != scale) {
--panelWidth;
--buttonsWidth;
}
// The + 1 is because the last button doesn't have a right border.
let enginesPerRow = Math.floor((panelWidth + 1) / this.buttonWidth);
let buttonWidth = Math.floor(panelWidth / enginesPerRow);
// There will be an emtpy area of:
// panelWidth - enginesPerRow * buttonWidth px
// If the header string is very long, then the searchbar buttons will
// overflow their container unless max-width is set.
this.buttons.style.setProperty(
this.compact ? "width" : "max-width",
`${buttonsWidth}px`
);
// 24: 12px left padding + 12px right padding.
if (this.compact) {
buttonsWidth -= 24;
}
// In very narrow windows, we should always have at least one button
// per row.
buttonsWidth = Math.max(buttonsWidth, this.buttonWidth);
let enginesPerRow = Math.floor(buttonsWidth / this.buttonWidth);
// There will be an empty area of:
// buttonsWidth - enginesPerRow * this.buttonWidth px
// at the end of each row.
// If the <description> tag with the list of search engines doesn't have
// If the <div> with the list of search engines doesn't have
// a fixed height, the panel will be sized incorrectly, causing the bottom
// of the suggestion <tree> to be hidden.
if (this.compact) {
++oneOffCount;
}
let rowCount = Math.ceil(oneOffCount / enginesPerRow);
let height = rowCount * 33; // 32px per row, 1px border.
this.buttons.setAttribute("height", height + "px");
let height = rowCount * this.buttonHeight;
this.buttons.style.setProperty("height", `${height}px`);
// Ensure we can refer to the settings buttons by ID:
let origin = this.telemetryOrigin;
this.settingsButton.id = origin + "-anon-search-settings";
this.settingsButtonCompact.id = origin + "-anon-search-settings-compact";
let dummyItems =
enginesPerRow - (oneOffCount % enginesPerRow || enginesPerRow);
for (let i = 0; i < engines.length; ++i) {
let engine = engines[i];
let button = document.createXULElement("button");
@ -557,53 +524,9 @@ class SearchOneOffs {
button.setAttribute("image", uri);
button.setAttribute("class", "searchbar-engine-one-off-item");
button.setAttribute("tooltiptext", engine.name);
button.setAttribute("width", buttonWidth);
button.engine = engine;
if ((i + 1) % enginesPerRow == 0) {
button.classList.add("last-of-row");
}
if (i + 1 == engines.length) {
button.classList.add("last-engine");
}
if (i >= oneOffCount + dummyItems - enginesPerRow) {
button.classList.add("last-row");
}
this.buttons.insertBefore(button, this.settingsButtonCompact);
}
let hasDummyItems = !!dummyItems;
while (dummyItems) {
let button = document.createXULElement("button");
button.setAttribute(
"class",
"searchbar-engine-one-off-item dummy last-row"
);
button.setAttribute("width", buttonWidth);
if (!--dummyItems) {
button.classList.add("last-of-row");
}
this.buttons.insertBefore(button, this.settingsButtonCompact);
}
if (this.compact) {
this.settingsButtonCompact.setAttribute("width", buttonWidth);
if (rowCount == 1 && hasDummyItems) {
// When there's only one row, make the compact settings button
// hug the right edge of the panel. It may not due to the panel's
// width not being an integral multiple of the button width. (See
// the "There will be an emtpy area" comment above.) Increase the
// width of the last dummy item by the remainder.
let remainder = panelWidth - enginesPerRow * buttonWidth;
let width = remainder + buttonWidth;
let lastDummyItem = this.settingsButtonCompact.previousElementSibling;
lastDummyItem.setAttribute("width", width);
}
this.buttons.appendChild(button);
}
}
@ -732,37 +655,16 @@ class SearchOneOffs {
_updateStateForButton(mousedOverButton) {
let button = mousedOverButton;
// Ignore dummy buttons.
if (button && button.classList.contains("dummy")) {
button = null;
}
// If there's no moused-over button, then the one-offs should reflect
// the selected button, if any.
button = button || this.selectedButton;
if (!button) {
this.header.selectedIndex = this.query ? 1 : 0;
if (this.textbox) {
this.textbox.removeAttribute("aria-activedescendant");
}
return;
}
if (
button.classList.contains("searchbar-engine-one-off-item") &&
button.engine
) {
let headerEngineText = this.querySelector(
".searchbar-oneoffheader-engine"
);
this.header.selectedIndex = 2;
headerEngineText.value = button.engine.name;
} else {
this.header.selectedIndex = this.query ? 1 : 0;
}
if (this.textbox) {
this.textbox.setAttribute("aria-activedescendant", button.id);
if (!button) {
this.textbox.removeAttribute("aria-activedescendant");
} else {
this.textbox.setAttribute("aria-activedescendant", button.id);
}
}
}
@ -773,19 +675,7 @@ class SearchOneOffs {
oneOff;
oneOff = oneOff.nextElementSibling
) {
// oneOff may be a text node since the list xul:description contains
// whitespace and the compact settings button. See the markup
// above. _rebuild removes text nodes, but it may not have been
// called yet (because e.g. the popup hasn't been opened yet).
if (oneOff.nodeType == Node.ELEMENT_NODE) {
if (
oneOff.classList.contains("dummy") ||
oneOff.classList.contains("search-setting-button-compact")
) {
break;
}
buttons.push(oneOff);
}
buttons.push(oneOff);
}
if (aIncludeNonEngineButtons) {
@ -850,7 +740,7 @@ class SearchOneOffs {
* If true, the index is incremented, and if false, the index is
* decremented.
* @param {boolean} aIncludeNonEngineButtons
* If true, non-dummy buttons that do not have engines are included.
* If true, buttons that do not have engines are included.
* These buttons include the OpenSearch and settings buttons. For
* example, if the currently selected button is an engine button,
* the next button is the settings button, and you pass true for
@ -1202,9 +1092,7 @@ class SearchOneOffs {
return;
}
let isOneOff =
target.classList.contains("searchbar-engine-one-off-item") &&
!target.classList.contains("dummy");
let isOneOff = target.classList.contains("searchbar-engine-one-off-item");
if (
isOneOff ||
target.classList.contains("addengine-item") ||
@ -1349,8 +1237,7 @@ class SearchOneOffs {
// Prevent the context menu from appearing except on the one off buttons.
if (
!target.classList.contains("searchbar-engine-one-off-item") ||
target.classList.contains("search-setting-button-compact") ||
target.classList.contains("dummy")
target.classList.contains("search-setting-button-compact")
) {
event.preventDefault();
return;

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

@ -39,8 +39,6 @@ skip-if = (verify && debug && (os == 'win' || os == 'linux'))
[browser_oneOffContextMenu.js]
skip-if = verify
[browser_oneOffContextMenu_setDefault.js]
[browser_oneOffHeader.js]
skip-if = os == "mac" #1421238
[browser_private_search_perwindowpb.js]
[browser_searchbar_openpopup.js]
skip-if = os == "linux" # Linux has different focus behaviours.

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

@ -189,16 +189,23 @@ async function openPopupAndGetEngineButton(
}
const contextMenu = oneOffInstance.contextMenuPopup;
const oneOffButtons = oneOffInstance.buttons;
let oneOffButton = oneOffInstance.buttons;
// Get the one-off button for the test engine.
let oneOffButton;
for (let node of oneOffButtons.children) {
if (node.engine && node.engine.name == TEST_ENGINE_NAME) {
oneOffButton = node;
for (
oneOffButton = oneOffButton.firstChild;
oneOffButton;
oneOffButton = oneOffButton.nextSibling
) {
if (
oneOffButton.nodeType == Node.ELEMENT_NODE &&
oneOffButton.engine &&
oneOffButton.engine.name == TEST_ENGINE_NAME
) {
break;
}
}
Assert.notEqual(
oneOffButton,
undefined,

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

@ -1,176 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Tests that keyboard navigation in the search panel works as designed.
const isMac = "nsILocalFileMac" in Ci;
const searchPopup = document.getElementById("PopupSearchAutoComplete");
const oneOffsContainer = searchPopup.searchOneOffsContainer;
const searchSettings = oneOffsContainer.querySelector(".search-setting-button");
var header = oneOffsContainer.querySelector(".search-panel-one-offs-header");
function getHeaderText() {
let headerChild = header.selectedPanel;
while (headerChild.hasChildNodes()) {
headerChild = headerChild.firstElementChild;
}
let headerStrings = [];
for (let label = headerChild; label; label = label.nextElementSibling) {
headerStrings.push(label.value);
}
return headerStrings.join("");
}
const msg = isMac ? 5 : 1;
const utils = window.windowUtils;
const scale = utils.screenPixelsPerCSSPixel;
function synthesizeNativeMouseMove(aElement) {
let rect = aElement.getBoundingClientRect();
let win = aElement.ownerGlobal;
let x = win.mozInnerScreenX + (rect.left + rect.right) / 2;
let y = win.mozInnerScreenY + (rect.top + rect.bottom) / 2;
// Wait for the mousemove event to occur before continuing.
return new Promise((resolve, reject) => {
function eventOccurred(e) {
aElement.removeEventListener("mousemove", eventOccurred, true);
SimpleTest.executeSoon(resolve);
}
aElement.addEventListener("mousemove", eventOccurred, true);
utils.sendNativeMouseEvent(x * scale, y * scale, msg, 0, null);
});
}
let searchbar;
let searchIcon;
add_task(async function init() {
searchbar = await gCUITestUtils.addSearchBar();
registerCleanupFunction(() => {
gCUITestUtils.removeSearchBar();
});
searchIcon = searchbar.querySelector(".searchbar-search-button");
await promiseNewEngine("testEngine.xml");
});
add_task(async function test_notext() {
let promise = promiseEvent(searchPopup, "popupshown");
info("Opening search panel");
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
await promise;
is(
header.getAttribute("selectedIndex"),
0,
"Header has the correct index selected with no search terms."
);
is(
getHeaderText(),
"Search with:",
"Search header string is correct when no search terms have been entered"
);
await synthesizeNativeMouseMove(searchSettings);
is(
header.getAttribute("selectedIndex"),
0,
"Header has the correct index when no search terms have been entered and the Change Search Settings button is selected."
);
is(
getHeaderText(),
"Search with:",
"Header has the correct text when no search terms have been entered and the Change Search Settings button is selected."
);
let buttons = getOneOffs();
await synthesizeNativeMouseMove(buttons[0]);
is(
header.getAttribute("selectedIndex"),
2,
"Header has the correct index selected when a search engine has been selected"
);
is(
getHeaderText(),
"Search " + buttons[0].engine.name,
"Is the header text correct when a search engine is selected and no terms have been entered."
);
promise = promiseEvent(searchPopup, "popuphidden");
info("Closing search panel");
EventUtils.synthesizeKey("KEY_Escape");
await promise;
});
add_task(async function test_text() {
searchbar.textbox.value = "foo";
let promise = promiseEvent(searchPopup, "popupshown");
info("Opening search panel");
SimpleTest.executeSoon(() => {
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
});
await promise;
is(
header.getAttribute("selectedIndex"),
1,
"Header has the correct index selected with a search term."
);
is(
getHeaderText(),
"Search for foo with:",
"Search header string is correct when a search term has been entered"
);
let buttons = getOneOffs();
await synthesizeNativeMouseMove(buttons[0]);
is(
header.getAttribute("selectedIndex"),
2,
"Header has the correct index selected when a search engine has been selected"
);
is(
getHeaderText(),
"Search " + buttons[0].engine.name,
"Is the header text correct when search terms are entered after a search engine has been selected."
);
await synthesizeNativeMouseMove(searchSettings);
is(
header.getAttribute("selectedIndex"),
1,
"Header has the correct index selected when search terms have been entered and the Change Search Settings button is selected."
);
is(
getHeaderText(),
"Search for foo with:",
"Header has the correct text when search terms have been entered and the Change Search Settings button is selected."
);
// Click the "Foo Search" header at the top of the popup and make sure it
// loads the search results.
let searchbarEngine = searchPopup.searchbarEngine;
await synthesizeNativeMouseMove(searchbarEngine);
SimpleTest.executeSoon(() => {
EventUtils.synthesizeMouseAtCenter(searchbarEngine, {});
});
let url = (await Services.search.getDefault()).getSubmission(
searchbar.textbox.value
).uri.spec;
await promiseTabLoadEvent(gBrowser.selectedTab, url);
// Move the cursor out of the panel area to avoid messing with other tests.
await synthesizeNativeMouseMove(searchbar);
});
add_task(async function cleanup() {
searchbar.textbox.value = "";
});

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

@ -207,12 +207,6 @@ function getOneOffs() {
let oneOff = oneOffsContainer.querySelector(".search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.nodeType == Node.ELEMENT_NODE) {
if (
oneOff.classList.contains("dummy") ||
oneOff.classList.contains("search-setting-button-compact")
) {
break;
}
oneOffs.push(oneOff);
}
}

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

@ -244,7 +244,7 @@ add_task(async function test_preload_crash() {
NewTabPagePreloading.removePreloadedBrowser(window);
// Create a fresh preloaded browser
NewTabPagePreloading.maybeCreatePreloadedBrowser(window);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
await BrowserTestUtils.crashBrowser(gBrowser.preloadedBrowser, false);

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

@ -80,6 +80,8 @@ class UrlbarInput {
);
this.panel = this.document.getElementById("urlbar-results");
this.megabar = UrlbarPrefs.get("megabar");
this.controller =
options.controller ||
new UrlbarController({

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

@ -98,6 +98,9 @@ const PREF_URLBAR_DEFAULTS = new Map([
// The maximum number of results in the urlbar popup.
["maxRichResults", 10],
// Whether the quantum bar displays the major design update.
["megabar", false],
// One-off search buttons enabled status.
["oneOffSearches", false],

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

@ -198,7 +198,6 @@
#ifdef ENABLE_REMOTE_AGENT
@RESPATH@/chrome/remote@JAREXT@
@RESPATH@/chrome/remote.manifest
@RESPATH@/defaults/pref/remote.js
#endif
; Marionette remote control protocol
@ -207,7 +206,6 @@
@RESPATH@/chrome/marionette.manifest
@RESPATH@/components/marionette.manifest
@RESPATH@/components/marionette.js
@RESPATH@/defaults/pref/marionette.js
#endif
#if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)

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

@ -94,6 +94,9 @@ convenience of Safari and Chrome users on macOS. See bug 1398988. -->
<!ENTITY fullScreenExit.label "Exit Full Screen Mode">
<!ENTITY fullScreenExit.accesskey "F">
<!ENTITY pictureInPictureHideToggle.label "Hide Picture-in-Picture Toggle">
<!ENTITY pictureInPictureHideToggle.accesskey "H">
<!-- LOCALIZATION NOTE (fxa.menu) Used to define the different labels
for the Firefox Account toolbar menu screen. The `Signed in as` text is
followed by the user's email. -->
@ -428,26 +431,11 @@ convenience of Safari and Chrome users on macOS. See bug 1398988. -->
<!ENTITY searchInput.placeholder "Search">
<!ENTITY searchIcon.tooltip "Search">
<!-- LOCALIZATION NOTE (searchFor.label, searchWith.label):
These two strings are used to build the header above the list of one-click
search providers: "Search for <used typed keywords> with:" -->
<!ENTITY searchFor.label "Search for ">
<!ENTITY searchWith.label " with:">
<!-- LOCALIZATION NOTE (searchWithDesc.label):
This string prompts the user to use the list of one-click search engines in
the Urlbar and searchbar. -->
<!ENTITY searchWithDesc.label "This time, search with:">
<!-- LOCALIZATION NOTE (search.label, searchAfter.label):
This string is used to build the header above the list of one-click search
providers when a one off engine has been selected. The searchAfter text is
intentionally left empty for en-US and can be used by other localizations to
display a string after the search engine name. This string will be displayed
as: "Search <selected engine name><searchAfter.label text>" -->
<!ENTITY search.label "Search ">
<!ENTITY searchAfter.label "">
<!-- LOCALIZATION NOTE (searchWithHeader.label):
The wording of this string should be as close as possible to
searchFor.label and searchWith.label. This string will be used instead of
them when the user has not typed any keyword. -->
<!ENTITY searchWithHeader.label "Search with:">
<!-- LOCALIZATION NOTE (changeSearchSettings.button):
This string won't wrap, so if the translated string is longer,
consider translating it as if it said only "Search Settings". -->

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

@ -315,7 +315,7 @@ notification[value="translation"] menulist > .menulist-dropmarker {
border-top: 1px solid ThreeDShadow;
}
#urlbarView-results {
#urlbar-results {
font-size: 1.05em;
}

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

@ -318,7 +318,7 @@
border-top: 1px solid #C7C7C7;
}
#urlbarView-results {
#urlbar-results {
font-size: 14px;
}

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

@ -4,11 +4,6 @@
%include ../shared/searchbar.inc.css
.search-panel-header,
.addengine-item {
font-size: 10px;
}
.searchbar-popup {
margin-top: 4px;
margin-inline-start: 3px;

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

@ -12,6 +12,8 @@
.search-one-offs {
-moz-box-orient: vertical;
border-top: 1px solid var(--panel-separator-color);
width: 100%;
}
/**
@ -49,36 +51,27 @@
.search-panel-header {
font-weight: normal;
background-color: var(--arrowpanel-dimmed);
border-top: 1px solid var(--panel-separator-color);
margin: 0;
padding: 3px 6px;
padding: 3px;
color: var(--panel-disabled-color);
}
:root[lwt-popup-brighttext] .search-panel-header {
color: var(--autocomplete-popup-color);
}
.search-panel-header > label {
margin-top: 2px !important;
margin-bottom: 1px !important;
}
.search-panel-current-input > label {
margin: 2px 0 !important;
}
.search-panel-input-value {
color: var(--autocomplete-popup-color);
}
.search-panel-one-offs {
margin: 0 !important;
border-top: 1px solid var(--panel-separator-color);
background-color: var(--arrowpanel-dimmed);
/* Bug 1108841: prevent font-size from affecting the layout */
line-height: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.searchbar-engine-one-off-item {
@ -88,35 +81,10 @@
height: 32px;
margin: 0;
padding: 0;
background: linear-gradient(transparent 15%, var(--panel-separator-color) 15%, var(--panel-separator-color) 85%, transparent 85%);
background-size: 1px auto;
background-repeat: no-repeat;
background-position: right center;
color: var(--panel-disabled-color);
}
.searchbar-engine-one-off-item:-moz-locale-dir(rtl) {
background-position-x: left;
}
.searchbar-engine-one-off-item:not(.last-row) {
box-sizing: content-box;
border-bottom: 1px solid var(--panel-separator-color);
}
.search-setting-button-compact {
border-bottom: none !important;
}
.search-one-offs:not([compact=true]) .searchbar-engine-one-off-item.last-of-row,
.search-one-offs[compact=true] .searchbar-engine-one-off-item.last-of-row:not(.dummy),
.search-one-offs[compact=true] .searchbar-engine-one-off-item.dummy:not(.last-of-row),
.search-one-offs[compact=true] .searchbar-engine-one-off-item.last-engine,
.search-setting-button-compact {
background-image: none;
}
.searchbar-engine-one-off-item:not([selected]):not(.dummy):hover,
.searchbar-engine-one-off-item:not([selected]):hover,
.addengine-item:hover {
background-color: var(--arrowpanel-dimmed-further);
color: inherit;
@ -124,7 +92,6 @@
.searchbar-engine-one-off-item[selected] {
background-color: var(--autocomplete-popup-highlight-background);
background-image: none;
color: var(--autocomplete-popup-highlight-color);
}
@ -143,10 +110,6 @@
height: 16px;
}
.search-add-engines {
background-color: var(--arrowpanel-dimmed);
}
.addengine-item {
-moz-appearance: none;
color: inherit;
@ -238,6 +201,13 @@
-moz-appearance: none;
margin: 0;
min-height: 32px;
border-top: 1px solid var(--panel-separator-color);
background-color: var(--arrowpanel-dimmed);
color: var(--panel-disabled-color);
}
.search-setting-button-compact {
max-height: 32px;
}
.search-setting-button:hover,

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

@ -248,6 +248,33 @@
color: var(--autocomplete-popup-highlight-background);
}
/* Search one-offs. */
#urlbar-results > .search-one-offs {
-moz-box-orient: horizontal;
padding-inline-start: var(--item-padding-start, 5px);
padding-inline-end: var(--item-padding-end, 5px);
padding-top: 16px;
padding-bottom: 16px;
}
#urlbar-results .search-panel-one-offs {
padding-left: 12px;
padding-right: 12px;
}
#urlbar-results .search-panel-header {
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
}
#urlbar-results .searchbar-engine-one-off-item {
min-width: 32px;
height: 32px;
margin: 0 4px;
}
/* search bar popup */
#PopupSearchAutoComplete {

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

@ -609,7 +609,7 @@ menuitem.bookmark-item {
%include ../shared/autocomplete.inc.css
%include ../shared/urlbar-autocomplete.inc.css
#urlbarView-results {
#urlbar-results {
font-size: 1.15em;
}

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

@ -55,12 +55,11 @@ if
#if variable
#if !variable
#if variable==string
#if variable!=string
#if variable == string
#if variable != string
Disables output if the conditional is false. This can be nested to arbitrary
depths. Note that in the equality checks, the variable must come first, and
the comparison operator must not be surrounded by any whitespace.
depths. Note that in the equality checks, the variable must come first.
else
^^^^
@ -73,22 +72,6 @@ Reverses the state of the previous conditional block; for example, if the
last ``#if`` was true (output was enabled), an ``#else`` makes it off
(output gets disabled).
.. warning:: An ``#else`` is relative to the last conditional block only,
unlike the C preprocessor.
It does not matter whether any blocks before it were true. This behavior
changed on trunk (Gecko 1.9) on 2006-12-07; see Bug 277122 for details.
::
#if 1
always included
#elif 1
never included
#else
always included
#endif
endif
^^^^^
@ -140,12 +123,6 @@ The following two blocks are equivalent::
#endif
#endif
.. warning:: An ``#elif``, ``#elifdef``, or ``#elifndef`` is relative to
the last conditional block only (as well as the condition it implies),
unlike the C preprocessor. It does not matter whether any blocks before
it were true. This behavior changed on trunk (Gecko 1.9) on 2006-12-07.
See Bug 277122 for details.
File Inclusion
--------------

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

@ -208,42 +208,42 @@ with only_when(host_is_osx):
# Xcode state
# ===========
js_option('--disable-xcode-checks',
help='Do not check that Xcode is installed and properly configured')
help='Do not check that Xcode is installed and properly configured')
@depends(host, '--disable-xcode-checks')
def xcode_path(host, xcode_checks):
if host.kernel != 'Darwin' or not xcode_checks:
return
if host.kernel != 'Darwin' or not xcode_checks:
return
# xcode-select -p prints the path to the installed Xcode. It
# should exit 0 and return non-empty result if Xcode is installed.
# xcode-select -p prints the path to the installed Xcode. It
# should exit 0 and return non-empty result if Xcode is installed.
def bad_xcode_select():
die('Could not find installed Xcode; install Xcode from the App '
'Store, run it once to perform initial configuration, and then '
'try again; in the rare case you wish to build without Xcode '
'installed, add the --disable-xcode-checks configure flag')
def bad_xcode_select():
die('Could not find installed Xcode; install Xcode from the App '
'Store, run it once to perform initial configuration, and then '
'try again; in the rare case you wish to build without Xcode '
'installed, add the --disable-xcode-checks configure flag')
xcode_path = check_cmd_output('xcode-select', '--print-path',
onerror=bad_xcode_select).strip()
xcode_path = check_cmd_output('xcode-select', '--print-path',
onerror=bad_xcode_select).strip()
if not xcode_path:
bad_xcode_select()
if not xcode_path:
bad_xcode_select()
# Now look for the Command Line Tools.
def no_cltools():
die('Could not find installed Xcode Command Line Tools; '
'run `xcode-select --install` and follow the instructions '
'to install them then try again; if you wish to build without '
'Xcode Command Line Tools installed, '
'add the --disable-xcode-checks configure flag')
# Now look for the Command Line Tools.
def no_cltools():
die('Could not find installed Xcode Command Line Tools; '
'run `xcode-select --install` and follow the instructions '
'to install them then try again; if you wish to build without '
'Xcode Command Line Tools installed, '
'add the --disable-xcode-checks configure flag')
check_cmd_output('pkgutil', '--pkg-info',
'com.apple.pkg.CLTools_Executables',
onerror=no_cltools)
check_cmd_output('pkgutil', '--pkg-info',
'com.apple.pkg.CLTools_Executables',
onerror=no_cltools)
return xcode_path
return xcode_path
set_config('XCODE_PATH', xcode_path)

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

@ -14,7 +14,7 @@ const { main } = require("devtools/client/shared/vendor/react-dom-factories");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
const PageContainer = createFactory(require("./layout/PageContainer"));
const PageSwitcher = createFactory(require("./routing/PageSwitcher"));
/**
* This is the main component for the application panel.
@ -31,7 +31,7 @@ class App extends PureComponent {
return LocalizationProvider(
{ bundles: fluentBundles },
main({ className: `application` }, PageContainer({}))
main({ className: `application` }, PageSwitcher({}))
);
}
}

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

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'layout',
'routing',
'manifest',
'service-workers',
'ui',

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

@ -16,7 +16,7 @@ const { PAGE_TYPES } = require("../../constants");
const ManifestPage = createFactory(require("../manifest/ManifestPage"));
const WorkersPage = createFactory(require("../service-workers/WorkersPage"));
class PageContainer extends PureComponent {
class PageSwitcher extends PureComponent {
static get propTypes() {
return {
page: PropTypes.oneOf(Object.values(PAGE_TYPES)),
@ -48,4 +48,4 @@ function mapStateToProps(state) {
};
}
module.exports = connect(mapStateToProps)(PageContainer);
module.exports = connect(mapStateToProps)(PageSwitcher);

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

@ -3,5 +3,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'PageContainer.js',
'PageSwitcher.js',
)

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

@ -5,7 +5,7 @@ exports[`App renders the expected snapshot 1`] = `
<main
className="application"
>
<Connect(PageContainer) />
<Connect(PageSwitcher) />
</main>
</LocalizationProvider>
`;

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

@ -1,9 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PageContainer renders nothing when an invalid page is selected 1`] = `""`;
exports[`PageContainer renders nothing when no page is selected 1`] = `""`;
exports[`PageContainer renders the ManifestPage component when manifest page is selected 1`] = `<ManifestPage />`;
exports[`PageContainer renders the WorkersPage component when workers page is selected 1`] = `<Connect(WorkersPage) />`;

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

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PageSwitcher renders nothing when an invalid page is selected 1`] = `""`;
exports[`PageSwitcher renders nothing when no page is selected 1`] = `""`;
exports[`PageSwitcher renders the ManifestPage component when manifest page is selected 1`] = `<ManifestPage />`;
exports[`PageSwitcher renders the WorkersPage component when workers page is selected 1`] = `<Connect(WorkersPage) />`;

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

@ -14,8 +14,8 @@ const {
setupStore,
} = require("devtools/client/application/test/components/helpers/helpers");
const PageContainer = createFactory(
require("devtools/client/application/src/components/layout/PageContainer")
const PageSwitcher = createFactory(
require("devtools/client/application/src/components/routing/PageSwitcher")
);
const { PAGE_TYPES } = require("devtools/client/application/src/constants");
@ -24,7 +24,7 @@ const { PAGE_TYPES } = require("devtools/client/application/src/constants");
* Test for workerListEmpty.js component
*/
describe("PageContainer", () => {
describe("PageSwitcher", () => {
function buildStoreWithSelectedPage(selectedPage) {
return setupStore({
preloadedState: {
@ -41,26 +41,26 @@ describe("PageContainer", () => {
it("renders the ManifestPage component when manifest page is selected", () => {
const store = buildStoreWithSelectedPage(PAGE_TYPES.MANIFEST);
const wrapper = shallow(PageContainer({ store })).dive();
const wrapper = shallow(PageSwitcher({ store })).dive();
expect(wrapper).toMatchSnapshot();
});
it("renders the WorkersPage component when workers page is selected", () => {
const store = buildStoreWithSelectedPage(PAGE_TYPES.SERVICE_WORKERS);
const wrapper = shallow(PageContainer({ store })).dive();
const wrapper = shallow(PageSwitcher({ store })).dive();
expect(wrapper).toMatchSnapshot();
});
it("renders nothing when no page is selected", () => {
const store = buildStoreWithSelectedPage(null);
const wrapper = shallow(PageContainer({ store })).dive();
const wrapper = shallow(PageSwitcher({ store })).dive();
expect(console.error).toHaveBeenCalledTimes(1);
expect(wrapper).toMatchSnapshot();
});
it("renders nothing when an invalid page is selected", () => {
const store = buildStoreWithSelectedPage("foo");
const wrapper = shallow(PageContainer({ store })).dive();
const wrapper = shallow(PageSwitcher({ store })).dive();
expect(console.error).toHaveBeenCalledTimes(1);
expect(wrapper).toMatchSnapshot();
});

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

@ -198,9 +198,9 @@ function getExpressionNameAndValue(
const property: Object = properties.find(
prop => prop.name === meta.property
);
displayValue = property.contents.value;
displayValue = property && property.contents.value;
displayName += `.${meta.property}`;
} else {
} else if (displayValue && displayValue.preview) {
const { ownProperties } = displayValue.preview;
for (const prop in ownProperties) {
if (prop === meta.property) {

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

@ -22,7 +22,6 @@ class InlinePreview extends PureComponent<Props> {
showInScopes(variable: string) {
// TODO: focus on variable value in the scopes sidepanel
// we will need more info from parent comp
console.log(`show ${variable}`);
}
render() {

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

@ -237,8 +237,6 @@ function Toolbox(
this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
this.closeToolbox = this.closeToolbox.bind(this);
this.destroy = this.destroy.bind(this);
this._highlighterReady = this._highlighterReady.bind(this);
this._highlighterHidden = this._highlighterHidden.bind(this);
this._applyCacheSettings = this._applyCacheSettings.bind(this);
this._applyServiceWorkersTestingSettings = this._applyServiceWorkersTestingSettings.bind(
this
@ -3339,8 +3337,6 @@ Toolbox.prototype = {
"picker-node-canceled",
this._onPickerCanceled
);
this.walker.on("highlighter-ready", this._highlighterReady);
this.walker.on("highlighter-hide", this._highlighterHidden);
this._selection.on("new-node-front", this._onNewSelectedNodeFront);
registerWalkerListeners(this);
}.bind(this)();
@ -3704,14 +3700,6 @@ Toolbox.prototype = {
Services.obs.removeObserver(leakCheckObserver, topic);
},
_highlighterReady: function() {
this.emit("highlighter-ready");
},
_highlighterHidden: function() {
this.emit("highlighter-hide");
},
/**
* Enable / disable necessary textbox menu items using globalOverlay.js.
*/

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

@ -30,11 +30,12 @@ registerCleanupFunction(() => {
*/
async function selectAndHighlightNode(selectorOrNodeFront, inspector) {
info("Highlighting and selecting the node " + selectorOrNodeFront);
const nodeFront = await getNodeFront(selectorOrNodeFront, inspector);
const updated = inspector.toolbox.once("highlighter-ready");
const onHovered = inspector.inspectorFront.nodePicker.once(
"picker-node-hovered"
);
inspector.selection.setNodeFront(nodeFront, { reason: "test-highlight" });
await updated;
await onHovered;
}
/**

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

@ -19,13 +19,13 @@ add_task(async function() {
await selectNode("span", inspector);
const container = await getContainerForSelector("h1", inspector);
const onHighlighterReady = toolbox.once("highlighter-ready");
const onHighlight = toolbox.highlighter.once("node-highlight");
EventUtils.synthesizeMouseAtCenter(
container.tagLine,
{ type: "mousemove" },
inspector.markup.doc.defaultView
);
await onHighlighterReady;
await onHighlight;
isVisible = await testActor.isHighlighting();
ok(isVisible, "The highlighter is shown on a markup container hover");

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

@ -53,17 +53,15 @@ add_task(async function() {
function doKeyHover(args) {
info("Key pressed. Waiting for element to be highlighted/hovered");
const onHighlighterReady = toolbox.once("highlighter-ready");
const onPickerNodeHovered = inspectorFront.nodePicker.once(
"picker-node-hovered"
);
testActor.synthesizeKey(args);
return promise.all([onHighlighterReady, onPickerNodeHovered]);
return onPickerNodeHovered;
}
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
const onHighlighterReady = toolbox.once("highlighter-ready");
const onPickerNodeHovered = inspectorFront.nodePicker.once(
"picker-node-hovered"
);
@ -72,6 +70,6 @@ add_task(async function() {
center: true,
selector: selector,
});
return promise.all([onHighlighterReady, onPickerNodeHovered]);
return onPickerNodeHovered;
}
});

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

@ -69,7 +69,6 @@ add_task(async function() {
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
const onHighlighterReady = toolbox.once("highlighter-ready");
const onPickerNodeHovered = inspector.inspectorFront.nodePicker.once(
"picker-node-hovered"
);
@ -78,6 +77,6 @@ add_task(async function() {
center: true,
selector: selector,
});
return promise.all([onHighlighterReady, onPickerNodeHovered]);
return onPickerNodeHovered;
}
});

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

@ -18,15 +18,17 @@ add_task(async function() {
info("Starting element picker.");
await startPicker(toolbox);
info("Waiting for highlighter to activate.");
const highlighterShowing = toolbox.once("highlighter-ready");
info("Waiting for body to be hovered.");
const onHovered = inspector.inspectorFront.nodePicker.once(
"picker-node-hovered"
);
testActor.synthesizeMouse({
selector: "body",
options: { type: "mousemove" },
x: 1,
y: 1,
});
await highlighterShowing;
await onHovered;
let isVisible = await testActor.isHighlighting();
ok(isVisible, "Inspector is highlighting.");

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

@ -758,6 +758,19 @@ netmonitor.search.labels.responseHeaders=Response Header
# LOCALIZATION NOTE (netmonitor.search.labels.requestHeaders): This is the label
# displayed in the search results as the label for the request headers
netmonitor.search.labels.requestHeaders=Request Header
# LOCALIZATION NOTE (messagesTruncated): This is the text displayed
# in the messages panel when the number of messages is over the
# truncation limit.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
netmonitor.ws.truncated-messages.warning=One message has been truncated to conserve memory;#1 messages have been truncated to conserve memory
# LOCALIZATION NOTE (disableMessagesTruncation): This is the text displayed
# in the messages panel checkbox label for toggling message truncation.
toggleMessagesTruncation=Keep all future messages
# LOCALIZATION NOTE (toggleMessagesTruncation.title): This is the title used
# to describe the checkbox used to toggle message truncation.
toggleMessagesTruncation.title=Keep all future messages or continue showing truncated messages
# LOCALIZATION NOTE (messageDataTruncated): This is the text displayed
# to describe to describe data truncation in the messages panel.

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

@ -37,6 +37,7 @@
}
/* Use lining numbers so that seconds and milliseconds align */
#messages-panel .ws-frames-list-time {
font-variant-numeric: tabular-nums;
}
@ -84,3 +85,49 @@
padding: 4px 8px;
font-size: 12px;
}
/* Styles related to truncated messages */
.theme-light #messages-panel .truncated-messages-header {
background: var(--grey-20);
}
.theme-dark #messages-panel .truncated-messages-header {
background: var(--grey-70);
}
.theme-dark #messages-panel .truncated-messages-warning-icon {
fill: var(--grey-40);
}
#messages-panel .truncated-messages-cell {
padding: 0; /* reset td default padding */
}
#messages-panel .truncated-messages-header {
border-bottom: 1px solid var(--theme-splitter-color);
padding: 2px 8px;
display: flex;
justify-content: space-between;
align-items: center;
}
#messages-panel .truncated-messages-container,
#messages-panel .truncated-messages-checkbox-label {
display: flex;
align-items: center;
}
#messages-panel .truncated-messages-warning-icon {
width: 12px;
height: 12px;
margin-right: 8px;
background-image: url(chrome://global/skin/icons/info.svg);
background-repeat: no-repeat;
-moz-context-properties: fill;
fill: inherit;
}
#messages-panel .truncation-checkbox {
margin-right: 5px;
}

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

@ -9,16 +9,23 @@ const {
createFactory,
} = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Services = require("Services");
const {
connect,
} = require("devtools/client/shared/redux/visibility-handler-connect");
const { PluralForm } = require("devtools/shared/plural-form");
const { getDisplayedFrames } = require("../../selectors/index");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { table, tbody, div } = dom;
const { table, tbody, tr, td, div, input, label } = dom;
const { L10N } = require("../../utils/l10n");
const FRAMES_EMPTY_TEXT = L10N.getStr("messagesEmptyText");
const TOGGLE_MESSAGES_TRUNCATION = L10N.getStr("toggleMessagesTruncation");
const TOGGLE_MESSAGES_TRUNCATION_TITLE = L10N.getStr(
"toggleMessagesTruncation.title"
);
const TRUNCATED_MESSAGES_WARNING = L10N.getStr(
"netmonitor.ws.truncated-messages.warning"
);
const Actions = require("../../actions/index");
const { getSelectedFrame } = require("../../selectors/index");
@ -46,6 +53,18 @@ class FrameListContent extends Component {
};
}
constructor(props) {
super(props);
this.framesLimit = Services.prefs.getIntPref(
"devtools.netmonitor.ws.displayed-frames.limit"
);
this.currentTruncatedNum = 0;
this.state = {
checked: false,
};
}
onMouseDown(evt, item) {
if (evt.button === LEFT_MOUSE_BUTTON) {
this.props.selectFrame(item);
@ -66,23 +85,96 @@ class FrameListContent extends Component {
.filter(([name, isVisible]) => isVisible)
.map(([name]) => name);
return table(
{ className: "ws-frames-list-table" },
FrameListHeader(),
tbody(
{
className: "ws-frames-list-body",
},
frames.map((item, index) =>
FrameListItem({
key: "ws-frame-list-item-" + index,
item,
index,
isSelected: item === selectedFrame,
onMouseDown: evt => this.onMouseDown(evt, item),
connector,
visibleColumns,
})
let displayedFrames;
let MESSAGES_TRUNCATED;
const shouldTruncate = frames.length > this.framesLimit;
if (shouldTruncate) {
// If the checkbox is checked, we display all frames after the currentedTruncatedNum limit.
// If the checkbox is unchecked, we display all frames after the framesLimit.
this.currentTruncatedNum = this.state.checked
? this.currentTruncatedNum
: frames.length - this.framesLimit;
displayedFrames = frames.slice(this.currentTruncatedNum);
MESSAGES_TRUNCATED = PluralForm.get(
this.currentTruncatedNum,
L10N.getStr("netmonitor.ws.truncated-messages.warning")
).replace("#1", this.currentTruncatedNum);
} else {
displayedFrames = frames;
}
return div(
{},
table(
{ className: "ws-frames-list-table" },
FrameListHeader(),
tr(
{
tabIndex: 0,
},
td(
{
className: "truncated-messages-cell",
colSpan: visibleColumns.length,
},
shouldTruncate &&
div(
{
className: "truncated-messages-header",
},
div(
{
className: "truncated-messages-container",
},
div({
className: "truncated-messages-warning-icon",
title: TRUNCATED_MESSAGES_WARNING,
}),
div(
{
className: "truncated-message",
title: MESSAGES_TRUNCATED,
},
MESSAGES_TRUNCATED
)
),
label(
{
className: "truncated-messages-checkbox-label",
title: TOGGLE_MESSAGES_TRUNCATION_TITLE,
},
input({
type: "checkbox",
className: "truncation-checkbox",
title: TOGGLE_MESSAGES_TRUNCATION_TITLE,
checked: this.state.checked,
onClick: () => {
this.setState({
checked: !this.state.checked,
});
},
}),
TOGGLE_MESSAGES_TRUNCATION
)
)
)
),
tbody(
{
className: "ws-frames-list-body",
},
displayedFrames.map((item, index) =>
FrameListItem({
key: "ws-frame-list-item-" + index,
item,
index,
isSelected: item === selectedFrame,
onMouseDown: evt => this.onMouseDown(evt, item),
connector,
visibleColumns,
})
)
)
)
);

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

@ -184,6 +184,7 @@ pref("devtools.netmonitor.ws.payload-preview-height", 128);
pref("devtools.netmonitor.ws.visibleColumns",
'["data", "time"]'
);
pref("devtools.netmonitor.ws.displayed-frames.limit", 500);
pref("devtools.netmonitor.response.ui.limit", 10240);

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

@ -114,8 +114,6 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
this._highlighterEnv = new HighlighterEnvironment();
this._highlighterEnv.initFromTargetActor(this._targetActor);
this._highlighterReady = this._highlighterReady.bind(this);
this._highlighterHidden = this._highlighterHidden.bind(this);
this._onNavigate = this._onNavigate.bind(this);
const doc = this._targetActor.window.document;
@ -148,8 +146,6 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
this._highlighterEnv,
this._inspector
);
this._highlighter.on("ready", this._highlighterReady);
this._highlighter.on("hide", this._highlighterHidden);
} else {
this._highlighter = new SimpleOutlineHighlighter(this._highlighterEnv);
}
@ -157,10 +153,6 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
_destroyHighlighter: function() {
if (this._highlighter) {
if (!this._isPreviousWindowXUL) {
this._highlighter.off("ready", this._highlighterReady);
this._highlighter.off("hide", this._highlighterHidden);
}
this._highlighter.destroy();
this._highlighter = null;
}
@ -481,14 +473,6 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
this._setSuppressedEventListener(null);
},
_highlighterReady: function() {
this._inspector.walker.emit("highlighter-ready");
},
_highlighterHidden: function() {
this._inspector.walker.emit("highlighter-hide");
},
cancelPick: function() {
if (this._targetActor.threadActor) {
this._targetActor.threadActor.showOverlay();

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

@ -331,7 +331,6 @@ class BoxModelHighlighter extends AutoRefreshHighlighter {
const shown = this._update();
this._trackMutations();
this.emit("ready");
return shown;
}

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

@ -9922,6 +9922,7 @@ exports.CSS_PROPERTIES = {
"dashed",
"dotted",
"double",
"from-font",
"hsl",
"hsla",
"inherit",

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

@ -69,12 +69,6 @@ const walkerSpec = generateActorSpec({
"picker-node-canceled": {
type: "pickerNodeCanceled",
},
"highlighter-ready": {
type: "highlighter-ready",
},
"highlighter-hide": {
type: "highlighter-hide",
},
"display-change": {
type: "display-change",
nodes: Arg(0, "array:domnode"),

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

@ -197,7 +197,8 @@ BrowsingContext::BrowsingContext(BrowsingContext* aParent,
mGroup(aGroup),
mParent(aParent),
mIsInProcess(false),
mIsDiscarded(false) {
mIsDiscarded(false),
mDanglingRemoteOuterProxies(false) {
MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
MOZ_RELEASE_ASSERT(mGroup);
@ -208,9 +209,54 @@ void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
// process to the parent & do other validation here.
MOZ_RELEASE_ASSERT(aDocShell->GetBrowsingContext() == this);
mDocShell = aDocShell;
mDanglingRemoteOuterProxies = !mIsInProcess;
mIsInProcess = true;
}
// This class implements a callback that will return the remote window proxy for
// mBrowsingContext in that compartment, if it has one. It also removes the
// proxy from the map, because the object will be transplanted into another kind
// of object.
class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
: public js::CompartmentTransplantCallback {
public:
explicit CompartmentRemoteProxyTransplantCallback(
BrowsingContext* aBrowsingContext)
: mBrowsingContext(aBrowsingContext) {}
virtual JSObject* getObjectToTransplant(
JS::Compartment* compartment) override {
auto* priv = xpc::CompartmentPrivate::Get(compartment);
if (!priv) {
return nullptr;
}
auto& map = priv->GetRemoteProxyMap();
auto result = map.lookup(mBrowsingContext);
if (!result) {
return nullptr;
}
JSObject* resultObject = result->value();
map.remove(result);
return resultObject;
}
private:
BrowsingContext* mBrowsingContext;
};
void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
JSContext* aCx, JS::MutableHandle<JSObject*> aOuter) {
if (!mDanglingRemoteOuterProxies) {
return;
}
mDanglingRemoteOuterProxies = false;
CompartmentRemoteProxyTransplantCallback cb(this);
js::RemapRemoteWindowProxies(aCx, &cb, aOuter);
}
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
// Notify the parent process of the embedding status. We don't need to do
// this when clearing our embedder, as we're being destroyed either way.

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

@ -139,6 +139,15 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
void SetDocShell(nsIDocShell* aDocShell);
void ClearDocShell() { mDocShell = nullptr; }
// This cleans up remote outer window proxies that might have been left behind
// when the browsing context went from being remote to local. It does this by
// turning them into cross-compartment wrappers to aOuter. If there is already
// a remote proxy in the compartment of aOuter, then aOuter will get swapped
// to it and the value of aOuter will be set to the object that used to be the
// remote proxy and is now an OuterWindowProxy.
void CleanUpDanglingRemoteOuterWindowProxies(
JSContext* aCx, JS::MutableHandle<JSObject*> aOuter);
// Get the embedder element for this BrowsingContext if the embedder is
// in-process, or null if it's not.
Element* GetEmbedderElement() const { return mEmbedderElement; }
@ -491,6 +500,10 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
// Has this browsing context been discarded? BrowsingContexts should
// only be discarded once.
bool mIsDiscarded : 1;
// This is true if the BrowsingContext was out of process, but is now in
// process, and might have remote window proxies that need to be cleaned up.
bool mDanglingRemoteOuterProxies : 1;
};
/**

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

@ -15819,6 +15819,12 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) {
}
}
// static
bool Document::UseOverlayScrollbars(const Document* aDocument) {
return LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) ||
(aDocument && aDocument->InRDMPane());
}
bool Document::HasRecentlyStartedForegroundLoads() {
if (!sLoadingForegroundTopLevelContentDocument) {
return false;

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

@ -4123,6 +4123,10 @@ class Document : public nsINode,
bool InRDMPane() const { return mInRDMPane; }
void SetInRDMPane(bool aInRDMPane) { mInRDMPane = aInRDMPane; }
// Returns true if we use overlay scrollbars on the system wide or on the
// given document.
static bool UseOverlayScrollbars(const Document* aDocument);
static bool HasRecentlyStartedForegroundLoads();
protected:

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

@ -783,7 +783,7 @@ void nsContentList::PopulateSelf(uint32_t aNeededLength,
if (mDeep) {
// If we already have nodes start searching at the last one, otherwise
// start searching at the root.
nsINode* cur = count ? mElements[count - 1] : mRootNode;
nsINode* cur = count ? mElements[count - 1].get() : mRootNode;
do {
cur = cur->GetNextNode(mRootNode);
if (!cur) {

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

@ -4211,3 +4211,9 @@ nsDOMWindowUtils::GetLayersId(uint64_t* aOutLayersId) {
*aOutLayersId = (uint64_t)child->GetLayersId();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetUsesOverlayScrollbars(bool* aResult) {
*aResult = Document::UseOverlayScrollbars(GetDocument());
return NS_OK;
}

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

@ -2070,6 +2070,9 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
mBrowsingContext->CleanUpDanglingRemoteOuterWindowProxies(cx, &outer);
MOZ_ASSERT(js::IsWindowProxy(outer));
js::SetProxyReservedSlot(outer, OUTER_WINDOW_SLOT,
js::PrivateValue(ToSupports(this)));

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

@ -15,18 +15,6 @@ add_task(async function() {
});
});
// Ensure that the preloaded browser exists, and it's finished loading.
async function ensurePreloaded(gBrowser) {
NewTabPagePreloading.maybeCreatePreloadedBrowser(gBrowser.ownerGlobal);
// We cannot use the regular BrowserTestUtils helper for waiting here, since that
// would try to insert the preloaded browser, which would only break things.
await ContentTask.spawn(gBrowser.preloadedBrowser, null, async () => {
await ContentTaskUtils.waitForCondition(() => {
return content.document && content.document.readyState == "complete";
});
});
}
add_task(async function() {
// This test is only relevant in e10s.
if (!gMultiProcessBrowser) {
@ -36,7 +24,7 @@ add_task(async function() {
ppmm.releaseCachedProcesses();
// Wait for the preloaded browser to load.
await ensurePreloaded(gBrowser);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
// Store the number of processes (note: +1 for the parent process).
const { childCount: originalChildCount } = ppmm;
@ -44,7 +32,7 @@ add_task(async function() {
// Use the preloaded browser and create another one.
BrowserOpenTab();
let tab1 = gBrowser.selectedTab;
await ensurePreloaded(gBrowser);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
// Check that the process count did not change.
is(
@ -56,7 +44,7 @@ add_task(async function() {
// Let's do another round.
BrowserOpenTab();
let tab2 = gBrowser.selectedTab;
await ensurePreloaded(gBrowser);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
// Check that the process count did not change.
is(
@ -102,7 +90,7 @@ add_task(async function() {
add_task(async function preloaded_state_attribute() {
// Wait for a preloaded browser to exist, use it, and then create another one
await ensurePreloaded(gBrowser);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
let preloadedTabState = gBrowser.preloadedBrowser.getAttribute(
"preloadedState"
);
@ -113,7 +101,7 @@ add_task(async function preloaded_state_attribute() {
);
BrowserOpenTab();
await ensurePreloaded(gBrowser);
await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
// Now check that the tabs have the correct browser attributes set
let consumedTabState = gBrowser.selectedBrowser.getAttribute(

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

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=0.5">
<style>
html {
scrollbar-width: none; /* avoid scrollbar width is included in some metrics */
}
html, body {
margin: 0;
width: 100%;
height: 100%;
overflow: none;
}
#twice-width {
width: 200%;
height: 100%;
position: absolute;
}
</style>
<div id="twice-width"></div>
<script>
const is = opener.is.bind(opener);
const todo_is = opener.todo_is.bind(opener);
const add_task = opener.add_task.bind(opener);
const original_finish = opener.SimpleTest.finish;
const SimpleTest = opener.SimpleTest;
SimpleTest.finish = function finish() {
self.close();
original_finish();
}
add_task(async () => {
// Explicitly set to 0.5x so that this test doesn't need to reply on our
// auto initial-scale calculation.
SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(0.5);
is(window.visualViewport.scale, 0.5, "The content should be scaled by 0.5x");
// Now the visual viewport size is same as the layout viewport.
const layoutViewportHeight = window.visualViewport.height;
is(window.innerHeight, layoutViewportHeight,
"window.innerHeight should reflect the layout viewport");
is(document.documentElement.scrollHeight, layoutViewportHeight,
"The root element's scrollHeight should be the layout viewport height");
is(document.documentElement.getBoundingClientRect().height,
layoutViewportHeight / 2,
"The content height should be half of the layout viewport height");
// Set scale to 1.0x so that the visual viport size becomes 0.5x of the layout
// viewport.
SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(1);
is(window.visualViewport.scale, 1, "The content should be scaled by 1.0x");
is(window.visualViewport.height, layoutViewportHeight / 2,
"Now the visual viewport height should be changed to half of the layout " +
"viewport height");
todo_is(window.innerHeight, layoutViewportHeight,
"window.innerHeight shouldn't be changed (Bug 1514429)");
is(document.documentElement.scrollHeight, layoutViewportHeight,
"The root element's scrollHeight shouldn't be changed");
});
</script>
</html>

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

@ -852,6 +852,9 @@ support-files = file_title.xul
[test_treewalker_nextsibling.xml]
[test_user_select.html]
skip-if = toolkit == 'android'
[test_viewport_metrics_on_landscape_content.html]
support-files =
file_viewport_metrics_on_landscape_content.html
[test_viewport_scroll.html]
[test_viewsource_forbidden_in_object.html]
[test_w3element_traversal.html]

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

@ -0,0 +1,21 @@
<!doctype html>
<meta charset=utf-8>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script>
'use strict';
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
"set": [
["apz.allow_zooming", true],
["dom.meta-viewport.enabled", true],
]
}, () => {
// We need to open a new window to avoid running tests in an iframe since
// we want to test metrics on the root document.
window.open("file_viewport_metrics_on_landscape_content.html");
});
</script>

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

@ -2932,7 +2932,7 @@ class CGNativeProperties(CGList):
post = fill(
"""
$*{post}
static_assert(${propertyInfoCount} < 1ull << CHAR_BIT * sizeof(${name}.propertyInfoCount),
static_assert(${propertyInfoCount} < 1ull << (CHAR_BIT * sizeof(${name}.propertyInfoCount)),
"We have a property info count that is oversized");
""",
post=post,

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

@ -1,35 +1,25 @@
#! /usr/bin/env python2
#! /usr/bin/env python3
import sys
import os.path
import pathlib
import re
assert len(sys.argv) == 2
mochiPath = sys.argv[1]
MOCHI_PATH = pathlib.Path(sys.argv[1])
assert MOCHI_PATH.suffix == '.html'
extDotPos = mochiPath.find('.html')
assert extDotPos != -1, 'mochitest target must be an html doc.'
TEST_PATH = MOCHI_PATH.with_suffix('.solo.html')
testPath = mochiPath[:extDotPos] + '.solo.html'
def ReadLocalFile(include):
incPath = os.path.dirname(mochiPath)
filePath = os.path.join(incPath, include)
data = None
try:
f = open(filePath, 'r')
data = f.read()
except:
pass
def read_local_file(include):
inc_path = MOCHI_PATH.parent
file_path = inc_path / include
try:
f.close()
except:
pass
return file_path.read_bytes()
except IOError:
return b''
return data
kSimpleTestReplacement = '''
SIMPLETEST_REPLACEMENT = b'''
<script>
// SimpleTest.js replacement
@ -72,42 +62,42 @@ SpecialPowers = {
'''
fin = open(mochiPath, 'rb')
fout = open(testPath, 'wb')
includePattern = re.compile('<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
cssPattern = re.compile('<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
for line in fin:
skipLine = False
for css in cssPattern.findall(line):
skipLine = True
print('Ignoring stylesheet: ' + css)
INCLUDE_PATTERN = re.compile(b'<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
CSS_PATTERN = re.compile(b'<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
for inc in includePattern.findall(line):
skipLine = True
if inc == '/MochiKit/MochiKit':
with open(TEST_PATH, 'wb') as fout:
with open(MOCHI_PATH, 'rb') as fin:
for line in fin:
skip_line = False
for css in CSS_PATTERN.findall(line):
skip_line = True
print('Ignoring stylesheet: ' + css.decode())
for inc in INCLUDE_PATTERN.findall(line):
skip_line = True
if inc == b'/MochiKit/MochiKit':
continue
if inc == b'/tests/SimpleTest/SimpleTest':
print('Injecting SimpleTest replacement')
fout.write(SIMPLETEST_REPLACEMENT);
continue
inc_js = inc.decode() + '.js'
inc_data = read_local_file(inc_js)
if not inc_data:
print('Warning: Unknown JS file ignored: ' + inc_js)
continue
print('Injecting include: ' + inc_js)
fout.write(b'\n<script>\n// Imported from: ' + inc_js.encode() + b'\n');
fout.write(inc_data);
fout.write(b'\n</script>\n');
continue
if skip_line:
continue
fout.write(line)
continue
if inc == '/tests/SimpleTest/SimpleTest':
print('Injecting SimpleTest replacement')
fout.write(kSimpleTestReplacement);
continue
incData = ReadLocalFile(inc + '.js')
if not incData:
print('Warning: Unknown JS file ignored: ' + inc + '.js')
continue
print('Injecting include: ' + inc + '.js')
fout.write('\n<script>\n// Imported from: ' + inc + '.js\n');
fout.write(incData);
fout.write('\n</script>\n');
continue
if skipLine:
continue
fout.write(line)
continue
fin.close()
fout.close()

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

@ -44,9 +44,7 @@ skip-if = (toolkit == 'android') # Android: Bug 775227
[test_fileapi_slice_image.html]
skip-if = (toolkit == 'android') # Android: Bug 775227
[test_mozfiledataurl.html]
skip-if =
toolkit == 'android' || #TIMED_OUT
fission # Crashes: @ mozilla::dom::RemoteObjectProxyBase::GetOrCreateProxyObject(JSContext*, void*, js::Class const*, JS::Handle<JSObject*>, JS::MutableHandle<JSObject*>, bool&) const
skip-if = toolkit == 'android' #TIMED_OUT
[test_bug1507893.html]
support-files = worker_bug1507893.js
[test_blob_reading.html]

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

@ -1999,6 +1999,9 @@ interface nsIDOMWindowUtils : nsISupports {
void syncFlushCompositor();
unsigned long long getLayersId();
// Returns true if we are using overlay scrollbars.
readonly attribute bool usesOverlayScrollbars;
};
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]

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

@ -52,6 +52,24 @@ static void FrameCallback(void* aEncoder, void* aFrameParams, OSStatus aStatus,
static_cast<AppleVTEncoder*>(aEncoder)->OutputFrame(aSampleBuffer);
}
static bool SetAverageBitrate(VTCompressionSessionRef& aSession,
MediaDataEncoder::Rate aBitsPerSec) {
int64_t bps(aBitsPerSec);
AutoCFRelease<CFNumberRef> bitrate(
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &bps));
return VTSessionSetProperty(aSession,
kVTCompressionPropertyKey_AverageBitRate,
bitrate) == noErr;
}
static bool SetRealtimeProperties(VTCompressionSessionRef& aSession) {
return VTSessionSetProperty(aSession, kVTCompressionPropertyKey_RealTime,
kCFBooleanTrue) == noErr &&
VTSessionSetProperty(aSession,
kVTCompressionPropertyKey_AllowFrameReordering,
kCFBooleanFalse) == noErr;
}
static bool SetProfileLevel(VTCompressionSessionRef& aSession,
AppleVTEncoder::H264Specific::ProfileLevel aValue) {
CFStringRef profileLevel = nullptr;
@ -77,8 +95,10 @@ RefPtr<MediaDataEncoder::InitPromise> AppleVTEncoder::Init() {
AutoCFRelease<CFDictionaryRef> srcBufferAttr(
BuildSourceImageBufferAttributes());
if (!srcBufferAttr) {
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR,
__func__);
return InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR,
"fail to create source buffer attributes"),
__func__);
}
OSStatus status = VTCompressionSessionCreate(
@ -86,28 +106,49 @@ RefPtr<MediaDataEncoder::InitPromise> AppleVTEncoder::Init() {
kCMVideoCodecType_H264, spec, srcBufferAttr, kCFAllocatorDefault,
&FrameCallback, this, &mSession);
if (status != noErr) {
VTENC_LOGE("fail to create encoder session");
// TODO: new error codes for encoder
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR, __func__);
return InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
"fail to create encoder session"),
__func__);
}
const Maybe<H264Specific>& h264Config = mConfig.mCodecSpecific;
if (h264Config) {
if (!SetProfileLevel(mSession, h264Config.ref().mProfileLevel)) {
VTENC_LOGE("fail to configurate profile level");
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR,
__func__);
if (!SetAverageBitrate(mSession, mConfig.mBitsPerSec)) {
return InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
"fail to configurate average bitrate"),
__func__);
}
if (mConfig.mUsage == Usage::Realtime && !SetRealtimeProperties(mSession)) {
VTENC_LOGE("fail to configurate realtime properties");
return InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
"fail to configurate average bitrate"),
__func__);
}
if (mConfig.mCodecSpecific) {
const H264Specific& specific = mConfig.mCodecSpecific.ref();
if (!SetProfileLevel(mSession, specific.mProfileLevel)) {
return InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
nsPrintfCString("fail to configurate profile level:%d",
specific.mProfileLevel)),
__func__);
}
int64_t interval = h264Config.ref().mKeyframeInterval;
int64_t interval = specific.mKeyframeInterval;
AutoCFRelease<CFNumberRef> cf(
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &interval));
if (VTSessionSetProperty(mSession,
kVTCompressionPropertyKey_MaxKeyFrameInterval,
cf) != noErr) {
VTENC_LOGE("fail to configurate keyframe interval");
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR,
__func__);
return InitPromise::CreateAndReject(
MediaResult(
NS_ERROR_DOM_MEDIA_FATAL_ERR,
nsPrintfCString("fail to configurate keyframe interval:%" PRId64,
interval)),
__func__);
}
}
@ -543,11 +584,7 @@ RefPtr<GenericPromise> AppleVTEncoder::SetBitrate(
RefPtr<AppleVTEncoder> self = this;
return InvokeAsync(mTaskQueue, __func__, [self, aBitsPerSec]() {
MOZ_ASSERT(self->mSession);
AutoCFRelease<CFNumberRef> bitrate(
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &aBitsPerSec));
return VTSessionSetProperty(self->mSession,
kVTCompressionPropertyKey_AverageBitRate,
bitrate) == noErr
return SetAverageBitrate(self->mSession, aBitsPerSec)
? GenericPromise::CreateAndResolve(true, __func__)
: GenericPromise::CreateAndReject(
NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, __func__);

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

@ -514,12 +514,9 @@ void nsContentSecurityManager::AssertEvalNotRestricted(
/* static */
nsresult nsContentSecurityManager::CheckFTPSubresourceLoad(
nsIChannel* aChannel) {
// We dissallow using FTP resources as a subresource almost everywhere.
// We dissallow using FTP resources as a subresource everywhere.
// The only valid way to use FTP resources is loading it as
// a top level document.
if (!mozilla::net::nsIOService::BlockFTPSubresources()) {
return NS_OK;
}
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsContentPolicyType type = loadInfo->GetExternalContentPolicyType();
@ -550,13 +547,6 @@ nsresult nsContentSecurityManager::CheckFTPSubresourceLoad(
return NS_OK;
}
// Allow loading FTP subresources in FTP documents, like XML.
nsCOMPtr<nsIURI> triggeringURI;
triggeringPrincipal->GetURI(getter_AddRefs(triggeringURI));
if (triggeringURI && nsContentUtils::SchemeIs(triggeringURI, "ftp")) {
return NS_OK;
}
nsCOMPtr<Document> doc;
if (nsINode* node = loadInfo->LoadingNode()) {
doc = node->OwnerDoc();

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

@ -39,13 +39,11 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_block_subresource_redir_to_data.html]
[test_same_site_cookies_subrequest.html]
skip-if = fission && debug # Crashes: @ mozilla::dom::RemoteObjectProxyBase::GetOrCreateProxyObject(JSContext*, void*, js::Class const*, JS::Handle<JSObject*>, JS::MutableHandle<JSObject*>, bool&) const
[test_same_site_cookies_toplevel_nav.html]
skip-if = fission # Crashes: @ mozilla::dom::ContentParent::CommonCreateWindow(mozilla::dom::PBrowserParent*, bool, unsigned int const&, bool const&, bool const&, bool const&, nsIURI*, nsTString<char> const&, float const&, unsigned long, nsTString<char16_t> const&, nsresult&, nsCOMPtr<nsIRemoteTab>&, bool*, int&, nsIPrincipal*, nsIReferrerInfo*, bool, nsIContentSecurityPolicy*)
[test_same_site_cookies_cross_origin_context.html]
[test_same_site_cookies_from_script.html]
[test_same_site_cookies_redirect.html]
skip-if = fission # Crashes: @ mozilla::dom::RemoteObjectProxyBase::GetOrCreateProxyObject(JSContext*, void*, js::Class const*, JS::Handle<JSObject*>, JS::MutableHandle<JSObject*>, bool&) const
[test_same_site_cookies_toplevel_set_cookie.html]
skip-if = fission
[test_same_site_cookies_iframe.html]

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

@ -90,6 +90,11 @@ add_task(async function() {
content.win1 = iframe.contentWindow;
let chromeWin1 = iframe.contentWindow;
let chromeWin1x = Cu.waiveXrays(iframe.contentWindow);
content.win1x = Cu.waiveXrays(iframe.contentWindow);
ok(chromeWin1 != chromeWin1x, "waiving xrays creates a new thing?");
content.bc1 = iframe.browsingContext;
is(
@ -148,6 +153,14 @@ add_task(async function() {
!Cu.isDeadWrapper(chromeWin1),
"chromeWin1 shouldn't be a dead wrapper after navigation"
);
ok(
Cu.isDeadWrapper(chromeWin1x),
"chromeWin1x should be a dead wrapper after navigation"
);
ok(
Cu.isDeadWrapper(content.win1x),
"content.win1x should be a dead wrapper after navigation"
);
is(
content.bc1,
@ -193,8 +206,9 @@ add_task(async function() {
content.bc4,
"cross to same-origin navigation BrowsingContext match"
);
todo(
content.win3 == content.win4,
is(
content.win3,
content.win4,
"cross to same-origin navigation WindowProxy match"
);
}

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

@ -4134,6 +4134,7 @@ void WorkerPrivate::ReportError(JSContext* aCx,
&stackGlobal);
if (stack) {
JSAutoRealm ar(aCx, stackGlobal);
report->SerializeWorkerStack(aCx, this, stack);
}

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

@ -16,7 +16,7 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/WorkletImpl.h"
#include "js/CompilationAndEvaluation.h"
#include "js/Modules.h"
#include "js/SourceText.h"
#include "nsIInputStreamPump.h"
#include "nsIThreadRetargetableRequest.h"
@ -50,6 +50,8 @@ class ExecutionRunnable final : public Runnable {
void RunOnMainThread();
bool ParseAndLinkModule(JSContext* aCx, JS::MutableHandle<JSObject*> aModule);
RefPtr<WorkletFetchHandler> mHandler;
RefPtr<WorkletImpl> mWorkletImpl;
JS::UniqueTwoByteChars mScriptBuffer;
@ -336,6 +338,33 @@ ExecutionRunnable::Run() {
return NS_OK;
}
bool ExecutionRunnable::ParseAndLinkModule(
JSContext* aCx, JS::MutableHandle<JSObject*> aModule) {
JS::CompileOptions compileOptions(aCx);
compileOptions.setIntroductionType("Worklet");
compileOptions.setFileAndLine(mHandler->URL().get(), 0);
compileOptions.setIsRunOnce(true);
compileOptions.setNoScriptRval(true);
JS::SourceText<char16_t> buffer;
if (!buffer.init(aCx, std::move(mScriptBuffer), mScriptLength)) {
return false;
}
JS::Rooted<JSObject*> module(aCx,
JS::CompileModule(aCx, compileOptions, buffer));
if (!module) {
return false;
}
// Link() was previously named Instantiate().
// https://github.com/tc39/ecma262/pull/1312
// Any imports will fail here - bug 1572644.
if (!JS::ModuleInstantiate(aCx, module)) {
return false;
}
aModule.set(module);
return true;
}
void ExecutionRunnable::RunOnWorkletThread() {
WorkletThread::EnsureCycleCollectedJSContext(mParentRuntime);
@ -345,20 +374,8 @@ void ExecutionRunnable::RunOnWorkletThread() {
AutoEntryScript aes(globalScope, "Worklet");
JSContext* cx = aes.cx();
JS::Rooted<JSObject*> globalObj(cx, globalScope->GetGlobalJSObject());
JS::CompileOptions compileOptions(cx);
compileOptions.setIntroductionType("Worklet");
compileOptions.setFileAndLine(mHandler->URL().get(), 0);
compileOptions.setIsRunOnce(true);
compileOptions.setNoScriptRval(true);
JSAutoRealm ar(cx, globalObj);
JS::Rooted<JS::Value> unused(cx);
JS::SourceText<char16_t> buffer;
if (!buffer.init(cx, std::move(mScriptBuffer), mScriptLength) ||
!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
JS::Rooted<JSObject*> module(cx);
if (!ParseAndLinkModule(cx, &module)) {
ErrorResult error;
error.MightThrowJSException();
error.StealExceptionFromJSContext(cx);
@ -366,6 +383,14 @@ void ExecutionRunnable::RunOnWorkletThread() {
return;
}
// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
// invokes
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script
// without /rethrow errors/ and so unhandled exceptions do not cause the
// promise to be rejected.
JS::ModuleEvaluate(cx, module);
JS::Rooted<JS::Value> unused(cx);
// All done.
mResult = NS_OK;
}

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

@ -32,9 +32,9 @@ function runTestInIframe() {
return audioContext.audioWorklet.addModule("worklet_exception.js")
})
.then(() => {
ok(false, "We should not be called!");
ok(true, "The script threw but we are still here.");
}, () => {
ok(true, "The script thrown but we are still here.");
ok(false, "We should not be called!");
})
.then(() => {

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

@ -12,5 +12,5 @@ class DummyProcessWorkletProcessor extends AudioWorkletProcessor {
// and the console.log won't be executed
registerProcessor("sure!", DummyProcessWorkletProcessor);
console.log(
this instanceof AudioWorkletGlobalScope ? "So far so good" : "error"
globalThis instanceof AudioWorkletGlobalScope ? "So far so good" : "error"
);

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

@ -1,5 +1,5 @@
// This should work for real... at some point.
registerPaint("sure!", () => {});
console.log(
this instanceof PaintWorkletGlobalScope ? "So far so good" : "error"
globalThis instanceof PaintWorkletGlobalScope ? "So far so good" : "error"
);

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

@ -44,6 +44,7 @@ class gfxVarReceiver;
_(UseWebRenderDCompWin, bool, false) \
_(UseWebRenderTripleBufferingWin, bool, false) \
_(UseWebRenderProgramBinaryDisk, bool, false) \
_(WorkaroundWebRenderIntelBug1556634, bool, false) \
_(WebRenderDebugFlags, int32_t, 0) \
_(ScreenDepth, int32_t, 0) \
_(GREDirectory, nsString, nsString()) \

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

@ -1133,6 +1133,7 @@
#define LOCAL_GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
#define LOCAL_GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF
#define LOCAL_GL_DEPTH_CLAMP 0x864F
#define LOCAL_GL_DEPTH_CLAMP_EXT 0x864F
#define LOCAL_GL_DEPTH_CLAMP_FAR_AMD 0x901F
#define LOCAL_GL_DEPTH_CLAMP_NEAR_AMD 0x901E
#define LOCAL_GL_DEPTH_CLAMP_NV 0x864F
@ -4737,6 +4738,19 @@
#define LOCAL_GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216
#define LOCAL_GL_STRICT_LIGHTING_HINT_PGI 0x1A217
#define LOCAL_GL_STRICT_SCISSOR_HINT_PGI 0x1A218
#define LOCAL_GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004
#define LOCAL_GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008
#define LOCAL_GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001
#define LOCAL_GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040
#define LOCAL_GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV 0x00000100
#define LOCAL_GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080
#define LOCAL_GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010
#define LOCAL_GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020
#define LOCAL_GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002
#define LOCAL_GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535
#define LOCAL_GL_SUBGROUP_SIZE_KHR 0x9532
#define LOCAL_GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534
#define LOCAL_GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533
#define LOCAL_GL_SUBPIXEL_BITS 0x0D50
#define LOCAL_GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347
#define LOCAL_GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348
@ -5569,6 +5583,7 @@
#define LOCAL_GL_UNSIGNED_SHORT_8_8_MESA 0x85BA
#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB
#define LOCAL_GL_UPLOAD_GPU_MASK_NVX 0x954A
#define LOCAL_GL_UPPER_LEFT 0x8CA2
#define LOCAL_GL_UPPER_LEFT_EXT 0x8CA2
#define LOCAL_GL_USE_MISSING_GLYPH_NV 0x90AA
@ -5577,6 +5592,7 @@
#define LOCAL_GL_UUID_SIZE_EXT 16
#define LOCAL_GL_V2F 0x2A20
#define LOCAL_GL_V3F 0x2A21
#define LOCAL_GL_VALIDATE_SHADER_BINARY_QCOM 0x96A3
#define LOCAL_GL_VALIDATE_STATUS 0x8B83
#define LOCAL_GL_VARIABLE_A_NV 0x8523
#define LOCAL_GL_VARIABLE_B_NV 0x8524
@ -5806,8 +5822,27 @@
#define LOCAL_GL_VIEW_CLASS_64_BITS 0x82C6
#define LOCAL_GL_VIEW_CLASS_8_BITS 0x82CB
#define LOCAL_GL_VIEW_CLASS_96_BITS 0x82C5
#define LOCAL_GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393
#define LOCAL_GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390
#define LOCAL_GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391
#define LOCAL_GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392
#define LOCAL_GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394
#define LOCAL_GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395
#define LOCAL_GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388
#define LOCAL_GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389
#define LOCAL_GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A
#define LOCAL_GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B
#define LOCAL_GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C
#define LOCAL_GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D
#define LOCAL_GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E
#define LOCAL_GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F
#define LOCAL_GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
#define LOCAL_GL_VIEW_CLASS_BPTC_UNORM 0x82D2
#define LOCAL_GL_VIEW_CLASS_EAC_R11 0x9383
#define LOCAL_GL_VIEW_CLASS_EAC_RG11 0x9384
#define LOCAL_GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387
#define LOCAL_GL_VIEW_CLASS_ETC2_RGB 0x9385
#define LOCAL_GL_VIEW_CLASS_ETC2_RGBA 0x9386
#define LOCAL_GL_VIEW_CLASS_RGTC1_RED 0x82D0
#define LOCAL_GL_VIEW_CLASS_RGTC2_RG 0x82D1
#define LOCAL_GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
@ -5887,7 +5922,6 @@
#define LOCAL_GL_ZOOM_Y 0x0D17
#define LOCAL_GL_Z_EXT 0x87D7
// EGL
#define LOCAL_EGL_ALPHA_FORMAT 0x3088
#define LOCAL_EGL_ALPHA_FORMAT_NONPRE 0x308B
@ -5926,6 +5960,7 @@
#define LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
#define LOCAL_EGL_BITMAP_POINTER_KHR 0x30C6
#define LOCAL_EGL_BLUE_SIZE 0x3022
#define LOCAL_EGL_BOTTOM_NV 0x336E
#define LOCAL_EGL_BUFFER_AGE_EXT 0x313D
#define LOCAL_EGL_BUFFER_AGE_KHR 0x313D
#define LOCAL_EGL_BUFFER_COUNT_NV 0x321D
@ -5961,6 +5996,7 @@
#define LOCAL_EGL_CONFORMANT 0x3042
#define LOCAL_EGL_CONFORMANT_KHR 0x3042
#define LOCAL_EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
#define LOCAL_EGL_CONSUMER_AUTO_ORIENTATION_NV 0x3369
#define LOCAL_EGL_CONSUMER_FRAME_KHR 0x3213
#define LOCAL_EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
#define LOCAL_EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338
@ -6059,6 +6095,7 @@
#define LOCAL_EGL_DRM_CONNECTOR_EXT 0x3236
#define LOCAL_EGL_DRM_CRTC_EXT 0x3234
#define LOCAL_EGL_DRM_DEVICE_FILE_EXT 0x3233
#define LOCAL_EGL_DRM_MASTER_FD_EXT 0x333C
#define LOCAL_EGL_DRM_PLANE_EXT 0x3235
#define LOCAL_EGL_EXTENSIONS 0x3055
#define LOCAL_EGL_EXTERNAL_REF_ID_EXT 0x3461
@ -6069,20 +6106,92 @@
#define LOCAL_EGL_FOREVER 0xFFFFFFFFFFFFFFFF
#define LOCAL_EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFF
#define LOCAL_EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFF
#define LOCAL_EGL_FORMAT_ASTC_10X10_QCOM 0x33ED
#define LOCAL_EGL_FORMAT_ASTC_10X10_SRGB_QCOM 0x340B
#define LOCAL_EGL_FORMAT_ASTC_10X5_QCOM 0x33EA
#define LOCAL_EGL_FORMAT_ASTC_10X5_SRGB_QCOM 0x3408
#define LOCAL_EGL_FORMAT_ASTC_10X6_QCOM 0x33EB
#define LOCAL_EGL_FORMAT_ASTC_10X6_SRGB_QCOM 0x3409
#define LOCAL_EGL_FORMAT_ASTC_10X8_QCOM 0x33EC
#define LOCAL_EGL_FORMAT_ASTC_10X8_SRGB_QCOM 0x340A
#define LOCAL_EGL_FORMAT_ASTC_12X10_QCOM 0x33EE
#define LOCAL_EGL_FORMAT_ASTC_12X10_SRGB_QCOM 0x340C
#define LOCAL_EGL_FORMAT_ASTC_12X12_QCOM 0x33EF
#define LOCAL_EGL_FORMAT_ASTC_12X12_SRGB_QCOM 0x340D
#define LOCAL_EGL_FORMAT_ASTC_4X4_QCOM 0x33E2
#define LOCAL_EGL_FORMAT_ASTC_4X4_SRGB_QCOM 0x3400
#define LOCAL_EGL_FORMAT_ASTC_5X4_QCOM 0x33E3
#define LOCAL_EGL_FORMAT_ASTC_5X4_SRGB_QCOM 0x3401
#define LOCAL_EGL_FORMAT_ASTC_5X5_QCOM 0x33E4
#define LOCAL_EGL_FORMAT_ASTC_5X5_SRGB_QCOM 0x3402
#define LOCAL_EGL_FORMAT_ASTC_6X5_QCOM 0x33E5
#define LOCAL_EGL_FORMAT_ASTC_6X5_SRGB_QCOM 0x3403
#define LOCAL_EGL_FORMAT_ASTC_6X6_QCOM 0x33E6
#define LOCAL_EGL_FORMAT_ASTC_6X6_SRGB_QCOM 0x3404
#define LOCAL_EGL_FORMAT_ASTC_8X5_QCOM 0x33E7
#define LOCAL_EGL_FORMAT_ASTC_8X5_SRGB_QCOM 0x3405
#define LOCAL_EGL_FORMAT_ASTC_8X6_QCOM 0x33E8
#define LOCAL_EGL_FORMAT_ASTC_8X6_SRGB_QCOM 0x3406
#define LOCAL_EGL_FORMAT_ASTC_8X8_QCOM 0x33E9
#define LOCAL_EGL_FORMAT_ASTC_8X8_SRGB_QCOM 0x3407
#define LOCAL_EGL_FORMAT_BGRA_8888_QCOM 0x3129
#define LOCAL_EGL_FORMAT_BGRX_8888_QCOM 0x312A
#define LOCAL_EGL_FORMAT_FLAG_MACROTILE_QCOM 0x33E1
#define LOCAL_EGL_FORMAT_FLAG_QCOM 0x31CF
#define LOCAL_EGL_FORMAT_FLAG_UBWC_QCOM 0x33E0
#define LOCAL_EGL_FORMAT_IYUV_QCOM 0x31C7
#define LOCAL_EGL_FORMAT_NV12_4R_QCOM 0x3412
#define LOCAL_EGL_FORMAT_NV12_4R_UV_QCOM 0x3414
#define LOCAL_EGL_FORMAT_NV12_4R_Y_QCOM 0x3413
#define LOCAL_EGL_FORMAT_NV12_QCOM 0x31C2
#define LOCAL_EGL_FORMAT_NV12_TILED_QCOM 0x3128
#define LOCAL_EGL_FORMAT_NV12_UV_QCOM 0x3410
#define LOCAL_EGL_FORMAT_NV12_Y_QCOM 0x340F
#define LOCAL_EGL_FORMAT_NV21_QCOM 0x3127
#define LOCAL_EGL_FORMAT_NV21_VU_QCOM 0x3411
#define LOCAL_EGL_FORMAT_P010_QCOM 0x3415
#define LOCAL_EGL_FORMAT_P010_UV_QCOM 0x3417
#define LOCAL_EGL_FORMAT_P010_Y_QCOM 0x3416
#define LOCAL_EGL_FORMAT_R8_QCOM 0x31C0
#define LOCAL_EGL_FORMAT_RG88_QCOM 0x31C1
#define LOCAL_EGL_FORMAT_RGBA_1010102_QCOM 0x31CE
#define LOCAL_EGL_FORMAT_RGBA_16_FLOAT_QCOM 0x31CD
#define LOCAL_EGL_FORMAT_RGBA_4444_QCOM 0x31CA
#define LOCAL_EGL_FORMAT_RGBA_5551_QCOM 0x31C9
#define LOCAL_EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
#define LOCAL_EGL_FORMAT_RGBA_8888_KHR 0x30C3
#define LOCAL_EGL_FORMAT_RGBA_8888_QCOM 0x3122
#define LOCAL_EGL_FORMAT_RGBX_8888_QCOM 0x312F
#define LOCAL_EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
#define LOCAL_EGL_FORMAT_RGB_565_KHR 0x30C1
#define LOCAL_EGL_FORMAT_RGB_565_QCOM 0x3123
#define LOCAL_EGL_FORMAT_RGB_888_QCOM 0x31C8
#define LOCAL_EGL_FORMAT_RG_1616_FLOAT_QCOM 0x31CC
#define LOCAL_EGL_FORMAT_R_16_FLOAT_QCOM 0x31CB
#define LOCAL_EGL_FORMAT_SRGBA_8888_QCOM 0x31C4
#define LOCAL_EGL_FORMAT_SRGBX_8888_QCOM 0x31C3
#define LOCAL_EGL_FORMAT_TP10_QCOM 0x340E
#define LOCAL_EGL_FORMAT_TP10_UV_QCOM 0x3419
#define LOCAL_EGL_FORMAT_TP10_Y_QCOM 0x3418
#define LOCAL_EGL_FORMAT_UYVY_QCOM 0x3125
#define LOCAL_EGL_FORMAT_VYUY_QCOM 0x31C6
#define LOCAL_EGL_FORMAT_YUYV_QCOM 0x3124
#define LOCAL_EGL_FORMAT_YV12_QCOM 0x3126
#define LOCAL_EGL_FORMAT_YVYU_QCOM 0x31C5
#define LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
#define LOCAL_EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
#define LOCAL_EGL_FRONT_BUFFER_EXT 0x3464
#define LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C
#define LOCAL_EGL_GENERIC_TOKEN_1_QCOM 0x3420
#define LOCAL_EGL_GENERIC_TOKEN_2_QCOM 0x3421
#define LOCAL_EGL_GENERIC_TOKEN_3_QCOM 0x3422
#define LOCAL_EGL_GL_COLORSPACE 0x309D
#define LOCAL_EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
#define LOCAL_EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340
#define LOCAL_EGL_GL_COLORSPACE_DEFAULT_EXT 0x314D
#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
#define LOCAL_EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490
#define LOCAL_EGL_GL_COLORSPACE_KHR 0x309D
#define LOCAL_EGL_GL_COLORSPACE_LINEAR 0x308A
#define LOCAL_EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
@ -6112,9 +6221,28 @@
#define LOCAL_EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
#define LOCAL_EGL_GL_TEXTURE_ZOFFSET 0x30BD
#define LOCAL_EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
#define LOCAL_EGL_GPU_PERF_HINT_QCOM 0x32D0
#define LOCAL_EGL_GREEN_SIZE 0x3023
#define LOCAL_EGL_HEIGHT 0x3056
#define LOCAL_EGL_HINT_PERSISTENT_QCOM 0x32D1
#define LOCAL_EGL_HORIZONTAL_RESOLUTION 0x3090
#define LOCAL_EGL_IMAGE_FORMAT_QCOM 0x3121
#define LOCAL_EGL_IMAGE_NUM_PLANES_QCOM 0x32B0
#define LOCAL_EGL_IMAGE_PLANE_DEPTH_0_QCOM 0x32B4
#define LOCAL_EGL_IMAGE_PLANE_DEPTH_1_QCOM 0x32B5
#define LOCAL_EGL_IMAGE_PLANE_DEPTH_2_QCOM 0x32B6
#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_0_QCOM 0x32BA
#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_1_QCOM 0x32BB
#define LOCAL_EGL_IMAGE_PLANE_HEIGHT_2_QCOM 0x32BC
#define LOCAL_EGL_IMAGE_PLANE_PITCH_0_QCOM 0x32B1
#define LOCAL_EGL_IMAGE_PLANE_PITCH_1_QCOM 0x32B2
#define LOCAL_EGL_IMAGE_PLANE_PITCH_2_QCOM 0x32B3
#define LOCAL_EGL_IMAGE_PLANE_POINTER_0_QCOM 0x32BD
#define LOCAL_EGL_IMAGE_PLANE_POINTER_1_QCOM 0x32BE
#define LOCAL_EGL_IMAGE_PLANE_POINTER_2_QCOM 0x32BF
#define LOCAL_EGL_IMAGE_PLANE_WIDTH_0_QCOM 0x32B7
#define LOCAL_EGL_IMAGE_PLANE_WIDTH_1_QCOM 0x32B8
#define LOCAL_EGL_IMAGE_PLANE_WIDTH_2_QCOM 0x32B9
#define LOCAL_EGL_IMAGE_PRESERVED 0x30D2
#define LOCAL_EGL_IMAGE_PRESERVED_KHR 0x30D2
#define LOCAL_EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472
@ -6126,6 +6254,7 @@
#define LOCAL_EGL_ITU_REC709_EXT 0x3280
#define LOCAL_EGL_LARGEST_PBUFFER 0x3058
#define LOCAL_EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
#define LOCAL_EGL_LEFT_NV 0x336B
#define LOCAL_EGL_LEVEL 0x3029
#define LOCAL_EGL_LINUX_DMA_BUF_EXT 0x3270
#define LOCAL_EGL_LINUX_DRM_FOURCC_EXT 0x3271
@ -6178,6 +6307,7 @@
#define LOCAL_EGL_NATIVE_SURFACE_TIZEN 0x32A1
#define LOCAL_EGL_NATIVE_VISUAL_ID 0x302E
#define LOCAL_EGL_NATIVE_VISUAL_TYPE 0x302F
#define LOCAL_EGL_NEW_IMAGE_QCOM 0x3120
#define LOCAL_EGL_NONE 0x3038
#define LOCAL_EGL_NON_CONFORMANT_CONFIG 0x3051
#define LOCAL_EGL_NOT_INITIALIZED 0x3001
@ -6242,10 +6372,12 @@
#define LOCAL_EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
#define LOCAL_EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
#define LOCAL_EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460
#define LOCAL_EGL_PRODUCER_AUTO_ORIENTATION_NV 0x336A
#define LOCAL_EGL_PRODUCER_FRAME_KHR 0x3212
#define LOCAL_EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337
#define LOCAL_EGL_PRODUCER_METADATA_NV 0x3253
#define LOCAL_EGL_PROTECTED_CONTENT_EXT 0x32C0
#define LOCAL_EGL_QUADRUPLE_BUFFER_NV 0x3231
#define LOCAL_EGL_READ 0x305A
#define LOCAL_EGL_READS_DONE_TIME_ANDROID 0x343C
#define LOCAL_EGL_READ_SURFACE_BIT_KHR 0x0001
@ -6256,6 +6388,7 @@
#define LOCAL_EGL_RENDER_BUFFER 0x3086
#define LOCAL_EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
#define LOCAL_EGL_RGB_BUFFER 0x308E
#define LOCAL_EGL_RIGHT_NV 0x336C
#define LOCAL_EGL_SAMPLES 0x3031
#define LOCAL_EGL_SAMPLE_BUFFERS 0x3032
#define LOCAL_EGL_SAMPLE_RANGE_HINT_EXT 0x327C
@ -6287,9 +6420,14 @@
#define LOCAL_EGL_STREAM_CROSS_PARTITION_NV 0x323F
#define LOCAL_EGL_STREAM_CROSS_PROCESS_NV 0x3245
#define LOCAL_EGL_STREAM_CROSS_SYSTEM_NV 0x334F
#define LOCAL_EGL_STREAM_DMA_NV 0x3371
#define LOCAL_EGL_STREAM_DMA_SERVER_NV 0x3372
#define LOCAL_EGL_STREAM_ENDPOINT_NV 0x3243
#define LOCAL_EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
#define LOCAL_EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336
#define LOCAL_EGL_STREAM_FRAME_MAJOR_AXIS_NV 0x3368
#define LOCAL_EGL_STREAM_FRAME_ORIGIN_X_NV 0x3366
#define LOCAL_EGL_STREAM_FRAME_ORIGIN_Y_NV 0x3367
#define LOCAL_EGL_STREAM_LOCAL_NV 0x3244
#define LOCAL_EGL_STREAM_PRODUCER_NV 0x3247
#define LOCAL_EGL_STREAM_PROTOCOL_FD_NV 0x3246
@ -6358,12 +6496,14 @@
#define LOCAL_EGL_TIMESTAMPS_ANDROID 0x3430
#define LOCAL_EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID,-1)
#define LOCAL_EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID,-2)
#define LOCAL_EGL_TOP_NV 0x336D
#define LOCAL_EGL_TRACK_REFERENCES_KHR 0x3352
#define LOCAL_EGL_TRANSPARENT_BLUE_VALUE 0x3035
#define LOCAL_EGL_TRANSPARENT_GREEN_VALUE 0x3036
#define LOCAL_EGL_TRANSPARENT_RED_VALUE 0x3037
#define LOCAL_EGL_TRANSPARENT_RGB 0x3052
#define LOCAL_EGL_TRANSPARENT_TYPE 0x3034
#define LOCAL_EGL_TRIPLE_BUFFER_NV 0x3230
#define LOCAL_EGL_TRUE 1
#define LOCAL_EGL_UNKNOWN EGL_CAST(EGLint,-1)
#define LOCAL_EGL_UNSIGNALED 0x30F3
@ -6387,6 +6527,7 @@
#define LOCAL_EGL_WIDTH 0x3057
#define LOCAL_EGL_WINDOW_BIT 0x0004
#define LOCAL_EGL_WRITE_SURFACE_BIT_KHR 0x0002
#define LOCAL_EGL_X_AXIS_NV 0x336F
#define LOCAL_EGL_YUV_BUFFER_EXT 0x3300
#define LOCAL_EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
#define LOCAL_EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
@ -6422,9 +6563,9 @@
#define LOCAL_EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314
#define LOCAL_EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315
#define LOCAL_EGL_YUV_SUBSAMPLE_EXT 0x3312
#define LOCAL_EGL_Y_AXIS_NV 0x3370
#define LOCAL_EGL_Y_INVERTED_NOK 0x307F
// GLX
#define LOCAL_GLX_3DFX_FULLSCREEN_MODE_MESA 0x2
#define LOCAL_GLX_3DFX_WINDOW_MODE_MESA 0x1
@ -6491,6 +6632,10 @@
#define LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define LOCAL_GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
#define LOCAL_GLX_CONTEXT_PRIORITY_HIGH_EXT 0x3101
#define LOCAL_GLX_CONTEXT_PRIORITY_LEVEL_EXT 0x3100
#define LOCAL_GLX_CONTEXT_PRIORITY_LOW_EXT 0x3103
#define LOCAL_GLX_CONTEXT_PRIORITY_MEDIUM_EXT 0x3102
#define LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#define LOCAL_GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define LOCAL_GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
@ -6597,7 +6742,6 @@
#define LOCAL_GLX_RED_SIZE 8
#define LOCAL_GLX_RENDERER_ACCELERATED_MESA 0x8186
#define LOCAL_GLX_RENDERER_DEVICE_ID_MESA 0x8184
#define LOCAL_GLX_RENDERER_ID_MESA 0x818E
#define LOCAL_GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
#define LOCAL_GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A
#define LOCAL_GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D
@ -6712,7 +6856,6 @@
#define LOCAL_GLX_X_VISUAL_TYPE_EXT 0x22
#define LOCAL_GLX_Y_INVERTED_EXT 0x20D4
// WGL
#define LOCAL_WGL_ACCELERATION_ARB 0x2003
#define LOCAL_WGL_ACCELERATION_EXT 0x2003
@ -6781,6 +6924,11 @@
#define LOCAL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define LOCAL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define LOCAL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC
#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD
#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE
#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_NV 0x20AA
#define LOCAL_WGL_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB
#define LOCAL_WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
#define LOCAL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define LOCAL_WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097

172
gfx/gl/GLConsts.py Executable file
Просмотреть файл

@ -0,0 +1,172 @@
#!/usr/bin/env python3
'''
This script will regenerate and update GLConsts.h.
Step 1:
Download the last gl.xml, egl.xml, glx.xml and wgl.xml from
http://www.opengl.org/registry/#specfiles into some XML_DIR:
wget https://www.khronos.org/registry/OpenGL/xml/gl.xml
wget https://www.khronos.org/registry/OpenGL/xml/glx.xml
wget https://www.khronos.org/registry/OpenGL/xml/wgl.xml
wget https://www.khronos.org/registry/EGL/api/egl.xml
Step 2:
`py ./GLConsts.py <XML_DIR>`
Step 3:
Do not add the downloaded XML in the patch
Step 4:
Enjoy =)
'''
# includes
from typing import List # mypy!
import pathlib
import sys
import xml.etree.ElementTree
# -
(_, XML_DIR_STR) = sys.argv
XML_DIR = pathlib.Path(XML_DIR_STR)
# -
HEADER = b'''
/* 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/. */
// clang-format off
#ifndef GLCONSTS_H_
#define GLCONSTS_H_
/**
* GENERATED FILE, DO NOT MODIFY DIRECTLY.
* This is a file generated directly from the official OpenGL registry
* xml available http://www.opengl.org/registry/#specfiles.
*
* To generate this file, see tutorial in \'GLParseRegistryXML.py\'.
*/
'''[1:]
FOOTER = b'''
#endif // GLCONSTS_H_
// clang-format on
'''[1:]
# -
def format_lib_constant(lib, name, value):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
# name is the name of the const (example: MAX_TEXTURE_SIZE)
# value is the value of the const (example: 0xABCD)
define = '#define LOCAL_' + lib + '_' + name
whitespace = 60 - len(define)
if whitespace < 0:
whitespace = whitespace % 8
return define + ' ' * whitespace + ' ' + value
# -
class GLConst:
def __init__(self, lib, name, value, type):
self.lib = lib
self.name = name
self.value = value
self.type = type
# -
class GLDatabase:
LIBS = ['GL', 'EGL', 'GLX', 'WGL']
def __init__(self):
self.consts = {}
self.libs = set(GLDatabase.LIBS)
self.vendors = set(['EXT', 'ATI'])
# there is no vendor="EXT" and vendor="ATI" in gl.xml,
# so we manualy declare them
def load_xml(self, xml_path):
tree = xml.etree.ElementTree.parse(xml_path)
root = tree.getroot()
for enums in root.iter('enums'):
vendor = enums.get('vendor')
if not vendor:
# there some standart enums that do have the vendor attribute,
# so we fake them as ARB's enums
vendor = 'ARB'
if vendor not in self.vendors:
# we map this new vendor in the vendors set.
self.vendors.add(vendor)
namespaceType = enums.get('type')
for enum in enums:
if enum.tag != 'enum':
# this is not an enum => we skip it
continue
lib = enum.get('name').split('_')[0]
if lib not in self.libs:
# unknown library => we skip it
continue
name = enum.get('name')[len(lib) + 1:]
value = enum.get('value')
type = enum.get('type')
if not type:
# if no type specified, we get the namespace's default type
type = namespaceType
self.consts[lib + '_' + name] = GLConst(lib, name, value, type)
# -
db = GLDatabase()
db.load_xml(XML_DIR / 'gl.xml')
db.load_xml(XML_DIR / 'glx.xml')
db.load_xml(XML_DIR / 'wgl.xml')
db.load_xml(XML_DIR / 'egl.xml')
# -
lines: List[str] = []
keys = sorted(db.consts.keys())
for lib in db.LIBS:
lines.append('// ' + lib)
for k in keys:
const = db.consts[k]
if const.lib != lib:
continue
const_str = format_lib_constant(lib, const.name, const.value)
lines.append(const_str)
lines.append('')
# -
b_lines: List[bytes] = [HEADER] + [x.encode() for x in lines] + [FOOTER]
b_data: bytes = b'\n'.join(b_lines)
dest = pathlib.Path('GLConsts.h')
dest.write_bytes(b_data)
print(f'Wrote {len(b_data)} bytes.') # Some indication that we're successful.

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

@ -1,203 +0,0 @@
#!/usr/bin/env python2
################################################################################
# TUTORIAL
# This script will generate GLConsts.h
#
# Step 1:
# Download the last gl.xml, egl.xml, glx.xml and wgl.xml from
# http://www.opengl.org/registry/#specfiles into a directory of your choice
#
# Step 2:
# Execute this script ./GLParseRegistryXML.py [your dir containing XML files]
#
# Step 3:
# Do not add the downloaded XML in the patch
#
# Step 4:
# Enjoy =)
#
################################################################################
# includes
from __future__ import absolute_import, print_function
import os
import sys
import xml.etree.ElementTree
assert len(sys.argv) == 3, (
'Usage: ./GLParseRegistryXML.py path/to/OpenGL-Registry path/to/EGL-Registry')
(_, GL_REGISTRY_PATH, EGL_REGISTRY_PATH) = sys.argv
################################################################################
# export management
class GLConstHeader:
def __init__(self, f):
self.f = f
def write(self, arg):
if isinstance(arg, list):
self.f.write('\n'.join(arg) + '\n')
elif isinstance(arg, (int, long)):
self.f.write('\n' * arg)
else:
self.f.write(str(arg) + '\n')
def formatFileBegin(self):
self.write([
'/* 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/. */',
'',
'// clang-format off',
'',
'#ifndef GLCONSTS_H_',
'#define GLCONSTS_H_',
'',
'/**',
' * GENERATED FILE, DO NOT MODIFY DIRECTLY.',
' * This is a file generated directly from the official OpenGL registry',
' * xml available http://www.opengl.org/registry/#specfiles.',
' *',
' * To generate this file, see tutorial in \'GLParseRegistryXML.py\'.',
' */',
'',
])
def formatLibBegin(self, lib):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
self.write('// ' + lib)
def formatLibConstant(self, lib, name, value):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
# name is the name of the const (example: MAX_TEXTURE_SIZE)
# value is the value of the const (example: 0xABCD)
define = '#define LOCAL_' + lib + '_' + name
whitespace = 60 - len(define)
if whitespace < 0:
whitespace = whitespace % 8
self.write(define + ' ' * whitespace + ' ' + value)
def formatLibEnd(self, lib):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
self.write(2)
def formatFileEnd(self):
self.write([
'',
'#endif // GLCONSTS_H_',
'',
'// clang-format on',
])
################################################################################
# underground code
def getScriptDir():
return os.path.dirname(__file__) + '/'
class GLConst:
def __init__(self, lib, name, value, type):
self.lib = lib
self.name = name
self.value = value
self.type = type
class GLDatabase:
LIBS = ['GL', 'EGL', 'GLX', 'WGL']
def __init__(self):
self.consts = {}
self.libs = set(GLDatabase.LIBS)
self.vendors = set(['EXT', 'ATI'])
# there is no vendor="EXT" and vendor="ATI" in gl.xml,
# so we manualy declare them
def loadXML(self, xmlPath):
if not os.path.isfile(xmlPath):
print('missing file "' + xmlPath + '"')
return False
tree = xml.etree.ElementTree.parse(xmlPath)
root = tree.getroot()
for enums in root.iter('enums'):
vendor = enums.get('vendor')
if not vendor:
# there some standart enums that do have the vendor attribute,
# so we fake them as ARB's enums
vendor = 'ARB'
if vendor not in self.vendors:
# we map this new vendor in the vendors set.
self.vendors.add(vendor)
namespaceType = enums.get('type')
for enum in enums:
if enum.tag != 'enum':
# this is not an enum => we skip it
continue
lib = enum.get('name').split('_')[0]
if lib not in self.libs:
# unknown library => we skip it
continue
name = enum.get('name')[len(lib) + 1:]
value = enum.get('value')
type = enum.get('type')
if not type:
# if no type specified, we get the namespace's default type
type = namespaceType
self.consts[lib + '_' + name] = GLConst(lib, name, value, type)
return True
def exportConsts(self, path):
with open(getScriptDir() + path, 'wb') as f:
headerFile = GLConstHeader(f)
headerFile.formatFileBegin()
constNames = self.consts.keys()
constNames.sort()
for lib in GLDatabase.LIBS:
headerFile.formatLibBegin(lib)
for constName in constNames:
const = self.consts[constName]
if const.lib != lib:
continue
headerFile.formatLibConstant(lib, const.name, const.value)
headerFile.formatLibEnd(lib)
headerFile.formatFileEnd()
glDatabase = GLDatabase()
success = glDatabase.loadXML(GL_REGISTRY_PATH + '/xml/gl.xml')
success = success and glDatabase.loadXML(GL_REGISTRY_PATH + '/xml/glx.xml')
success = success and glDatabase.loadXML(GL_REGISTRY_PATH + '/xml/wgl.xml')
success = success and glDatabase.loadXML(EGL_REGISTRY_PATH + '/api/egl.xml')
if success:
glDatabase.exportConsts('GLConsts.h')

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

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html class="reftest-wait"><head>
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body onload="scrollTo(450,0); document.documentElement.classList.remove('reftest-wait')">
<div style="width: 9000px; height: 10px; background: white;"></div>

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

@ -2,7 +2,7 @@
<html class="reftest-wait"
reftest-async-scroll
reftest-async-scroll-x="449" reftest-async-scroll-y="0"><head>
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<!-- Doing scrollTo(1,0) is to activate the left arrow in the scrollbar
for non-overlay scrollbar environments -->

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

@ -655,8 +655,8 @@ void DeviceManagerDx::CreateWARPCompositorDevice() {
textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
}
DxgiAdapterDesc nullAdapter;
PodZero(&nullAdapter);
DXGI_ADAPTER_DESC desc;
D3D11Checks::GetDxgiDesc(device, &desc);
int featureLevel = device->GetFeatureLevel();
@ -666,9 +666,9 @@ void DeviceManagerDx::CreateWARPCompositorDevice() {
mCompositorDevice = device;
int32_t sequenceNumber = GetNextDeviceCounter();
mDeviceStatus =
Some(D3D11DeviceStatus(true, textureSharingWorks, featureLevel,
nullAdapter, sequenceNumber, formatOptions));
mDeviceStatus = Some(D3D11DeviceStatus(
true, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
sequenceNumber, formatOptions));
}
mCompositorDevice->SetExceptionMode(0);

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

@ -3115,6 +3115,22 @@ void gfxPlatform::InitWebRenderConfig() {
gfxVars::SetUseWebRenderTripleBufferingWin(true);
}
}
// When Windows version is mort than 1903 and GPU is intel GPU, it could cause
// flickering with DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. See Bug 1556634.
// As a workaround, use DXGI_ALPHA_MODE_PREMULTIPLIED instead of
// DXGI_ALPHA_MODE_IGNORE at SwapChain.
// XXX remove this workaround.
if (IsWin10May2019UpdateOrLater() && UseWebRender() &&
gfxVars::UseWebRenderDCompWin()) {
nsAutoString adapterVendorID;
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
gfxInfo->GetAdapterVendorID(adapterVendorID);
if (adapterVendorID == u"0x8086") { // Intel
gfxVars::SetWorkaroundWebRenderIntelBug1556634(true);
gfxCriticalNote << "Use Premul SwapChain for Intel GPU";
}
}
#endif
// Set features that affect WR's RendererOptions

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

@ -1340,6 +1340,12 @@ void gfxWindowsPlatform::InitializeD3D11Config() {
d3d11.EnableByDefault();
// Check if the user really, really wants WARP.
if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
// Force D3D11 on even if we disabled it.
d3d11.UserForceEnable("User force-enabled WARP");
}
if (!IsWin8OrLater() &&
!DeviceManagerDx::Get()->CheckRemotePresentSupport()) {
nsCOMPtr<nsIGfxInfo> gfxInfo;
@ -1367,12 +1373,6 @@ void gfxWindowsPlatform::InitializeD3D11Config() {
d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
}
// Check if the user really, really wants WARP.
if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
// Force D3D11 on even if we disabled it.
d3d11.UserForceEnable("User force-enabled WARP");
}
InitializeAdvancedLayersConfig();
}

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

@ -317,7 +317,9 @@ void RenderCompositorANGLE::CreateSwapChainForDCompIfPossible(
// DXGI_SCALING_NONE caused swap chain creation failure.
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
desc.AlphaMode = gfx::gfxVars::WorkaroundWebRenderIntelBug1556634()
? DXGI_ALPHA_MODE_PREMULTIPLIED
: DXGI_ALPHA_MODE_IGNORE;
desc.Flags = 0;
hr = aDXGIFactory2->CreateSwapChainForComposition(mDevice, &desc, nullptr,

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

@ -1039,6 +1039,25 @@ void DisplayListBuilder::PushClearRectWithComplexRegion(
&spaceAndClip);
}
void DisplayListBuilder::PushBackdropFilter(
const wr::LayoutRect& aBounds, const wr::ComplexClipRegion& aRegion,
const nsTArray<wr::FilterOp>& aFilters,
const nsTArray<wr::WrFilterData>& aFilterDatas, bool aIsBackfaceVisible) {
wr::LayoutRect clip = MergeClipLeaf(aBounds);
WRDL_LOG("PushBackdropFilter b=%s c=%s\n", mWrState,
Stringify(aBounds).c_str(), Stringify(clip).c_str());
AutoTArray<wr::ComplexClipRegion, 1> clips;
clips.AppendElement(aRegion);
auto clipId = DefineClip(Nothing(), aBounds, &clips, nullptr);
auto spaceAndClip = WrSpaceAndClip{mCurrentSpaceAndClipChain.space, clipId};
wr_dp_push_backdrop_filter_with_parent_clip(
mWrState, aBounds, clip, aIsBackfaceVisible, &spaceAndClip,
aFilters.Elements(), aFilters.Length(), aFilterDatas.Elements(),
aFilterDatas.Length());
}
void DisplayListBuilder::PushLinearGradient(
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
bool aIsBackfaceVisible, const wr::LayoutPoint& aStartPoint,

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

@ -344,7 +344,8 @@ struct MOZ_STACK_CLASS StackingContextParams : public WrStackingContextParams {
nullptr,
/* is_backface_visible = */ true,
/* cache_tiles = */ false,
wr::MixBlendMode::Normal} {}
wr::MixBlendMode::Normal,
/* is_backdrop_root = */ false} {}
void SetPreserve3D(bool aPreserve) {
transform_style =
@ -449,6 +450,12 @@ class DisplayListBuilder final {
void PushClearRectWithComplexRegion(const wr::LayoutRect& aBounds,
const wr::ComplexClipRegion& aRegion);
void PushBackdropFilter(const wr::LayoutRect& aBounds,
const wr::ComplexClipRegion& aRegion,
const nsTArray<wr::FilterOp>& aFilters,
const nsTArray<wr::WrFilterData>& aFilterDatas,
bool aIsBackfaceVisible);
void PushLinearGradient(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
const wr::LayoutPoint& aStartPoint,

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

@ -2085,6 +2085,9 @@ pub struct WrStackingContextParams {
/// True if picture caching should be enabled for this stacking context.
pub cache_tiles: bool,
pub mix_blend_mode: MixBlendMode,
/// True if this stacking context is a backdrop root.
/// https://drafts.fxtf.org/filter-effects-2/#BackdropRoot
pub is_backdrop_root: bool,
}
#[no_mangle]
@ -2206,7 +2209,8 @@ pub extern "C" fn wr_dp_push_stacking_context(
&r_filter_datas,
&[],
glyph_raster_space,
params.cache_tiles);
params.cache_tiles,
params.is_backdrop_root);
result
}
@ -2428,6 +2432,60 @@ pub extern "C" fn wr_dp_push_rect_with_parent_clip(
);
}
#[no_mangle]
pub extern "C" fn wr_dp_push_backdrop_filter_with_parent_clip(
state: &mut WrState,
rect: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClip,
filters: *const FilterOp,
filter_count: usize,
filter_datas: *const WrFilterData,
filter_datas_count: usize,
) {
debug_assert!(unsafe { !is_in_render_thread() });
let c_filters = unsafe { make_slice(filters, filter_count) };
let filters : Vec<FilterOp> = c_filters.iter()
.map(|c_filter| { c_filter.clone() })
.collect();
let c_filter_datas = unsafe { make_slice(filter_datas, filter_datas_count) };
let filter_datas : Vec<FilterData> = c_filter_datas.iter().map(|c_filter_data| {
FilterData {
func_r_type: c_filter_data.funcR_type,
r_values: unsafe { make_slice(c_filter_data.R_values, c_filter_data.R_values_count).to_vec() },
func_g_type: c_filter_data.funcG_type,
g_values: unsafe { make_slice(c_filter_data.G_values, c_filter_data.G_values_count).to_vec() },
func_b_type: c_filter_data.funcB_type,
b_values: unsafe { make_slice(c_filter_data.B_values, c_filter_data.B_values_count).to_vec() },
func_a_type: c_filter_data.funcA_type,
a_values: unsafe { make_slice(c_filter_data.A_values, c_filter_data.A_values_count).to_vec() },
}
}).collect();
let space_and_clip = parent.to_webrender(state.pipeline_id);
let clip_rect = clip.intersection(&rect);
if clip_rect.is_none() { return; }
let prim_info = CommonItemProperties {
clip_rect: clip_rect.unwrap(),
clip_id: space_and_clip.clip_id,
spatial_id: space_and_clip.spatial_id,
is_backface_visible,
hit_info: state.current_tag,
};
state.frame_builder.dl_builder.push_backdrop_filter(
&prim_info,
&filters,
&filter_datas,
&[],
);
}
#[no_mangle]
pub extern "C" fn wr_dp_push_clear_rect(state: &mut WrState,
rect: LayoutRect,

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

@ -51,7 +51,8 @@ bool gecko_profiler_thread_is_being_profiled();
macro(radial_grad); \
macro(picture); \
macro(text_run); \
macro(filterdata);
macro(filterdata); \
macro(backdrop);
// Prelude of types necessary before including webrender_ffi_generated.h
namespace mozilla {

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

@ -1632,9 +1632,19 @@ impl BatchBuilder {
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache)
.as_int();
let textures = match render_tasks[cache_task_id].saved_index {
Some(saved_index) => BatchTextures {
colors: [
TextureSource::RenderTaskCache(saved_index, Swizzle::default()),
TextureSource::PrevPassAlpha,
TextureSource::Invalid,
]
},
None => BatchTextures::render_target_cache(),
};
let batch_params = BrushBatchParameters::shared(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
BatchTextures::render_target_cache(),
textures,
[
ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
RasterizationSpace::Screen as i32,
@ -2367,6 +2377,67 @@ impl BatchBuilder {
);
}
}
PrimitiveInstanceKind::Backdrop { data_handle } => {
let prim_data = &ctx.data_stores.backdrop[data_handle];
let backdrop_pic_index = prim_data.kind.pic_index;
let backdrop_surface_index = ctx.prim_store.pictures[backdrop_pic_index.0]
.raster_config
.as_ref()
.expect("backdrop surface should be alloc by now")
.surface_index;
let backdrop_task_id = ctx.surfaces[backdrop_surface_index.0]
.render_tasks
.as_ref()
.expect("backdrop task not available")
.root;
let backdrop_uv_rect_address = render_tasks[backdrop_task_id]
.get_texture_address(gpu_cache)
.as_int();
let textures = BatchTextures::render_target_cache();
let batch_key = BatchKey::new(
BatchKind::Brush(BrushBatchKind::Image(ImageBufferKind::Texture2DArray)),
BlendMode::PremultipliedAlpha,
textures,
);
let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
let backdrop_picture = &ctx.prim_store.pictures[backdrop_pic_index.0];
let prim_header = PrimitiveHeader {
local_rect: backdrop_picture.snapped_local_rect,
local_clip_rect: prim_info.combined_local_clip_rect,
transform_id,
snap_offsets,
specific_prim_address: prim_cache_address,
};
let prim_header_index = prim_headers.push(
&prim_header,
z_id,
[
ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
RasterizationSpace::Screen as i32,
get_shader_opacity(1.0),
0
],
);
self.add_brush_instance_to_batches(
batch_key,
batch_features,
bounding_rect,
z_id,
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
OPAQUE_TASK_ADDRESS,
BrushFlags::empty(),
prim_header_index,
backdrop_uv_rect_address,
prim_vis_mask,
);
}
}
}
@ -2695,7 +2766,8 @@ impl PrimitiveInstance {
PrimitiveInstanceKind::RadialGradient { .. } |
PrimitiveInstanceKind::PushClipChain |
PrimitiveInstanceKind::PopClipChain |
PrimitiveInstanceKind::Clear { .. } => {
PrimitiveInstanceKind::Clear { .. } |
PrimitiveInstanceKind::Backdrop { .. } => {
return true;
}
};

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

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter};
use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, RasterSpace};
use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId};
use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, ComponentTransferFuncType, RasterSpace};
use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId, FilterData};
use api::{FilterOp, FilterPrimitive, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop};
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth};
use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
@ -21,12 +21,13 @@ use crate::image::simplify_repeated_primitive;
use crate::intern::Interner;
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo, Filter};
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
use crate::picture::{BlitReason, PrimitiveList, TileCacheInstance};
use crate::picture::{BlitReason, OrderedPictureChild, PrimitiveList, TileCacheInstance};
use crate::prim_store::{PrimitiveInstance, PrimitiveSceneData};
use crate::prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveStore};
use crate::prim_store::{ScrollNodeAndClipChain, PictureIndex};
use crate::prim_store::{InternablePrimitive, SegmentInstanceIndex};
use crate::prim_store::{register_prim_chase_id, get_line_decoration_sizes};
use crate::prim_store::backdrop::Backdrop;
use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
use crate::prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams};
use crate::prim_store::image::{Image, YuvImage};
@ -331,6 +332,7 @@ impl<'a> DisplayListFlattener<'a> {
ROOT_SPATIAL_NODE_INDEX,
ClipChainId::NONE,
RasterSpace::Screen,
/* is_backdrop_root = */ true,
);
flattener.flatten_items(
@ -808,9 +810,9 @@ impl<'a> DisplayListFlattener<'a> {
let composition_operations = {
CompositeOps::new(
stacking_context.filter_ops_for_compositing(filters),
stacking_context.filter_datas_for_compositing(filter_datas),
stacking_context.filter_primitives_for_compositing(filter_primitives),
filter_ops_for_compositing(filters),
filter_datas_for_compositing(filter_datas),
filter_primitives_for_compositing(filter_primitives),
stacking_context.mix_blend_mode_for_compositing(),
)
};
@ -829,6 +831,7 @@ impl<'a> DisplayListFlattener<'a> {
spatial_node_index,
clip_chain_id,
stacking_context.raster_space,
stacking_context.is_backdrop_root,
);
if cfg!(debug_assertions) && apply_pipeline_clip && clip_chain_id != ClipChainId::NONE {
@ -1311,6 +1314,24 @@ impl<'a> DisplayListFlattener<'a> {
parent_space,
);
}
DisplayItem::BackdropFilter(ref info) => {
let (layout, clip_and_scroll) = self.process_common_properties(
&info.common,
apply_pipeline_clip,
);
let filters = filter_ops_for_compositing(item.filters());
let filter_datas = filter_datas_for_compositing(item.filter_datas());
let filter_primitives = filter_primitives_for_compositing(item.filter_primitives());
self.add_backdrop_filter(
clip_and_scroll,
&layout,
filters,
filter_datas,
filter_primitives,
);
}
// Do nothing; these are dummy items for the display list parser
DisplayItem::SetGradientStops |
@ -1571,6 +1592,7 @@ impl<'a> DisplayListFlattener<'a> {
spatial_node_index: SpatialNodeIndex,
clip_chain_id: ClipChainId,
requested_raster_space: RasterSpace,
is_backdrop_root: bool,
) {
// Check if this stacking context is the root of a pipeline, and the caller
// has requested it as an output frame.
@ -1594,16 +1616,25 @@ impl<'a> DisplayListFlattener<'a> {
// which determines if we *might* need to draw this on
// an intermediate surface for plane splitting purposes.
let (parent_is_3d, extra_3d_instance) = match self.sc_stack.last_mut() {
Some(sc) => {
Some(ref mut sc) if sc.is_3d() => {
let flat_items_context_3d = match sc.context_3d {
Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In {
root_data: None,
ancestor_index,
},
Picture3DContext::Out => panic!("Unexpected out of 3D context"),
};
// Cut the sequence of flat children before starting a child stacking context,
// so that the relative order between them and our current SC is preserved.
let extra_instance = sc.cut_flat_item_sequence(
let extra_instance = sc.cut_item_sequence(
&mut self.prim_store,
&mut self.interners,
Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D)),
flat_items_context_3d,
);
(sc.is_3d(), extra_instance)
(true, extra_instance.map(|(_, instance)| instance))
},
None => (false, None),
_ => (false, None),
};
if let Some(instance) = extra_3d_instance {
@ -1677,6 +1708,7 @@ impl<'a> DisplayListFlattener<'a> {
transform_style,
context_3d,
create_tile_cache,
is_backdrop_root,
});
}
@ -1907,145 +1939,20 @@ impl<'a> DisplayListFlattener<'a> {
);
}
// For each filter, create a new image with that composite mode.
let mut current_filter_data_index = 0;
for filter in &mut stacking_context.composite_ops.filters {
filter.sanitize();
let (filtered_pic_index, filtered_instance) = self.wrap_prim_with_filters(
cur_instance,
current_pic_index,
stacking_context.composite_ops.filters,
stacking_context.composite_ops.filter_primitives,
stacking_context.composite_ops.filter_datas,
stacking_context.is_backface_visible,
stacking_context.requested_raster_space,
stacking_context.spatial_node_index,
true,
);
let composite_mode = Some(match *filter {
Filter::ComponentTransfer => {
let filter_data =
&stacking_context.composite_ops.filter_datas[current_filter_data_index];
let filter_data = filter_data.sanitize();
current_filter_data_index = current_filter_data_index + 1;
if filter_data.is_identity() {
continue
} else {
let filter_data_key = SFilterDataKey {
data:
SFilterData {
r_func: SFilterDataComponent::from_functype_values(
filter_data.func_r_type, &filter_data.r_values),
g_func: SFilterDataComponent::from_functype_values(
filter_data.func_g_type, &filter_data.g_values),
b_func: SFilterDataComponent::from_functype_values(
filter_data.func_b_type, &filter_data.b_values),
a_func: SFilterDataComponent::from_functype_values(
filter_data.func_a_type, &filter_data.a_values),
},
};
let handle = self.interners
.filter_data
.intern(&filter_data_key, || ());
PictureCompositeMode::ComponentTransferFilter(handle)
}
}
_ => PictureCompositeMode::Filter(filter.clone()),
});
let filter_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
composite_mode.clone(),
Picture3DContext::Out,
None,
true,
stacking_context.is_backface_visible,
stacking_context.requested_raster_space,
PrimitiveList::new(
vec![cur_instance.clone()],
&self.interners,
),
stacking_context.spatial_node_index,
None,
PictureOptions::default(),
))
);
current_pic_index = filter_pic_index;
cur_instance = create_prim_instance(
current_pic_index,
composite_mode.into(),
stacking_context.is_backface_visible,
ClipChainId::NONE,
stacking_context.spatial_node_index,
&mut self.interners,
);
if cur_instance.is_chased() {
println!("\tis a composite picture for a stacking context with {:?}", filter);
}
// Run the optimize pass on this picture, to see if we can
// collapse opacity and avoid drawing to an off-screen surface.
self.prim_store.optimize_picture_if_possible(current_pic_index);
}
if !stacking_context.composite_ops.filter_primitives.is_empty() {
let filter_datas = stacking_context.composite_ops.filter_datas.iter()
.map(|filter_data| filter_data.sanitize())
.map(|filter_data| {
SFilterData {
r_func: SFilterDataComponent::from_functype_values(
filter_data.func_r_type, &filter_data.r_values),
g_func: SFilterDataComponent::from_functype_values(
filter_data.func_g_type, &filter_data.g_values),
b_func: SFilterDataComponent::from_functype_values(
filter_data.func_b_type, &filter_data.b_values),
a_func: SFilterDataComponent::from_functype_values(
filter_data.func_a_type, &filter_data.a_values),
}
})
.collect();
// Sanitize filter inputs
for primitive in &mut stacking_context.composite_ops.filter_primitives {
primitive.sanitize();
}
let composite_mode = PictureCompositeMode::SvgFilter(
stacking_context.composite_ops.filter_primitives,
filter_datas,
);
let filter_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
Some(composite_mode.clone()),
Picture3DContext::Out,
None,
true,
stacking_context.is_backface_visible,
stacking_context.requested_raster_space,
PrimitiveList::new(
vec![cur_instance.clone()],
&self.interners,
),
stacking_context.spatial_node_index,
None,
PictureOptions::default(),
))
);
current_pic_index = filter_pic_index;
cur_instance = create_prim_instance(
current_pic_index,
Some(composite_mode).into(),
stacking_context.is_backface_visible,
ClipChainId::NONE,
stacking_context.spatial_node_index,
&mut self.interners,
);
if cur_instance.is_chased() {
println!("\tis a composite picture for a stacking context with an SVG filter");
}
// Run the optimize pass on this picture, to see if we can
// collapse opacity and avoid drawing to an off-screen surface.
self.prim_store.optimize_picture_if_possible(current_pic_index);
}
current_pic_index = filtered_pic_index;
cur_instance = filtered_instance;
// Same for mix-blend-mode, except we can skip if this primitive is the first in the parent
// stacking context.
@ -3058,6 +2965,313 @@ impl<'a> DisplayListFlattener<'a> {
}
}
}
pub fn add_backdrop_filter(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
filters: Vec<Filter>,
filter_datas: Vec<FilterData>,
filter_primitives: Vec<FilterPrimitive>,
) {
let mut backdrop_pic_index = match self.cut_backdrop_picture() {
// Backdrop contains no content, so no need to add backdrop-filter
None => return,
Some(backdrop_pic_index) => backdrop_pic_index,
};
let backdrop_spatial_node_index = self.prim_store.pictures[backdrop_pic_index.0].spatial_node_index;
let requested_raster_space = self.sc_stack.last().expect("no active stacking context").requested_raster_space;
let mut instance = self.create_primitive(
info,
// TODO(cbrewster): This is a bit of a hack to help figure out the correct sizing of the backdrop
// region. By makings sure to include this, the clip chain instance computes the correct clip rect,
// but we don't actually apply the filtered backdrop clip yet (this is done to the last instance in
// the filter chain below).
clip_and_scroll.clip_chain_id,
backdrop_spatial_node_index,
Backdrop {
pic_index: backdrop_pic_index,
spatial_node_index: clip_and_scroll.spatial_node_index,
border_rect: info.rect.into(),
},
);
// We will append the filtered backdrop to the backdrop root, but we need to
// make sure all clips between the current stacking context and backdrop root
// are taken into account. So we wrap the backdrop filter instance with a picture with
// a clip for each stacking context.
for stacking_context in self.sc_stack.iter().rev().take_while(|sc| !sc.is_backdrop_root) {
let clip_chain_id = stacking_context.clip_chain_id;
let is_backface_visible = stacking_context.is_backface_visible;
let composite_mode = None;
backdrop_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
composite_mode.clone(),
Picture3DContext::Out,
None,
true,
is_backface_visible,
requested_raster_space,
PrimitiveList::new(
vec![instance],
&mut self.interners,
),
backdrop_spatial_node_index,
None,
PictureOptions {
inflate_if_required: false,
},
))
);
instance = create_prim_instance(
backdrop_pic_index,
composite_mode.into(),
is_backface_visible,
clip_chain_id,
backdrop_spatial_node_index,
&mut self.interners,
);
}
let (mut filtered_pic_index, mut filtered_instance) = self.wrap_prim_with_filters(
instance,
backdrop_pic_index,
filters,
filter_primitives,
filter_datas,
info.is_backface_visible,
requested_raster_space,
backdrop_spatial_node_index,
false,
);
// Apply filters from all stacking contexts up to, but not including the backdrop root.
// Gecko pushes separate stacking contexts for filters and opacity,
// so we must iterate through multiple stacking contexts to find all effects
// that need to be applied to the filtered backdrop.
let backdrop_root_pos = self.sc_stack.iter().rposition(|sc| sc.is_backdrop_root).expect("no backdrop root?");
for i in ((backdrop_root_pos + 1)..self.sc_stack.len()).rev() {
let stacking_context = &self.sc_stack[i];
let filters = stacking_context.composite_ops.filters.clone();
let filter_primitives = stacking_context.composite_ops.filter_primitives.clone();
let filter_datas = stacking_context.composite_ops.filter_datas.clone();
let (pic_index, instance) = self.wrap_prim_with_filters(
filtered_instance,
filtered_pic_index,
filters,
filter_primitives,
filter_datas,
info.is_backface_visible,
requested_raster_space,
backdrop_spatial_node_index,
false,
);
filtered_instance = instance;
filtered_pic_index = pic_index;
}
filtered_instance.clip_chain_id = clip_and_scroll.clip_chain_id;
self.sc_stack.iter_mut().rev().find(|sc| sc.is_backdrop_root).unwrap().primitives.push(filtered_instance);
}
pub fn cut_backdrop_picture(&mut self) -> Option<PictureIndex> {
let mut flattened_items = None;
let mut backdrop_root = None;
for sc in self.sc_stack.iter_mut().rev() {
// Add child contents to parent stacking context
if let Some((_, flattened_instance)) = flattened_items.take() {
sc.primitives.push(flattened_instance);
}
flattened_items = sc.cut_item_sequence(
&mut self.prim_store,
&mut self.interners,
None,
Picture3DContext::Out,
);
if sc.is_backdrop_root {
backdrop_root = Some(sc);
break;
}
}
let (pic_index, instance) = flattened_items?;
self.prim_store.pictures[pic_index.0].requested_composite_mode = Some(PictureCompositeMode::Blit(BlitReason::BACKDROP));
backdrop_root.expect("no backdrop root found").primitives.push(instance);
Some(pic_index)
}
fn wrap_prim_with_filters(
&mut self,
mut cur_instance: PrimitiveInstance,
mut current_pic_index: PictureIndex,
mut filter_ops: Vec<Filter>,
mut filter_primitives: Vec<FilterPrimitive>,
filter_datas: Vec<FilterData>,
is_backface_visible: bool,
requested_raster_space: RasterSpace,
spatial_node_index: SpatialNodeIndex,
inflate_if_required: bool,
) -> (PictureIndex, PrimitiveInstance) {
// TODO(cbrewster): Currently CSS and SVG filters live side by side in WebRender, but unexpected results will
// happen if they are used simulataneously. Gecko only provides either filter ops or filter primitives.
// At some point, these two should be combined and CSS filters should be expressed in terms of SVG filters.
assert!(filter_ops.is_empty() || filter_primitives.is_empty(),
"Filter ops and filter primitives are not allowed on the same stacking context.");
// For each filter, create a new image with that composite mode.
let mut current_filter_data_index = 0;
for filter in &mut filter_ops {
filter.sanitize();
let composite_mode = Some(match *filter {
Filter::ComponentTransfer => {
let filter_data =
&filter_datas[current_filter_data_index];
let filter_data = filter_data.sanitize();
current_filter_data_index = current_filter_data_index + 1;
if filter_data.is_identity() {
continue
} else {
let filter_data_key = SFilterDataKey {
data:
SFilterData {
r_func: SFilterDataComponent::from_functype_values(
filter_data.func_r_type, &filter_data.r_values),
g_func: SFilterDataComponent::from_functype_values(
filter_data.func_g_type, &filter_data.g_values),
b_func: SFilterDataComponent::from_functype_values(
filter_data.func_b_type, &filter_data.b_values),
a_func: SFilterDataComponent::from_functype_values(
filter_data.func_a_type, &filter_data.a_values),
},
};
let handle = self.interners
.filter_data
.intern(&filter_data_key, || ());
PictureCompositeMode::ComponentTransferFilter(handle)
}
}
_ => PictureCompositeMode::Filter(filter.clone()),
});
let filter_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
composite_mode.clone(),
Picture3DContext::Out,
None,
true,
is_backface_visible,
requested_raster_space,
PrimitiveList::new(
vec![cur_instance.clone()],
&mut self.interners,
),
spatial_node_index,
None,
PictureOptions {
inflate_if_required,
},
))
);
current_pic_index = filter_pic_index;
cur_instance = create_prim_instance(
current_pic_index,
composite_mode.into(),
is_backface_visible,
ClipChainId::NONE,
spatial_node_index,
&mut self.interners,
);
if cur_instance.is_chased() {
println!("\tis a composite picture for a stacking context with {:?}", filter);
}
// Run the optimize pass on this picture, to see if we can
// collapse opacity and avoid drawing to an off-screen surface.
self.prim_store.optimize_picture_if_possible(current_pic_index);
}
if !filter_primitives.is_empty() {
let filter_datas = filter_datas.iter()
.map(|filter_data| filter_data.sanitize())
.map(|filter_data| {
SFilterData {
r_func: SFilterDataComponent::from_functype_values(
filter_data.func_r_type, &filter_data.r_values),
g_func: SFilterDataComponent::from_functype_values(
filter_data.func_g_type, &filter_data.g_values),
b_func: SFilterDataComponent::from_functype_values(
filter_data.func_b_type, &filter_data.b_values),
a_func: SFilterDataComponent::from_functype_values(
filter_data.func_a_type, &filter_data.a_values),
}
})
.collect();
// Sanitize filter inputs
for primitive in &mut filter_primitives {
primitive.sanitize();
}
let composite_mode = PictureCompositeMode::SvgFilter(
filter_primitives,
filter_datas,
);
let filter_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
Some(composite_mode.clone()),
Picture3DContext::Out,
None,
true,
is_backface_visible,
requested_raster_space,
PrimitiveList::new(
vec![cur_instance.clone()],
&mut self.interners,
),
spatial_node_index,
None,
PictureOptions {
inflate_if_required,
},
))
);
current_pic_index = filter_pic_index;
cur_instance = create_prim_instance(
current_pic_index,
Some(composite_mode).into(),
is_backface_visible,
ClipChainId::NONE,
spatial_node_index,
&mut self.interners,
);
if cur_instance.is_chased() {
println!("\tis a composite picture for a stacking context with an SVG filter");
}
// Run the optimize pass on this picture, to see if we can
// collapse opacity and avoid drawing to an off-screen surface.
self.prim_store.optimize_picture_if_possible(current_pic_index);
}
(current_pic_index, cur_instance)
}
}
@ -3112,6 +3326,9 @@ struct FlattenedStackingContext {
/// If true, create a tile cache for this stacking context.
create_tile_cache: bool,
/// True if this stacking context is a backdrop root.
is_backdrop_root: bool,
}
impl FlattenedStackingContext {
@ -3171,28 +3388,22 @@ impl FlattenedStackingContext {
true
}
/// For a Preserve3D context, cut the sequence of the immediate flat children
/// recorded so far and generate a picture from them.
pub fn cut_flat_item_sequence(
/// Cut the sequence of the immediate children recorded so far and generate a picture from them.
pub fn cut_item_sequence(
&mut self,
prim_store: &mut PrimitiveStore,
interners: &mut Interners,
) -> Option<PrimitiveInstance> {
if !self.is_3d() || self.primitives.is_empty() {
composite_mode: Option<PictureCompositeMode>,
flat_items_context_3d: Picture3DContext<OrderedPictureChild>,
) -> Option<(PictureIndex, PrimitiveInstance)> {
if self.primitives.is_empty() {
return None
}
let flat_items_context_3d = match self.context_3d {
Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In {
root_data: None,
ancestor_index,
},
Picture3DContext::Out => panic!("Unexpected out of 3D context"),
};
let pic_index = PictureIndex(prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D)),
composite_mode.clone(),
flat_items_context_3d,
None,
true,
@ -3210,14 +3421,14 @@ impl FlattenedStackingContext {
let prim_instance = create_prim_instance(
pic_index,
PictureCompositeKey::Identity,
composite_mode.into(),
self.is_backface_visible,
self.clip_chain_id,
self.spatial_node_index,
interners,
);
Some(prim_instance)
Some((pic_index, prim_instance))
}
}
@ -3327,3 +3538,47 @@ fn create_clip_prim_instance(
spatial_node_index,
)
}
fn filter_ops_for_compositing(
input_filters: ItemRange<FilterOp>,
) -> Vec<Filter> {
// TODO(gw): Now that we resolve these later on,
// we could probably make it a bit
// more efficient than cloning these here.
input_filters.iter().map(|filter| filter.into()).collect()
}
fn filter_datas_for_compositing(
input_filter_datas: &[TempFilterData],
) -> Vec<FilterData> {
// TODO(gw): Now that we resolve these later on,
// we could probably make it a bit
// more efficient than cloning these here.
let mut filter_datas = vec![];
for temp_filter_data in input_filter_datas {
let func_types : Vec<ComponentTransferFuncType> = temp_filter_data.func_types.iter().collect();
debug_assert!(func_types.len() == 4);
filter_datas.push( FilterData {
func_r_type: func_types[0],
r_values: temp_filter_data.r_values.iter().collect(),
func_g_type: func_types[1],
g_values: temp_filter_data.g_values.iter().collect(),
func_b_type: func_types[2],
b_values: temp_filter_data.b_values.iter().collect(),
func_a_type: func_types[3],
a_values: temp_filter_data.a_values.iter().collect(),
});
}
filter_datas
}
fn filter_primitives_for_compositing(
input_filter_primitives: ItemRange<FilterPrimitive>,
) -> Vec<FilterPrimitive> {
// Resolve these in the flattener?
// TODO(gw): Now that we resolve these later on,
// we could probably make it a bit
// more efficient than cloning these here.
input_filter_primitives.iter().map(|primitive| primitive.into()).collect()
}

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

@ -1565,7 +1565,8 @@ impl TileCacheInstance {
PrimitiveInstanceKind::Clear { .. } |
PrimitiveInstanceKind::NormalBorder { .. } |
PrimitiveInstanceKind::LinearGradient { .. } |
PrimitiveInstanceKind::RadialGradient { .. } => {
PrimitiveInstanceKind::RadialGradient { .. } |
PrimitiveInstanceKind::Backdrop { .. } => {
// These don't contribute dependencies
}
};
@ -1891,6 +1892,8 @@ bitflags! {
const CLIP = 2;
/// Preserve-3D requires a surface for plane-splitting.
const PRESERVE3D = 4;
/// A backdrop that is reused which requires a surface.
const BACKDROP = 8;
}
}
@ -2162,6 +2165,10 @@ impl PrimitiveList {
let data = &interners.yuv_image[data_handle];
(data.is_backface_visible, data.prim_size)
}
PrimitiveInstanceKind::Backdrop { data_handle, .. } => {
let data = &interners.backdrop[data_handle];
(data.is_backface_visible, data.prim_size)
}
PrimitiveInstanceKind::PushClipChain |
PrimitiveInstanceKind::PopClipChain => {
(true, LayoutSize::zero())
@ -2303,7 +2310,7 @@ pub struct PicturePrimitive {
pub tile_cache: Option<Box<TileCacheInstance>>,
/// The config options for this picture.
options: PictureOptions,
pub options: PictureOptions,
}
impl PicturePrimitive {
@ -2556,39 +2563,45 @@ impl PicturePrimitive {
blur_std_deviation * scale_factors.0,
blur_std_deviation * scale_factors.1
);
let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil();
let device_rect = if self.options.inflate_if_required {
let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil();
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
// We cast clipped to f32 instead of casting unclipped to i32
// because unclipped can overflow an i32.
let device_rect = clipped.to_f32()
.inflate(inflation_factor, inflation_factor)
.intersection(&unclipped)
.unwrap();
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
// We cast clipped to f32 instead of casting unclipped to i32
// because unclipped can overflow an i32.
let device_rect = clipped.to_f32()
.inflate(inflation_factor, inflation_factor)
.intersection(&unclipped)
.unwrap();
let mut device_rect = match device_rect.try_cast::<i32>() {
Some(rect) => rect,
None => {
return None
}
let mut device_rect = match device_rect.try_cast::<i32>() {
Some(rect) => rect,
None => {
return None
}
};
// Adjust the size to avoid introducing sampling errors during the down-scaling passes.
// what would be even better is to rasterize the picture at the down-scaled size
// directly.
device_rect.size = RenderTask::adjusted_blur_source_size(
device_rect.size,
blur_std_deviation,
);
device_rect
} else {
clipped
};
// Adjust the size to avoid introducing sampling errors during the down-scaling passes.
// what would be even better is to rasterize the picture at the down-scaled size
// directly.
device_rect.size = RenderTask::adjusted_blur_source_size(
device_rect.size,
blur_std_deviation,
);
let uv_rect_kind = calculate_uv_rect_kind(
&pic_rect,
&transform,
@ -3325,7 +3338,9 @@ impl PicturePrimitive {
let surface = state.current_surface_mut();
// Inflate the local bounding rect if required by the filter effect.
// This inflaction factor is to be applied to the surface itself.
surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor);
if self.options.inflate_if_required {
surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor);
}
let mut surface_rect = surface.rect * Scale::new(1.0);

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