зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
bac38ea0ea
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче