mirror of
https://github.com/zen-browser/desktop.git
synced 2026-09-14 00:50:46 +00:00
gh-15384: Sync upstream Firefox to version 156.0 (gh-15385)
This commit is contained in:
@@ -35,7 +35,7 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
||||
### Firefox Versions
|
||||
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `155.0.1`!
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 155.0.1`!
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 156.0`!
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
b6d45eac914fd4886c9b6e5f1447f613771228ff
|
||||
931c2f71dc0b1e11668a5ca165dd75e2e4297174
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||
index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5361e060f 100644
|
||||
index a76bb7aae7636c07989a4acb35281777d3103505..c5eafbdad5270cd9926ed4f1d850d134440d775b 100644
|
||||
--- a/browser/base/content/navigator-toolbox.inc.xhtml
|
||||
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||
@@ -2,7 +2,7 @@
|
||||
@@ -26,7 +26,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
||||
<toolbar id="TabsToolbar"
|
||||
class="browser-toolbar browser-titlebar"
|
||||
fullscreentoolbar="true"
|
||||
@@ -54,6 +58,8 @@
|
||||
@@ -56,6 +60,8 @@
|
||||
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
|
||||
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
|
||||
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||
@@ -35,7 +35,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
||||
<hbox class="tab-drop-indicator" hidden="true"/>
|
||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
||||
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="" visuallyselected="" fadein=""/>
|
||||
@@ -73,6 +79,7 @@
|
||||
@@ -75,6 +81,7 @@
|
||||
tooltip="dynamic-shortcut-tooltip"
|
||||
data-l10n-id="tabs-toolbar-new-tab"/>
|
||||
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
|
||||
@@ -43,7 +43,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
||||
</tabs>
|
||||
|
||||
<toolbarbutton id="new-tab-button"
|
||||
@@ -99,9 +106,10 @@
|
||||
@@ -102,9 +109,10 @@
|
||||
|
||||
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>
|
||||
|
||||
@@ -54,4 +54,4 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
||||
+</hbox>
|
||||
|
||||
<toolbar id="nav-bar"
|
||||
class="browser-toolbar chromeclass-location"
|
||||
class="browser-toolbar"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||
index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa13303d3a3 100644
|
||||
index 875f8b03d979353ef44a57c15ef1ae09d33ab730..3d6e092e7ed126cdee8c32229df2cfa13303d3a3 100644
|
||||
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||
@@ -13,6 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
@@ -19,7 +19,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
},
|
||||
false
|
||||
);
|
||||
@@ -362,27 +363,23 @@ var CustomizableUIInternal = {
|
||||
@@ -362,20 +363,15 @@ var CustomizableUIInternal = {
|
||||
"back-button",
|
||||
"forward-button",
|
||||
"stop-reload-button",
|
||||
@@ -41,27 +41,29 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
this.registerArea(
|
||||
CustomizableUI.AREA_NAVBAR,
|
||||
{
|
||||
type: CustomizableUI.TYPE_TOOLBAR,
|
||||
@@ -383,9 +379,6 @@ var CustomizableUIInternal = {
|
||||
overflowable: true,
|
||||
defaultPlacements: navbarPlacements,
|
||||
- verticalTabsDefaultPlacements: ["alltabs-button", "ai-window-toggle"],
|
||||
+ verticalTabsDefaultPlacements: [
|
||||
+ ],
|
||||
verticalTabsDefaultPlacements: [
|
||||
- "alltabs-button",
|
||||
- "smartwindow-group-tabs-button",
|
||||
- "ai-window-toggle",
|
||||
],
|
||||
defaultCollapsed: false,
|
||||
},
|
||||
true
|
||||
@@ -406,10 +403,6 @@ var CustomizableUIInternal = {
|
||||
@@ -410,11 +403,6 @@ var CustomizableUIInternal = {
|
||||
type: CustomizableUI.TYPE_TOOLBAR,
|
||||
defaultPlacements: [
|
||||
"tabbrowser-tabs",
|
||||
- "new-tab-button",
|
||||
- "spring",
|
||||
- "alltabs-button",
|
||||
- "smartwindow-group-tabs-button",
|
||||
- "ai-window-toggle",
|
||||
],
|
||||
verticalTabsDefaultPlacements: [],
|
||||
defaultCollapsed: null,
|
||||
@@ -502,6 +495,7 @@ var CustomizableUIInternal = {
|
||||
@@ -507,6 +495,7 @@ var CustomizableUIInternal = {
|
||||
CustomizableUI.AREA_NAVBAR,
|
||||
CustomizableUI.AREA_BOOKMARKS,
|
||||
CustomizableUI.AREA_TABSTRIP,
|
||||
@@ -69,7 +71,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
]);
|
||||
if (AppConstants.platform != "macosx") {
|
||||
toolbars.add(CustomizableUI.AREA_MENUBAR);
|
||||
@@ -1334,6 +1328,9 @@ var CustomizableUIInternal = {
|
||||
@@ -1339,6 +1328,9 @@ var CustomizableUIInternal = {
|
||||
placements = gPlacements.get(area);
|
||||
}
|
||||
|
||||
@@ -79,7 +81,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
// For toolbars that need it, mark as dirty.
|
||||
let defaultPlacements = areaProperties.get("defaultPlacements");
|
||||
if (
|
||||
@@ -1842,7 +1839,6 @@ var CustomizableUIInternal = {
|
||||
@@ -1847,7 +1839,6 @@ var CustomizableUIInternal = {
|
||||
lazy.log.info(
|
||||
"Widget " + aWidgetId + " not found, unable to remove from " + aArea
|
||||
);
|
||||
@@ -87,7 +89,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
}
|
||||
|
||||
this.notifyDOMChange(widgetNode, null, container, true, () => {
|
||||
@@ -1852,7 +1848,7 @@ var CustomizableUIInternal = {
|
||||
@@ -1857,7 +1848,7 @@ var CustomizableUIInternal = {
|
||||
// We also need to remove the panel context menu if it's there:
|
||||
this.ensureButtonContextMenu(widgetNode);
|
||||
if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
|
||||
@@ -96,7 +98,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
} else {
|
||||
window.gNavToolbox.palette.appendChild(widgetNode);
|
||||
}
|
||||
@@ -2020,16 +2016,16 @@ var CustomizableUIInternal = {
|
||||
@@ -2025,16 +2016,16 @@ var CustomizableUIInternal = {
|
||||
elem.setAttribute("skipintoolbarset", "true");
|
||||
}
|
||||
}
|
||||
@@ -116,7 +118,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
// Handle initial state of vertical tabs.
|
||||
if (isVerticalTabs) {
|
||||
// Show the vertical tabs toolbar
|
||||
@@ -2271,6 +2267,10 @@ var CustomizableUIInternal = {
|
||||
@@ -2276,6 +2267,10 @@ var CustomizableUIInternal = {
|
||||
* The identifier string of the area that aNode is being inserted into.
|
||||
*/
|
||||
insertWidgetBefore(aNode, aNextNode, aContainer, aAreaId) {
|
||||
@@ -127,7 +129,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
this.notifyDOMChange(aNode, aNextNode, aContainer, false, () => {
|
||||
this.setLocationAttributes(aNode, aAreaId);
|
||||
aContainer.insertBefore(aNode, aNextNode);
|
||||
@@ -4647,7 +4647,7 @@ var CustomizableUIInternal = {
|
||||
@@ -4652,7 +4647,7 @@ var CustomizableUIInternal = {
|
||||
* For all registered areas, builds those areas to reflect the current
|
||||
* placement state of all widgets.
|
||||
*/
|
||||
@@ -136,7 +138,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
for (let [areaId, areaNodes] of gBuildAreas) {
|
||||
let placements = gPlacements.get(areaId);
|
||||
let isFirstChangedToolbar = true;
|
||||
@@ -4658,7 +4658,7 @@ var CustomizableUIInternal = {
|
||||
@@ -4663,7 +4658,7 @@ var CustomizableUIInternal = {
|
||||
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
|
||||
let defaultCollapsed = area.get("defaultCollapsed");
|
||||
let win = areaNode.documentGlobal;
|
||||
@@ -145,7 +147,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
win.setToolbarVisibility(
|
||||
areaNode,
|
||||
typeof defaultCollapsed == "string"
|
||||
@@ -5971,6 +5971,7 @@ export var CustomizableUI = {
|
||||
@@ -5976,6 +5971,7 @@ export var CustomizableUI = {
|
||||
unregisterArea(aName, aDestroyPlacements) {
|
||||
CustomizableUIInternal.unregisterArea(aName, aDestroyPlacements);
|
||||
},
|
||||
@@ -153,7 +155,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
/**
|
||||
* Add a widget to an area.
|
||||
* If the area to which you try to add is not known to CustomizableUI,
|
||||
@@ -7946,7 +7947,9 @@ class OverflowableToolbar {
|
||||
@@ -7951,7 +7947,9 @@ class OverflowableToolbar {
|
||||
);
|
||||
|
||||
if (webExtList && CustomizableUI.isWebExtensionWidget(child.id)) {
|
||||
@@ -163,7 +165,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
webExtList.insertBefore(child, webExtList.firstElementChild);
|
||||
} else {
|
||||
child.setAttribute("cui-anchorid", this.#defaultListButton.id);
|
||||
@@ -7995,6 +7998,7 @@ class OverflowableToolbar {
|
||||
@@ -8000,6 +7998,7 @@ class OverflowableToolbar {
|
||||
return aElement.getBoundingClientRect().width;
|
||||
}
|
||||
|
||||
@@ -171,7 +173,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
function sumChildrenInlineSize(aParent, aExceptChild = null) {
|
||||
let sum = 0;
|
||||
for (let child of aParent.children) {
|
||||
@@ -8006,7 +8010,10 @@ class OverflowableToolbar {
|
||||
@@ -8011,7 +8010,10 @@ class OverflowableToolbar {
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -183,7 +185,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
if (child != aExceptChild) {
|
||||
sum += getInlineSize(child);
|
||||
}
|
||||
@@ -8030,11 +8037,11 @@ class OverflowableToolbar {
|
||||
@@ -8035,11 +8037,11 @@ class OverflowableToolbar {
|
||||
parseFloat(style.paddingLeft) -
|
||||
parseFloat(style.paddingRight) -
|
||||
toolbarChildrenWidth;
|
||||
@@ -197,7 +199,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
});
|
||||
|
||||
lazy.log.debug(
|
||||
@@ -8049,7 +8056,39 @@ class OverflowableToolbar {
|
||||
@@ -8054,7 +8056,39 @@ class OverflowableToolbar {
|
||||
Math.max(targetWidth, targetChildrenWidth)
|
||||
);
|
||||
totalAvailWidth = Math.ceil(totalAvailWidth);
|
||||
@@ -238,7 +240,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
return { isOverflowing, targetContentWidth, totalAvailWidth };
|
||||
}
|
||||
|
||||
@@ -8110,7 +8149,11 @@ class OverflowableToolbar {
|
||||
@@ -8115,7 +8149,11 @@ class OverflowableToolbar {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -251,7 +253,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
lazy.log.debug(
|
||||
`Need ${minSize} but width is ${totalAvailWidth} so bailing`
|
||||
);
|
||||
@@ -8143,7 +8186,7 @@ class OverflowableToolbar {
|
||||
@@ -8148,7 +8186,7 @@ class OverflowableToolbar {
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
@@ -260,7 +262,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
}
|
||||
child.removeAttribute("cui-anchorid");
|
||||
child.removeAttribute("overflowedItem");
|
||||
@@ -8269,6 +8312,9 @@ class OverflowableToolbar {
|
||||
@@ -8274,6 +8312,9 @@ class OverflowableToolbar {
|
||||
* if no such list exists.
|
||||
*/
|
||||
get #webExtList() {
|
||||
@@ -270,7 +272,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
if (!this.#webExtListRef) {
|
||||
let targetID = this.#toolbar.getAttribute("addon-webext-overflowtarget");
|
||||
if (!targetID) {
|
||||
@@ -8280,6 +8326,9 @@ class OverflowableToolbar {
|
||||
@@ -8285,6 +8326,9 @@ class OverflowableToolbar {
|
||||
let win = this.#toolbar.documentGlobal;
|
||||
let { panel } = win.gUnifiedExtensions;
|
||||
this.#webExtListRef = panel.querySelector(`#${targetID}`);
|
||||
@@ -280,7 +282,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
||||
}
|
||||
return this.#webExtListRef;
|
||||
}
|
||||
@@ -8488,7 +8537,7 @@ class OverflowableToolbar {
|
||||
@@ -8493,7 +8537,7 @@ class OverflowableToolbar {
|
||||
break;
|
||||
}
|
||||
case "mousedown": {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
diff --git a/browser/components/sessionstore/SessionFile.sys.mjs b/browser/components/sessionstore/SessionFile.sys.mjs
|
||||
index 5580838acd72bf0e1189d367984859529d89f5b4..e5fa6076a9cc6ada016ccc4e129cad455010a522 100644
|
||||
index 370e5c105c3d9bee05c2d9d7b63d0ee45b8331e1..1c37c19794ebe863a25f780e9a74d63526b929d7 100644
|
||||
--- a/browser/components/sessionstore/SessionFile.sys.mjs
|
||||
+++ b/browser/components/sessionstore/SessionFile.sys.mjs
|
||||
@@ -22,6 +22,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
RunState: "resource:///modules/sessionstore/RunState.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionWriter: "resource:///modules/sessionstore/SessionWriter.sys.mjs",
|
||||
@@ -25,6 +25,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
SessionWriter:
|
||||
"moz-src:///browser/components/sessionstore/SessionWriter.sys.mjs",
|
||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||
});
|
||||
|
||||
const PREF_UPGRADE_BACKUP = "browser.sessionstore.upgradeBackup.latestBuildID";
|
||||
@@ -381,7 +382,7 @@ var SessionFileInternal = {
|
||||
@@ -384,7 +385,7 @@ var SessionFileInternal = {
|
||||
this._readOrigin = result.origin;
|
||||
|
||||
result.noFilesFound = noFilesFound;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
diff --git a/browser/components/sessionstore/SessionSaver.sys.mjs b/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||
index 9141793550f7c7ff6aa63d4c85bf571b4499e2d0..6906fd9be7ae6ca4316133e0d6552b797c54a7ec 100644
|
||||
index 1f26bc5fdb83f55bdf0b9b7d01fafe1cd37f77f4..5916f741d0fa04c392dcdd10f843e595fe5e058c 100644
|
||||
--- a/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||
+++ b/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||
@@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionFile: "resource:///modules/sessionstore/SessionFile.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
||||
@@ -20,6 +20,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
sessionStoreLogger:
|
||||
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
diff --git a/browser/components/sessionstore/SessionStartup.sys.mjs b/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||
index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b595052264c67d351 100644
|
||||
index 919d4536c5462603346684bbe26794ae9279b517..5a8fae0708e4a9a82c5e85f8a473ebaeafebe71f 100644
|
||||
--- a/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||
+++ b/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||
@@ -40,6 +40,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
StartupPerformance:
|
||||
"resource:///modules/sessionstore/StartupPerformance.sys.mjs",
|
||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
||||
@@ -41,6 +41,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
"moz-src:///browser/components/sessionstore/StartupPerformance.sys.mjs",
|
||||
sessionStoreLogger:
|
||||
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||
});
|
||||
|
||||
const STATE_RUNNING_STR = "running";
|
||||
@@ -85,7 +86,7 @@ export var SessionStartup = {
|
||||
@@ -86,7 +87,7 @@ export var SessionStartup = {
|
||||
}
|
||||
|
||||
// do not need to initialize anything in auto-started private browsing sessions
|
||||
@@ -19,7 +19,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
||||
this._initialized = true;
|
||||
gOnceInitializedDeferred.resolve();
|
||||
return;
|
||||
@@ -179,6 +180,8 @@ export var SessionStartup = {
|
||||
@@ -180,6 +181,8 @@ export var SessionStartup = {
|
||||
this._initialState = parsed;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
||||
if (this._initialState == null) {
|
||||
// No valid session found.
|
||||
this._sessionType = this.NO_SESSION;
|
||||
@@ -276,6 +279,8 @@ export var SessionStartup = {
|
||||
@@ -277,6 +280,8 @@ export var SessionStartup = {
|
||||
`Previous shutdown ok? ${this._previousSessionCrashed}, reason: ${previousSessionCrashedReason}`
|
||||
);
|
||||
|
||||
@@ -37,7 +37,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
||||
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
|
||||
|
||||
if (this.sessionType == this.NO_SESSION) {
|
||||
@@ -336,12 +341,7 @@ export var SessionStartup = {
|
||||
@@ -337,12 +342,7 @@ export var SessionStartup = {
|
||||
isAutomaticRestoreEnabled() {
|
||||
if (this._resumeSessionEnabled === null) {
|
||||
this._resumeSessionEnabled =
|
||||
@@ -51,7 +51,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
||||
}
|
||||
|
||||
return this._resumeSessionEnabled;
|
||||
@@ -354,8 +354,7 @@ export var SessionStartup = {
|
||||
@@ -355,8 +355,7 @@ export var SessionStartup = {
|
||||
*/
|
||||
willRestore() {
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||
index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2eaa1afed 100644
|
||||
index 52fc803050cd257d6de52b1e4a92f3211cbaba88..a9841832ddce540dc0f9b14c29e5eadac7510935 100644
|
||||
--- a/browser/components/sessionstore/SessionStore.sys.mjs
|
||||
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||
@@ -126,6 +126,11 @@ const TAB_EVENTS = [
|
||||
@@ -111,6 +111,11 @@ const TAB_EVENTS = [
|
||||
"TabSplitViewActivate",
|
||||
"SplitViewRemoved",
|
||||
"SplitViewCreated",
|
||||
@@ -14,16 +14,39 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
];
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
@@ -198,6 +203,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
||||
@@ -185,6 +190,8 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
TabStateFlusher:
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||
+ ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||
});
|
||||
blankURI: () => Services.io.newURI("about:blank"),
|
||||
gRestoreWindowsToVirtualDesktop: {
|
||||
pref: "browser.sessionstore.restore_windows_to_virtual_desktop",
|
||||
@@ -348,6 +355,22 @@ class _SessionStore {
|
||||
return this.#shouldRestoreLastSession;
|
||||
}
|
||||
|
||||
ChromeUtils.defineLazyGetter(lazy, "blankURI", () => {
|
||||
@@ -1314,10 +1321,7 @@ var SessionStoreInternal = {
|
||||
+ get _windows() {
|
||||
+ return this.#windows;
|
||||
+ }
|
||||
+
|
||||
+ get _browserWindows() {
|
||||
+ return this.#browserWindows;
|
||||
+ }
|
||||
+
|
||||
+ set _deferredInitialState(aState) {
|
||||
+ this.#deferredInitialState = aState;
|
||||
+ }
|
||||
+
|
||||
+ initializeWindow(aWindow, aInitialState) {
|
||||
+ this.#initializeWindow(aWindow, aInitialState);
|
||||
+ }
|
||||
+
|
||||
// whether we will potentially be restoring the session
|
||||
// more than once without Firefox restarting in between
|
||||
#restoreWithoutRestart = false;
|
||||
@@ -515,10 +538,7 @@ class _SessionStore {
|
||||
*/
|
||||
get willAutoRestore() {
|
||||
return (
|
||||
@@ -33,9 +56,9 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
- BROWSER_STARTUP_RESUME_SESSION)
|
||||
+ true
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2005,6 +2009,11 @@ var SessionStoreInternal = {
|
||||
@@ -1215,6 +1235,11 @@ class _SessionStore {
|
||||
case "TabPinned":
|
||||
case "TabUnpinned":
|
||||
case "SwapDocShells":
|
||||
@@ -44,47 +67,47 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
+ case "TabMove":
|
||||
+ case "TabGroupMoved":
|
||||
+ case "ZenWorkspaceDataChanged":
|
||||
this.saveStateDelayed(win);
|
||||
this.#saveStateDelayed(win);
|
||||
break;
|
||||
case "TabGroupCreate":
|
||||
@@ -2114,6 +2123,10 @@ var SessionStoreInternal = {
|
||||
this._windows[aWindow.__SSi].isTaskbarTab = true;
|
||||
@@ -1341,6 +1366,10 @@ class _SessionStore {
|
||||
this.#windows[aWindow.__SSi].isTaskbarTab = true;
|
||||
}
|
||||
|
||||
+ if (aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
||||
+ this._windows[aWindow.__SSi].isZenUnsynced = true;
|
||||
+ this.#windows[aWindow.__SSi].isZenUnsynced = true;
|
||||
+ }
|
||||
+
|
||||
if (lazy.AIWindow.isAIWindowActiveAndEnabled(aWindow)) {
|
||||
this._windows[aWindow.__SSi].isAIWindow = true;
|
||||
this.#windows[aWindow.__SSi].isAIWindow = true;
|
||||
}
|
||||
@@ -2150,7 +2163,7 @@ var SessionStoreInternal = {
|
||||
let isTaskbarTab = this._windows[aWindow.__SSi].isTaskbarTab;
|
||||
@@ -1377,7 +1406,7 @@ class _SessionStore {
|
||||
let isTaskbarTab = this.#windows[aWindow.__SSi].isTaskbarTab;
|
||||
// A regular window is not a private window, taskbar tab window, or popup window
|
||||
let isRegularWindow =
|
||||
- !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible;
|
||||
+ !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible && !this._windows[aWindow.__SSi].isZenUnsynced;
|
||||
+ !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible && !this.#windows[aWindow.__SSi].isZenUnsynced;
|
||||
|
||||
// perform additional initialization when the first window is loading
|
||||
if (lazy.RunState.isStopped) {
|
||||
@@ -2162,7 +2175,7 @@ var SessionStoreInternal = {
|
||||
@@ -1389,7 +1418,7 @@ class _SessionStore {
|
||||
// to disk to NOW() to enforce a full interval before the next write.
|
||||
lazy.SessionSaver.updateLastSaveTime();
|
||||
|
||||
- if (isPrivateWindow || isTaskbarTab) {
|
||||
+ if (isPrivateWindow || isTaskbarTab || aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
||||
this._log.debug(
|
||||
this.#log.debug(
|
||||
"initializeWindow, the window is private or a web app. Saving SessionStartup.state for possibly restoring later"
|
||||
);
|
||||
@@ -2206,6 +2219,7 @@ var SessionStoreInternal = {
|
||||
@@ -1433,6 +1462,7 @@ class _SessionStore {
|
||||
null,
|
||||
"sessionstore-one-or-no-tab-restored"
|
||||
);
|
||||
+ lazy.ZenSessionStore.onNewEmptySession(aWindow);
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
this.#deferredAllWindowsRestored.resolve();
|
||||
}
|
||||
// this window was opened by _openWindowWithState
|
||||
@@ -2255,7 +2269,6 @@ var SessionStoreInternal = {
|
||||
// this window was opened by #openWindowWithState
|
||||
@@ -1482,7 +1512,6 @@ class _SessionStore {
|
||||
if (closedWindowState) {
|
||||
let newWindowState;
|
||||
if (
|
||||
@@ -92,25 +115,25 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
!lazy.SessionStartup.willRestore()
|
||||
) {
|
||||
// We want to split the window up into pinned tabs and unpinned tabs.
|
||||
@@ -2291,6 +2304,7 @@ var SessionStoreInternal = {
|
||||
@@ -1518,6 +1547,7 @@ class _SessionStore {
|
||||
}
|
||||
|
||||
if (newWindowState) {
|
||||
+ lazy.ZenSessionStore.onRestoringClosedWindow(newWindowState);
|
||||
// Ensure that the window state isn't hidden
|
||||
this._restoreCount = 1;
|
||||
this.#restoreCount = 1;
|
||||
let state = { windows: [newWindowState] };
|
||||
@@ -2327,6 +2341,9 @@ var SessionStoreInternal = {
|
||||
@@ -1554,6 +1584,9 @@ class _SessionStore {
|
||||
});
|
||||
this._shouldRestoreLastSession = false;
|
||||
this.#shouldRestoreLastSession = false;
|
||||
}
|
||||
+ else if (!aInitialState && isRegularWindow) {
|
||||
+ lazy.ZenSessionStore.restoreNewWindow(aWindow, this);
|
||||
+ }
|
||||
|
||||
if (this._restoreLastWindow && aWindow.toolbar.visible) {
|
||||
if (this.#restoreLastWindow && aWindow.toolbar.visible) {
|
||||
// always reset (if not a popup window)
|
||||
@@ -2477,7 +2494,7 @@ var SessionStoreInternal = {
|
||||
@@ -1704,7 +1737,7 @@ class _SessionStore {
|
||||
|
||||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
@@ -119,56 +142,56 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
|
||||
TAB_EVENTS.forEach(function (aEvent) {
|
||||
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
||||
@@ -2528,7 +2545,7 @@ var SessionStoreInternal = {
|
||||
@@ -1755,7 +1788,7 @@ class _SessionStore {
|
||||
|
||||
let isLastRegularWindow =
|
||||
Object.values(this._windows).filter(
|
||||
Object.values(this.#windows).filter(
|
||||
- wData => !wData.isPrivate && !wData.isTaskbarTab
|
||||
+ wData => !wData.isPrivate && !wData.isTaskbarTab && !wData.isZenUnsynced
|
||||
).length == 1;
|
||||
this._log.debug(
|
||||
this.#log.debug(
|
||||
`onClose, closing window isLastRegularWindow? ${isLastRegularWindow}`
|
||||
@@ -2585,8 +2602,8 @@ var SessionStoreInternal = {
|
||||
@@ -1812,8 +1845,8 @@ class _SessionStore {
|
||||
// 2) Flush the window.
|
||||
// 3) When the flush is complete, revisit our decision to store the window
|
||||
// in _closedWindows, and add/remove as necessary.
|
||||
// in #closedWindows, and add/remove as necessary.
|
||||
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
||||
- this.maybeSaveClosedWindow(winData, isLastWindow);
|
||||
- this.#maybeSaveClosedWindow(winData, isLastWindow);
|
||||
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
||||
+ this.maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||
+ this.#maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||
}
|
||||
|
||||
completionPromise = lazy.TabStateFlusher.flushWindow(aWindow).then(() => {
|
||||
@@ -2606,8 +2623,9 @@ var SessionStoreInternal = {
|
||||
@@ -1833,8 +1866,9 @@ class _SessionStore {
|
||||
|
||||
// Save non-private windows if they have at
|
||||
// least one saveable tab or are the last window.
|
||||
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
||||
- this.maybeSaveClosedWindow(winData, isLastWindow);
|
||||
- this.#maybeSaveClosedWindow(winData, isLastWindow);
|
||||
+ lazy.ZenWindowSync.on_WindowCloseAndBrowserFlushed(browsers);
|
||||
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
||||
+ this.maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||
+ this.#maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||
|
||||
if (!isLastWindow && winData.closedId > -1) {
|
||||
this._addClosedAction(
|
||||
@@ -2683,7 +2701,7 @@ var SessionStoreInternal = {
|
||||
this.#addClosedAction(
|
||||
@@ -1910,7 +1944,7 @@ class _SessionStore {
|
||||
* to call this method again asynchronously (for example, after
|
||||
* a window flush).
|
||||
*/
|
||||
- maybeSaveClosedWindow(winData, isLastWindow) {
|
||||
+ maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow = false) {
|
||||
- #maybeSaveClosedWindow(winData, isLastWindow) {
|
||||
+ #maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow = false) {
|
||||
// Make sure SessionStore is still running, and make sure that we
|
||||
// haven't chosen to forget this window.
|
||||
if (
|
||||
@@ -2700,6 +2718,7 @@ var SessionStoreInternal = {
|
||||
// _closedWindows from a previous call to this function.
|
||||
let winIndex = this._closedWindows.indexOf(winData);
|
||||
@@ -1927,6 +1961,7 @@ class _SessionStore {
|
||||
// #closedWindows from a previous call to this function.
|
||||
let winIndex = this.#closedWindows.indexOf(winData);
|
||||
let alreadyStored = winIndex != -1;
|
||||
+ lazy.ZenSessionStore.maybeSaveClosedWindow(winData, isLastRegularWindow);
|
||||
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
|
||||
let shouldStore = hasSaveableTabs || isLastWindow;
|
||||
|
||||
@@ -3522,7 +3541,7 @@ var SessionStoreInternal = {
|
||||
@@ -2744,7 +2779,7 @@ class _SessionStore {
|
||||
if (!isPrivateWindow && tabState.isPrivate) {
|
||||
return;
|
||||
}
|
||||
@@ -177,7 +200,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4260,7 +4279,15 @@ var SessionStoreInternal = {
|
||||
@@ -3511,7 +3546,15 @@ class _SessionStore {
|
||||
1,
|
||||
Math.min(tabState.index, tabState.entries.length)
|
||||
);
|
||||
@@ -194,7 +217,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
|
||||
if (inBackground === false) {
|
||||
aWindow.gBrowser.selectedTab = newTab;
|
||||
@@ -4694,6 +4721,8 @@ var SessionStoreInternal = {
|
||||
@@ -4036,6 +4079,8 @@ class _SessionStore {
|
||||
// Append the tab if we're opening into a different window,
|
||||
tabIndex: aSource == aTargetWindow ? pos : Infinity,
|
||||
pinned: state.pinned,
|
||||
@@ -203,7 +226,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
userContextId: state.userContextId,
|
||||
skipLoad: true,
|
||||
preferredRemoteType,
|
||||
@@ -5191,9 +5220,10 @@ var SessionStoreInternal = {
|
||||
@@ -4608,9 +4653,10 @@ class _SessionStore {
|
||||
if (activePageData.title && activePageData.title != activePageData.url) {
|
||||
win.gBrowser.setInitialTabTitle(tab, activePageData.title, {
|
||||
isContentTitle: true,
|
||||
@@ -215,7 +238,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5561,7 +5591,7 @@ var SessionStoreInternal = {
|
||||
@@ -4982,7 +5028,7 @@ class _SessionStore {
|
||||
|
||||
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
|
||||
let tab = tabbrowser.tabs[i];
|
||||
@@ -224,30 +247,30 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
removableTabs.push(tab);
|
||||
}
|
||||
}
|
||||
@@ -5674,7 +5704,7 @@ var SessionStoreInternal = {
|
||||
@@ -5095,7 +5141,7 @@ class _SessionStore {
|
||||
|
||||
// collect the data for all windows
|
||||
for (ix in this._windows) {
|
||||
- if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab) {
|
||||
+ if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab && !this._windows[ix].isZenUnsynced) {
|
||||
// window data is still in _statesToRestore
|
||||
for (ix in this.#windows) {
|
||||
- if (this.#windows[ix]._restoring || this.#windows[ix].isTaskbarTab) {
|
||||
+ if (this.#windows[ix]._restoring || this.#windows[ix].isTaskbarTab && !this.#windows[ix].isZenUnsynced) {
|
||||
// window data is still in #statesToRestore
|
||||
continue;
|
||||
}
|
||||
@@ -5818,11 +5848,12 @@ var SessionStoreInternal = {
|
||||
@@ -5239,11 +5285,12 @@ class _SessionStore {
|
||||
}
|
||||
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
- let tabs = tabbrowser.tabs;
|
||||
+ let tabs = aWindow.gZenWorkspaces.allStoredTabs;
|
||||
/** @type {WindowStateData} */
|
||||
let winData = this._windows[aWindow.__SSi];
|
||||
let winData = this.#windows[aWindow.__SSi];
|
||||
let tabsData = (winData.tabs = []);
|
||||
|
||||
+ winData.splitViewData = aWindow.gZenViewSplitter?.storeDataForSessionStore();
|
||||
// update the internal state data for this window
|
||||
for (let tab of tabs) {
|
||||
if (tab == aWindow.FirefoxViewHandler.tab) {
|
||||
@@ -5833,6 +5864,9 @@ var SessionStoreInternal = {
|
||||
@@ -5254,6 +5301,9 @@ class _SessionStore {
|
||||
tabsData.push(tabData);
|
||||
}
|
||||
|
||||
@@ -257,7 +280,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
// update tab group state for this window
|
||||
winData.groups = [];
|
||||
for (let tabGroup of aWindow.gBrowser.tabGroups) {
|
||||
@@ -5849,7 +5883,7 @@ var SessionStoreInternal = {
|
||||
@@ -5270,7 +5320,7 @@ class _SessionStore {
|
||||
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
|
||||
// since it's only inserted into the tab strip after it's selected).
|
||||
if (aWindow.FirefoxViewHandler.tab?.selected) {
|
||||
@@ -266,7 +289,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
winData.title = tabbrowser.tabs[0].label;
|
||||
}
|
||||
winData.selected = selectedIndex;
|
||||
@@ -6051,8 +6085,8 @@ var SessionStoreInternal = {
|
||||
@@ -5472,8 +5522,8 @@ class _SessionStore {
|
||||
// selectTab represents.
|
||||
let selectTab = 0;
|
||||
if (overwriteTabs) {
|
||||
@@ -277,7 +300,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
selectTab = Math.min(selectTab, winData.tabs.length);
|
||||
}
|
||||
|
||||
@@ -6074,6 +6108,7 @@ var SessionStoreInternal = {
|
||||
@@ -5495,6 +5545,7 @@ class _SessionStore {
|
||||
if (overwriteTabs) {
|
||||
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
|
||||
if (!tabbrowser.tabs[i].selected) {
|
||||
@@ -285,7 +308,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
tabbrowser.removeTab(tabbrowser.tabs[i]);
|
||||
}
|
||||
}
|
||||
@@ -6108,6 +6143,12 @@ var SessionStoreInternal = {
|
||||
@@ -5529,6 +5580,12 @@ class _SessionStore {
|
||||
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
|
||||
);
|
||||
}
|
||||
@@ -298,7 +321,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
|
||||
// Move the originally open tabs to the end.
|
||||
if (initialTabs) {
|
||||
@@ -6674,6 +6715,25 @@ var SessionStoreInternal = {
|
||||
@@ -6098,6 +6155,25 @@ class _SessionStore {
|
||||
|
||||
// Most of tabData has been restored, now continue with restoring
|
||||
// attributes that may trigger external events.
|
||||
@@ -324,24 +347,25 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
|
||||
if (tabData.pinned) {
|
||||
tabbrowser.pinTab(tab);
|
||||
@@ -6859,6 +6919,9 @@ var SessionStoreInternal = {
|
||||
@@ -6272,6 +6348,9 @@ class _SessionStore {
|
||||
aWindow.gURLBar.readOnly = false;
|
||||
}
|
||||
}
|
||||
+ if (aWinData.isZenUnsynced) {
|
||||
+ this._windows[aWindow.__SSi].isZenUnsynced = true;
|
||||
+ this.#windows[aWindow.__SSi].isZenUnsynced = true;
|
||||
+ }
|
||||
|
||||
let promiseParts = Promise.withResolvers();
|
||||
aWindow.setTimeout(() => {
|
||||
@@ -7356,5 +7419,6 @@ var SessionStoreInternal = {
|
||||
const wasMinimized = aWindow.windowState == aWindow.STATE_MINIMIZED;
|
||||
@@ -6774,6 +6853,7 @@ class _SessionStore {
|
||||
*/
|
||||
_isCmdLineEmpty: function ssi_isCmdLineEmpty(aWindow, aState) {
|
||||
#isCmdLineEmpty(aWindow, aState) {
|
||||
var pinnedOnly =
|
||||
+ !Services.prefs.getBoolPref("zen.workspaces.continue-where-left-off") &&
|
||||
aState.windows &&
|
||||
aState.windows.every(win => win.tabs.every(tab => tab.pinned));
|
||||
@@ -7654,7 +7718,7 @@ var SessionStoreInternal = {
|
||||
|
||||
@@ -7116,7 +7196,7 @@ class _SessionStore {
|
||||
|
||||
let groupsToSave = new Map();
|
||||
for (let tIndex = 0; tIndex < window.tabs.length; ) {
|
||||
@@ -350,7 +374,7 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
// Adjust window.selected
|
||||
if (tIndex + 1 < window.selected) {
|
||||
window.selected -= 1;
|
||||
@@ -7669,7 +7733,7 @@ var SessionStoreInternal = {
|
||||
@@ -7131,7 +7211,7 @@ class _SessionStore {
|
||||
);
|
||||
// We don't want to increment tIndex here.
|
||||
continue;
|
||||
@@ -359,15 +383,15 @@ index 76a984f6e21409941ea038218d161e67f2e0c23d..52408568a33a89c0e3d0d1514152ded2
|
||||
// Convert any open groups into saved groups.
|
||||
let groupStateToSave = window.groups.find(
|
||||
groupState => groupState.id == window.tabs[tIndex].groupId
|
||||
@@ -8233,7 +8297,6 @@ var SessionStoreInternal = {
|
||||
@@ -7691,7 +7771,6 @@ class _SessionStore {
|
||||
timer.initWithCallback(
|
||||
function () {
|
||||
() => {
|
||||
if (beats <= 0) {
|
||||
- this._log.debug(`looseTimer of ${delay} timed out`);
|
||||
- this.#log.debug(`looseTimer of ${delay} timed out`);
|
||||
Glean.sessionRestore.shutdownFlushAllOutcomes.timed_out.add(1);
|
||||
deferred.resolve();
|
||||
}
|
||||
@@ -8711,6 +8774,7 @@ var SessionStoreInternal = {
|
||||
@@ -8174,6 +8253,7 @@ class _SessionStore {
|
||||
if (
|
||||
!savedTabGroupState.tabs.length ||
|
||||
this.getSavedTabGroup(savedTabGroupState.id)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs
|
||||
index a33deeb5b587d6a950960a1a4781176e4e730ad7..7927471d389f2626e4cc1b0e7a6eab6446dca432 100644
|
||||
index bb7bd8c7ca88f776188fce64e0c85beb5ceb27a5..bdec77ba26172fe1b41369b1d45d5a6f9d52ae25 100644
|
||||
--- a/browser/components/sessionstore/TabState.sys.mjs
|
||||
+++ b/browser/components/sessionstore/TabState.sys.mjs
|
||||
@@ -8,6 +8,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.sys.mjs",
|
||||
TabAttributes: "resource:///modules/sessionstore/TabAttributes.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
@@ -10,6 +10,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
"moz-src:///browser/components/sessionstore/TabAttributes.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
+ UrlbarShared: "chrome://browser/content/urlbar/UrlbarShared.mjs",
|
||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
||||
sessionStoreLogger:
|
||||
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||
});
|
||||
|
||||
@@ -103,10 +104,28 @@ class _TabState {
|
||||
@@ -106,10 +107,28 @@ class _TabState {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ index a33deeb5b587d6a950960a1a4781176e4e730ad7..7927471d389f2626e4cc1b0e7a6eab64
|
||||
|
||||
tabData.userContextId = tab.userContextId || 0;
|
||||
|
||||
@@ -132,6 +151,10 @@ class _TabState {
|
||||
@@ -135,6 +154,10 @@ class _TabState {
|
||||
tabData.image = tabbrowser.getIcon(tab);
|
||||
}
|
||||
|
||||
|
||||
1199
src/browser/components/tabbrowser/Tabbrowser-sys-mjs.patch
Normal file
1199
src/browser/components/tabbrowser/Tabbrowser-sys-mjs.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8edf9bcf4 100644
|
||||
index f9623f82499e516050d523068e70ebaa4fe9a66a..95bcc078a86b4ec4b35f5916b7e4a5e305afba9e 100644
|
||||
--- a/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
@@ -35,6 +35,9 @@
|
||||
@@ -42,6 +42,9 @@
|
||||
* @returns {MozTabbrowserTab|vbox}
|
||||
*/
|
||||
const elementToMove = element => {
|
||||
@@ -12,7 +12,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
if (isTab(element) || isSplitViewWrapper(element)) {
|
||||
return element;
|
||||
}
|
||||
@@ -128,6 +131,9 @@
|
||||
@@ -140,6 +143,9 @@
|
||||
}
|
||||
|
||||
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
@@ -22,15 +22,15 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
if (
|
||||
(dropEffect == "move" || dropEffect == "copy") &&
|
||||
document == draggedTab.ownerDocument &&
|
||||
@@ -148,6 +154,7 @@
|
||||
!draggedTab.group.collapsed
|
||||
@@ -161,6 +167,7 @@
|
||||
) {
|
||||
draggedTab.group.collapsedByDrag = true;
|
||||
draggedTab.group.collapsed = true;
|
||||
+ gZenFolders.animateGroupMove(draggedTab.group);
|
||||
}
|
||||
|
||||
if (dropEffect == "move") {
|
||||
@@ -155,10 +162,6 @@
|
||||
@@ -168,10 +175,6 @@
|
||||
|
||||
// Pinned tabs in expanded vertical mode are on a grid format and require
|
||||
// different logic to drag and drop.
|
||||
@@ -41,7 +41,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
this._animateTabMove(event);
|
||||
return;
|
||||
}
|
||||
@@ -297,6 +300,10 @@
|
||||
@@ -310,6 +313,10 @@
|
||||
|
||||
this._tabDropIndicator.hidden = true;
|
||||
event.stopPropagation();
|
||||
@@ -52,7 +52,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
if (draggedTab && dropEffect == "copy") {
|
||||
let duplicatedDraggedTab;
|
||||
let duplicatedTabs = [];
|
||||
@@ -324,12 +331,16 @@
|
||||
@@ -337,12 +344,16 @@
|
||||
let translateOffsetY = oldTranslateY % tabHeight;
|
||||
let newTranslateX = oldTranslateX - translateOffsetX;
|
||||
let newTranslateY = oldTranslateY - translateOffsetY;
|
||||
@@ -73,7 +73,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
|
||||
if (this._tabbrowserTabs.isContainerVerticalPinnedGrid(draggedTab)) {
|
||||
// Update both translate axis for pinned vertical expanded tabs
|
||||
@@ -404,11 +415,13 @@
|
||||
@@ -417,11 +428,13 @@
|
||||
this._dragToPinPromoCard,
|
||||
];
|
||||
let shouldPin =
|
||||
@@ -87,7 +87,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
isTab(draggedTab) &&
|
||||
draggedTab.pinned &&
|
||||
this._tabbrowserTabs.arrowScrollbox.contains(event.target);
|
||||
@@ -484,6 +497,7 @@
|
||||
@@ -492,6 +505,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
if (shouldTranslate) {
|
||||
this.#dropAnimationEndTime = Date.now() + DROP_ANIMATION_GRACE_MS;
|
||||
let translationPromises = [];
|
||||
@@ -496,7 +510,7 @@
|
||||
@@ -504,7 +518,7 @@
|
||||
item.removeAttribute("tabdrop-samewindow");
|
||||
resolve();
|
||||
};
|
||||
@@ -104,7 +104,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
postTransitionCleanup();
|
||||
} else {
|
||||
let onTransitionEnd = transitionendEvent => {
|
||||
@@ -580,7 +594,7 @@
|
||||
@@ -595,7 +609,7 @@
|
||||
if (tab.selected) {
|
||||
selectedTab = tab;
|
||||
indexForSelectedTab = newIndex;
|
||||
@@ -113,7 +113,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
const droppedIntoPinnedArea = dropIndex < gBrowser.pinnedTabCount;
|
||||
const newSplitView = gBrowser.adoptSplitView(tab, {
|
||||
elementIndex: droppedIntoPinnedArea
|
||||
@@ -605,7 +619,7 @@
|
||||
@@ -620,7 +634,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
const newTab = gBrowser.adoptTab(selectedTab, {
|
||||
elementIndex: indexForSelectedTab,
|
||||
selectTab: selectedTab == draggedTab,
|
||||
@@ -639,10 +653,6 @@
|
||||
@@ -654,10 +668,6 @@
|
||||
this._tabbrowserTabs.dragAndDropElements[
|
||||
gBrowser.pinnedTabCount + unpinnedSplitViews.length - 1
|
||||
];
|
||||
@@ -133,7 +133,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -703,6 +713,7 @@
|
||||
@@ -717,6 +727,7 @@
|
||||
|
||||
let nextItem = this._tabbrowserTabs.dragAndDropElements[newIndex];
|
||||
let tabGroup = isTab(nextItem) && nextItem.group;
|
||||
@@ -141,7 +141,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
gBrowser.loadTabs(urls, {
|
||||
inBackground,
|
||||
replace,
|
||||
@@ -744,6 +755,22 @@
|
||||
@@ -758,6 +769,22 @@
|
||||
this._expandGroupOnDrop(draggedTab);
|
||||
}
|
||||
this._resetTabsAfterDrop(draggedTab);
|
||||
@@ -164,7 +164,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
|
||||
if (
|
||||
dt.mozUserCancelled ||
|
||||
@@ -1074,11 +1101,10 @@
|
||||
@@ -1088,11 +1115,10 @@
|
||||
return this.#getHorizontalScrollboxDragTarget(event, ignoreSides);
|
||||
}
|
||||
while (target) {
|
||||
@@ -180,7 +180,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
break;
|
||||
}
|
||||
target = target.parentNode;
|
||||
@@ -1108,6 +1134,9 @@
|
||||
@@ -1122,6 +1148,9 @@
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -190,36 +190,43 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -1170,14 +1199,20 @@
|
||||
let releaseReservedSpace = () =>
|
||||
this.#releaseSpaceInScrolledContent(periphery);
|
||||
if (group.collapsed) {
|
||||
- // The group's tabs animate back to their full size, so hold on to the
|
||||
- // space reserved for them until they get there.
|
||||
- group.addEventListener(
|
||||
- "TabGroupAnimationComplete",
|
||||
- releaseReservedSpace,
|
||||
- { once: true }
|
||||
- );
|
||||
- group.collapsed = false;
|
||||
+ const expand = !group.hasAttribute("has-active");
|
||||
+ if (expand) {
|
||||
+ // The group's tabs animate back to their full size, so hold on to the
|
||||
+ // space reserved for them until they get there.
|
||||
+ group.addEventListener(
|
||||
+ "TabGroupAnimationComplete",
|
||||
+ releaseReservedSpace,
|
||||
+ { once: true }
|
||||
+ );
|
||||
+ } else {
|
||||
+ releaseReservedSpace();
|
||||
+ }
|
||||
+ group.collapsed = !expand;
|
||||
+ gZenFolders.animateGroupMove(group, true);
|
||||
} else {
|
||||
releaseReservedSpace();
|
||||
}
|
||||
@@ -1362,7 +1397,6 @@
|
||||
@@ -1188,17 +1217,24 @@
|
||||
let periphery = draggedTab.ownerDocument.getElementById(
|
||||
"tabbrowser-arrowscrollbox-periphery"
|
||||
);
|
||||
- // The group's tabs animate back to their full size, so hold on to the
|
||||
- // space reserved for them until they get there.
|
||||
- group.addEventListener(
|
||||
- "TabGroupAnimationComplete",
|
||||
- () => {
|
||||
- group.collapsedByDrag = false;
|
||||
- this.#releaseSpaceInScrolledContent(periphery);
|
||||
- },
|
||||
- { once: true }
|
||||
- );
|
||||
- group.collapsed = false;
|
||||
+ const expand = !group.hasAttribute("has-active");
|
||||
+ if (expand) {
|
||||
+ // The group's tabs animate back to their full size, so hold on to the
|
||||
+ // space reserved for them until they get there.
|
||||
+ group.addEventListener(
|
||||
+ "TabGroupAnimationComplete",
|
||||
+ () => {
|
||||
+ group.collapsedByDrag = false;
|
||||
+ this.#releaseSpaceInScrolledContent(periphery);
|
||||
+ },
|
||||
+ { once: true }
|
||||
+ );
|
||||
+ } else {
|
||||
+ group.collapsedByDrag = false;
|
||||
+ this.#releaseSpaceInScrolledContent(periphery);
|
||||
+ }
|
||||
+ group.collapsed = !expand;
|
||||
+ gZenFolders.animateGroupMove(group, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1380,7 +1416,6 @@
|
||||
// using updateDragImage. On Linux, we can use a panel.
|
||||
if (platform == "win" || platform == "macosx") {
|
||||
captureListener = function () {
|
||||
@@ -227,7 +234,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
};
|
||||
} else {
|
||||
// Create a panel to use it in setDragImage
|
||||
@@ -1400,7 +1434,6 @@
|
||||
@@ -1418,7 +1453,6 @@
|
||||
);
|
||||
dragImageOffset = dragImageOffset * scale;
|
||||
}
|
||||
@@ -235,7 +242,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
|
||||
// _dragData.offsetX/Y give the coordinates that the mouse should be
|
||||
// positioned relative to the corner of the new window created upon
|
||||
@@ -1419,7 +1452,7 @@
|
||||
@@ -1437,7 +1471,7 @@
|
||||
let dropEffect = this.getDropEffectForTabDrag(event);
|
||||
let isMovingInTabStrip = !fromTabList && dropEffect == "move";
|
||||
let collapseTabGroupDuringDrag =
|
||||
@@ -244,7 +251,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
|
||||
tab._dragData = {
|
||||
offsetX: this._tabbrowserTabs.verticalMode
|
||||
@@ -1429,7 +1462,7 @@
|
||||
@@ -1447,7 +1481,7 @@
|
||||
? event.screenY - window.screenY - tabOffset
|
||||
: event.screenY - window.screenY,
|
||||
scrollPos:
|
||||
@@ -253,7 +260,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
? this._tabbrowserTabs.pinnedTabsContainer.scrollPosition
|
||||
: this._tabbrowserTabs.arrowScrollbox.scrollPosition,
|
||||
screenX: event.screenX,
|
||||
@@ -1522,6 +1555,7 @@
|
||||
@@ -1540,6 +1574,7 @@
|
||||
if (tabStripItemElement.hasAttribute("dragtarget")) {
|
||||
return;
|
||||
}
|
||||
@@ -261,7 +268,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
let isPinned = tab.pinned;
|
||||
let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
|
||||
let isGrid = this._tabbrowserTabs.isContainerVerticalPinnedGrid(tab);
|
||||
@@ -1895,23 +1929,6 @@
|
||||
@@ -1913,23 +1948,6 @@
|
||||
|
||||
// Slide the relevant tabs to their new position.
|
||||
// non-moving tabs adjust for RTL
|
||||
@@ -285,7 +292,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
// moving tabs don't adjust for RTL
|
||||
for (let item of selectedElements) {
|
||||
if (
|
||||
@@ -1960,7 +1977,6 @@
|
||||
@@ -1978,7 +1996,6 @@
|
||||
for (let item of this._tabbrowserTabs.dragAndDropElements) {
|
||||
delete item._moveTogetherSelectedTabsData;
|
||||
item = elementToMove(item);
|
||||
@@ -293,7 +300,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
item.removeAttribute("multiselected-move-together");
|
||||
}
|
||||
}
|
||||
@@ -2812,7 +2828,6 @@
|
||||
@@ -2830,7 +2847,6 @@
|
||||
tab.style.top = "";
|
||||
tab.style.maxWidth = "";
|
||||
tab.style.pointerEvents = "";
|
||||
@@ -301,7 +308,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
||||
tab.removeAttribute("small-stack");
|
||||
tab.removeAttribute("big-stack");
|
||||
}
|
||||
@@ -2821,11 +2836,9 @@
|
||||
@@ -2839,11 +2855,9 @@
|
||||
)) {
|
||||
label.style.width = "";
|
||||
label.style.maxWidth = "";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||
index cfc232f038cd491db32e0c0ca35622360dd9dec5..4806a725ddefa9d0709020d537eae5464249a294 100644
|
||||
index e32b02941a6019703212cede4660a24b88845120..5cb363ed20d49c1ae8abedecc3b08540406b7a1b 100644
|
||||
--- a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||
@@ -77,22 +77,26 @@ export class UrlbarProviderHeuristicFallback extends UrlbarProvider {
|
||||
@@ -76,22 +76,26 @@ export class UrlbarProviderHeuristicFallback extends UrlbarProvider {
|
||||
// Since we can't tell if this is a real URL and whether the user wants
|
||||
// to visit or search for it, we provide an alternative searchengine
|
||||
// match if the string looks like an alphanumeric origin or an e-mail.
|
||||
- let str = queryContext.searchString;
|
||||
- if (!URL.canParse(str)) {
|
||||
- if (
|
||||
- lazy.UrlbarPrefs.get("keyword.enabled") &&
|
||||
- queryContext.keywordEnabled &&
|
||||
- (lazy.UrlUtils.looksLikeOrigin(str, {
|
||||
- noIp: true,
|
||||
- noPort: true,
|
||||
@@ -24,7 +24,7 @@ index cfc232f038cd491db32e0c0ca35622360dd9dec5..4806a725ddefa9d0709020d537eae546
|
||||
+ }
|
||||
+ );
|
||||
+ if (
|
||||
+ lazy.UrlbarPrefs.get("keyword.enabled") &&
|
||||
+ queryContext.keywordEnabled &&
|
||||
+ (lazy.UrlUtils.looksLikeUrl(searchCandidate) ||
|
||||
+ lazy.UrlUtils.looksLikeOrigin(searchCandidate, {
|
||||
+ allowPartialNumericalTLDs: true,
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
index 178cd5e84fda74a28b2de59b671b3399cc28fac4..b03c6e06de4ee9a95dcb4d33d7ac9f0b053be4e1 100644
|
||||
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
||||
@@ -214,6 +214,11 @@ export var UrlbarUtils = {
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_FALLBACK;
|
||||
case "UrlbarProviderHistoryUrlHeuristic":
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
||||
+ case "ZenUrlbarProviderGlobalActions":
|
||||
+ if (result.source == UrlbarShared.RESULT_SOURCE.WORKSPACES) {
|
||||
+ return UrlbarShared.RESULT_GROUP.ZEN_WORKSPACE;
|
||||
+ }
|
||||
+ return UrlbarShared.RESULT_GROUP.ZEN_ACTION;
|
||||
case "UrlbarProviderOmnibox":
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_OMNIBOX;
|
||||
case "UrlbarProviderRestrictKeywordsAutofill":
|
||||
@@ -1,16 +1,16 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarChildController.mjs b/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||
index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7549ff100 100644
|
||||
index 52ed36deac35d3de9f7f537313159fb4debe98a6..3bbc612a2e10eedafdabdaa8e17cf36831a6a27c 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||
@@ -438,7 +438,6 @@ export class UrlbarChildController {
|
||||
const isMac = AppConstants.platform == "macosx";
|
||||
@@ -446,7 +446,6 @@ export class UrlbarChildController {
|
||||
const isMac = UrlbarContentUtils.getPlatform() == "macosx";
|
||||
// Handle readline/emacs-style navigation bindings on Mac.
|
||||
if (
|
||||
- isMac &&
|
||||
this.view.isOpen &&
|
||||
event.ctrlKey &&
|
||||
(event.key == "n" || event.key == "p")
|
||||
@@ -630,6 +629,8 @@ export class UrlbarChildController {
|
||||
@@ -644,6 +643,8 @@ export class UrlbarChildController {
|
||||
});
|
||||
}
|
||||
event.preventDefault();
|
||||
@@ -19,7 +19,7 @@ index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -934,6 +935,10 @@ export class UrlbarChildController {
|
||||
@@ -905,6 +906,10 @@ export class UrlbarChildController {
|
||||
}
|
||||
reuseEmpty = true;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7
|
||||
// The browser window exists only in chrome; a content-process input has no
|
||||
// tab to reuse, so `gBrowser` is absent and the reuse is skipped.
|
||||
if (
|
||||
@@ -943,6 +948,10 @@ export class UrlbarChildController {
|
||||
@@ -914,6 +919,10 @@ export class UrlbarChildController {
|
||||
) {
|
||||
where = "current";
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36d7d74e8e 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
@@ -88,6 +88,13 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
logger: () => UrlbarShared.getLogger({ prefix: "Input" }),
|
||||
});
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInputBase.mjs b/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||
index 8be35b58c5369e123ca69426e852e3849bf75513..170cffbdd12a72dab15976cdab9207dc4292d4e6 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||
@@ -83,6 +83,12 @@ if (lazy) {
|
||||
Ci.nsIURLQueryStringStripper,
|
||||
],
|
||||
});
|
||||
+ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
+ lazy,
|
||||
+ "ZEN_URLBAR_BEHAVIOR",
|
||||
+ "zen.urlbar.behavior",
|
||||
+ 'default'
|
||||
+ );
|
||||
}
|
||||
|
||||
+XPCOMUtils.defineLazyPreferenceGetter(
|
||||
+ lazy,
|
||||
+ "ZEN_URLBAR_BEHAVIOR",
|
||||
+ "zen.urlbar.behavior",
|
||||
+ 'default'
|
||||
+);
|
||||
+
|
||||
const UNLIMITED_MAX_RESULTS = 99;
|
||||
|
||||
let getBoundsWithoutFlushing = element =>
|
||||
@@ -771,7 +778,16 @@ ${
|
||||
const logger = () => UrlbarShared.getLogger({ prefix: "Input" });
|
||||
@@ -917,7 +923,16 @@ ${
|
||||
// See _on_select(). HTMLInputElement.select() dispatches a "select"
|
||||
// event but does not set the primary selection.
|
||||
this._suppressPrimaryAdjustment = true;
|
||||
@@ -33,7 +32,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
this._suppressPrimaryAdjustment = false;
|
||||
}
|
||||
|
||||
@@ -846,6 +862,10 @@ ${
|
||||
@@ -992,6 +1007,10 @@ ${
|
||||
hideSearchTerms = false,
|
||||
isSameDocument = false,
|
||||
} = {}) {
|
||||
@@ -44,7 +43,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
if (!this.#isAddressbar) {
|
||||
throw new Error(
|
||||
"Cannot set URI for UrlbarInput that is not an address bar"
|
||||
@@ -1143,7 +1163,16 @@ ${
|
||||
@@ -1289,7 +1308,16 @@ ${
|
||||
this.searchModeSwitcher?.updateSearchIcon();
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1255,6 +1284,9 @@ ${
|
||||
@@ -1401,6 +1429,9 @@ ${
|
||||
where,
|
||||
query: searchString,
|
||||
});
|
||||
@@ -71,7 +70,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
this.controller.openSERP(
|
||||
engine.id,
|
||||
searchString,
|
||||
@@ -1726,7 +1758,11 @@ ${
|
||||
@@ -1884,7 +1915,11 @@ ${
|
||||
openParams.avoidBrowserFocus = keepViewOpen;
|
||||
|
||||
if (!this.#providesSearchMode(result) && !keepViewOpen) {
|
||||
@@ -84,12 +83,12 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
}
|
||||
|
||||
if (isCanonized) {
|
||||
@@ -3016,6 +3052,42 @@ ${
|
||||
@@ -3181,6 +3216,42 @@ ${
|
||||
await this.#updateLayoutBreakoutDimensions();
|
||||
}
|
||||
|
||||
+ zenFormatURLValue() {
|
||||
+ return this.#lazy.valueFormatter._formatURL();
|
||||
+ return this.#getValueFormatter().update();
|
||||
+ }
|
||||
+
|
||||
+ get zenUrlbarBehavior() {
|
||||
@@ -127,7 +126,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
startLayoutExtend() {
|
||||
if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) {
|
||||
// Do not expand if the Urlbar does not support being expanded or it is
|
||||
@@ -3030,6 +3102,13 @@ ${
|
||||
@@ -3195,6 +3266,13 @@ ${
|
||||
this.toggleAttribute("breakout-extend", true);
|
||||
this.#updateTextboxPosition();
|
||||
|
||||
@@ -141,7 +140,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
// Enable the animation only after the first extend call to ensure it
|
||||
// doesn't run when opening a new window.
|
||||
if (!this.hasAttribute("breakout-extend-animate")) {
|
||||
@@ -3053,6 +3132,29 @@ ${
|
||||
@@ -3218,6 +3296,29 @@ ${
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,7 +170,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
this.toggleAttribute("breakout-extend", false);
|
||||
this.#updateTextboxPosition();
|
||||
}
|
||||
@@ -3091,7 +3193,7 @@ ${
|
||||
@@ -3256,7 +3357,7 @@ ${
|
||||
forceUnifiedSearchButtonAvailable = false
|
||||
) {
|
||||
let prevState = this.getAttribute("pageproxystate");
|
||||
@@ -180,20 +179,20 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
this.setAttribute("pageproxystate", state);
|
||||
this._inputContainer.setAttribute("pageproxystate", state);
|
||||
this._identityBox?.setAttribute("pageproxystate", state);
|
||||
@@ -3355,10 +3457,12 @@ ${
|
||||
@@ -3533,7 +3634,11 @@ ${
|
||||
return;
|
||||
}
|
||||
|
||||
this.style.top = px(
|
||||
- this.style.top = px(getUntransformedTop(this.parentNode));
|
||||
+ this.style.top = px(
|
||||
+ this.window.gZenVerticalTabsManager._hasSetSingleToolbar ?
|
||||
this.parentNode.getBoxQuads({
|
||||
ignoreTransforms: true,
|
||||
flush: false,
|
||||
})[0].p1.y
|
||||
+ : (AppConstants.platform == "macosx" ? -2 : -5)
|
||||
);
|
||||
+ getUntransformedTop(this.parentNode)
|
||||
+ : (UrlbarContentUtils.getPlatform() == "macosx" ? -2 : -5)
|
||||
+ );
|
||||
}
|
||||
|
||||
@@ -3417,9 +3521,10 @@ ${
|
||||
#updateTextboxPositionNextFrame() {
|
||||
@@ -3591,9 +3696,10 @@ ${
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -205,7 +204,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
);
|
||||
|
||||
if (this.#breakoutBlockerCount) {
|
||||
@@ -3929,6 +4034,7 @@ ${
|
||||
@@ -4108,6 +4214,7 @@ ${
|
||||
}
|
||||
|
||||
_toggleActionOverride(event) {
|
||||
@@ -213,7 +212,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
if (
|
||||
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
|
||||
event.keyCode == KeyEvent.DOM_VK_ALT ||
|
||||
@@ -4027,9 +4133,10 @@ ${
|
||||
@@ -4206,9 +4313,10 @@ ${
|
||||
if (!this.#isAddressbar) {
|
||||
return val;
|
||||
}
|
||||
@@ -226,36 +225,36 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
+ : val;
|
||||
// Only trim value if the directionality doesn't change to RTL and we're not
|
||||
// showing a strikeout https protocol.
|
||||
return this.controller.isTextDirectionRTL(trimmedValue) ||
|
||||
@@ -4235,6 +4342,11 @@ ${
|
||||
return UrlbarContentUtils.isTextDirectionRTL(trimmedValue, window) ||
|
||||
@@ -4410,6 +4518,11 @@ ${
|
||||
keepViewOpen = false,
|
||||
browserId = null,
|
||||
}) {
|
||||
+ where = this.window.gZenUIManager.getOpenUILinkWhere(
|
||||
+ url,
|
||||
+ loadRequest.urlLoad?.url ?? "",
|
||||
+ this.window.gBrowser.selectedBrowser,
|
||||
+ where
|
||||
+ );
|
||||
let userTypedValue;
|
||||
if (this.#isAddressbar && where == "current") {
|
||||
// Make sure URL is formatted properly (don't show punycode).
|
||||
@@ -4576,6 +4688,7 @@ ${
|
||||
this.setResultForCurrentValue(null);
|
||||
this.handleCommand();
|
||||
this.controller.clearLastQueryContextCache();
|
||||
+ this.view.close();
|
||||
let keyDownEnterDeferred;
|
||||
if (
|
||||
this._keyDownEnterDeferred &&
|
||||
@@ -4731,6 +4844,7 @@ ${
|
||||
this.setResultForCurrentValue(null);
|
||||
this.handleCommand();
|
||||
this.controller.clearLastQueryContextCache();
|
||||
+ this.view.close();
|
||||
|
||||
this._suppressStartQuery = false;
|
||||
});
|
||||
@@ -4583,7 +4696,6 @@ ${
|
||||
contextMenu.addEventListener("popupshowing", () => {
|
||||
// Close the results pane when the input field contextual menu is open,
|
||||
// because paste and go doesn't want a result selection.
|
||||
- this.view.close();
|
||||
this._suppressStartQuery = false;
|
||||
});
|
||||
@@ -4742,7 +4856,6 @@ ${
|
||||
// Close the results pane, because paste and go doesn't want a result
|
||||
// selection. This has to happen before the menu opens: ending
|
||||
// breakout-extend once it's open keeps it from showing (bug 2037468).
|
||||
- this.view.close();
|
||||
|
||||
let controller =
|
||||
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||
@@ -4850,7 +4962,11 @@ ${
|
||||
let controller =
|
||||
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||
@@ -5025,7 +5138,11 @@ ${
|
||||
if (!engineName && !source && !this.hasAttribute("searchmode")) {
|
||||
return;
|
||||
}
|
||||
@@ -268,7 +267,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
if (this._searchModeIndicatorTitle) {
|
||||
this._searchModeIndicatorTitle.textContent = "";
|
||||
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
|
||||
@@ -5149,6 +5265,7 @@ ${
|
||||
@@ -5335,6 +5452,7 @@ ${
|
||||
|
||||
this.document.l10n.setAttributes(
|
||||
this.inputField,
|
||||
@@ -276,10 +275,10 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
l10nId,
|
||||
l10nId == "urlbar-placeholder-with-name"
|
||||
? { name: engineName }
|
||||
@@ -5199,6 +5316,12 @@ ${
|
||||
@@ -5385,6 +5503,12 @@ ${
|
||||
}
|
||||
|
||||
lazy.logger.debug("Blur Event");
|
||||
logger().debug("Blur Event");
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
||||
+ !UrlbarPrefs.get("closeOnWindowBlur")
|
||||
@@ -289,7 +288,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
// We cannot count every blur events after a missed engagement as abandoment
|
||||
// because the user may have clicked on some view element that executes
|
||||
// a command causing a focus change. For example opening preferences from
|
||||
@@ -5276,6 +5399,11 @@ ${
|
||||
@@ -5464,6 +5588,11 @@ ${
|
||||
}
|
||||
|
||||
_on_click(event) {
|
||||
@@ -301,7 +300,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
switch (event.target) {
|
||||
case this.inputField:
|
||||
case this._inputContainer:
|
||||
@@ -5371,10 +5499,11 @@ ${
|
||||
@@ -5558,10 +5687,11 @@ ${
|
||||
}
|
||||
if (untrim) {
|
||||
this.setValue(this._untrimmedValue);
|
||||
@@ -314,7 +313,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
this.view.autoOpen({ event });
|
||||
} else {
|
||||
if (this._untrimOnFocusAfterKeydown) {
|
||||
@@ -5414,9 +5543,16 @@ ${
|
||||
@@ -5605,9 +5735,16 @@ ${
|
||||
}
|
||||
|
||||
_on_mousedown(event) {
|
||||
@@ -332,7 +331,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
if (
|
||||
event.composedTarget != this.inputField &&
|
||||
event.composedTarget != this._inputContainer
|
||||
@@ -5426,6 +5562,10 @@ ${
|
||||
@@ -5617,6 +5754,10 @@ ${
|
||||
|
||||
this.focusedViaMousedown = !this.focused;
|
||||
this.#preventClickSelectsAll = this.focused;
|
||||
@@ -343,7 +342,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
|
||||
// Keep the focus status, since the attribute may be changed
|
||||
// upon calling this.focus().
|
||||
@@ -5463,7 +5603,7 @@ ${
|
||||
@@ -5654,7 +5795,7 @@ ${
|
||||
// view open on tab switch, and the TabSelect event arrived earlier.
|
||||
// Also ignore mousedown on the urlbarView context menu: opening/closing the
|
||||
// view is already handled by the result opening flow.
|
||||
@@ -352,7 +351,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..1746a052c304e7988447fdb869ad2e36
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5754,7 +5894,7 @@ ${
|
||||
@@ -5948,7 +6089,7 @@ ${
|
||||
// When we are in actions search mode we can show more results so
|
||||
// increase the limit.
|
||||
let maxResults =
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarShared.mjs b/browser/components/urlbar/content/UrlbarShared.mjs
|
||||
index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36119ae73e 100644
|
||||
index 0ac5330223c84fbb98880a5c2d83ae58a8f3079e..f9d3d27333f5552404bd8a1138fb1e5d6150a3d8 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarShared.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarShared.mjs
|
||||
@@ -100,6 +100,7 @@ export const UrlbarShared = {
|
||||
@@ -158,6 +158,7 @@ export const UrlbarShared = {
|
||||
// `looksLikeOrigin()` returned `LOOKS_LIKE_ORIGIN.OTHER` for this token.
|
||||
// It may or may not be an origin.
|
||||
POSSIBLE_ORIGIN_BUT_SEARCH_ALLOWED: 12,
|
||||
@@ -10,7 +10,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
}),
|
||||
|
||||
/**
|
||||
@@ -120,6 +121,7 @@ export const UrlbarShared = {
|
||||
@@ -178,6 +179,7 @@ export const UrlbarShared = {
|
||||
TITLE: "#",
|
||||
URL: "$",
|
||||
ACTION: ">",
|
||||
@@ -18,7 +18,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
}),
|
||||
|
||||
// Defines UrlbarResult types.
|
||||
@@ -165,6 +167,8 @@ export const UrlbarShared = {
|
||||
@@ -223,6 +225,8 @@ export const UrlbarShared = {
|
||||
OTHER_NETWORK: 6,
|
||||
ADDON: 7,
|
||||
ACTIONS: 8,
|
||||
@@ -27,7 +27,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
}),
|
||||
|
||||
// Results are categorized into groups to help the muxer compose them. See
|
||||
@@ -200,6 +204,8 @@ export const UrlbarShared = {
|
||||
@@ -258,6 +262,8 @@ export const UrlbarShared = {
|
||||
SEMANTIC_HISTORY: "semanticHistory",
|
||||
SUGGESTED_INDEX: "suggestedIndex",
|
||||
TAIL_SUGGESTION: "tailSuggestion",
|
||||
@@ -36,7 +36,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
}),
|
||||
|
||||
// Defines provider types.
|
||||
@@ -385,6 +391,14 @@ export const UrlbarShared = {
|
||||
@@ -443,6 +449,14 @@ export const UrlbarShared = {
|
||||
telemetryLabel: "actions",
|
||||
uiLabel: "urlbar-searchmode-actions3",
|
||||
},
|
||||
@@ -51,7 +51,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -402,6 +416,7 @@ export const UrlbarShared = {
|
||||
@@ -460,6 +474,7 @@ export const UrlbarShared = {
|
||||
if (UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
||||
keys.push(this.RESTRICT_TOKENS.ACTION);
|
||||
}
|
||||
@@ -59,3 +59,15 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
||||
return new Set(keys);
|
||||
},
|
||||
|
||||
@@ -1032,6 +1047,11 @@ export const UrlbarShared = {
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_FALLBACK;
|
||||
case "UrlbarProviderHistoryUrlHeuristic":
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
||||
+ case "ZenUrlbarProviderGlobalActions":
|
||||
+ if (result.source == UrlbarShared.RESULT_SOURCE.WORKSPACES) {
|
||||
+ return UrlbarShared.RESULT_GROUP.ZEN_WORKSPACE;
|
||||
+ }
|
||||
+ return UrlbarShared.RESULT_GROUP.ZEN_ACTION;
|
||||
case "UrlbarProviderOmnibox":
|
||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_OMNIBOX;
|
||||
case "UrlbarProviderRestrictKeywordsAutofill":
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
diff --git a/browser/modules/ExtensionsUI.sys.mjs b/browser/modules/ExtensionsUI.sys.mjs
|
||||
index 95a4b6e40bd568c3ea5003b648b0acbf96bbb725..6ab8a658721aa6470d482dc958e4b3ac78f49f44 100644
|
||||
index 73ef024602cb4554a024de4ddef83f492adc33ef..959c3403a48a3e4294ad5d2f72bad0e5d4fbfd75 100644
|
||||
--- a/browser/modules/ExtensionsUI.sys.mjs
|
||||
+++ b/browser/modules/ExtensionsUI.sys.mjs
|
||||
@@ -502,7 +502,7 @@ export var ExtensionsUI = {
|
||||
eventCallback,
|
||||
removeOnDismissal: true,
|
||||
@@ -507,7 +507,7 @@ export var ExtensionsUI = {
|
||||
// right after the panel opens can't accidentally grant permissions).
|
||||
autofocus: true,
|
||||
popupOptions: {
|
||||
- position: "bottomright topright",
|
||||
+ position: window.gZenUIManager.panelUIPosition(),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css
|
||||
index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc880775ff7 100644
|
||||
index 86400b643c8b2af4207d226fbd6d91e5e74548b9..3044e4ab87b7ebcfaa2ac624680da1cc5653c861 100644
|
||||
--- a/browser/themes/shared/tabbrowser/content-area.css
|
||||
+++ b/browser/themes/shared/tabbrowser/content-area.css
|
||||
@@ -239,7 +239,6 @@
|
||||
@@ -166,7 +166,6 @@
|
||||
min-width: 0;
|
||||
|
||||
/* We want to be able to show the frame color behind the clipped radiused corner */
|
||||
@@ -10,7 +10,7 @@ index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc8
|
||||
|
||||
display: grid;
|
||||
/**
|
||||
@@ -425,7 +424,6 @@
|
||||
@@ -355,7 +354,6 @@
|
||||
}
|
||||
|
||||
browser:is([blank], [pendingpaint]) {
|
||||
@@ -18,21 +18,21 @@ index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc8
|
||||
}
|
||||
|
||||
/* Exclude browsers with smartwindow-content attribute which inherit
|
||||
@@ -865,7 +863,7 @@ split-view-footer {
|
||||
@@ -735,7 +733,7 @@ split-view-footer {
|
||||
|
||||
.dialogStack {
|
||||
z-index: var(--browser-stack-z-index-dialog-stack);
|
||||
- position: absolute;
|
||||
+ position: fixed;
|
||||
inset: 0;
|
||||
|
||||
/* --browser-with-dialog set on browser[tabDialogShowing], we want to position the overlay
|
||||
only on the top of the <browser> element so it doesn't overlap the DevTools toolbox */
|
||||
@@ -1034,7 +1032,7 @@ split-view-footer {
|
||||
@@ -909,7 +907,7 @@ split-view-footer {
|
||||
|
||||
.dialogOverlay[topmost="true"],
|
||||
#window-modal-dialog::backdrop {
|
||||
- background-color: var(--background-color-overlay);
|
||||
+ background-color: light-dark(rgba(255, 255, 255, .3), rgba(0, 0, 0, .3));
|
||||
border-radius: var(--chrome-block-radius);
|
||||
}
|
||||
|
||||
.browserSidebarContainer.responsive-mode & {
|
||||
.dialogOverlay[hideContent="true"][topmost="true"] {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/themes/shared/toolbarbuttons.css b/browser/themes/shared/toolbarbuttons.css
|
||||
index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391fc5fcc79b 100644
|
||||
index bbf906c7bf1d6f0d71744953aeeb750c5181639a..dd116e22c38dc376c9c6b34dfa569bf4661a8971 100644
|
||||
--- a/browser/themes/shared/toolbarbuttons.css
|
||||
+++ b/browser/themes/shared/toolbarbuttons.css
|
||||
@@ -13,20 +13,6 @@
|
||||
@@ -23,7 +23,7 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
||||
&:where([uidensity="compact"]) {
|
||||
--toolbarbutton-padding-inner: var(--toolbarbutton-padding-inner-compact);
|
||||
--bookmark-block-padding: 1px;
|
||||
@@ -123,9 +109,7 @@
|
||||
@@ -119,9 +105,7 @@
|
||||
#TabsToolbar {
|
||||
/* Override the inner padding to ensure the dimensions match the tabs, but also making sure
|
||||
different types of buttons (combined-buttons-dropmarker or text) still look correct. */
|
||||
@@ -33,18 +33,16 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
||||
}
|
||||
|
||||
/* Primary toolbar buttons */
|
||||
@@ -205,8 +189,8 @@ toolbar .toolbarbutton-1 {
|
||||
@@ -174,7 +158,7 @@
|
||||
|
||||
> .toolbarbutton-icon {
|
||||
/* horizontal padding + actual icon width */
|
||||
- width: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
||||
- height: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
||||
+ width: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
||||
+ height: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
||||
}
|
||||
toolbar .toolbarbutton-1 {
|
||||
/* horizontal padding + actual icon width */
|
||||
- --toolbarbutton-icon-size: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
||||
+ --toolbarbutton-icon-size: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
||||
|
||||
> .toolbarbutton-text {
|
||||
@@ -216,7 +200,7 @@ toolbar .toolbarbutton-1 {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
@@ -214,7 +198,7 @@ toolbar .toolbarbutton-1 {
|
||||
* height as the button icons and the same vertical padding, but as a minimum,
|
||||
* because otherwise an increase in text sizes would break things.
|
||||
*/
|
||||
@@ -62,7 +60,7 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -536,7 +520,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) {
|
||||
@@ -427,7 +411,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) {
|
||||
*/
|
||||
align-items: stretch;
|
||||
> .toolbarbutton-icon {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css
|
||||
index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d2078419659065 100644
|
||||
--- a/browser/themes/shared/urlbar-searchbar.css
|
||||
+++ b/browser/themes/shared/urlbar-searchbar.css
|
||||
@@ -19,8 +19,8 @@
|
||||
diff --git a/browser/themes/shared/urlbar.css b/browser/themes/shared/urlbar.css
|
||||
index 06183c82e2869290a5fb476c47fb7db92bbef57f..c64cde1eef50d3457fb1c540d95fe3b8aa087294 100644
|
||||
--- a/browser/themes/shared/urlbar.css
|
||||
+++ b/browser/themes/shared/urlbar.css
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
@media not -moz-pref("browser.nova.enabled") {
|
||||
--urlbar-basic-component-size: calc(var(--urlbar-height) - 2 * (var(--urlbar-input-container-border-width) + var(--urlbar-input-container-padding)));
|
||||
@@ -13,7 +13,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
||||
}
|
||||
@media (max-width: 770px) {
|
||||
--urlbar-container-min-width: 240px;
|
||||
@@ -127,7 +127,7 @@ toolbar[inactive="true"] .urlbar,
|
||||
@@ -143,7 +143,7 @@ toolbar[inactive="true"] .urlbar,
|
||||
.urlbar:not([usertyping]) > .urlbar-input-container > .urlbar-go-button,
|
||||
.urlbar:not(#searchbar-new, [focused]) > .urlbar-input-container > .urlbar-go-button,
|
||||
#urlbar-revert-button-container {
|
||||
@@ -22,7 +22,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
||||
}
|
||||
|
||||
/* Document Picture-in-Picture API window */
|
||||
@@ -405,6 +405,10 @@ toolbar[inactive="true"] .urlbar,
|
||||
@@ -434,6 +434,10 @@ toolbar[inactive="true"] .urlbar,
|
||||
.urlbar:not([focused])[textoverflow="left"][domaindir="rtl"] > .urlbar-input-container > .urlbar-input-box > & {
|
||||
mask-image: linear-gradient(to right, transparent var(--urlbar-scheme-size), black calc(var(--urlbar-scheme-size) + 3ch));
|
||||
}
|
||||
@@ -33,7 +33,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
||||
}
|
||||
|
||||
#urlbar-scheme {
|
||||
@@ -476,10 +480,15 @@ toolbar[inactive="true"] .urlbar,
|
||||
@@ -505,10 +509,15 @@ toolbar[inactive="true"] .urlbar,
|
||||
}
|
||||
|
||||
.urlbar[breakout][breakout-extend] {
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/build/moz.configure/lto-pgo.configure b/build/moz.configure/lto-pgo.configure
|
||||
index df2b0bf0081edfdc2c7bccaefc780d2b0c6555ff..53a3b55de7650799e3730372e72ad7b4bb2eea03 100644
|
||||
index c72af5ed5f88fc80c810ef626e57a8b991dee514..53a3b55de7650799e3730372e72ad7b4bb2eea03 100644
|
||||
--- a/build/moz.configure/lto-pgo.configure
|
||||
+++ b/build/moz.configure/lto-pgo.configure
|
||||
@@ -234,6 +234,7 @@ def moz_pgo_rust(pgo, profile_use, profile_generate, c_compiler):
|
||||
@@ -14,7 +14,7 @@ index df2b0bf0081edfdc2c7bccaefc780d2b0c6555ff..53a3b55de7650799e3730372e72ad7b4
|
||||
help="Indicate that ld64 is free of symbol aliasing bugs",
|
||||
)
|
||||
|
||||
-imply_option("MOZ_LD64_KNOWN_GOOD", moz_automation)
|
||||
-imply_option("MOZ_LD64_KNOWN_GOOD", True, when=moz_automation)
|
||||
|
||||
use_fat_lto = cxx_compiler.try_link(
|
||||
ldflags=depends(stlport_libs)(
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
diff --git a/browser/components/sessionstore/test/browser.toml b/browser/components/sessionstore/test/browser.toml
|
||||
--- a/browser/components/sessionstore/test/browser.toml
|
||||
+++ b/browser/components/sessionstore/test/browser.toml
|
||||
@@ -14,10 +14,12 @@
|
||||
"browser_frame_history_c.html",
|
||||
"browser_frame_history_c1.html",
|
||||
"browser_frame_history_c2.html",
|
||||
"browser_formdata_format_sample.html",
|
||||
"browser_sessionHistory_slow.sjs",
|
||||
+ "browser_policy_container_sample.html",
|
||||
+ "browser_policy_container_sample_frame.html",
|
||||
"browser_scrollPositions_sample.html",
|
||||
"browser_scrollPositions_sample2.html",
|
||||
"browser_scrollPositions_sample_frameset.html",
|
||||
"browser_scrollPositions_readerModeArticle.html",
|
||||
"browser_sessionStorage.html",
|
||||
@@ -226,10 +228,12 @@
|
||||
["browser_pinned_tabs.js"]
|
||||
skip-if = [
|
||||
"ccov", # Bug 1625525
|
||||
]
|
||||
|
||||
+["browser_policy_container_not_stored.js"]
|
||||
+
|
||||
["browser_privatetabs.js"]
|
||||
|
||||
["browser_purge_domaindata.js"]
|
||||
|
||||
["browser_purge_shistory.js"]
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_not_stored.js b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
||||
@@ -0,0 +1,51 @@
|
||||
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
+
|
||||
+"use strict";
|
||||
+
|
||||
+/**
|
||||
+ * A session history entry only needs to retain the policy container for loads
|
||||
+ * that inherit their policies (about:blank, about:srcdoc, blob:, data:, ...).
|
||||
+ * Anything fetched over the network gets its policies from the response again,
|
||||
+ * so storing them would only bloat the session store (bug 2011236).
|
||||
+ */
|
||||
+
|
||||
+const TEST_ROOT = getRootDirectory(gTestPath).replace(
|
||||
+ "chrome://mochitests/content",
|
||||
+ "https://example.com"
|
||||
+);
|
||||
+const PARENT_URL = TEST_ROOT + "browser_policy_container_sample.html";
|
||||
+const FRAME_URL = TEST_ROOT + "browser_policy_container_sample_frame.html";
|
||||
+
|
||||
+add_task(async function test_policy_container_only_for_inheriting_loads() {
|
||||
+ const tab = BrowserTestUtils.addTab(gBrowser, PARENT_URL);
|
||||
+ gBrowser.selectedTab = tab;
|
||||
+ await promiseBrowserLoaded(tab.linkedBrowser, true, PARENT_URL);
|
||||
+ await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
+
|
||||
+ const state = JSON.parse(ss.getTabState(tab));
|
||||
+ const topEntry = state.entries.at(-1);
|
||||
+ is(topEntry.url, PARENT_URL, "collected the parent entry");
|
||||
+
|
||||
+ const children = topEntry.children ?? [];
|
||||
+ const networkFrame = children.find(child => child.url === FRAME_URL);
|
||||
+ const blankFrame = children.find(child => child.url === "about:blank");
|
||||
+
|
||||
+ ok(networkFrame, "collected the network-scheme subframe entry");
|
||||
+ ok(blankFrame, "collected the about:blank subframe entry");
|
||||
+
|
||||
+ // The parent has a CSP, so both subframes inherit a policy container onto
|
||||
+ // their load state. Only the one that cannot recover it from a response
|
||||
+ // should keep it in session history.
|
||||
+ ok(
|
||||
+ !("policyContainer" in networkFrame),
|
||||
+ "https subframe entry does not store a policyContainer"
|
||||
+ );
|
||||
+ ok(
|
||||
+ "policyContainer" in blankFrame,
|
||||
+ "about:blank subframe entry still stores its inherited policyContainer"
|
||||
+ );
|
||||
+
|
||||
+ await BrowserTestUtils.removeTab(tab);
|
||||
+});
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample.html b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
||||
@@ -0,0 +1,12 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+<head>
|
||||
+ <meta charset="utf-8">
|
||||
+ <meta http-equiv="Content-Security-Policy" content="default-src * data: blob: 'unsafe-inline'">
|
||||
+ <title>policyContainer session store sample</title>
|
||||
+</head>
|
||||
+<body>
|
||||
+ <iframe id="network" src="browser_policy_container_sample_frame.html"></iframe>
|
||||
+ <iframe id="blank" src="about:blank"></iframe>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample_frame.html b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
||||
@@ -0,0 +1,10 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+<head>
|
||||
+ <meta charset="utf-8">
|
||||
+ <title>policyContainer session store sample frame</title>
|
||||
+</head>
|
||||
+<body>
|
||||
+ frame
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp
|
||||
--- a/docshell/shistory/SessionHistoryEntry.cpp
|
||||
+++ b/docshell/shistory/SessionHistoryEntry.cpp
|
||||
@@ -41,10 +41,18 @@
|
||||
extern mozilla::LazyLogModule gSHLog;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
+// Only store policy container for loads that can't carry it themselves
|
||||
+// (about:blank, about:srcdoc, blob:, data:, ...)
|
||||
+// bug 1867137, bug 2011236
|
||||
+static nsIPolicyContainer* PolicyContainerToStore(
|
||||
+ nsIURI* aURI, nsIPolicyContainer* aPolicyContainer) {
|
||||
+ return CSP_ShouldURIInheritCSP(aURI) ? aPolicyContainer : nullptr;
|
||||
+}
|
||||
+
|
||||
SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
|
||||
nsIChannel* aChannel)
|
||||
: mURI(aLoadState->URI()),
|
||||
mOriginalURI(aLoadState->OriginalURI()),
|
||||
mResultPrincipalURI(aLoadState->ResultPrincipalURI()),
|
||||
@@ -59,11 +67,12 @@
|
||||
mLoadReplace(aLoadState->LoadReplace()),
|
||||
mHasUserActivation(aLoadState->HasValidUserGestureActivation()),
|
||||
mSharedState(SharedState::Create(
|
||||
aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
|
||||
aLoadState->PartitionedPrincipalToInherit(),
|
||||
- aLoadState->PolicyContainer(),
|
||||
+ PolicyContainerToStore(aLoadState->URI(),
|
||||
+ aLoadState->PolicyContainer()),
|
||||
/* FIXME Is this correct? */
|
||||
aLoadState->TypeHint())) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mURI->SchemeIs("javascript"));
|
||||
|
||||
// Pull the upload stream off of the channel instead of the load state, as
|
||||
@@ -124,11 +133,12 @@
|
||||
loadInfo->GetPrincipalToInherit(
|
||||
getter_AddRefs(mSharedState.Get()->mPrincipalToInherit));
|
||||
|
||||
mSharedState.Get()->mPartitionedPrincipalToInherit =
|
||||
aPartitionedPrincipalToInherit;
|
||||
- mSharedState.Get()->mPolicyContainer = aPolicyContainer;
|
||||
+ mSharedState.Get()->mPolicyContainer =
|
||||
+ PolicyContainerToStore(mURI, aPolicyContainer);
|
||||
aChannel->GetContentType(mSharedState.Get()->mContentType);
|
||||
aChannel->GetOriginalURI(getter_AddRefs(mOriginalURI));
|
||||
|
||||
uint32_t loadFlags;
|
||||
aChannel->GetLoadFlags(&loadFlags);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,558 +0,0 @@
|
||||
diff --git a/gfx/wr/webrender/res/ps_quad_mask.glsl b/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
--- a/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
+++ b/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
@@ -19,12 +19,14 @@
|
||||
// We pack 4 vec3 clip planes into 3 vec4 to save a varying slot.
|
||||
flat varying highp vec4 vClipPlane_A;
|
||||
flat varying highp vec4 vClipPlane_B;
|
||||
flat varying highp vec4 vClipPlane_C;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
flat varying highp vec4 vClipShape;
|
||||
flat varying highp vec4 vClipClampedInset;
|
||||
+#endif
|
||||
|
||||
#endif
|
||||
flat varying highp vec2 vClipMode;
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
@@ -40,12 +42,14 @@
|
||||
vec4 radii;
|
||||
#else
|
||||
vec4 radii_top;
|
||||
vec4 radii_bottom;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vec4 shape;
|
||||
vec4 inset;
|
||||
+#endif
|
||||
#endif
|
||||
float mode;
|
||||
int space;
|
||||
};
|
||||
|
||||
@@ -58,22 +62,29 @@
|
||||
vec4 texels[3] = fetch_from_gpu_buffer_3f(index);
|
||||
clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw);
|
||||
clip.radii = texels[1];
|
||||
clip.mode = texels[2].x;
|
||||
#else
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vec4 texels[6] = fetch_from_gpu_buffer_6f(index);
|
||||
+#else
|
||||
+ vec4 texels[4] = fetch_from_gpu_buffer_4f(index);
|
||||
+#endif
|
||||
clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw);
|
||||
clip.radii_top = texels[1];
|
||||
clip.radii_bottom = texels[2];
|
||||
clip.mode = texels[3].x;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
clip.shape = texels[4];
|
||||
clip.inset = texels[5];
|
||||
+#endif
|
||||
#endif
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vec4 precalc_corner(vec2 center, vec2 radii, vec2 inset, vec2 clip_sign, float k) {
|
||||
if (k == 1.0) {
|
||||
// round/ellipse corner, precalc the ellipse parameters
|
||||
return vec4(center, inverse_radii_squared(radii));
|
||||
} else {
|
||||
@@ -85,10 +96,11 @@
|
||||
radii = offset_radii.zw;
|
||||
}
|
||||
return vec4(center, inverse_radii(radii));
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
|
||||
void pattern_vertex(PrimitiveInfo prim_info) {
|
||||
|
||||
Clip clip = fetch_clip(aClipData.y);
|
||||
Transform clip_transform = fetch_transform(aClipData.x);
|
||||
@@ -121,10 +133,11 @@
|
||||
vec2 r_tl = clip.radii_top.xy;
|
||||
vec2 r_tr = clip.radii_top.zw;
|
||||
vec2 r_br = clip.radii_bottom.zw;
|
||||
vec2 r_bl = clip.radii_bottom.xy;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipCenter_Radius_TL = precalc_corner(clip.rect.p0 + r_tl,
|
||||
r_tl,
|
||||
clip.inset.wx,
|
||||
vec2(-1.0, -1.0),
|
||||
clip.shape.x);
|
||||
@@ -146,10 +159,25 @@
|
||||
clip.rect.p1.y - r_bl.y),
|
||||
r_bl,
|
||||
clip.inset.wz,
|
||||
vec2(-1.0, 1.0),
|
||||
clip.shape.w);
|
||||
+#else
|
||||
+ vClipCenter_Radius_TL = vec4(clip.rect.p0 + r_tl,
|
||||
+ inverse_radii_squared(r_tl));
|
||||
+
|
||||
+ vClipCenter_Radius_TR = vec4(clip.rect.p1.x - r_tr.x,
|
||||
+ clip.rect.p0.y + r_tr.y,
|
||||
+ inverse_radii_squared(r_tr));
|
||||
+
|
||||
+ vClipCenter_Radius_BR = vec4(clip.rect.p1 - r_br,
|
||||
+ inverse_radii_squared(r_br));
|
||||
+
|
||||
+ vClipCenter_Radius_BL = vec4(clip.rect.p0.x + r_bl.x,
|
||||
+ clip.rect.p1.y - r_bl.y,
|
||||
+ inverse_radii_squared(r_bl));
|
||||
+#endif
|
||||
|
||||
// We need to know the half-spaces of the corners separate from the center
|
||||
// and radius. We compute a point that falls on the diagonal (which is just
|
||||
// an inner vertex pushed out along one axis, but not on both) to get the
|
||||
// plane offset of the half-space. We also compute the direction vector of
|
||||
@@ -170,13 +198,15 @@
|
||||
|
||||
vClipPlane_A = vec4(tl.x, tl.y, tl.z, tr.x);
|
||||
vClipPlane_B = vec4(tr.y, tr.z, br.x, br.y);
|
||||
vClipPlane_C = vec4(br.z, bl.x, bl.y, bl.z);
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipShape = clip.shape;
|
||||
vClipClampedInset = min(clip.inset, 0.0);
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
@@ -205,11 +235,13 @@
|
||||
vec3 plane_tr = vec3(vClipPlane_A.w, vClipPlane_B.x, vClipPlane_B.y);
|
||||
vec3 plane_br = vec3(vClipPlane_B.z, vClipPlane_B.w, vClipPlane_C.x);
|
||||
vec3 plane_bl = vec3(vClipPlane_C.y, vClipPlane_C.z, vClipPlane_C.w);
|
||||
|
||||
float dist;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (vClipShape == vec4(1.0)) {
|
||||
+#endif
|
||||
dist = distance_to_rounded_rect(
|
||||
clip_local_pos,
|
||||
plane_tl,
|
||||
vClipCenter_Radius_TL,
|
||||
plane_tr,
|
||||
@@ -218,10 +250,11 @@
|
||||
vClipCenter_Radius_BR,
|
||||
plane_bl,
|
||||
vClipCenter_Radius_BL,
|
||||
vTransformBounds
|
||||
);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
dist = distance_to_shaped_rect(
|
||||
clip_local_pos,
|
||||
vClipCenter_Radius_TL,
|
||||
vClipCenter_Radius_TR,
|
||||
@@ -230,10 +263,11 @@
|
||||
vTransformBounds,
|
||||
vClipShape,
|
||||
vClipClampedInset
|
||||
);
|
||||
}
|
||||
+#endif
|
||||
#endif
|
||||
|
||||
// Compute AA for the given dist and range.
|
||||
float alpha = distance_aa(aa_range, dist);
|
||||
|
||||
@@ -340,13 +374,13 @@
|
||||
#define AA_RECT(local_pos) \
|
||||
sd_round_box(local_pos, v_clip_size, v_clip_radii)
|
||||
#else
|
||||
// The span fast path only handles elliptical corners. For superellipse
|
||||
// shapes, bail out and let SWGL fall back to the fragment shader.
|
||||
- if (vClipShape != vec4(1.0)) {
|
||||
+ #ifdef WR_FEATURE_SUPERELLIPSE
|
||||
return;
|
||||
- }
|
||||
+ #endif
|
||||
|
||||
// Unpack the corner half-spaces packed into vClipPlane_A/B/C.
|
||||
vec3 plane_tl = vec3(vClipPlane_A.x, vClipPlane_A.y, vClipPlane_A.z);
|
||||
vec3 plane_tr = vec3(vClipPlane_A.w, vClipPlane_B.x, vClipPlane_B.y);
|
||||
vec3 plane_br = vec3(vClipPlane_B.z, vClipPlane_B.w, vClipPlane_C.x);
|
||||
diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs
|
||||
--- a/gfx/wr/webrender/src/batch.rs
|
||||
+++ b/gfx/wr/webrender/src/batch.rs
|
||||
@@ -1224,25 +1224,29 @@
|
||||
/// A list of clip instances to be drawn into a target.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ClipMaskInstanceList {
|
||||
pub mask_instances_fast: FrameVec<MaskInstance>,
|
||||
+ pub mask_instances_superellipse: FrameVec<MaskInstance>,
|
||||
pub mask_instances_slow: FrameVec<MaskInstance>,
|
||||
|
||||
pub mask_instances_fast_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
|
||||
+ pub mask_instances_superellipse_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
|
||||
pub mask_instances_slow_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
|
||||
|
||||
pub image_mask_instances: FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>,
|
||||
pub image_mask_instances_with_scissor: FastHashMap<(DeviceIntRect, TextureSource), FrameVec<PrimitiveInstanceData>>,
|
||||
}
|
||||
|
||||
impl ClipMaskInstanceList {
|
||||
pub fn new(memory: &FrameMemory) -> Self {
|
||||
ClipMaskInstanceList {
|
||||
mask_instances_fast: memory.new_vec(),
|
||||
+ mask_instances_superellipse: memory.new_vec(),
|
||||
mask_instances_slow: memory.new_vec(),
|
||||
mask_instances_fast_with_scissor: FastHashMap::default(),
|
||||
+ mask_instances_superellipse_with_scissor: FastHashMap::default(),
|
||||
mask_instances_slow_with_scissor: FastHashMap::default(),
|
||||
image_mask_instances: FastHashMap::default(),
|
||||
image_mask_instances_with_scissor: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
@@ -1250,20 +1254,24 @@
|
||||
pub fn is_empty(&self) -> bool {
|
||||
// Destructure self to make sure we don't forget to update this method if
|
||||
// a new member is added.
|
||||
let ClipMaskInstanceList {
|
||||
mask_instances_fast,
|
||||
+ mask_instances_superellipse,
|
||||
mask_instances_slow,
|
||||
mask_instances_fast_with_scissor,
|
||||
+ mask_instances_superellipse_with_scissor,
|
||||
mask_instances_slow_with_scissor,
|
||||
image_mask_instances,
|
||||
image_mask_instances_with_scissor,
|
||||
} = self;
|
||||
|
||||
mask_instances_fast.is_empty()
|
||||
+ && mask_instances_superellipse.is_empty()
|
||||
&& mask_instances_slow.is_empty()
|
||||
&& mask_instances_fast_with_scissor.is_empty()
|
||||
+ && mask_instances_superellipse_with_scissor.is_empty()
|
||||
&& mask_instances_slow_with_scissor.is_empty()
|
||||
&& image_mask_instances.is_empty()
|
||||
&& image_mask_instances_with_scissor.is_empty()
|
||||
}
|
||||
}
|
||||
diff --git a/gfx/wr/webrender/src/quad.rs b/gfx/wr/webrender/src/quad.rs
|
||||
--- a/gfx/wr/webrender/src/quad.rs
|
||||
+++ b/gfx/wr/webrender/src/quad.rs
|
||||
@@ -1807,11 +1807,11 @@
|
||||
gpu_buffer: &mut GpuBufferBuilderF,
|
||||
clip_rect: LayoutRect,
|
||||
radius: &BorderRadius,
|
||||
inset: LayoutSideOffsets,
|
||||
mode: ClipMode,
|
||||
-) -> (GpuBufferAddress, bool) {
|
||||
+) -> (GpuBufferAddress, bool, bool) {
|
||||
let radius = clamped_radius(radius, clip_rect.size());
|
||||
|
||||
if radius.can_use_fast_path_in(&clip_rect) {
|
||||
let mut writer = gpu_buffer.write_blocks(3);
|
||||
writer.push_one(clip_rect);
|
||||
@@ -1821,13 +1821,15 @@
|
||||
radius.bottom_left.width,
|
||||
radius.top_left.width,
|
||||
]);
|
||||
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
|
||||
|
||||
- (writer.finish(), true)
|
||||
+ (writer.finish(), true, false)
|
||||
} else {
|
||||
- let mut writer = gpu_buffer.write_blocks(6);
|
||||
+ let superellipse = !radius.shapes_all_round();
|
||||
+ let block_count = if superellipse { 6 } else { 4 };
|
||||
+ let mut writer = gpu_buffer.write_blocks(block_count);
|
||||
writer.push_one(clip_rect);
|
||||
writer.push_one([
|
||||
radius.top_left.width,
|
||||
radius.top_left.height,
|
||||
radius.top_right.width,
|
||||
@@ -1838,19 +1840,21 @@
|
||||
radius.bottom_left.height,
|
||||
radius.bottom_right.width,
|
||||
radius.bottom_right.height,
|
||||
]);
|
||||
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
|
||||
- writer.push_one([
|
||||
- radius.shape_top_left,
|
||||
- radius.shape_top_right,
|
||||
- radius.shape_bottom_right,
|
||||
- radius.shape_bottom_left,
|
||||
- ]);
|
||||
- writer.push_one(inset);
|
||||
+ if superellipse {
|
||||
+ writer.push_one([
|
||||
+ radius.shape_top_left,
|
||||
+ radius.shape_top_right,
|
||||
+ radius.shape_bottom_right,
|
||||
+ radius.shape_bottom_left,
|
||||
+ ]);
|
||||
+ writer.push_one(inset);
|
||||
+ }
|
||||
|
||||
- (writer.finish(), false)
|
||||
+ (writer.finish(), false, superellipse)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_clip_task(
|
||||
clip_instance: &ClipNodeInstance,
|
||||
@@ -1865,11 +1869,11 @@
|
||||
gpu_buffer: &mut GpuBufferBuilderF,
|
||||
transforms: &mut TransformPalette,
|
||||
rg_builder: &mut RenderTaskGraphBuilder,
|
||||
sub_tasks: &mut SubTaskRange,
|
||||
) {
|
||||
- let (clip_address, fast_path) = match clip_item.kind {
|
||||
+ let (clip_address, fast_path, superellipse) = match clip_item.kind {
|
||||
ClipItemKind::RoundedRectangle { radius, inset, mode } => {
|
||||
write_rounded_rect_clip_blocks(
|
||||
gpu_buffer,
|
||||
clip_instance.clip_rect,
|
||||
&radius,
|
||||
@@ -1882,11 +1886,11 @@
|
||||
writer.push_one(clip_instance.clip_rect);
|
||||
writer.push_one([0.0, 0.0, 0.0, 0.0]);
|
||||
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
|
||||
let clip_address = writer.finish();
|
||||
|
||||
- (clip_address, true)
|
||||
+ (clip_address, true, false)
|
||||
}
|
||||
ClipItemKind::Image { .. } => {
|
||||
let transform_id = transforms.gpu.get_id_with_post_scale(
|
||||
clip_instance.spatial_node_index,
|
||||
raster_spatial_node_index,
|
||||
@@ -2033,10 +2037,11 @@
|
||||
clip_transform_id,
|
||||
quad_flags,
|
||||
clip_space,
|
||||
needs_scissor_rect,
|
||||
rounded_rect_fast_path: fast_path,
|
||||
+ rounded_rect_superellipse: superellipse,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn create_quad_primitive(
|
||||
diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs
|
||||
--- a/gfx/wr/webrender/src/render_target.rs
|
||||
+++ b/gfx/wr/webrender/src/render_target.rs
|
||||
@@ -441,11 +441,11 @@
|
||||
// so the target must be initialized to one.
|
||||
self.clears.push((target_rect, ColorF::WHITE));
|
||||
|
||||
let device_rect = DeviceRect::from_size(target_rect.size().to_f32());
|
||||
|
||||
- let (clip_address, fast_path) = quad::write_rounded_rect_clip_blocks(
|
||||
+ let (clip_address, fast_path, superellipse) = quad::write_rounded_rect_clip_blocks(
|
||||
&mut gpu_buffer_builder.f32,
|
||||
region_task.clip_rect,
|
||||
®ion_task.radius,
|
||||
region_task.inset,
|
||||
region_task.mode,
|
||||
@@ -495,10 +495,12 @@
|
||||
unused: 0,
|
||||
};
|
||||
|
||||
if fast_path {
|
||||
self.clip_masks.mask_instances_fast.push(instance);
|
||||
+ } else if superellipse {
|
||||
+ self.clip_masks.mask_instances_superellipse.push(instance);
|
||||
} else {
|
||||
self.clip_masks.mask_instances_slow.push(instance);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -925,19 +927,26 @@
|
||||
if task.rounded_rect_fast_path {
|
||||
results.mask_instances_fast_with_scissor
|
||||
.entry(*target_rect)
|
||||
.or_insert_with(|| memory.new_vec())
|
||||
.push(instance);
|
||||
+ } else if task.rounded_rect_superellipse {
|
||||
+ results.mask_instances_superellipse_with_scissor
|
||||
+ .entry(*target_rect)
|
||||
+ .or_insert_with(|| memory.new_vec())
|
||||
+ .push(instance);
|
||||
} else {
|
||||
results.mask_instances_slow_with_scissor
|
||||
.entry(*target_rect)
|
||||
.or_insert_with(|| memory.new_vec())
|
||||
.push(instance);
|
||||
}
|
||||
} else {
|
||||
if task.rounded_rect_fast_path {
|
||||
results.mask_instances_fast.push(instance);
|
||||
+ } else if task.rounded_rect_superellipse {
|
||||
+ results.mask_instances_superellipse.push(instance);
|
||||
} else {
|
||||
results.mask_instances_slow.push(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/gfx/wr/webrender/src/render_task.rs b/gfx/wr/webrender/src/render_task.rs
|
||||
--- a/gfx/wr/webrender/src/render_task.rs
|
||||
+++ b/gfx/wr/webrender/src/render_task.rs
|
||||
@@ -2240,10 +2240,11 @@
|
||||
/// Transform from the quad primitive's space to the clip's local space.
|
||||
pub clip_transform_id: GpuTransformId,
|
||||
pub quad_flags: QuadFlags,
|
||||
pub needs_scissor_rect: bool,
|
||||
pub rounded_rect_fast_path: bool,
|
||||
+ pub rounded_rect_superellipse: bool,
|
||||
}
|
||||
|
||||
/// An clip applied to a render task using the multiply blend mode on top of
|
||||
/// the content being clipped.
|
||||
#[derive(Debug)]
|
||||
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/mod.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
@@ -2450,10 +2450,54 @@
|
||||
}
|
||||
|
||||
self.device.disable_scissor();
|
||||
}
|
||||
|
||||
+ if !masks.mask_instances_superellipse.is_empty() {
|
||||
+ self.shaders.borrow_mut().ps_mask_superellipse().bind(
|
||||
+ &mut self.device,
|
||||
+ projection,
|
||||
+ None,
|
||||
+ &mut self.renderer_errors,
|
||||
+ &mut self.profile,
|
||||
+ &mut self.command_log,
|
||||
+ );
|
||||
+
|
||||
+ self.draw_instanced_batch(
|
||||
+ &masks.mask_instances_superellipse,
|
||||
+ VertexArrayKind::Mask,
|
||||
+ &BatchTextures::empty(),
|
||||
+ stats,
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ if !masks.mask_instances_superellipse_with_scissor.is_empty() {
|
||||
+ self.shaders.borrow_mut().ps_mask_superellipse().bind(
|
||||
+ &mut self.device,
|
||||
+ projection,
|
||||
+ None,
|
||||
+ &mut self.renderer_errors,
|
||||
+ &mut self.profile,
|
||||
+ &mut self.command_log,
|
||||
+ );
|
||||
+
|
||||
+ self.device.enable_scissor();
|
||||
+
|
||||
+ for (scissor_rect, instances) in &masks.mask_instances_superellipse_with_scissor {
|
||||
+ self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
|
||||
+
|
||||
+ self.draw_instanced_batch(
|
||||
+ instances,
|
||||
+ VertexArrayKind::Mask,
|
||||
+ &BatchTextures::empty(),
|
||||
+ stats,
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ self.device.disable_scissor();
|
||||
+ }
|
||||
+
|
||||
if !masks.image_mask_instances.is_empty() {
|
||||
self.shaders.borrow_mut().ps_quad_textured().bind(
|
||||
&mut self.device,
|
||||
projection,
|
||||
None,
|
||||
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/shade.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
@@ -65,10 +65,11 @@
|
||||
];
|
||||
|
||||
const DITHERING_FEATURE: &str = "DITHERING";
|
||||
const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
|
||||
const FAST_PATH_FEATURE: &str = "FAST_PATH";
|
||||
+const SUPERELLIPSE_FEATURE: &str = "SUPERELLIPSE";
|
||||
|
||||
pub(crate) enum ShaderKind {
|
||||
Primitive,
|
||||
Cache(VertexArrayKind),
|
||||
Text,
|
||||
@@ -449,10 +450,11 @@
|
||||
ps_quad_backdrop: ShaderHandle,
|
||||
ps_quad_blend: ShaderHandle,
|
||||
ps_quad_mix_blend: ShaderHandle,
|
||||
ps_mask: ShaderHandle,
|
||||
ps_mask_fast: ShaderHandle,
|
||||
+ ps_mask_superellipse: ShaderHandle,
|
||||
ps_clear: ShaderHandle,
|
||||
ps_copy: ShaderHandle,
|
||||
|
||||
composite: CompositorShaders,
|
||||
}
|
||||
@@ -514,10 +516,17 @@
|
||||
"ps_quad_mask",
|
||||
&[FAST_PATH_FEATURE],
|
||||
&shader_list,
|
||||
)?;
|
||||
|
||||
+ let ps_mask_superellipse = loader.create_shader(
|
||||
+ ShaderKind::Cache(VertexArrayKind::Mask),
|
||||
+ "ps_quad_mask",
|
||||
+ &[SUPERELLIPSE_FEATURE],
|
||||
+ &shader_list,
|
||||
+ )?;
|
||||
+
|
||||
let mut cs_scale = Vec::new();
|
||||
let scale_shader_num = IMAGE_BUFFER_KINDS.len();
|
||||
// PrimitiveShader is not clonable. Use push() to initialize the vec.
|
||||
for _ in 0 .. scale_shader_num {
|
||||
cs_scale.push(None);
|
||||
@@ -786,10 +795,11 @@
|
||||
ps_quad_backdrop,
|
||||
ps_quad_blend,
|
||||
ps_quad_mix_blend,
|
||||
ps_mask,
|
||||
ps_mask_fast,
|
||||
+ ps_mask_superellipse,
|
||||
ps_split_composite,
|
||||
ps_clear,
|
||||
ps_copy,
|
||||
composite,
|
||||
})
|
||||
@@ -963,10 +973,11 @@
|
||||
pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader {
|
||||
self.loader.get(self.ps_quad_textured)
|
||||
}
|
||||
pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) }
|
||||
pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) }
|
||||
+ pub fn ps_mask_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_superellipse) }
|
||||
pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) }
|
||||
pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) }
|
||||
|
||||
pub fn deinit(self, device: &mut Device) {
|
||||
self.loader.deinit(device);
|
||||
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
--- a/gfx/wr/webrender_build/src/shader_features.rs
|
||||
+++ b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
@@ -65,11 +65,11 @@
|
||||
let mut shaders = ShaderFeatures::new();
|
||||
|
||||
// Cache shaders
|
||||
shaders.insert("cs_blur", vec!["ALPHA_TARGET".to_string(), "COLOR_TARGET".to_string()]);
|
||||
|
||||
- shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string()]);
|
||||
+ shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string(), "SUPERELLIPSE".to_string()]);
|
||||
|
||||
for name in &[
|
||||
"cs_line_decoration",
|
||||
"cs_border_segment",
|
||||
"cs_border_solid",
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
diff --git a/gfx/wr/webrender/res/ps_quad_box_shadow.glsl b/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
|
||||
--- a/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
|
||||
+++ b/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
|
||||
@@ -49,22 +49,26 @@
|
||||
flat varying highp vec4 vElemCenter_Radius_TL;
|
||||
flat varying highp vec4 vElemCenter_Radius_TR;
|
||||
flat varying highp vec4 vElemCenter_Radius_BR;
|
||||
flat varying highp vec4 vElemCenter_Radius_BL;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
flat varying highp vec4 vElemShape;
|
||||
+#endif
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
void pattern_vertex(PrimitiveInfo info) {
|
||||
vec4 data0 = fetch_from_gpu_buffer_1f(info.pattern_input.x);
|
||||
vec4 data1 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 1);
|
||||
vec4 data2 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 2);
|
||||
vec4 data3 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 3);
|
||||
vec4 data4 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 4);
|
||||
vec4 data5 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 5);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vec4 data6 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 6);
|
||||
+#endif
|
||||
|
||||
vec2 alloc_size = data0.xy;
|
||||
vec2 dest_rect_size = data0.zw;
|
||||
vec2 dest_rect_off = data1.xy;
|
||||
v_uv_scale_inset = vec4(vec2(1.0) / alloc_size, data1.z, 0.0);
|
||||
@@ -84,11 +88,11 @@
|
||||
// Map nine-patch UV=1.0 to the true content edge (uv_p0 + content_device_size)
|
||||
// rather than the rounded atlas entry edge (info.segment.uv_rect.p1). The atlas
|
||||
// allocation is rounded up from content_device_size, so this edge always lies
|
||||
// inside the entry; using it keeps the mapping stable to sub-texel precision as
|
||||
// the blur animates (bug 2002194).
|
||||
- vec2 content_device_size = data6.xy;
|
||||
+ vec2 content_device_size = data5.xy;
|
||||
vec2 texture_size = vec2(TEX_SIZE(sColor0));
|
||||
vec2 uv_p0 = info.segment.uv_rect.p0;
|
||||
vec2 uv_p1 = uv_p0 + content_device_size;
|
||||
v_uv_rect = vec4(uv_p0, uv_p1) / texture_size.xyxy;
|
||||
v_uv_bounds = vec4(
|
||||
@@ -110,11 +114,13 @@
|
||||
vElemCenter_Radius_TL = vec4(elem_p0 + r_tl, r_tl);
|
||||
vElemCenter_Radius_TR = vec4(elem_p1.x - r_tr.x, elem_p0.y + r_tr.y, r_tr);
|
||||
vElemCenter_Radius_BR = vec4(elem_p1 - r_br, r_br);
|
||||
vElemCenter_Radius_BL = vec4(elem_p0.x + r_bl.x, elem_p1.y - r_bl.y, r_bl);
|
||||
|
||||
- vElemShape = data5;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
+ vElemShape = data6;
|
||||
+#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
@@ -170,22 +176,24 @@
|
||||
vec3 elem_plane_bl = vec3(n_bl, dot(n_bl, vec2(c_bl.x, c_bl.y + r_bl.y)));
|
||||
|
||||
// Reconstruct the element rect bounds from the TL and BR corner data.
|
||||
vec4 elem_bounds = vec4(c_tl - r_tl, c_br + r_br);
|
||||
|
||||
- vec4 elem_shape = vElemShape;
|
||||
-
|
||||
float elem_dist;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
+ vec4 elem_shape = vElemShape;
|
||||
if (elem_shape == vec4(1.0)) {
|
||||
+#endif
|
||||
elem_dist = distance_to_rounded_rect(
|
||||
local_pos,
|
||||
elem_plane_tl, vec4(c_tl, inverse_radii_squared(r_tl)),
|
||||
elem_plane_tr, vec4(c_tr, inverse_radii_squared(r_tr)),
|
||||
elem_plane_br, vec4(c_br, inverse_radii_squared(r_br)),
|
||||
elem_plane_bl, vec4(c_bl, inverse_radii_squared(r_bl)),
|
||||
elem_bounds
|
||||
);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
elem_dist = distance_to_shaped_rect(
|
||||
local_pos,
|
||||
vec4(c_tl, elem_shape.x == 1.0 ? inverse_radii_squared(r_tl) : inverse_radii(r_tl)),
|
||||
vec4(c_tr, elem_shape.y == 1.0 ? inverse_radii_squared(r_tr) : inverse_radii(r_tr)),
|
||||
@@ -194,10 +202,11 @@
|
||||
elem_bounds,
|
||||
elem_shape,
|
||||
vec4(0.0)
|
||||
);
|
||||
}
|
||||
+#endif
|
||||
|
||||
// Outset (inset=0): dist < 0 = inside element → should be clipped out → use -elem_dist.
|
||||
// Inset (inset=1): dist < 0 = inside element → should be kept → use elem_dist.
|
||||
float element_clip = distance_aa(aa_range, mix(-elem_dist, elem_dist, inset));
|
||||
|
||||
diff --git a/gfx/wr/webrender/src/pattern/box_shadow.rs b/gfx/wr/webrender/src/pattern/box_shadow.rs
|
||||
--- a/gfx/wr/webrender/src/pattern/box_shadow.rs
|
||||
+++ b/gfx/wr/webrender/src/pattern/box_shadow.rs
|
||||
@@ -41,11 +41,14 @@
|
||||
_sub_rect: Option<DeviceRect>,
|
||||
_offset: LayoutVector2D,
|
||||
_ctx: &PatternBuilderContext,
|
||||
state: &mut PatternBuilderState,
|
||||
) -> Pattern {
|
||||
- let mut writer = state.frame_gpu_data.f32.write_blocks(7);
|
||||
+ let superellipse = !self.element_radius.shapes_all_round();
|
||||
+
|
||||
+ let block_count = if superellipse { 7 } else { 6 };
|
||||
+ let mut writer = state.frame_gpu_data.f32.write_blocks(block_count);
|
||||
writer.push_one([
|
||||
self.shadow_rect_alloc_size.width,
|
||||
self.shadow_rect_alloc_size.height,
|
||||
self.dest_rect_size.width,
|
||||
self.dest_rect_size.height,
|
||||
@@ -72,26 +75,28 @@
|
||||
self.element_radius.bottom_right.width,
|
||||
self.element_radius.bottom_right.height,
|
||||
self.element_radius.bottom_left.width,
|
||||
self.element_radius.bottom_left.height,
|
||||
]);
|
||||
- writer.push_one([
|
||||
- self.element_radius.shape_top_left,
|
||||
- self.element_radius.shape_top_right,
|
||||
- self.element_radius.shape_bottom_right,
|
||||
- self.element_radius.shape_bottom_left,
|
||||
- ]);
|
||||
writer.push_one([
|
||||
self.content_device_size.width,
|
||||
self.content_device_size.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
+ if superellipse {
|
||||
+ writer.push_one([
|
||||
+ self.element_radius.shape_top_left,
|
||||
+ self.element_radius.shape_top_right,
|
||||
+ self.element_radius.shape_bottom_right,
|
||||
+ self.element_radius.shape_bottom_left,
|
||||
+ ]);
|
||||
+ }
|
||||
let addr = writer.finish();
|
||||
|
||||
Pattern {
|
||||
- kind: PatternKind::BoxShadow,
|
||||
+ kind: if superellipse { PatternKind::BoxShadowSuperellipse } else { PatternKind::BoxShadow },
|
||||
shader_input: PatternShaderInput(addr.as_int(), 0),
|
||||
texture_input: PatternTextureInput::new(self.render_task),
|
||||
base_color: self.color,
|
||||
is_opaque: false,
|
||||
blend_mode: BlendMode::PremultipliedAlpha,
|
||||
diff --git a/gfx/wr/webrender/src/pattern/mod.rs b/gfx/wr/webrender/src/pattern/mod.rs
|
||||
--- a/gfx/wr/webrender/src/pattern/mod.rs
|
||||
+++ b/gfx/wr/webrender/src/pattern/mod.rs
|
||||
@@ -29,36 +29,37 @@
|
||||
Gradient = 1,
|
||||
Repeat = 2,
|
||||
|
||||
Mask = 3,
|
||||
BoxShadow = 4,
|
||||
+ BoxShadowSuperellipse = 5,
|
||||
// Variants of ColorOrTexture that use a non-default sampler type
|
||||
// (samplerExternalOES / __samplerExternal2DY2YEXT / sampler2DRect). The
|
||||
// quad shader is compiled in matching per-kind variants; see
|
||||
// ps_quad_textured.glsl.
|
||||
- TextureExternal = 5,
|
||||
- TextureExternalBT709 = 6,
|
||||
- TextureRect = 7,
|
||||
+ TextureExternal = 6,
|
||||
+ TextureExternalBT709 = 7,
|
||||
+ TextureRect = 8,
|
||||
// Samples up to three planes (sColor0/1/2) and converts from YUV to RGB.
|
||||
// Like ColorOrTexture, the YUV pattern comes in sampler-type-specific
|
||||
// variants so that the planes are sampled with the matching sColor
|
||||
// declaration; see ps_quad_yuv.glsl. `Yuv` is the default (TEXTURE_2D).
|
||||
- Yuv = 8,
|
||||
- YuvTextureExternal = 9,
|
||||
- YuvTextureExternalBT709 = 10,
|
||||
- YuvTextureRect = 11,
|
||||
+ Yuv = 9,
|
||||
+ YuvTextureExternal = 10,
|
||||
+ YuvTextureExternalBT709 = 11,
|
||||
+ YuvTextureRect = 12,
|
||||
// Samples a captured backdrop texture using a (bilerp) 4-corner uv quad.
|
||||
- Backdrop = 12,
|
||||
+ Backdrop = 13,
|
||||
// Applies a filter to a sampled source texture; see ps_quad_blend.glsl.
|
||||
- Blend = 13,
|
||||
+ Blend = 14,
|
||||
// Composites a picture over its backdrop with a software mix-blend-mode;
|
||||
// samples two textures (backdrop + source). See ps_quad_mix_blend.glsl.
|
||||
- MixBlend = 14,
|
||||
+ MixBlend = 15,
|
||||
// When adding patterns, don't forget to update the NUM_PATTERNS constant.
|
||||
}
|
||||
|
||||
-pub const NUM_PATTERNS: u32 = 15;
|
||||
+pub const NUM_PATTERNS: u32 = 16;
|
||||
|
||||
impl PatternKind {
|
||||
pub fn from_u32(val: u32) -> Self {
|
||||
assert!(val < NUM_PATTERNS);
|
||||
unsafe { std::mem::transmute(val) }
|
||||
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/mod.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
@@ -251,10 +251,11 @@
|
||||
BatchKind::Quad(PatternKind::TextureExternalBT709) => GPU_TAG_PRIMITIVE,
|
||||
BatchKind::Quad(PatternKind::TextureRect) => GPU_TAG_PRIMITIVE,
|
||||
BatchKind::Quad(PatternKind::Gradient) => GPU_TAG_GRADIENT,
|
||||
BatchKind::Quad(PatternKind::Repeat) => GPU_TAG_REPEAT,
|
||||
BatchKind::Quad(PatternKind::BoxShadow) => GPU_TAG_PRIMITIVE,
|
||||
+ BatchKind::Quad(PatternKind::BoxShadowSuperellipse) => GPU_TAG_PRIMITIVE,
|
||||
BatchKind::Quad(PatternKind::Yuv) => GPU_TAG_BRUSH_YUV_IMAGE,
|
||||
BatchKind::Quad(PatternKind::YuvTextureExternal) => GPU_TAG_BRUSH_YUV_IMAGE,
|
||||
BatchKind::Quad(PatternKind::YuvTextureExternalBT709) => GPU_TAG_BRUSH_YUV_IMAGE,
|
||||
BatchKind::Quad(PatternKind::YuvTextureRect) => GPU_TAG_BRUSH_YUV_IMAGE,
|
||||
BatchKind::Quad(PatternKind::Backdrop) => GPU_TAG_PRIMITIVE,
|
||||
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/shade.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
@@ -438,10 +438,11 @@
|
||||
ps_quad_textured_external_bt709: Option<ShaderHandle>,
|
||||
ps_quad_textured_rect: Option<ShaderHandle>,
|
||||
ps_quad_repeat: ShaderHandle,
|
||||
ps_quad_gradient: ShaderHandle,
|
||||
ps_quad_box_shadow: ShaderHandle,
|
||||
+ ps_quad_box_shadow_superellipse: ShaderHandle,
|
||||
// ps_quad_yuv, like ps_quad_textured, comes in sampler-type-specific
|
||||
// variants so the YUV planes are sampled with the matching sColor
|
||||
// declaration. The variant is selected via PatternKind.
|
||||
ps_quad_yuv: ShaderHandle,
|
||||
ps_quad_yuv_external: Option<ShaderHandle>,
|
||||
@@ -651,10 +652,17 @@
|
||||
"ps_quad_box_shadow",
|
||||
&[],
|
||||
&shader_list,
|
||||
)?;
|
||||
|
||||
+ let ps_quad_box_shadow_superellipse = loader.create_shader(
|
||||
+ ShaderKind::Primitive,
|
||||
+ "ps_quad_box_shadow",
|
||||
+ &[SUPERELLIPSE_FEATURE],
|
||||
+ &shader_list,
|
||||
+ )?;
|
||||
+
|
||||
let ps_quad_yuv = loader.create_shader(
|
||||
ShaderKind::Primitive,
|
||||
"ps_quad_yuv",
|
||||
&["TEXTURE_2D"],
|
||||
&shader_list,
|
||||
@@ -786,10 +794,11 @@
|
||||
ps_quad_textured_external_bt709,
|
||||
ps_quad_textured_rect,
|
||||
ps_quad_repeat,
|
||||
ps_quad_gradient,
|
||||
ps_quad_box_shadow,
|
||||
+ ps_quad_box_shadow_superellipse,
|
||||
ps_quad_yuv,
|
||||
ps_quad_yuv_external,
|
||||
ps_quad_yuv_external_bt709,
|
||||
ps_quad_yuv_rect,
|
||||
ps_quad_backdrop,
|
||||
@@ -867,10 +876,11 @@
|
||||
PatternKind::TextureRect => self.ps_quad_textured_rect
|
||||
.expect("bug: ps_quad_textured TEXTURE_RECT variant not loaded"),
|
||||
PatternKind::Gradient => self.ps_quad_gradient,
|
||||
PatternKind::Repeat => self.ps_quad_repeat,
|
||||
PatternKind::BoxShadow => self.ps_quad_box_shadow,
|
||||
+ PatternKind::BoxShadowSuperellipse => self.ps_quad_box_shadow_superellipse,
|
||||
PatternKind::Yuv => self.ps_quad_yuv,
|
||||
PatternKind::YuvTextureExternal => self.ps_quad_yuv_external
|
||||
.expect("bug: ps_quad_yuv TEXTURE_EXTERNAL variant not loaded"),
|
||||
PatternKind::YuvTextureExternalBT709 => self.ps_quad_yuv_external_bt709
|
||||
.expect("bug: ps_quad_yuv TEXTURE_EXTERNAL_BT709 variant not loaded"),
|
||||
@@ -923,10 +933,13 @@
|
||||
self.ps_quad_repeat
|
||||
}
|
||||
BatchKind::Quad(PatternKind::BoxShadow) => {
|
||||
self.ps_quad_box_shadow
|
||||
}
|
||||
+ BatchKind::Quad(PatternKind::BoxShadowSuperellipse) => {
|
||||
+ self.ps_quad_box_shadow_superellipse
|
||||
+ }
|
||||
BatchKind::Quad(PatternKind::Yuv) => {
|
||||
self.ps_quad_yuv
|
||||
}
|
||||
BatchKind::Quad(PatternKind::YuvTextureExternal) => {
|
||||
self.ps_quad_yuv_external
|
||||
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
--- a/gfx/wr/webrender_build/src/shader_features.rs
|
||||
+++ b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
@@ -166,11 +166,11 @@
|
||||
}
|
||||
shaders.insert("ps_quad_textured", ps_quad_textured_features);
|
||||
|
||||
shaders.insert("ps_quad_repeat", vec![base_prim_features.finish()]);
|
||||
|
||||
- shaders.insert("ps_quad_box_shadow", vec![base_prim_features.finish()]);
|
||||
+ shaders.insert("ps_quad_box_shadow", vec![base_prim_features.finish(), "SUPERELLIPSE".to_string()]);
|
||||
|
||||
// Like ps_quad_textured, ps_quad_yuv needs per-texture-kind variants so that
|
||||
// the YUV planes are sampled with the correct sampler type.
|
||||
let mut ps_quad_yuv_features: Vec<String> = vec!["TEXTURE_2D".to_string()];
|
||||
if flags.contains(ShaderFeatureFlags::GL) {
|
||||
|
||||
@@ -1,560 +0,0 @@
|
||||
diff --git a/gfx/wr/webrender/res/border_shared.glsl b/gfx/wr/webrender/res/border_shared.glsl
|
||||
--- a/gfx/wr/webrender/res/border_shared.glsl
|
||||
+++ b/gfx/wr/webrender/res/border_shared.glsl
|
||||
@@ -27,25 +27,33 @@
|
||||
vec4 rect;
|
||||
vec4 color0;
|
||||
vec4 color1;
|
||||
vec2 widths;
|
||||
vec2 radii;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
float shape;
|
||||
vec2 shape_offset;
|
||||
vec2 inset;
|
||||
+#endif
|
||||
};
|
||||
|
||||
BorderInstanceGpuData fetch_gpu_data(int index) {
|
||||
BorderInstanceGpuData data;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vec4 texels[6] = fetch_from_gpu_buffer_6f(index);
|
||||
+#else
|
||||
+ vec4 texels[4] = fetch_from_gpu_buffer_4f(index);
|
||||
+#endif
|
||||
data.rect = texels[0];
|
||||
data.color0 = texels[1];
|
||||
data.color1 = texels[2];
|
||||
data.widths = texels[3].xy;
|
||||
data.radii = texels[3].zw;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
data.shape = texels[4].x;
|
||||
data.shape_offset = texels[4].yz;
|
||||
data.inset = texels[5].xy;
|
||||
+#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
diff --git a/gfx/wr/webrender/res/cs_border_segment.glsl b/gfx/wr/webrender/res/cs_border_segment.glsl
|
||||
--- a/gfx/wr/webrender/res/cs_border_segment.glsl
|
||||
+++ b/gfx/wr/webrender/res/cs_border_segment.glsl
|
||||
@@ -30,11 +30,13 @@
|
||||
flat varying highp vec4 vClipCenter_Sign;
|
||||
|
||||
// An outer and inner elliptical radii for border
|
||||
// corner clipping.
|
||||
flat varying highp vec4 vClipRadii;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
flat varying highp vec4 vClipOffsets;
|
||||
+#endif
|
||||
|
||||
// Reference point for determine edge clip lines.
|
||||
flat varying highp vec4 vEdgeReference;
|
||||
|
||||
// Stores widths/2 and widths/3 to save doing this in FS.
|
||||
@@ -192,26 +194,34 @@
|
||||
vColor00 = color0[0];
|
||||
vColor01 = color0[1];
|
||||
vec4[2] color1 = get_colors_for_side(data.color1, style1);
|
||||
vColor10 = color1[0];
|
||||
vColor11 = color1[1];
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipCenter_Sign = vec4(outer + clip_sign * (data.radii + data.shape_offset), clip_sign);
|
||||
+#else
|
||||
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
|
||||
+#endif
|
||||
vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipOffsets = vec4(0.0);
|
||||
+#endif
|
||||
vColorLine = vec4(outer, data.widths.y * -clip_sign.y, data.widths.x * clip_sign.x);
|
||||
vEdgeReference = vec4(edge_reference, edge_reference + data.widths);
|
||||
vClipParams1 = aClipParams1;
|
||||
vClipParams2 = aClipParams2;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape != 1.0)
|
||||
{
|
||||
vec2 reference_radii = (data.radii == vec2(0.0)) ? vec2(0.0) : data.radii + data.inset;
|
||||
vec4 contour1 = compute_contoured_superellipse(reference_radii, data.shape, data.inset);
|
||||
vec4 contour2 = compute_contoured_superellipse(reference_radii, data.shape, data.inset + data.widths);
|
||||
vClipOffsets = vec4(contour1.xy, contour2.xy);
|
||||
vClipRadii = vec4(contour1.zw, contour2.zw);
|
||||
}
|
||||
+#endif
|
||||
|
||||
// For the case of dot and dash clips, optimize the number of pixels that
|
||||
// are hit to just include the dot itself.
|
||||
if (clip_mode == CLIP_DOT) {
|
||||
float radius = aClipParams1.z;
|
||||
@@ -258,19 +268,22 @@
|
||||
// also 0.67 of the radii. Use these to form a
|
||||
// SDF subtraction which will clip out the inside
|
||||
// third of the rounded edge.
|
||||
float d_radii_a;
|
||||
float d_radii_b;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape == 1.0) {
|
||||
+#endif
|
||||
d_radii_a = distance_to_ellipse(
|
||||
clip_relative_pos,
|
||||
clip_radii.xy - vPartialWidths.xy
|
||||
);
|
||||
d_radii_b = distance_to_ellipse(
|
||||
clip_relative_pos,
|
||||
clip_radii.xy - 2.0 * vPartialWidths.xy
|
||||
);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
d_radii_a = distance_to_superellipse(
|
||||
clip_relative_pos - mix(vClipOffsets.xy, vClipOffsets.zw, 1.0 / 3.0),
|
||||
mix(clip_radii.xy, clip_radii.zw, 1.0 / 3.0),
|
||||
data.shape
|
||||
@@ -286,24 +299,28 @@
|
||||
d_radii_a = max(d_radii_a, -min(included_region_a.x, included_region_a.y));
|
||||
|
||||
vec2 included_region_b = data.radii - 2.0 * vPartialWidths.xy - clip_relative_pos;
|
||||
d_radii_b = max(d_radii_b, -min(included_region_b.x, included_region_b.y));
|
||||
}
|
||||
+#endif
|
||||
|
||||
float d = min(-d_radii_a, d_radii_b);
|
||||
|
||||
color0 *= distance_aa(aa_range, d);
|
||||
break;
|
||||
}
|
||||
case BORDER_STYLE_GROOVE:
|
||||
case BORDER_STYLE_RIDGE: {
|
||||
float d;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape == 1.0) {
|
||||
+#endif
|
||||
d = distance_to_ellipse(
|
||||
clip_relative_pos,
|
||||
clip_radii.xy - vPartialWidths.zw
|
||||
);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
d = distance_to_superellipse(
|
||||
clip_relative_pos - mix(vClipOffsets.xy, vClipOffsets.zw, 0.5),
|
||||
mix(clip_radii.xy, clip_radii.zw, 0.5),
|
||||
data.shape
|
||||
@@ -311,10 +328,11 @@
|
||||
|
||||
// Clamp to the middle of the adjacent borders
|
||||
vec2 included_region = data.radii - vPartialWidths.zw - clip_relative_pos;
|
||||
d = max(d, -min(included_region.x, included_region.y));
|
||||
}
|
||||
+#endif
|
||||
float alpha = distance_aa(aa_range, d);
|
||||
float swizzled_factor;
|
||||
switch (segment) {
|
||||
case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
|
||||
case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
|
||||
@@ -435,22 +453,26 @@
|
||||
|
||||
if (in_clip_region) {
|
||||
float d_radii_a;
|
||||
float d_radii_b;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape == 1.0) {
|
||||
+#endif
|
||||
d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy);
|
||||
d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
clip_relative_pos = abs(clip_relative_pos) - data.shape_offset;
|
||||
d_radii_a = distance_to_superellipse(clip_relative_pos - vClipOffsets.xy, vClipRadii.xy, data.shape);
|
||||
d_radii_b = distance_to_superellipse(clip_relative_pos - vClipOffsets.zw, vClipRadii.zw, data.shape);
|
||||
|
||||
// exclude the straight border part from the subtracted region
|
||||
vec2 included_region = data.radii - data.widths - clip_relative_pos;
|
||||
d_radii_b = max(d_radii_b, -min(included_region.x, included_region.y));
|
||||
}
|
||||
+#endif
|
||||
|
||||
float d_radii = max(d_radii_a, -d_radii_b);
|
||||
d = max(d, d_radii);
|
||||
|
||||
color0 = evaluate_color_for_style_in_corner(
|
||||
diff --git a/gfx/wr/webrender/res/cs_border_solid.glsl b/gfx/wr/webrender/res/cs_border_solid.glsl
|
||||
--- a/gfx/wr/webrender/res/cs_border_solid.glsl
|
||||
+++ b/gfx/wr/webrender/res/cs_border_solid.glsl
|
||||
@@ -31,11 +31,13 @@
|
||||
flat varying highp vec4 vClipCenter_Sign;
|
||||
|
||||
// An outer and inner elliptical radii for border
|
||||
// corner clipping.
|
||||
flat varying highp vec4 vClipRadii;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
flat varying highp vec4 vClipOffsets;
|
||||
+#endif
|
||||
|
||||
// Position, scale, and radii of horizontally and vertically adjacent corner clips.
|
||||
flat varying highp vec4 vHorizontalClipCenter_Sign;
|
||||
flat varying highp vec2 vHorizontalClipRadii;
|
||||
flat varying highp vec4 vVerticalClipCenter_Sign;
|
||||
@@ -74,11 +76,11 @@
|
||||
void main(void) {
|
||||
BorderInstanceGpuData data = fetch_gpu_data(aGpuDataAddress);
|
||||
vGpuDataAddress.x = aGpuDataAddress;
|
||||
|
||||
int segment = aFlags & 0xff;
|
||||
- bool do_aa = ((aFlags >> 24) & 0xf0) != 0;
|
||||
+ bool do_aa = ((aFlags >> 28) & 0x1) != 0;
|
||||
|
||||
vec2 outer_scale = get_outer_corner_scale(segment);
|
||||
vec2 size = data.rect.zw - data.rect.xy;
|
||||
vec2 outer = outer_scale * size;
|
||||
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
|
||||
@@ -100,23 +102,31 @@
|
||||
vMixColors.x = mix_colors;
|
||||
vPos = size * aPosition.xy;
|
||||
|
||||
vColor0 = data.color0;
|
||||
vColor1 = data.color1;
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipCenter_Sign = vec4(outer + clip_sign * (data.radii + data.shape_offset), clip_sign);
|
||||
+#else
|
||||
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
|
||||
+#endif
|
||||
vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
vClipOffsets = vec4(0.0);
|
||||
+#endif
|
||||
vColorLine = vec4(outer, data.widths.y * -clip_sign.y, data.widths.x * clip_sign.x);
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape != 1.0)
|
||||
{
|
||||
vec2 reference_radii = (data.radii == vec2(0.0)) ? vec2(0.0) : data.radii + data.inset;
|
||||
vec4 contour1 = compute_contoured_superellipse(reference_radii, data.shape, data.inset);
|
||||
vec4 contour2 = compute_contoured_superellipse(reference_radii, data.shape, data.inset + data.widths);
|
||||
vClipOffsets = vec4(contour1.xy, contour2.xy);
|
||||
vClipRadii = vec4(contour1.zw, contour2.zw);
|
||||
}
|
||||
+#endif
|
||||
|
||||
vec2 horizontal_clip_sign = vec2(-clip_sign.x, clip_sign.y);
|
||||
vHorizontalClipCenter_Sign = vec4(aClipParams1.xy +
|
||||
horizontal_clip_sign * aClipParams1.zw,
|
||||
horizontal_clip_sign);
|
||||
@@ -156,22 +166,26 @@
|
||||
float d = -1.0;
|
||||
if (in_clip_region) {
|
||||
float d_radii_a;
|
||||
float d_radii_b;
|
||||
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
if (data.shape == 1.0) {
|
||||
+#endif
|
||||
d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy);
|
||||
d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw);
|
||||
+#ifdef WR_FEATURE_SUPERELLIPSE
|
||||
} else {
|
||||
clip_relative_pos = abs(clip_relative_pos) - data.shape_offset;
|
||||
d_radii_a = distance_to_superellipse(clip_relative_pos - vClipOffsets.xy, vClipRadii.xy, data.shape);
|
||||
d_radii_b = distance_to_superellipse(clip_relative_pos - vClipOffsets.zw, vClipRadii.zw, data.shape);
|
||||
|
||||
// exclude the straight border part from the subtracted region
|
||||
vec2 included_region = data.radii - data.widths - clip_relative_pos;
|
||||
d_radii_b = max(d_radii_b, -min(included_region.x, included_region.y));
|
||||
}
|
||||
+#endif
|
||||
|
||||
d = max(d_radii_a, -d_radii_b);
|
||||
}
|
||||
|
||||
// And again for horizontally-adjacent corner
|
||||
diff --git a/gfx/wr/webrender/src/border.rs b/gfx/wr/webrender/src/border.rs
|
||||
--- a/gfx/wr/webrender/src/border.rs
|
||||
+++ b/gfx/wr/webrender/src/border.rs
|
||||
@@ -855,14 +855,17 @@
|
||||
h_adjacent_corner_radius: DeviceSize,
|
||||
v_adjacent_corner_outer: DevicePoint,
|
||||
v_adjacent_corner_radius: DeviceSize,
|
||||
gpu_buffer_builder: &mut GpuBufferBuilderF,
|
||||
) {
|
||||
+ let superellipse = shape != 1.0;
|
||||
+
|
||||
let base_flags = (segment as i32) |
|
||||
((style0 as i32) << 8) |
|
||||
((style1 as i32) << 16) |
|
||||
- ((do_aa as i32) << 28);
|
||||
+ ((do_aa as i32) << 28) |
|
||||
+ ((superellipse as i32) << 29);
|
||||
|
||||
let instance_gpu_data = BorderInstanceGpuData {
|
||||
local_rect: task_rect,
|
||||
color0: color0.premultiplied(),
|
||||
color1: color1.premultiplied(),
|
||||
@@ -875,11 +878,11 @@
|
||||
|
||||
let base_instance = BorderInstance {
|
||||
task_origin: DevicePoint::zero(),
|
||||
flags: base_flags,
|
||||
clip_params: [0.0; 8],
|
||||
- gpu_data_address: instance_gpu_data.write(gpu_buffer_builder)
|
||||
+ gpu_data_address: instance_gpu_data.write(superellipse, gpu_buffer_builder)
|
||||
};
|
||||
|
||||
match segment {
|
||||
BorderSegment::TopLeft |
|
||||
BorderSegment::TopRight |
|
||||
diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs
|
||||
--- a/gfx/wr/webrender/src/gpu_types.rs
|
||||
+++ b/gfx/wr/webrender/src/gpu_types.rs
|
||||
@@ -192,18 +192,21 @@
|
||||
pub shape_offset: DeviceSize,
|
||||
pub inset: DeviceSize,
|
||||
}
|
||||
|
||||
impl BorderInstanceGpuData {
|
||||
- pub fn write(&self, gpu_buffer_builder: &mut GpuBufferBuilderF) -> GpuBufferAddress {
|
||||
- let mut writer = gpu_buffer_builder.write_blocks(6);
|
||||
+ pub fn write(&self, superellipse: bool, gpu_buffer_builder: &mut GpuBufferBuilderF) -> GpuBufferAddress {
|
||||
+ let block_count = if superellipse { 6 } else { 4 };
|
||||
+ let mut writer = gpu_buffer_builder.write_blocks(block_count);
|
||||
writer.push_one(self.local_rect);
|
||||
writer.push_one(self.color0);
|
||||
writer.push_one(self.color1);
|
||||
writer.push_one([self.widths.width, self.widths.height, self.radius.width, self.radius.height]);
|
||||
- writer.push_one([self.shape, self.shape_offset.width, self.shape_offset.height, 0.0]);
|
||||
- writer.push_one([self.inset.width, self.inset.height, 0.0, 0.0]);
|
||||
+ if superellipse {
|
||||
+ writer.push_one([self.shape, self.shape_offset.width, self.shape_offset.height, 0.0]);
|
||||
+ writer.push_one([self.inset.width, self.inset.height, 0.0, 0.0]);
|
||||
+ }
|
||||
|
||||
writer.finish()
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs
|
||||
--- a/gfx/wr/webrender/src/render_target.rs
|
||||
+++ b/gfx/wr/webrender/src/render_target.rs
|
||||
@@ -33,10 +33,11 @@
|
||||
use crate::spatial_tree::SpatialNodeIndex;
|
||||
|
||||
|
||||
const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
|
||||
const STYLE_MASK: i32 = 0x00FF_FF00;
|
||||
+const SUPERELLIPSE_MASK: i32 = 1 << 29;
|
||||
|
||||
/// A tag used to identify the output format of a `RenderTarget`.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
@@ -163,10 +164,12 @@
|
||||
|
||||
pub clip_masks: ClipMaskInstanceList,
|
||||
|
||||
pub border_segments_complex: FrameVec<BorderInstance>,
|
||||
pub border_segments_solid: FrameVec<BorderInstance>,
|
||||
+ pub border_segments_complex_superellipse: FrameVec<BorderInstance>,
|
||||
+ pub border_segments_solid_superellipse: FrameVec<BorderInstance>,
|
||||
pub line_decorations: FrameVec<LineDecorationJob>,
|
||||
|
||||
// Clearing render targets has a fair amount of special cases.
|
||||
// The general rules are:
|
||||
// - Depth (for at least the used potion of the target) is always cleared if it
|
||||
@@ -223,10 +226,12 @@
|
||||
prim_instances: std::array::from_fn(|_| FastHashMap::default()),
|
||||
prim_instances_with_scissor: FastHashMap::default(),
|
||||
clip_masks: ClipMaskInstanceList::new(memory),
|
||||
border_segments_complex: memory.new_vec(),
|
||||
border_segments_solid: memory.new_vec(),
|
||||
+ border_segments_complex_superellipse: memory.new_vec(),
|
||||
+ border_segments_solid_superellipse: memory.new_vec(),
|
||||
clears: memory.new_vec(),
|
||||
line_decorations: memory.new_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,14 +552,23 @@
|
||||
let instances = task_info.instances.clone();
|
||||
for mut instance in instances {
|
||||
// TODO(gw): It may be better to store the task origin in
|
||||
// the render task data instead of per instance.
|
||||
instance.task_origin = task_origin;
|
||||
+ let superellipse = (instance.flags & SUPERELLIPSE_MASK) != 0;
|
||||
if instance.flags & STYLE_MASK == STYLE_SOLID {
|
||||
- self.border_segments_solid.push(instance);
|
||||
+ if superellipse {
|
||||
+ self.border_segments_solid_superellipse.push(instance);
|
||||
+ } else {
|
||||
+ self.border_segments_solid.push(instance);
|
||||
+ }
|
||||
} else {
|
||||
- self.border_segments_complex.push(instance);
|
||||
+ if superellipse {
|
||||
+ self.border_segments_complex_superellipse.push(instance);
|
||||
+ } else {
|
||||
+ self.border_segments_complex.push(instance);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderTaskKind::Image(..) |
|
||||
RenderTaskKind::Cached(..) |
|
||||
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/mod.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
@@ -3394,11 +3394,13 @@
|
||||
draw_target,
|
||||
);
|
||||
|
||||
// Draw any borders for this target.
|
||||
if !target.border_segments_solid.is_empty() ||
|
||||
- !target.border_segments_complex.is_empty()
|
||||
+ !target.border_segments_complex.is_empty() ||
|
||||
+ !target.border_segments_solid_superellipse.is_empty() ||
|
||||
+ !target.border_segments_complex_superellipse.is_empty()
|
||||
{
|
||||
let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_BORDER);
|
||||
|
||||
self.set_blend(true, FramebufferKind::Other);
|
||||
self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
|
||||
@@ -3437,10 +3439,46 @@
|
||||
&BatchTextures::empty(),
|
||||
stats,
|
||||
);
|
||||
}
|
||||
|
||||
+ if !target.border_segments_solid_superellipse.is_empty() {
|
||||
+ self.shaders.borrow_mut().cs_border_solid_superellipse().bind(
|
||||
+ &mut self.device,
|
||||
+ &projection,
|
||||
+ None,
|
||||
+ &mut self.renderer_errors,
|
||||
+ &mut self.profile,
|
||||
+ &mut self.command_log,
|
||||
+ );
|
||||
+
|
||||
+ self.draw_instanced_batch(
|
||||
+ &target.border_segments_solid_superellipse,
|
||||
+ VertexArrayKind::Border,
|
||||
+ &BatchTextures::empty(),
|
||||
+ stats,
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ if !target.border_segments_complex_superellipse.is_empty() {
|
||||
+ self.shaders.borrow_mut().cs_border_segment_superellipse().bind(
|
||||
+ &mut self.device,
|
||||
+ &projection,
|
||||
+ None,
|
||||
+ &mut self.renderer_errors,
|
||||
+ &mut self.profile,
|
||||
+ &mut self.command_log,
|
||||
+ );
|
||||
+
|
||||
+ self.draw_instanced_batch(
|
||||
+ &target.border_segments_complex_superellipse,
|
||||
+ VertexArrayKind::Border,
|
||||
+ &BatchTextures::empty(),
|
||||
+ stats,
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
self.set_blend(false, FramebufferKind::Other);
|
||||
}
|
||||
|
||||
// Draw any line decorations for this target.
|
||||
if !target.line_decorations.is_empty() {
|
||||
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/shade.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/shade.rs
|
||||
@@ -413,10 +413,12 @@
|
||||
// draw intermediate results to cache targets. The results
|
||||
// of these shaders are then used by the primitive shaders.
|
||||
cs_blur_rgba8: ShaderHandle,
|
||||
cs_border_segment: ShaderHandle,
|
||||
cs_border_solid: ShaderHandle,
|
||||
+ cs_border_segment_superellipse: ShaderHandle,
|
||||
+ cs_border_solid_superellipse: ShaderHandle,
|
||||
cs_scale: Vec<Option<ShaderHandle>>,
|
||||
cs_line_decoration: ShaderHandle,
|
||||
cs_svg_filter_node: ShaderHandle,
|
||||
|
||||
// The are "primitive shaders". These shaders draw and blend
|
||||
@@ -774,19 +776,35 @@
|
||||
"cs_border_solid",
|
||||
&[],
|
||||
&shader_list,
|
||||
)?;
|
||||
|
||||
+ let cs_border_segment_superellipse = loader.create_shader(
|
||||
+ ShaderKind::Cache(VertexArrayKind::Border),
|
||||
+ "cs_border_segment",
|
||||
+ &[SUPERELLIPSE_FEATURE],
|
||||
+ &shader_list,
|
||||
+ )?;
|
||||
+
|
||||
+ let cs_border_solid_superellipse = loader.create_shader(
|
||||
+ ShaderKind::Cache(VertexArrayKind::Border),
|
||||
+ "cs_border_solid",
|
||||
+ &[SUPERELLIPSE_FEATURE],
|
||||
+ &shader_list,
|
||||
+ )?;
|
||||
+
|
||||
let composite = CompositorShaders::new(device, gl_type, &mut loader)?;
|
||||
|
||||
Ok(Shaders {
|
||||
loader,
|
||||
|
||||
cs_blur_rgba8,
|
||||
cs_border_segment,
|
||||
- cs_line_decoration,
|
||||
cs_border_solid,
|
||||
+ cs_border_segment_superellipse,
|
||||
+ cs_border_solid_superellipse,
|
||||
+ cs_line_decoration,
|
||||
cs_scale,
|
||||
cs_svg_filter_node,
|
||||
ps_text_run,
|
||||
ps_text_run_dual_source,
|
||||
ps_quad_textured,
|
||||
@@ -979,10 +997,12 @@
|
||||
}
|
||||
|
||||
pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) }
|
||||
pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) }
|
||||
pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) }
|
||||
+ pub fn cs_border_segment_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment_superellipse) }
|
||||
+ pub fn cs_border_solid_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid_superellipse) }
|
||||
pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) }
|
||||
pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) }
|
||||
pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader {
|
||||
self.loader.get(self.ps_quad_textured)
|
||||
}
|
||||
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
--- a/gfx/wr/webrender_build/src/shader_features.rs
|
||||
+++ b/gfx/wr/webrender_build/src/shader_features.rs
|
||||
@@ -69,17 +69,22 @@
|
||||
|
||||
shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string(), "SUPERELLIPSE".to_string()]);
|
||||
|
||||
for name in &[
|
||||
"cs_line_decoration",
|
||||
- "cs_border_segment",
|
||||
- "cs_border_solid",
|
||||
"cs_svg_filter_node",
|
||||
] {
|
||||
shaders.insert(name, vec![String::new()]);
|
||||
}
|
||||
|
||||
+ for name in &[
|
||||
+ "cs_border_segment",
|
||||
+ "cs_border_solid",
|
||||
+ ] {
|
||||
+ shaders.insert(name, vec![String::new(), "SUPERELLIPSE".to_string()]);
|
||||
+ }
|
||||
+
|
||||
let mut base_prim_features = FeatureList::new();
|
||||
|
||||
let mut texture_types = vec!["TEXTURE_2D"];
|
||||
if flags.contains(ShaderFeatureFlags::GL) {
|
||||
texture_types.push("TEXTURE_RECT");
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
diff --git a/devtools/client/responsive/test/browser/browser.toml b/devtools/client/responsive/test/browser/browser.toml
|
||||
--- a/devtools/client/responsive/test/browser/browser.toml
|
||||
+++ b/devtools/client/responsive/test/browser/browser.toml
|
||||
@@ -275,7 +275,10 @@
|
||||
skip-if = [
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && asan", # Bug 2016837
|
||||
]
|
||||
|
||||
["browser_window_sizing.js"]
|
||||
+skip-if = [
|
||||
+ "os == 'win' && opt && standalone", # Bug 2063169
|
||||
+]
|
||||
|
||||
["browser_zoom.js"]
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
|
||||
--- a/layout/painting/nsDisplayList.cpp
|
||||
+++ b/layout/painting/nsDisplayList.cpp
|
||||
@@ -4606,12 +4606,12 @@
|
||||
wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
|
||||
|
||||
nscoord spread = shadow.spread.ToAppUnits();
|
||||
float spreadRadius = float(spread) / float(appUnitsPerDevPixel);
|
||||
|
||||
- wr::BorderRadius borderRadius{};
|
||||
- wr::BorderRadius shadowRadius{};
|
||||
+ wr::BorderRadius borderRadius = wr::EmptyBorderRadius();
|
||||
+ wr::BorderRadius shadowRadius = wr::EmptyBorderRadius();
|
||||
if (hasBorderRadius) {
|
||||
borderRadius = wr::ToBorderRadius(borderRadii);
|
||||
if (spreadRadius) {
|
||||
auto shadowRadii = borderRadii;
|
||||
shadowRadii.AdjustOutwards(
|
||||
@@ -4727,12 +4727,12 @@
|
||||
float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
|
||||
|
||||
nscoord spread = shadow.spread.ToAppUnits();
|
||||
float spreadRadius = spread / float(appUnitsPerDevPixel);
|
||||
|
||||
- wr::BorderRadius borderRadius{};
|
||||
- wr::BorderRadius shadowRadius{};
|
||||
+ wr::BorderRadius borderRadius = wr::EmptyBorderRadius();
|
||||
+ wr::BorderRadius shadowRadius = wr::EmptyBorderRadius();
|
||||
if (hasBorderRadius) {
|
||||
borderRadius = wr::ToBorderRadius(innerRadii);
|
||||
if (spreadRadius) {
|
||||
RectCornerRadii shadowRadii = innerRadii;
|
||||
shadowRadii.AdjustInwards(
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
diff --git a/gfx/wr/webrender/res/ps_quad_mask.glsl b/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
--- a/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
+++ b/gfx/wr/webrender/res/ps_quad_mask.glsl
|
||||
@@ -318,12 +318,30 @@
|
||||
#endif
|
||||
|
||||
vec4 clip_dist =
|
||||
mix(clip_rect, clip_rect.zwxy, lessThan(local_step, vec2(0.0)).xyxy)
|
||||
- local_pos0.xyxy;
|
||||
+
|
||||
+ // Half-width, in local units, of the band around an edge over which
|
||||
+ // distance_aa() produces partial coverage.
|
||||
+ float aa_band = 0.5 * recip(aa_range);
|
||||
+ // An axis the span does not step along has the same distance to its two
|
||||
+ // edges for every pixel of the span, so the inside/outside test below
|
||||
+ // cannot resolve an edge that runs parallel to the span and coverage ends
|
||||
+ // up quantized to whole spans. Grow the rect by the AA band so that a span
|
||||
+ // landing inside the band counts as inside, which leaves the corner
|
||||
+ // selection below unchanged, and remember that the span is only partially
|
||||
+ // covered so the opaque run can be dropped further down.
|
||||
+ // `inset` is the distance from the span to the nearer of an axis' two
|
||||
+ // edges, positive when the span is between them.
|
||||
+ vec2 inset = min(-clip_dist.xy, clip_dist.zw);
|
||||
+ bvec2 flat_axis = equal(local_step, vec2(0.0));
|
||||
+ bvec2 partial = lessThan(inset, vec2(aa_band));
|
||||
+ bool aa_span = (flat_axis.x && partial.x) || (flat_axis.y && partial.y);
|
||||
+
|
||||
clip_dist =
|
||||
- mix(1.0e6 * step(0.0, clip_dist),
|
||||
+ mix(1.0e6 * step(0.0, clip_dist - vec4(aa_band, aa_band, -aa_band, -aa_band)),
|
||||
clip_dist * recip(local_step).xyxy,
|
||||
notEqual(local_step, vec2(0.0)).xyxy);
|
||||
|
||||
float opaque_start = max(clip_dist.x, clip_dist.y);
|
||||
float opaque_end = min(clip_dist.z, clip_dist.w);
|
||||
@@ -404,10 +422,16 @@
|
||||
|
||||
aa_margin = max(aa_margin - max(aa_start - aa_end, 0.0), 0.0);
|
||||
aa_start -= aa_margin;
|
||||
aa_end += aa_margin;
|
||||
|
||||
+ if (aa_span) {
|
||||
+ // No pixel of the span is fully covered, so collapse the opaque run and
|
||||
+ // let the anti-aliased runs on either side of it cover the whole span.
|
||||
+ opaque_end = min(opaque_end, opaque_start);
|
||||
+ }
|
||||
+
|
||||
ivec4 steps = ivec4(clamp(
|
||||
swgl_SpanLength -
|
||||
swgl_StepSize *
|
||||
vec4(floor(aa_start), ceil(opaque_start), floor(opaque_end), ceil(aa_end)),
|
||||
0.0, swgl_SpanLength));
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/global-shared.css
|
||||
--- a/toolkit/themes/shared/global-shared.css
|
||||
+++ b/toolkit/themes/shared/global-shared.css
|
||||
@@ -80,11 +80,10 @@
|
||||
@@ -80,10 +80,9 @@
|
||||
background-color: transparent;
|
||||
--panel-background: transparent;
|
||||
--panel-box-shadow: none;
|
||||
--panel-border-color: transparent;
|
||||
--panel-box-shadow-margin: 0px;
|
||||
|
||||
@@ -46,27 +46,11 @@
|
||||
" jsonLengthHint,": " lengthHint: jsonLengthHint,"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "phabricator",
|
||||
"id": "D320897",
|
||||
"name": "Bug 2011236"
|
||||
},
|
||||
{
|
||||
"type": "phabricator",
|
||||
"id": "D321446",
|
||||
"name": "Issue 14710"
|
||||
},
|
||||
{
|
||||
"type": "local",
|
||||
// Sorts before bug_2063169/ on purpose: D319869 builds on the border
|
||||
// shader hunks in here, and surfer applies patches in path order.
|
||||
"path": "firefox/bug_2047627_corner_shape_borders.patch"
|
||||
},
|
||||
{
|
||||
"type": "phabricator",
|
||||
"ids": ["D319577", "D319796", "D319869", "D320211", "D320568", "D321282"],
|
||||
"name": "Bug 2063169"
|
||||
},
|
||||
{
|
||||
"type": "local",
|
||||
"path": "firefox/override_cert_checks_temp.patch"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp
|
||||
index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d24fb106ce 100644
|
||||
index 7ddc4f7e259272e7b905f44aff7316c1ba540c22..277a92e5d10e6a04b12373854ffe6791d562215e 100644
|
||||
--- a/layout/painting/nsImageRenderer.cpp
|
||||
+++ b/layout/painting/nsImageRenderer.cpp
|
||||
@@ -90,7 +90,7 @@ static already_AddRefed<imgIContainer> GetSymbolicIconImage(nsAtom* aName,
|
||||
@@ -95,7 +95,7 @@ static already_AddRefed<imgIContainer> GetSymbolicIconImage(nsAtom* aName,
|
||||
if (NS_WARN_IF(!XRE_IsParentProcess())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
||||
auto key = std::make_tuple(aName, aScale, fg);
|
||||
auto* cache = aFrame->GetOrCreateDeletableProperty(SymbolicImageCacheProp());
|
||||
auto lookup = cache->Lookup(key);
|
||||
@@ -575,7 +575,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
|
||||
@@ -580,7 +580,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
|
||||
}
|
||||
case StyleImage::Tag::Gradient: {
|
||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||
@@ -20,7 +20,7 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
||||
|
||||
renderer.Paint(*ctx, aDest, aFill, aRepeatSize, aSrc, aDirtyRect,
|
||||
aOpacity);
|
||||
@@ -652,7 +652,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||
@@ -657,7 +657,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||
switch (mType) {
|
||||
case StyleImage::Tag::Gradient: {
|
||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||
@@ -29,16 +29,16 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
||||
|
||||
renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aDest, aFill,
|
||||
aRepeatSize, aSrc,
|
||||
@@ -678,6 +678,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||
nsPresContext::AppUnitsToIntCSSPixels(aDest.height)};
|
||||
@@ -679,6 +679,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||
}
|
||||
|
||||
SVGImageContext svgContext(Some(destCSSSize));
|
||||
SVGImageContext svgContext(Some(CSSSize::FromAppUnits(aDest.Size())));
|
||||
+ SVGImageContext::MaybeStoreZenBoosts(svgContext,
|
||||
+ *mForFrame->PresContext());
|
||||
Maybe<ImageIntRegion> region;
|
||||
|
||||
const int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
|
||||
@@ -1092,7 +1094,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
|
||||
@@ -1098,7 +1100,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
|
||||
|
||||
if (mImage->IsGradient()) {
|
||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/layout/svg/SVGGradientFrame.cpp b/layout/svg/SVGGradientFrame.cpp
|
||||
index b0d38b0fab01797328af0b1f1f48af8fb5eebe4d..953feffdc96143dc2d8f8e57f8bb4a6aeb33f0c5 100644
|
||||
index eebcced86ec1e9010b761d5df4a92684dde44009..4dc018a73a979f50ac7842e4a3f3fcf9d0071b56 100644
|
||||
--- a/layout/svg/SVGGradientFrame.cpp
|
||||
+++ b/layout/svg/SVGGradientFrame.cpp
|
||||
@@ -229,8 +229,9 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
|
||||
@@ -228,8 +228,9 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
|
||||
SVGColorStopInterpolator(
|
||||
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
|
||||
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
|
||||
@@ -14,8 +14,8 @@ index b0d38b0fab01797328af0b1f1f48af8fb5eebe4d..953feffdc96143dc2d8f8e57f8bb4a6a
|
||||
mGradient(aGradient) {}
|
||||
|
||||
void CreateStop(float aPosition, DeviceColor aColor) {
|
||||
@@ -270,7 +271,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
|
||||
if (nStops == 1 || GradientVectorLengthIsZero()) {
|
||||
@@ -269,7 +270,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
|
||||
if (nStops == 1 || GradientVectorLengthIsZero(gradientUnits)) {
|
||||
// The gradient paints a single colour, using the stop-color of the last
|
||||
// gradient step if there are more than one.
|
||||
- return MakeAndAddRef<gfxPattern>(ToDeviceColor(stops.LastElement().mColor));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h
|
||||
index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd6178f9e3 100644
|
||||
index 63f3c4926cfdb8b12e9e4a38016fc66f50cf3129..5ba3f2c07f521905a086ee6eea87975d5a3441ec 100644
|
||||
--- a/layout/svg/SVGImageContext.h
|
||||
+++ b/layout/svg/SVGImageContext.h
|
||||
@@ -6,6 +6,7 @@
|
||||
@@ -7,10 +7,10 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
||||
|
||||
#include "Units.h"
|
||||
+#include "nsColor.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/SVGContextPaint.h"
|
||||
#include "mozilla/SVGPreserveAspectRatio.h"
|
||||
@@ -63,6 +64,11 @@ class SVGImageContext {
|
||||
@@ -64,6 +65,11 @@ class SVGImageContext {
|
||||
nsISVGPaintContext* aPaintContext,
|
||||
imgIContainer* aImgContainer);
|
||||
|
||||
@@ -19,10 +19,10 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
||||
+ static void MaybeStoreZenBoosts(SVGImageContext& aContext,
|
||||
+ const nsPresContext& aPresContext);
|
||||
+
|
||||
const Maybe<CSSIntSize>& GetViewportSize() const { return mViewportSize; }
|
||||
const Maybe<CSSSize>& GetViewportSize() const { return mViewportSize; }
|
||||
|
||||
void SetViewportSize(const Maybe<CSSIntSize>& aSize) {
|
||||
@@ -75,6 +81,21 @@ class SVGImageContext {
|
||||
void SetViewportSize(const Maybe<CSSSize>& aSize) { mViewportSize = aSize; }
|
||||
@@ -74,6 +80,21 @@ class SVGImageContext {
|
||||
mColorScheme = aScheme;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
||||
const Maybe<SVGPreserveAspectRatio>& GetPreserveAspectRatio() const {
|
||||
return mPreserveAspectRatio;
|
||||
}
|
||||
@@ -110,7 +131,11 @@ class SVGImageContext {
|
||||
@@ -109,7 +130,11 @@ class SVGImageContext {
|
||||
return contextPaintIsEqual && mViewportSize == aOther.mViewportSize &&
|
||||
mPreserveAspectRatio == aOther.mPreserveAspectRatio &&
|
||||
mColorScheme == aOther.mColorScheme &&
|
||||
@@ -56,8 +56,8 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
||||
+ mZenBoostsInverted == aOther.mZenBoostsInverted;
|
||||
}
|
||||
|
||||
bool operator!=(const SVGImageContext&) const = default;
|
||||
@@ -123,7 +148,8 @@ class SVGImageContext {
|
||||
PLDHashNumber Hash() const {
|
||||
@@ -120,7 +145,8 @@ class SVGImageContext {
|
||||
return AddToHash(hash, mViewportSize.map(HashSize).valueOr(0),
|
||||
mPreserveAspectRatio.map(HashPAR).valueOr(0),
|
||||
mColorScheme.map(HashColorScheme).valueOr(0),
|
||||
@@ -67,7 +67,7 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -156,6 +182,9 @@ class SVGImageContext {
|
||||
@@ -154,6 +180,9 @@ class SVGImageContext {
|
||||
Maybe<SVGPreserveAspectRatio> mPreserveAspectRatio;
|
||||
Maybe<ColorScheme> mColorScheme;
|
||||
StyleLinkParameters mLinkParameters;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
diff --git a/toolkit/content/widgets/panel-list/panel-list.mjs b/toolkit/content/widgets/panel-list/panel-list.mjs
|
||||
index 68ad2fafc8b31dfff541cf8381d9b9533e376d1c..fa62fec6bfb33338091fc06d3736fb76fd5c47c4 100644
|
||||
--- a/toolkit/content/widgets/panel-list/panel-list.mjs
|
||||
+++ b/toolkit/content/widgets/panel-list/panel-list.mjs
|
||||
@@ -223,7 +223,12 @@ export class PanelList extends HTMLElement {
|
||||
this.setAttribute("showing", "true");
|
||||
// Tell the host element to hide any overflow in case the panel extends off
|
||||
// the page before the alignment is set.
|
||||
- hostElement.style.overflow = "hidden";
|
||||
+ const hostHidesOverflow = !getComputedStyle(hostElement)
|
||||
+ .overflow.split(" ")
|
||||
+ .includes("visible");
|
||||
+ if (!hostHidesOverflow) {
|
||||
+ hostElement.style.overflow = "hidden";
|
||||
+ }
|
||||
|
||||
// Wait for a layout flush, then find the bounds.
|
||||
let {
|
||||
@@ -344,7 +349,9 @@ export class PanelList extends HTMLElement {
|
||||
// Set the alignments and show the panel.
|
||||
this.setAttribute("align", align);
|
||||
this.setAttribute("valign", valign);
|
||||
- hostElement.style.overflow = "";
|
||||
+ if (!hostHidesOverflow) {
|
||||
+ hostElement.style.overflow = "";
|
||||
+ }
|
||||
// Decide positioning based on where this panel will be rendered
|
||||
const offsetParentIsBody =
|
||||
this.supportsPopover() ||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/toolkit/themes/shared/design-system/dist/tokens-shared.css b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||
index 63c641f560d4c0ce06b40a652ca99d1c48cd6941..39c81e773a442870763396e68fb57bd336e3625a 100644
|
||||
index b0f8fa146de335c53e73d46853f45dda9b15cc73..1b7592c0e9ca12fd9d1f8a555633fd39c2efb537 100644
|
||||
--- a/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||
+++ b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||
@@ -7,6 +7,8 @@
|
||||
@@ -8,9 +8,9 @@ index 63c641f560d4c0ce06b40a652ca99d1c48cd6941..39c81e773a442870763396e68fb57bd3
|
||||
|
||||
+@import url("chrome://browser/content/zen-styles/zen-theme.css");
|
||||
+
|
||||
@layer tokens-foundation {
|
||||
:root,
|
||||
:host(.anonymous-content-host) {
|
||||
:root,
|
||||
:host(.anonymous-content-host) {
|
||||
@layer tokens-foundation {
|
||||
@@ -28,10 +30,10 @@
|
||||
--border-color-selected: var(--color-accent-primary);
|
||||
--border-color-transparent: transparent;
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
index 2efd02e4a92433fd29bbfdb707aa81cfec45031e..3b763c3927f07e529c826f8e4f62bc80a324b247 100644
|
||||
index 887e4c052d5dd2b73d4c2059463529fb4b09dcab..36da18e19018b1b216576c299f938e75093546d3 100644
|
||||
--- a/widget/cocoa/nsCocoaWindow.mm
|
||||
+++ b/widget/cocoa/nsCocoaWindow.mm
|
||||
@@ -86,6 +86,7 @@
|
||||
@@ -86,6 +86,8 @@
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/StaticPrefs_ui.h"
|
||||
#include "mozilla/StaticPrefs_widget.h"
|
||||
+#include "mozilla/StaticPrefs_zen.h"
|
||||
+#include "mozilla/nsZenDragAndDrop.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
@@ -1332,6 +1333,110 @@ - (NSRect)_opaqueRectForWindowMoveWhenInTitlebar {
|
||||
@@ -1332,6 +1334,110 @@ - (NSRect)_opaqueRectForWindowMoveWhenInTitlebar {
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -121,7 +122,28 @@ index 2efd02e4a92433fd29bbfdb707aa81cfec45031e..3b763c3927f07e529c826f8e4f62bc80
|
||||
void nsCocoaWindow::UpdateWindowDraggingRegion(
|
||||
const LayoutDeviceIntRegion& aRegion) {
|
||||
// mChildView returns YES from mouseDownCanMoveWindow, so we need to put
|
||||
@@ -4919,6 +5024,10 @@ - (BOOL)wantsBestResolutionOpenGLSurface {
|
||||
@@ -3858,7 +3964,9 @@ - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||
// NSDraggingDestination
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
|
||||
MOZ_LOG(sCocoaLog, LogLevel::Info, ("ChildView draggingUpdated: entered\n"));
|
||||
- return [self doDragAction:eDragOver sender:sender];
|
||||
+ NSDragOperation operation = [self doDragAction:eDragOver sender:sender];
|
||||
+ zen::PrepareDropLanding(sender);
|
||||
+ return operation;
|
||||
}
|
||||
|
||||
// NSDraggingDestination
|
||||
@@ -3874,6 +3982,9 @@ - (void)draggingExited:(id<NSDraggingInfo>)sender {
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
BOOL handled = [self doDragAction:eDrop sender:sender] != NSDragOperationNone;
|
||||
+ if (handled) {
|
||||
+ zen::LandDrop(sender);
|
||||
+ }
|
||||
NS_IF_RELEASE(mDragService);
|
||||
return handled;
|
||||
}
|
||||
@@ -4919,6 +5030,10 @@ - (BOOL)wantsBestResolutionOpenGLSurface {
|
||||
nsCocoaWindow::~nsCocoaWindow() {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm
|
||||
index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..32fc707ccfa56fa8c307860868d092c4a9050419 100644
|
||||
index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..ba597ba4373ba3ace7455ce0859f2339349ffc06 100644
|
||||
--- a/widget/cocoa/nsDragService.mm
|
||||
+++ b/widget/cocoa/nsDragService.mm
|
||||
@@ -10,6 +10,7 @@
|
||||
@@ -45,3 +45,112 @@ index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..32fc707ccfa56fa8c307860868d092c4
|
||||
#endif
|
||||
src += 4;
|
||||
dest += 4;
|
||||
@@ -249,12 +254,44 @@
|
||||
[[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
|
||||
[dragItem setDraggingFrame:localDragRect contents:image];
|
||||
|
||||
+ NSMutableArray* dragItems = [NSMutableArray arrayWithObject:dragItem];
|
||||
+ auto zenDragAndDrop = zen::nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||
+ const nsTArray<nsCOMPtr<nsINode>> noExtraImages;
|
||||
+ @try {
|
||||
+ for (const auto& extraImageNode :
|
||||
+ zenDragAndDrop ? zenDragAndDrop->DragImages() : noExtraImages) {
|
||||
+ nsCOMPtr<nsINode> mainImage = std::move(mImage);
|
||||
+ mImage = extraImageNode;
|
||||
+ NSPoint extraPoint;
|
||||
+ NSImage* extraImage = ConstructDragImage(mSourceNode, aRegion, &extraPoint);
|
||||
+ mImage = std::move(mainImage);
|
||||
+ if (!extraImage) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ NSRect extraRect = extraImage.alignmentRect;
|
||||
+ extraRect.origin.x = extraPoint.x;
|
||||
+ extraRect.origin.y = extraPoint.y - extraRect.size.height;
|
||||
+ NSPasteboardItem* extraPbItem = [[NSPasteboardItem new] autorelease];
|
||||
+ [extraPbItem setData:[NSData data]
|
||||
+ forType:[UTIHelper stringFromPboardType:kMozWildcardPboardType]];
|
||||
+ NSDraggingItem* extraItem = [[[NSDraggingItem alloc]
|
||||
+ initWithPasteboardWriter:extraPbItem] autorelease];
|
||||
+ [extraItem setDraggingFrame:extraRect contents:extraImage];
|
||||
+ [dragItems addObject:extraItem];
|
||||
+ }
|
||||
+ } @catch (NSException* e) {
|
||||
+ dragItems = [NSMutableArray arrayWithObject:dragItem];
|
||||
+ }
|
||||
+
|
||||
OpenDragPopup();
|
||||
|
||||
mNSDraggingSession = [mNativeDragView
|
||||
- beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem]
|
||||
+ beginDraggingSessionWithItems:dragItems
|
||||
event:mNativeDragEvent
|
||||
source:mNativeDragView];
|
||||
+ if (dragItems.count > 1) {
|
||||
+ mNSDraggingSession.draggingFormation = NSDraggingFormationStack;
|
||||
+ }
|
||||
|
||||
mNSDraggingSession.animatesToStartingPositionsOnCancelOrFail =
|
||||
!mDataTransfer || mDataTransfer->MozShowFailAnimation();
|
||||
@@ -455,29 +492,44 @@
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
+ nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||
+ devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||
+ CSSIntPoint screenPoint =
|
||||
+ CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||
+ nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||
+
|
||||
+ NSMutableArray* images = [NSMutableArray array];
|
||||
+ NSMutableArray* rects = [NSMutableArray array];
|
||||
+ auto render = [&]() {
|
||||
+ LayoutDeviceIntRect newRect;
|
||||
+ NSImage* image =
|
||||
+ ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||
+ [images addObject:image ? (id)image : (id)[NSNull null]];
|
||||
+ [rects addObject:[NSValue valueWithRect:
|
||||
+ image ? nsCocoaUtils::GeckoRectToCocoaRectDevPix(
|
||||
+ newRect, scaleFactor)
|
||||
+ : NSZeroRect]];
|
||||
+ };
|
||||
+ render();
|
||||
+ if (auto zenDragAndDrop = zen::nsZenDragAndDrop::GetZenDragAndDropInstance()) {
|
||||
+ for (const auto& extraImageNode : zenDragAndDrop->DragImages()) {
|
||||
+ nsCOMPtr<nsINode> mainImage = std::move(mImage);
|
||||
+ mImage = extraImageNode;
|
||||
+ render();
|
||||
+ mImage = std::move(mainImage);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = ^(
|
||||
NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
||||
- // We never add more than one item right now, but check just in case.
|
||||
- if (idx > 0) {
|
||||
+ if ((NSUInteger)idx >= images.count || images[idx] == [NSNull null]) {
|
||||
return;
|
||||
}
|
||||
-
|
||||
- nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||
- devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||
- CSSIntPoint screenPoint =
|
||||
- CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||
- nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||
-
|
||||
- // Create a new image; if one isn't returned don't change the current
|
||||
- // one.
|
||||
- LayoutDeviceIntRect newRect;
|
||||
- NSImage* image =
|
||||
- ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||
- if (image) {
|
||||
- NSRect draggingRect =
|
||||
- nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
||||
- [draggingItem setDraggingFrame:draggingRect contents:image];
|
||||
+ NSRect frame = [rects[idx] rectValue];
|
||||
+ if (idx > 0) {
|
||||
+ frame.origin = draggingItem.draggingFrame.origin;
|
||||
}
|
||||
+ [draggingItem setDraggingFrame:frame contents:images[idx]];
|
||||
};
|
||||
|
||||
[mNSDraggingSession
|
||||
|
||||
@@ -1589,7 +1589,7 @@ window.gZenVerticalTabsManager = {
|
||||
gURLBar._initCopyCutController();
|
||||
gURLBar._initPasteAndGo();
|
||||
gURLBar._initStripOnShare();
|
||||
gURLBar._updatePlaceholderFromDefaultEngine();
|
||||
gURLBar.updatePlaceholder();
|
||||
},
|
||||
|
||||
rebuildAreas() {
|
||||
|
||||
@@ -32,6 +32,7 @@ panel[type="arrow"]:not(#feature-callout) {
|
||||
|
||||
@media (-moz-platform: linux) or ((-moz-platform: windows) and (not (-moz-windows-mica-popups))) {
|
||||
&::part(content) {
|
||||
/* stylelint-disable-next-line property-no-unknown */
|
||||
corner-shape: round;
|
||||
border-radius: calc(var(--panel-border-radius) / var(--zen-squircle-value));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
||||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
|
||||
class nsZenUIMigration {
|
||||
|
||||
@@ -160,7 +160,7 @@ document.addEventListener(
|
||||
}
|
||||
case "cmd_zenDuplicateTab": {
|
||||
const selectedTabs = gBrowser.selectedTabs;
|
||||
let insertAt = selectedTabs.at(-1)._tPos + 1;
|
||||
let insertAt = selectedTabs.at(-1).index + 1;
|
||||
for (const tab of selectedTabs) {
|
||||
gBrowser.duplicateTab(tab, true, { tabIndex: insertAt++ });
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* - <tab-group> label element wrapper (.tab-group-label-container)
|
||||
*
|
||||
* When working with tab strip items, if you need logical information, you
|
||||
* can get it directly, e.g. `element.elementIndex` or `element._tPos`. If
|
||||
* can get it directly, e.g. `element.elementIndex` or `element._index`. If
|
||||
* you need spatial information like position or dimensions, then you should
|
||||
* call this function. For example, `elementToMove(element).getBoundingClientRect()`
|
||||
* or `elementToMove(element).style.top`.
|
||||
@@ -69,6 +69,7 @@
|
||||
#changeSpaceTimer = null;
|
||||
#isAnimatingTabMove = false;
|
||||
#firstHapticFeedbackPlayed = false;
|
||||
#dragImageEssential = false;
|
||||
|
||||
#dragOverSplit = {};
|
||||
|
||||
@@ -152,10 +153,14 @@
|
||||
);
|
||||
const dragImage = this.#createDragImageForTabs(draggingTabs);
|
||||
this.originalDragImageArgs = [dragImage, offsetX, offsetY];
|
||||
this.#dragImageEssential = tab.hasAttribute("zen-essential");
|
||||
dt.setDragImage(...this.originalDragImageArgs);
|
||||
if (tab.hasAttribute("zen-essential")) {
|
||||
tab.style.visibility = "hidden";
|
||||
}
|
||||
this.ZenDragAndDropService.armDropLanding(
|
||||
!args[0]?.fromTabList && this.getDropEffectForTabDrag(event) == "move"
|
||||
);
|
||||
}
|
||||
|
||||
#createDragImageForTabs(movingTabs) {
|
||||
@@ -165,62 +170,79 @@
|
||||
const tabRect = window.windowUtils.getBoundsWithoutFlushing(
|
||||
movingTabs[0]
|
||||
);
|
||||
const native = AppConstants.platform == "macosx";
|
||||
const stacked = native ? 1 : Math.min(movingTabs.length, 3);
|
||||
const wrapper = this.#createDragImageWrapper(periphery, tabRect, stacked);
|
||||
for (let i = 0; i < stacked; i++) {
|
||||
this.#appendDragImageClone(wrapper, movingTabs[i], tabRect, i);
|
||||
}
|
||||
this._dragImageTabs = native ? [...movingTabs] : [movingTabs[0]];
|
||||
this._extraDragImages = [];
|
||||
if (native) {
|
||||
for (const tab of movingTabs.slice(1)) {
|
||||
const extra = this.#createDragImageWrapper(periphery, tabRect, 1);
|
||||
this.#appendDragImageClone(extra, tab, tabRect, 0);
|
||||
this.ZenDragAndDropService.addDragImage(extra);
|
||||
this._extraDragImages.push(extra);
|
||||
}
|
||||
} else {
|
||||
this.#maybeCreateDragImageDot(movingTabs, wrapper);
|
||||
}
|
||||
this._tempDragImageParent = wrapper;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
#createDragImageWrapper(periphery, tabRect, count) {
|
||||
const wrapper = document.createElement("div");
|
||||
let movingTabsCount = Math.min(movingTabs.length, 3);
|
||||
wrapper.style.width = tabRect.width + "px";
|
||||
wrapper.style.height = tabRect.height * movingTabsCount + "px";
|
||||
wrapper.style.height = tabRect.height * count + "px";
|
||||
wrapper.style.position = "fixed";
|
||||
wrapper.style.top = "-9999px";
|
||||
periphery.appendChild(wrapper);
|
||||
for (let i = 0; i < movingTabsCount; i++) {
|
||||
const tab = movingTabs[i];
|
||||
const tabClone = tab.cloneNode(true);
|
||||
if (tab.hasAttribute("zen-essential")) {
|
||||
const rect = tab.getBoundingClientRect();
|
||||
tabClone.style.minWidth = tabClone.style.maxWidth = `${rect.width}px`;
|
||||
tabClone.style.minHeight =
|
||||
tabClone.style.maxHeight = `${rect.height}px`;
|
||||
if (tabClone.hasAttribute("visuallyselected")) {
|
||||
tabClone.style.transform = "translate(-50%, -50%)";
|
||||
}
|
||||
} else if (AppConstants.platform == "win" && !tab.isZenFolder) {
|
||||
// On windows, the shell applies its own translucency to the drag
|
||||
// image which we can't control, so force some extra contrast for
|
||||
// the tab to be more visible. This is a hacky workaround.
|
||||
tabClone.style.colorScheme = "light";
|
||||
tabClone.style.setProperty("--tab-selected-textcolor", "black");
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
#appendDragImageClone(wrapper, tab, tabRect, i) {
|
||||
const tabClone = tab.cloneNode(true);
|
||||
if (tab.hasAttribute("zen-essential")) {
|
||||
const rect = tab.getBoundingClientRect();
|
||||
tabClone.style.minWidth = tabClone.style.maxWidth = `${rect.width}px`;
|
||||
tabClone.style.minHeight =
|
||||
tabClone.style.maxHeight = `${rect.height}px`;
|
||||
if (tabClone.hasAttribute("visuallyselected")) {
|
||||
tabClone.style.transform = "translate(-50%, -50%)";
|
||||
}
|
||||
if (i > 0) {
|
||||
tabClone.style.transform = `translate(${i * 4}px, -${i * (tabRect.height - 4)}px)`;
|
||||
tabClone.style.opacity = "0.2";
|
||||
tabClone.style.zIndex = `${-i}`;
|
||||
}
|
||||
tabClone.setAttribute("drag-image", "true");
|
||||
wrapper.appendChild(tabClone);
|
||||
if (isTab(tabClone)) {
|
||||
// We need to limit the label content so the drag image doesn't grow too big.
|
||||
const label = tabClone.textLabel;
|
||||
const tabLabelParentWidth =
|
||||
label.parentElement.getBoundingClientRect().width;
|
||||
label.textContent = label.textContent.slice(
|
||||
0,
|
||||
Math.floor(tabLabelParentWidth / 6)
|
||||
);
|
||||
} else if (
|
||||
gBrowser.isTabGroup(tabClone) &&
|
||||
tabClone.hasAttribute("split-view-group")
|
||||
) {
|
||||
let tabs = tab.tabs;
|
||||
for (let j = 0; j < tabs.length; j++) {
|
||||
const tabInGroup = tabs[j];
|
||||
const tabInGroupClone = tabInGroup.cloneNode(true);
|
||||
tabClone.appendChild(tabInGroupClone);
|
||||
}
|
||||
} else if (AppConstants.platform == "win" && !tab.isZenFolder) {
|
||||
// On windows, the shell applies its own translucency to the drag
|
||||
// image which we can't control, so force some extra contrast for
|
||||
// the tab to be more visible. This is a hacky workaround.
|
||||
tabClone.style.colorScheme = "light";
|
||||
tabClone.style.setProperty("--tab-selected-textcolor", "black");
|
||||
}
|
||||
if (i > 0) {
|
||||
tabClone.style.transform = `translate(${i * 4}px, -${i * (tabRect.height - 4)}px)`;
|
||||
tabClone.style.opacity = "0.2";
|
||||
tabClone.style.zIndex = `${-i}`;
|
||||
}
|
||||
tabClone.setAttribute("drag-image", "true");
|
||||
wrapper.appendChild(tabClone);
|
||||
if (isTab(tabClone)) {
|
||||
// We need to limit the label content so the drag image doesn't grow too big.
|
||||
const label = tabClone.textLabel;
|
||||
const tabLabelParentWidth =
|
||||
label.parentElement.getBoundingClientRect().width;
|
||||
label.textContent = label.textContent.slice(
|
||||
0,
|
||||
Math.floor(tabLabelParentWidth / 6)
|
||||
);
|
||||
} else if (
|
||||
gBrowser.isTabGroup(tabClone) &&
|
||||
tabClone.hasAttribute("split-view-group")
|
||||
) {
|
||||
for (const tabInGroup of tab.tabs) {
|
||||
tabClone.appendChild(tabInGroup.cloneNode(true));
|
||||
}
|
||||
}
|
||||
this.#maybeCreateDragImageDot(movingTabs, wrapper);
|
||||
this._tempDragImageParent = wrapper;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
#maybeCreateDragImageDot(movingTabs, wrapper) {
|
||||
@@ -255,7 +277,10 @@
|
||||
return;
|
||||
}
|
||||
return this.#animateVerticalPinnedGridDragOver(event);
|
||||
} else if (this._fakeEssentialTab) {
|
||||
} else if (
|
||||
this.#dragImageEssential &&
|
||||
!event.target.closest("zen-essentials-promo")
|
||||
) {
|
||||
this.#makeDragImageNonEssential(event);
|
||||
}
|
||||
let dragData = draggedTab._dragData;
|
||||
@@ -557,7 +582,7 @@
|
||||
dropElementSize
|
||||
);
|
||||
|
||||
moveOverThreshold = gBrowser._tabGroupsEnabled
|
||||
moveOverThreshold = gBrowser.tabGroupsEnabled
|
||||
? Services.prefs.getIntPref(
|
||||
"browser.tabs.dragDrop.moveOverThresholdPercent"
|
||||
) / 100
|
||||
@@ -902,9 +927,54 @@
|
||||
}
|
||||
this.#isOutOfWindow = false;
|
||||
const dt = event.dataTransfer;
|
||||
for (const extra of this._extraDragImages ?? []) {
|
||||
this.#restoreExtraDragImage(extra);
|
||||
}
|
||||
dt.updateDragImage(...this.originalDragImageArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Out of the window, every dragged tab becomes the window. Each further
|
||||
* drag item gets a copy of the preview the drag image shows.
|
||||
*
|
||||
* @param {Element} extra - The image of a further tab
|
||||
* @param {HTMLCanvasElement} canvas - The window preview
|
||||
*/
|
||||
#previewExtraDragImage(extra, canvas) {
|
||||
if (extra._tabContents) {
|
||||
return;
|
||||
}
|
||||
extra._tabContents = {
|
||||
nodes: [...extra.childNodes],
|
||||
width: extra.style.width,
|
||||
height: extra.style.height,
|
||||
};
|
||||
const copy = document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"canvas"
|
||||
);
|
||||
copy.width = canvas.width;
|
||||
copy.height = canvas.height;
|
||||
copy.getContext("2d").drawImage(canvas, 0, 0);
|
||||
copy.style.width = copy.style.height = "100%";
|
||||
copy.style.borderRadius = canvas.style.borderRadius;
|
||||
copy.style.border = canvas.style.border;
|
||||
extra.style.width = this._browserDragImageWrapper.style.width;
|
||||
extra.style.height = this._browserDragImageWrapper.style.height;
|
||||
extra.replaceChildren(copy);
|
||||
}
|
||||
|
||||
#restoreExtraDragImage(extra) {
|
||||
const contents = extra._tabContents;
|
||||
if (!contents) {
|
||||
return;
|
||||
}
|
||||
delete extra._tabContents;
|
||||
extra.style.width = contents.width;
|
||||
extra.style.height = contents.height;
|
||||
extra.replaceChildren(...contents.nodes);
|
||||
}
|
||||
|
||||
handle_windowDragLeave(event) {
|
||||
// If relatedTarget exists, then we are still in the window
|
||||
if (
|
||||
@@ -930,8 +1000,6 @@
|
||||
this.clearDragOverVisuals();
|
||||
this.clearSpaceSwitchTimer();
|
||||
const dt = event.dataTransfer;
|
||||
let dragData = draggedTab._dragData;
|
||||
let movingTabs = dragData.movingTabs;
|
||||
if (!this._browserDragImageWrapper) {
|
||||
const wrappingDiv = document.createXULElement("vbox");
|
||||
canvas.style.borderRadius = "8px";
|
||||
@@ -939,11 +1007,13 @@
|
||||
wrappingDiv.style.width = 200 + "px";
|
||||
wrappingDiv.style.height = 130 + "px";
|
||||
wrappingDiv.style.position = "relative";
|
||||
this.#maybeCreateDragImageDot(movingTabs, wrappingDiv);
|
||||
wrappingDiv.appendChild(canvas);
|
||||
this._browserDragImageWrapper = wrappingDiv;
|
||||
document.documentElement.appendChild(wrappingDiv);
|
||||
}
|
||||
for (const extra of this._extraDragImages ?? []) {
|
||||
this.#previewExtraDragImage(extra, canvas);
|
||||
}
|
||||
dt.updateDragImage(
|
||||
this._browserDragImageWrapper,
|
||||
this.originalDragImageArgs[1],
|
||||
@@ -975,6 +1045,45 @@
|
||||
this.#handle_dropSwitchSpace(event);
|
||||
this.#handle_dropCreateSplit(event);
|
||||
this._clearDragOverSplit();
|
||||
this.#landDragImage(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the drag image land on the dropped tab rather than vanish. The OS
|
||||
* slides it onto the tab's new place and ends the drag once it is there,
|
||||
* which is when the tab shows again. Only macOS does so.
|
||||
*
|
||||
* @param {DragEvent} event - The drop
|
||||
*/
|
||||
#landDragImage(event) {
|
||||
// The drop is done, so its indicator goes before the image lands.
|
||||
this.clearDragOverVisuals();
|
||||
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
if (draggedTab?.documentGlobal !== window || gReduceMotion) {
|
||||
return;
|
||||
}
|
||||
const elements = (this._dragImageTabs ?? [draggedTab])
|
||||
.map(elementToMove)
|
||||
.filter(element => element?.isConnected);
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
for (const tab of this._dragImageTabs ?? [draggedTab]) {
|
||||
const element = elementToMove(tab);
|
||||
const rect = (
|
||||
element?.isConnected ? element : elements[0]
|
||||
).getBoundingClientRect();
|
||||
this.ZenDragAndDropService.addDropLandingRect(
|
||||
Math.round(window.mozInnerScreenX + rect.left),
|
||||
Math.round(window.mozInnerScreenY + rect.top),
|
||||
Math.round(rect.width),
|
||||
Math.round(rect.height)
|
||||
);
|
||||
}
|
||||
for (const element of elements) {
|
||||
element.style.visibility = "hidden";
|
||||
}
|
||||
this._landingElements = elements;
|
||||
}
|
||||
|
||||
#handle_dropSwitchSpace(event) {
|
||||
@@ -1175,6 +1284,10 @@
|
||||
let ownerGlobal = draggedTab?.documentGlobal;
|
||||
draggedTab.style.visibility = "";
|
||||
let thisFromGlobal = ownerGlobal?.gBrowser.tabContainer.tabDragAndDrop;
|
||||
for (const element of thisFromGlobal._landingElements ?? []) {
|
||||
element.style.visibility = "";
|
||||
}
|
||||
delete thisFromGlobal._landingElements;
|
||||
let currentEssenialContainer =
|
||||
ownerGlobal.gZenWorkspaces.getCurrentEssentialsContainer();
|
||||
if (currentEssenialContainer?.essentialsPromo) {
|
||||
@@ -1211,6 +1324,11 @@
|
||||
thisFromGlobal._tempDragImageParent.remove();
|
||||
delete thisFromGlobal._tempDragImageParent;
|
||||
}
|
||||
for (const extra of thisFromGlobal._extraDragImages ?? []) {
|
||||
extra.remove();
|
||||
}
|
||||
delete thisFromGlobal._extraDragImages;
|
||||
delete thisFromGlobal._dragImageTabs;
|
||||
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
|
||||
if (dt.dropEffect !== "move") {
|
||||
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
|
||||
@@ -1494,6 +1612,7 @@
|
||||
switch (essentialsPromoStatus) {
|
||||
case "shown":
|
||||
case "created":
|
||||
this.#makeDragImageEssential(event);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1781,53 +1900,131 @@
|
||||
#makeDragImageEssential(event) {
|
||||
const dt = event.dataTransfer;
|
||||
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
if (draggedTab.hasAttribute("zen-essential")) {
|
||||
if (this.#dragImageEssential) {
|
||||
return;
|
||||
}
|
||||
this.#dragImageEssential = true;
|
||||
const dragData = draggedTab._dragData;
|
||||
const [wrapper] = this.originalDragImageArgs;
|
||||
const tab = wrapper.firstElementChild;
|
||||
tab.setAttribute("zen-essential", "true");
|
||||
tab.setAttribute("pinned", "true");
|
||||
tab.setAttribute("selected", "true");
|
||||
const draggedTabRect = window.windowUtils.getBoundsWithoutFlushing(
|
||||
this._fakeEssentialTab
|
||||
const wasEssential = draggedTab.hasAttribute("zen-essential");
|
||||
const draggedTabRect = this.#essentialTileRect(event, draggedTab);
|
||||
for (const { wrapper, tab } of this.#dragImageClones(draggedTab)) {
|
||||
tab.setAttribute("zen-essential", "true");
|
||||
tab.setAttribute("pinned", "true");
|
||||
tab.setAttribute("selected", "true");
|
||||
tab.style.minWidth =
|
||||
tab.style.maxWidth =
|
||||
wrapper.style.width =
|
||||
draggedTabRect.width + "px";
|
||||
tab.style.minHeight =
|
||||
tab.style.maxHeight =
|
||||
wrapper.style.height =
|
||||
draggedTabRect.height + "px";
|
||||
if (wasEssential) {
|
||||
// Back to how the drag began.
|
||||
tab.style.transform = "";
|
||||
continue;
|
||||
}
|
||||
const offsetY = dragData.offsetY;
|
||||
const offsetX = dragData.offsetX;
|
||||
// Apply a transform translate to the tab in order to center it within the drag image
|
||||
tab.style.transform = `translate(${(54 - offsetX) / 2}px, ${(50 - offsetY) / 2}px)`;
|
||||
gZenPinnedTabManager.setEssentialTabIcon(tab);
|
||||
}
|
||||
if (wasEssential) {
|
||||
dt.updateDragImage(...this.originalDragImageArgs);
|
||||
} else {
|
||||
dt.updateDragImage(this.originalDragImageArgs[0], -16, -16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Every drag image with the tab it shows. The drag image itself and,
|
||||
* on macOS, one for each further dragged tab.
|
||||
*
|
||||
* @param {Element} draggedTab
|
||||
* @returns {{wrapper: Element, tab: Element, source: Element}[]} Each
|
||||
* image's wrapper, the clone in it, and the tab it was cloned from
|
||||
*/
|
||||
#dragImageClones(draggedTab) {
|
||||
const wrappers = [
|
||||
this.originalDragImageArgs[0],
|
||||
...(this._extraDragImages ?? []),
|
||||
];
|
||||
const sources = this._dragImageTabs ?? [draggedTab];
|
||||
return wrappers.map((wrapper, i) => ({
|
||||
wrapper,
|
||||
tab: wrapper.firstElementChild,
|
||||
source: sources[i] ?? draggedTab,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* The size the dragged tab takes as an essential. Its own when it is
|
||||
* one, the tile made for it in the grid, or, with only the promo shown,
|
||||
* a tile as the grid would lay it out.
|
||||
*
|
||||
* @param {DragEvent} event
|
||||
* @param {Element} draggedTab
|
||||
* @returns {{width: number, height: number}}
|
||||
*/
|
||||
#essentialTileRect(event, draggedTab) {
|
||||
const bounds = element =>
|
||||
window.windowUtils.getBoundsWithoutFlushing(element);
|
||||
if (draggedTab.hasAttribute("zen-essential")) {
|
||||
return bounds(draggedTab);
|
||||
}
|
||||
if (this._fakeEssentialTab?.isConnected) {
|
||||
return bounds(this._fakeEssentialTab);
|
||||
}
|
||||
const container =
|
||||
event.target.closest(".zen-essentials-container") ??
|
||||
gZenWorkspaces.getCurrentEssentialsContainer();
|
||||
const height = parseFloat(
|
||||
getComputedStyle(container).getPropertyValue("--tab-min-height")
|
||||
);
|
||||
tab.style.minWidth =
|
||||
tab.style.maxWidth =
|
||||
wrapper.style.width =
|
||||
draggedTabRect.width + "px";
|
||||
tab.style.minHeight =
|
||||
tab.style.maxHeight =
|
||||
wrapper.style.height =
|
||||
draggedTabRect.height + "px";
|
||||
const offsetY = dragData.offsetY;
|
||||
const offsetX = dragData.offsetX;
|
||||
// Apply a transform translate to the tab in order to center it within the drag image
|
||||
tab.style.transform = `translate(${(54 - offsetX) / 2}px, ${(50 - offsetY) / 2}px)`;
|
||||
gZenPinnedTabManager.setEssentialTabIcon(tab);
|
||||
dt.updateDragImage(wrapper, -16, -16);
|
||||
return {
|
||||
width: Math.max(bounds(container).width * 0.237, height + 4),
|
||||
height,
|
||||
};
|
||||
}
|
||||
|
||||
#makeDragImageNonEssential(event) {
|
||||
const dt = event.dataTransfer;
|
||||
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
if (draggedTab.hasAttribute("zen-essential")) {
|
||||
if (!this.#dragImageEssential) {
|
||||
return;
|
||||
}
|
||||
const wrapper = this.originalDragImageArgs[0];
|
||||
const tab = wrapper.firstElementChild;
|
||||
tab.style.setProperty("transition", "none", "important");
|
||||
tab.removeAttribute("zen-essential");
|
||||
tab.removeAttribute("pinned");
|
||||
tab.style.minWidth = tab.style.maxWidth = "";
|
||||
tab.style.minHeight = tab.style.maxHeight = "";
|
||||
tab.style.transform = "";
|
||||
const rect = window.windowUtils.getBoundsWithoutFlushing(draggedTab);
|
||||
wrapper.style.width = rect.width + "px";
|
||||
wrapper.style.height = rect.height + "px";
|
||||
this.#dragImageEssential = false;
|
||||
// An essential takes the size of a row in the strip, as any tab there.
|
||||
let model = draggedTab;
|
||||
if (draggedTab.hasAttribute("zen-essential")) {
|
||||
model =
|
||||
this._tabbrowserTabs.ariaFocusableItems.find(
|
||||
item => isTab(item) && !item.hasAttribute("zen-essential")
|
||||
) ?? draggedTab;
|
||||
}
|
||||
const rect = window.windowUtils.getBoundsWithoutFlushing(model);
|
||||
const clones = this.#dragImageClones(draggedTab);
|
||||
for (const { wrapper, tab, source } of clones) {
|
||||
tab.style.setProperty("transition", "none", "important");
|
||||
tab.removeAttribute("zen-essential");
|
||||
tab.removeAttribute("pinned");
|
||||
tab.style.minWidth = tab.style.maxWidth = "";
|
||||
tab.style.minHeight = tab.style.maxHeight = "";
|
||||
tab.style.transform = "";
|
||||
wrapper.style.width = rect.width + "px";
|
||||
wrapper.style.height = rect.height + "px";
|
||||
if (source.hasAttribute("zen-essential") && tab.textLabel) {
|
||||
tab.textLabel.textContent = source.label.slice(
|
||||
0,
|
||||
Math.floor(rect.width / 6)
|
||||
);
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
tab.style.transition = "";
|
||||
for (const { tab } of clones) {
|
||||
tab.style.transition = "";
|
||||
}
|
||||
dt.updateDragImage(...this.originalDragImageArgs);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@ SOURCES += [
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
SOURCES += ["nsZenNativeWindowMove.mm"]
|
||||
SOURCES += [
|
||||
"nsZenDropLandingCocoa.mm",
|
||||
"nsZenNativeWindowMove.mm",
|
||||
]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
||||
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface mozIDOMWindowProxy;
|
||||
webidl Node;
|
||||
|
||||
/**
|
||||
* @brief Interface for Zen's drag and drop functionality.
|
||||
@@ -33,4 +34,24 @@ interface nsIZenDragAndDrop : nsISupports {
|
||||
* @param window The chrome window to move.
|
||||
*/
|
||||
void beginNativeWindowMove(in mozIDOMWindowProxy window);
|
||||
|
||||
/**
|
||||
* @brief Slide the drag image onto the drop instead of removing it.
|
||||
* macOS only, the drag ends once it lands.
|
||||
* @param arm Whether this drag's drops land the image.
|
||||
*/
|
||||
void armDropLanding(in boolean arm);
|
||||
|
||||
/**
|
||||
* @brief Drag an extra image along as its own item, one per further tab.
|
||||
* macOS stacks and counts them. Add before the drag starts.
|
||||
* @param image The element to render.
|
||||
*/
|
||||
void addDragImage(in Node image);
|
||||
|
||||
/**
|
||||
* @brief Where a drag item lands, in screen CSS pixels. One call per
|
||||
* item in order, from within the drop event.
|
||||
*/
|
||||
void addDropLandingRect(in long x, in long y, in long width, in long height);
|
||||
};
|
||||
|
||||
@@ -91,9 +91,37 @@ nsZenDragAndDrop::OnDragStart(float opacity) {
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::OnDragEnd() {
|
||||
mDragImageOpacity = kZenDefaultDragImageOpacity;
|
||||
mDropLandingArmed = false;
|
||||
mDragImages.Clear();
|
||||
mDropLandingRects.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::ArmDropLanding(bool aArm) {
|
||||
mDropLandingArmed = aArm;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::AddDragImage(nsINode* aImage) {
|
||||
NS_ENSURE_ARG_POINTER(aImage);
|
||||
mDragImages.AppendElement(aImage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::AddDropLandingRect(int32_t aX, int32_t aY, int32_t aWidth,
|
||||
int32_t aHeight) {
|
||||
mDropLandingRects.AppendElement(
|
||||
mozilla::DesktopIntRect(aX, aY, aWidth, aHeight));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<mozilla::DesktopIntRect> nsZenDragAndDrop::TakeDropLandingRects() {
|
||||
return std::move(mDropLandingRects);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenDragAndDrop::BeginNativeWindowMove(mozIDOMWindowProxy* aWindow) {
|
||||
NS_ENSURE_ARG_POINTER(aWindow);
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
|
||||
#include "nsIZenDragAndDrop.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "Units.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__OBJC__)
|
||||
@protocol NSDraggingInfo;
|
||||
#endif
|
||||
|
||||
#define ZEN_DND_MANAGER_CONTRACTID "@mozilla.org/zen/drag-and-drop;1"
|
||||
|
||||
@@ -26,6 +33,15 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
|
||||
public:
|
||||
explicit nsZenDragAndDrop();
|
||||
auto GetDragImageOpacity() const { return mDragImageOpacity; }
|
||||
auto DropLandingArmed() const { return mDropLandingArmed; }
|
||||
const auto& DragImages() const { return mDragImages; }
|
||||
|
||||
/**
|
||||
* @brief Take the rects the drag items are to land on after the drop
|
||||
* being handled, as the drop added them, in screen CSS pixels and item
|
||||
* order. Empty when the drop added none.
|
||||
*/
|
||||
nsTArray<mozilla::DesktopIntRect> TakeDropLandingRects();
|
||||
|
||||
/**
|
||||
* @brief Get the singleton instance of nsZenDragAndDrop. There may be
|
||||
@@ -39,8 +55,25 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
|
||||
private:
|
||||
~nsZenDragAndDrop() = default;
|
||||
float mDragImageOpacity{};
|
||||
bool mDropLandingArmed{};
|
||||
nsTArray<nsCOMPtr<nsINode>> mDragImages;
|
||||
nsTArray<mozilla::DesktopIntRect> mDropLandingRects;
|
||||
};
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__OBJC__)
|
||||
/**
|
||||
* @brief From the drag destination view, once a dragover is handled, ask
|
||||
* the OS to land the drag image on the drop, if the drag wants that.
|
||||
*/
|
||||
void PrepareDropLanding(id<NSDraggingInfo> aInfo);
|
||||
|
||||
/**
|
||||
* @brief From the drag destination view, once a drop is handled, send the
|
||||
* drag image to the rect the drop set, if it set one.
|
||||
*/
|
||||
void LandDrop(id<NSDraggingInfo> aInfo);
|
||||
#endif
|
||||
|
||||
} // namespace zen
|
||||
|
||||
#endif
|
||||
|
||||
54
src/zen/drag-and-drop/nsZenDropLandingCocoa.mm
Normal file
54
src/zen/drag-and-drop/nsZenDropLandingCocoa.mm
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsZenDragAndDrop.h"
|
||||
|
||||
namespace zen {
|
||||
|
||||
void PrepareDropLanding(id<NSDraggingInfo> aInfo) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
auto zen = nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||
aInfo.animatesToDestination = zen && zen->DropLandingArmed();
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
void LandDrop(id<NSDraggingInfo> aInfo) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
auto zen = nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||
if (!zen) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray* targets = [NSMutableArray array];
|
||||
for (const auto& landing : zen->TakeDropLandingRects()) {
|
||||
[targets
|
||||
addObject:[NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(
|
||||
landing)]];
|
||||
}
|
||||
if (!targets.count) {
|
||||
return;
|
||||
}
|
||||
[aInfo enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
||||
forView:nil
|
||||
classes:@[ [NSPasteboardItem class] ]
|
||||
searchOptions:@{}
|
||||
usingBlock:^(NSDraggingItem* item, NSInteger idx, BOOL* stop) {
|
||||
NSRect target =
|
||||
[targets[MIN((NSUInteger)idx, targets.count - 1)] rectValue];
|
||||
NSRect frame = item.draggingFrame;
|
||||
frame.origin.x = target.origin.x;
|
||||
frame.origin.y = NSMaxY(target) - frame.size.height;
|
||||
item.draggingFrame = frame;
|
||||
}];
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
} // namespace zen
|
||||
@@ -327,7 +327,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
||||
if (isActiveFolder) {
|
||||
for (const folder of group.activeGroups) {
|
||||
folder.activeTabs = [...new Set([...folder.activeTabs, tab])].sort(
|
||||
(a, b) => a._tPos > b._tPos
|
||||
(a, b) => a.index - b.index
|
||||
);
|
||||
this.setFolderIndentation([tab], folder, /* for collapse = */ true);
|
||||
}
|
||||
@@ -378,7 +378,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
||||
if (isActiveFolder && isSplitView) {
|
||||
parentFolder.activeTabs = [
|
||||
...new Set([...parentFolder.activeTabs, ...folder.tabs]),
|
||||
].sort((a, b) => a._tPos > b._tPos);
|
||||
].sort((a, b) => a.index - b.index);
|
||||
}
|
||||
parentFolder.collapsed = isActiveFolder;
|
||||
}
|
||||
@@ -1919,7 +1919,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
||||
// It is important to keep the sequence of elements as in the DOM
|
||||
currentGroup.activeTabs = [
|
||||
...new Set([...currentGroup.activeTabs, ...activeTabs]),
|
||||
].sort((a, b) => a._tPos > b._tPos);
|
||||
].sort((a, b) => a.index - b.index);
|
||||
} else {
|
||||
currentGroup.setAttribute("has-active", "true");
|
||||
currentGroup.activeTabs = activeTabs;
|
||||
|
||||
@@ -6,7 +6,8 @@ const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
|
||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||
FeatureCallout: "resource:///modules/asrouter/FeatureCallout.sys.mjs",
|
||||
});
|
||||
|
||||
@@ -11,9 +11,12 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
ZenLiveFoldersManager:
|
||||
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
|
||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStartup:
|
||||
"moz-src:///browser/components/sessionstore/SessionStartup.sys.mjs",
|
||||
TabStateFlusher:
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||
gWindowSyncEnabled: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||
gSyncOnlyPinnedTabs: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
|
||||
|
||||
@@ -10,13 +10,15 @@ const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
||||
TabStateFlusher:
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||
// eslint-disable-next-line mozilla/valid-lazy
|
||||
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||
RunState: "resource:///modules/sessionstore/RunState.sys.mjs",
|
||||
RunState: "moz-src:///browser/components/sessionstore/RunState.sys.mjs",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
|
||||
@@ -8,7 +8,8 @@ import { nsZenThemePicker } from "resource:///modules/zen/ZenGradientGenerator.m
|
||||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
ZenShareClient: "resource:///modules/zen/share/ZenShareClient.sys.mjs",
|
||||
ZenShareError: "resource:///modules/zen/share/ZenShareClient.sys.mjs",
|
||||
});
|
||||
@@ -440,8 +441,8 @@ class nsZenShareManager extends nsZenDOMOperatedFeature {
|
||||
gZenUIManager.motion
|
||||
.animate(
|
||||
group,
|
||||
{ x: [-28, 0] },
|
||||
{ type: "spring", bounce: 0.9, duration: 1.4 }
|
||||
{ x: [-32, 0] },
|
||||
{ type: "spring", bounce: 0.5, duration: 1.5 }
|
||||
)
|
||||
.then(() => {
|
||||
group.style.removeProperty("transform");
|
||||
|
||||
@@ -1773,10 +1773,10 @@ class nsZenWorkspaces {
|
||||
if (this.tabContainer) {
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
}
|
||||
// Fix tabs _tPos values relative to the actual order
|
||||
// Fix tabs _index values relative to the actual order
|
||||
const tabs = gBrowser.tabs;
|
||||
const usedGroups = new Set();
|
||||
let tPos = 0; // _tPos is used for the session store, not needed for folders
|
||||
let tPos = 0; // _index is used for the session store, not needed for folders
|
||||
let pPos = 0; // _pPos is used for the pinned tabs manager
|
||||
const recurseFolder = tab => {
|
||||
if (tab.group) {
|
||||
@@ -1789,7 +1789,7 @@ class nsZenWorkspaces {
|
||||
};
|
||||
for (const tab of tabs) {
|
||||
recurseFolder(tab);
|
||||
tab._tPos = tPos++;
|
||||
tab._index = tPos++;
|
||||
if (!tab.hasAttribute("zen-empty-tab")) {
|
||||
tab._pPos = pPos++;
|
||||
}
|
||||
|
||||
@@ -352,6 +352,8 @@ zen-workspace {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: color-mix(in srgb, currentColor 35%, transparent 65%) transparent; /* Custom scrollbar */
|
||||
overflow-y: auto;
|
||||
padding-block-end: 120px;
|
||||
overscroll-behavior: auto;
|
||||
}
|
||||
|
||||
:root[swipe-gesture] &::part(scrollbox) {
|
||||
|
||||
@@ -1601,7 +1601,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
tab.hasAttribute("pending")
|
||||
);
|
||||
if (pendingTabs.length) {
|
||||
pendingTabs.forEach(tab => gBrowser._insertBrowser(tab));
|
||||
pendingTabs.forEach(tab => gBrowser.insertBrowser(tab));
|
||||
// SessionStore listens for this on the tab container and restores each
|
||||
// tab's saved history, scroll position and form data. Kept non-bubbling
|
||||
// so it doesn't reach tabbrowser, which tracks Firefox's own split view.
|
||||
|
||||
@@ -23,10 +23,13 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||
);
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionSaver: "resource:///modules/sessionstore/SessionSaver.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionSaver:
|
||||
"moz-src:///browser/components/sessionstore/SessionSaver.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||
ZenLiveFoldersManager:
|
||||
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
|
||||
|
||||
@@ -34,7 +34,8 @@ class ZenPinnedTabsObserver {
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
// eslint-disable-next-line mozilla/valid-lazy
|
||||
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
});
|
||||
this.#listenPinnedTabEvents();
|
||||
}
|
||||
|
||||
@@ -329,6 +329,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
&[drag-image] {
|
||||
border-radius: calc(var(--border-radius-medium) / var(--zen-squircle-value));
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
|
||||
:root:not([zen-renaming-tab="true"])
|
||||
#tabbrowser-tabs:not([movingtab])
|
||||
@@ -1268,10 +1272,6 @@
|
||||
left: calc(var(--indicator-left) + 2 * var(--zen-drag-indicator-height) + 4px);
|
||||
width: calc(var(--indicator-width) - 2 * var(--zen-drag-indicator-height) - 4px);
|
||||
height: var(--zen-drag-indicator-height);
|
||||
transition:
|
||||
top 0.05s ease-out,
|
||||
left 0.05s ease-out,
|
||||
width 0.05s ease-out;
|
||||
|
||||
&::before {
|
||||
left: calc(-2 * var(--zen-drag-indicator-height));
|
||||
@@ -1284,10 +1284,6 @@
|
||||
top: calc(var(--indicator-top) + 2 * var(--zen-drag-indicator-height) + 4px);
|
||||
height: calc(var(--indicator-height) - 2 * var(--zen-drag-indicator-height) - 4px);
|
||||
width: var(--zen-drag-indicator-height);
|
||||
transition:
|
||||
top 0.1s ease-out,
|
||||
left 0.1s ease-out,
|
||||
height 0.1s ease-out;
|
||||
|
||||
&::before {
|
||||
top: calc(-2 * var(--zen-drag-indicator-height));
|
||||
|
||||
@@ -11,10 +11,10 @@ const { ZenSpacesSyncApplier } = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/ZenSpacesSyncApplier.sys.mjs"
|
||||
);
|
||||
const { SessionSaver } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionSaver.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionSaver.sys.mjs"
|
||||
);
|
||||
const { TabStateFlusher } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs"
|
||||
);
|
||||
const { TestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/TestUtils.sys.mjs"
|
||||
|
||||
@@ -44,8 +44,16 @@ add_task(async function test_Issue_9981() {
|
||||
|
||||
const tab2ResetButton = tab2.querySelector(".tab-reset-button");
|
||||
tab2ResetButton.style.display = "flex";
|
||||
await TestUtils.waitForCondition(
|
||||
() => tab2ResetButton.getBoundingClientRect().width != 0
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(tab2ResetButton, {});
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() => !tab2.hasAttribute("folder-active"),
|
||||
"Tab 2 should be unloaded out of the active folder"
|
||||
);
|
||||
|
||||
ok(
|
||||
tab1.hasAttribute("folder-active"),
|
||||
"Tab 1 should be in the active folder"
|
||||
|
||||
@@ -17,8 +17,8 @@ add_task(async function test_Glance_Basic_Open() {
|
||||
"There should be no zen-glance-tab attribute on any tab"
|
||||
);
|
||||
Assert.greater(
|
||||
glanceTab._tPos,
|
||||
selectedTab._tPos,
|
||||
glanceTab.index,
|
||||
selectedTab.index,
|
||||
"The glance tab should be on the right of the selected tab"
|
||||
);
|
||||
BrowserTestUtils.removeTab(glanceTab);
|
||||
@@ -42,8 +42,8 @@ add_task(async function test_Glance_Open_Sibling() {
|
||||
await openGlanceOnTab(async glanceTab => {
|
||||
await gZenGlanceManager.fullyOpenGlance();
|
||||
Assert.equal(
|
||||
glanceTab._tPos,
|
||||
selectedTab._tPos + 1,
|
||||
glanceTab._index,
|
||||
selectedTab._index + 1,
|
||||
"The glance tab should be on the right of the selected tab"
|
||||
);
|
||||
BrowserTestUtils.removeTab(glanceTab);
|
||||
|
||||
@@ -19,7 +19,7 @@ add_task(async function test_Glance_Select_Parent() {
|
||||
);
|
||||
const tabToRemove = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gZenGlanceManager.getTabOrGlanceParent(glanceTab);
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return glanceTab.selected;
|
||||
});
|
||||
ok(true, "The glance tab should be selected");
|
||||
|
||||
@@ -146,6 +146,12 @@ xpcshell = true
|
||||
source = "browser/components/tabbrowser/test/browser/tabMediaIndicator"
|
||||
is_direct_path = true
|
||||
|
||||
[tabMediaIndicator.replace-manifest]
|
||||
"[DEFAULT]" = """[DEFAULT]
|
||||
prefs = [
|
||||
"zen.window-sync.enabled=false",
|
||||
]"""
|
||||
|
||||
[tooltiptext]
|
||||
source = "toolkit/components/tooltiptext"
|
||||
disable = [
|
||||
|
||||
@@ -21,7 +21,7 @@ add_task(async function test_media_bar_shows_metadata_from_page() {
|
||||
const titleEl = card.querySelector(".zen-media-title");
|
||||
const artistEl = card.querySelector(".zen-media-artist");
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => titleEl.textContent === "Sandstorm",
|
||||
"title label reflects the page's mediaSession metadata"
|
||||
);
|
||||
@@ -36,7 +36,7 @@ add_task(async function test_media_bar_shows_metadata_from_page() {
|
||||
title: "Levels",
|
||||
artist: "Avicii",
|
||||
});
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => titleEl.textContent === "Levels",
|
||||
"title updates live when the page changes its mediaSession metadata"
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ add_task(async function test_mute_from_media_bar() {
|
||||
);
|
||||
|
||||
clickMediaButton("zen-media-mute-button");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => mediaTab.linkedBrowser.audioMuted,
|
||||
"tab becomes muted after clicking the media bar mute button"
|
||||
);
|
||||
@@ -34,7 +34,7 @@ add_task(async function test_mute_from_media_bar() {
|
||||
);
|
||||
|
||||
clickMediaButton("zen-media-mute-button");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => !mediaTab.linkedBrowser.audioMuted,
|
||||
"clicking again unmutes the tab"
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ add_task(async function test_next_track_relays_to_page() {
|
||||
|
||||
// supportedkeyschange propagates asynchronously; wait for the bar's
|
||||
// next-track button to become enabled before clicking.
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => !nextButton.disabled,
|
||||
"next-track button becomes enabled once the page registers a handler"
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
add_task(async function test_media_bar_shows_when_switching_off_playing_tab() {
|
||||
gZenMediaController.closeAllCards();
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => !isMediaBarVisible(),
|
||||
"media bar hides again once the playing tab regains focus"
|
||||
);
|
||||
@@ -31,7 +31,7 @@ add_task(async function test_media_bar_shows_when_switching_off_playing_tab() {
|
||||
// timer; wait for the visibility flip rather than racing it.
|
||||
await BrowserTestUtils.switchTab(gBrowser, originalTab);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
isMediaBarVisible,
|
||||
"media bar becomes visible after switching off the playing tab"
|
||||
);
|
||||
@@ -44,7 +44,7 @@ add_task(async function test_media_bar_shows_when_switching_off_playing_tab() {
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, mediaTab);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => !isMediaBarVisible(),
|
||||
"media bar hides again once the playing tab regains focus"
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ add_task(async function test_media_stack_shows_multiple_cards() {
|
||||
await waitForMediaBarVisible();
|
||||
|
||||
// Cards reappear on the 500ms tab-switch debounce; wait for both.
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => visibleMediaCards().length === 2,
|
||||
"both playing tabs get their own card in the stack"
|
||||
);
|
||||
@@ -32,7 +32,7 @@ add_task(async function test_media_stack_shows_multiple_cards() {
|
||||
"front card belongs to the most recently started media"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
await TestUtils.waitForCondition(() => {
|
||||
const titles = visibleMediaCards().map(
|
||||
card => card.querySelector(".zen-media-title").textContent
|
||||
);
|
||||
@@ -41,7 +41,7 @@ add_task(async function test_media_stack_shows_multiple_cards() {
|
||||
|
||||
// Closing the front card only removes that session.
|
||||
clickMediaButton("zen-media-close-button");
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => visibleMediaCards().length === 1,
|
||||
"closing the front card only removes that card"
|
||||
);
|
||||
|
||||
@@ -31,7 +31,7 @@ async function playVideoIn(tab) {
|
||||
);
|
||||
// Wait for the browser to actually consider the tab "playing" — this is
|
||||
// what drives the soundplaying TabAttrModified into the media controller.
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
() => tab.soundPlaying,
|
||||
"tab reports soundplaying"
|
||||
);
|
||||
@@ -57,7 +57,7 @@ function isMediaBarVisible() {
|
||||
}
|
||||
|
||||
async function waitForMediaBarVisible() {
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
await TestUtils.waitForCondition(
|
||||
isMediaBarVisible,
|
||||
"media bar becomes visible"
|
||||
);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
BrowserTestUtils: "resource://testing-common/BrowserTestUtils.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
TabStateFlusher:
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||
TestUtils: "resource://testing-common/TestUtils.sys.mjs",
|
||||
});
|
||||
|
||||
@@ -89,7 +91,7 @@ export var SessionStoreTestUtils = {
|
||||
"browser.sessionstore.restore_hidden_tabs"
|
||||
);
|
||||
// This should match the |restoreTabsLazily| value that
|
||||
// SessionStore.restoreWindow() uses.
|
||||
// SessionStore's #restoreWindow() uses.
|
||||
let restoreTabsLazily =
|
||||
Services.prefs.getBoolPref("browser.sessionstore.restore_on_demand") &&
|
||||
Services.prefs.getBoolPref("browser.sessionstore.restore_tabs_lazily");
|
||||
|
||||
@@ -293,6 +293,8 @@ disabled="Disabled by import_external_tests.py"
|
||||
["browser_restore_redirect.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_restore_respects_pending_minimize.js"]
|
||||
|
||||
["browser_restore_reversed_z_order.js"]
|
||||
skip-if = [
|
||||
"true", # Bug 1455602
|
||||
@@ -355,7 +357,7 @@ skip-if = [
|
||||
|
||||
["browser_sizemodeBeforeMinimized.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64' && opt && nova", # Bug 2057856
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64'", # Bug 2057856
|
||||
"os == 'win' && os_version == '11.26200' && asan", # Bug 2019745
|
||||
]
|
||||
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.require_user_interaction_for_beforeunload", false]],
|
||||
set: [
|
||||
["dom.require_user_interaction_for_beforeunload", false],
|
||||
// Keep the tab closing animation, which this test relies on to observe
|
||||
// a tab in its closing state.
|
||||
["ui.prefersReducedMotion", 0],
|
||||
],
|
||||
});
|
||||
|
||||
let url = "about:robots";
|
||||
@@ -37,12 +42,15 @@ add_task(async function test() {
|
||||
ok(tab0.linkedPanel, "active tab is not able to be suspended");
|
||||
|
||||
// Test that tab that is closing is not able to be suspended.
|
||||
gBrowser._beginRemoveTab(tab1);
|
||||
gBrowser.removeTab(tab1, { animate: true });
|
||||
gBrowser.discardBrowser(tab1);
|
||||
|
||||
ok(tab1.linkedPanel, "cannot suspend a tab that is closing");
|
||||
|
||||
gBrowser._endRemoveTab(tab1);
|
||||
await TestUtils.waitForCondition(
|
||||
() => !tab1.isConnected,
|
||||
"tab1 finished closing"
|
||||
);
|
||||
|
||||
// Open tab containing a page which has a beforeunload handler which shows a prompt.
|
||||
url =
|
||||
|
||||
@@ -17,7 +17,7 @@ add_task(async function test_urlbarFocus() {
|
||||
newWin = openDialog(
|
||||
location,
|
||||
"_blank",
|
||||
"chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no"
|
||||
"chrome,resizable,toolbar=no,dialog=no"
|
||||
);
|
||||
await promiseWindowLoaded(newWin);
|
||||
let state2 = ss.getWindowState(newWin);
|
||||
|
||||
@@ -64,6 +64,6 @@ function test_duplicateTab() {
|
||||
window.addEventListener("SSWindowStateReady", onSSWindowStateReady);
|
||||
gBrowser.tabContainer.addEventListener("SSTabRestoring", onSSTabRestoring);
|
||||
|
||||
gBrowser._insertBrowser(tab);
|
||||
gBrowser.insertBrowser(tab);
|
||||
newTab = ss.duplicateTab(window, tab);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,6 @@ function test_setTabState() {
|
||||
window.addEventListener("SSWindowStateReady", onSSWindowStateReady);
|
||||
tab.addEventListener("SSTabRestoring", onSSTabRestoring, { once: true });
|
||||
// Browser must be inserted in order to restore.
|
||||
gBrowser._insertBrowser(tab);
|
||||
gBrowser.insertBrowser(tab);
|
||||
ss.setTabState(tab, newTabState);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ add_task(async function test() {
|
||||
!gBrowser.browsers[1].isConnected,
|
||||
"The browser that we're attempting to insert is indeed lazy"
|
||||
);
|
||||
gBrowser._insertBrowser(gBrowser.tabs[1]);
|
||||
gBrowser.insertBrowser(gBrowser.tabs[1]);
|
||||
is(countNonLazyTabs(), 2, "Window now has 2 non-lazy tabs");
|
||||
|
||||
// Check if any lazy tabs got inserted when window closes.
|
||||
@@ -122,7 +122,7 @@ add_task(async function test() {
|
||||
!newWindow.gBrowser.browsers[1].isConnected,
|
||||
"The browser that we're attempting to insert is indeed lazy"
|
||||
);
|
||||
newWindow.gBrowser._insertBrowser(newWindow.gBrowser.tabs[1]);
|
||||
newWindow.gBrowser.insertBrowser(newWindow.gBrowser.tabs[1]);
|
||||
is(
|
||||
countNonLazyTabs(newWindow),
|
||||
1,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
TabStateCache:
|
||||
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore:
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { _LastSession } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
const { sinon } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/Sinon.sys.mjs"
|
||||
|
||||
@@ -153,7 +153,7 @@ skip-if = [
|
||||
|
||||
["browser_477657.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64' && opt && nova", # Bug 2057857
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64'", # Bug 2057857
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11'", # Bug 1610668
|
||||
]
|
||||
|
||||
@@ -184,7 +184,7 @@ skip-if = [
|
||||
|
||||
["browser_524745.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64' && debug && nova", # Bug 2057858
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64'", # Bug 2057858
|
||||
]
|
||||
|
||||
["browser_528776.js"]
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
const { _LastSession, _lastClosedActions } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
|
||||
/**
|
||||
* Tests that the _lastClosedAction list is truncated correctly
|
||||
* by removing oldest actions in SessionStore._addClosedAction
|
||||
* by removing oldest actions in SessionStore's #addClosedAction
|
||||
*/
|
||||
add_task(async function test_undo_last_action_correct_order() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
const { _LastSession, _lastClosedActions } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
|
||||
async function testLastClosedActionsEntries() {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/* 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/. */
|
||||
|
||||
const { sinon } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/Sinon.sys.mjs"
|
||||
);
|
||||
|
||||
function holdNextZeroTimeout(win) {
|
||||
const realSetTimeout = win.setTimeout.bind(win);
|
||||
let callback;
|
||||
let callbackArgs;
|
||||
let holding = true;
|
||||
|
||||
const stub = sinon.stub(win, "setTimeout").callsFake((fn, delay, ...args) => {
|
||||
if (!callback && delay === 0) {
|
||||
callback = fn;
|
||||
callbackArgs = args;
|
||||
return 1;
|
||||
}
|
||||
return realSetTimeout(fn, delay, ...args);
|
||||
});
|
||||
|
||||
return {
|
||||
stopHolding() {
|
||||
if (!holding) {
|
||||
return;
|
||||
}
|
||||
holding = false;
|
||||
stub.restore();
|
||||
Assert.ok(callback, "captured the window feature restore timer");
|
||||
},
|
||||
|
||||
run() {
|
||||
callback(...callbackArgs);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function setSizeMode(win, method) {
|
||||
const changed = BrowserTestUtils.waitForEvent(win, "sizemodechange");
|
||||
win[method]();
|
||||
await changed;
|
||||
}
|
||||
|
||||
function getWindowState(win, sizemode = "normal") {
|
||||
return {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
width: Math.max(200, win.outerWidth - 20),
|
||||
height: Math.max(200, win.outerHeight - 20),
|
||||
screenX: win.screenX,
|
||||
screenY: win.screenY,
|
||||
sizemode,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
add_task(async function test_minimize_while_restore_is_pending_wins() {
|
||||
const win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
let heldTimer;
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
if (!win.closed) {
|
||||
heldTimer?.stopHolding();
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
});
|
||||
|
||||
if (win.windowState != win.STATE_NORMAL) {
|
||||
await setSizeMode(win, "restore");
|
||||
}
|
||||
|
||||
heldTimer = holdNextZeroTimeout(win);
|
||||
const restoring = promiseWindowRestoring(win);
|
||||
const restored = promiseWindowRestored(win);
|
||||
ss.setWindowState(win, JSON.stringify(getWindowState(win)), true);
|
||||
await restoring;
|
||||
heldTimer.stopHolding();
|
||||
|
||||
if (win.windowState != win.STATE_MINIMIZED) {
|
||||
await setSizeMode(win, "minimize");
|
||||
}
|
||||
|
||||
heldTimer.run();
|
||||
await restored;
|
||||
|
||||
Assert.equal(
|
||||
win.windowState,
|
||||
win.STATE_MINIMIZED,
|
||||
"the newer minimized state is preserved"
|
||||
);
|
||||
|
||||
if (win.windowState == win.STATE_MINIMIZED) {
|
||||
await setSizeMode(win, "restore");
|
||||
}
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(async function test_initial_minimized_state_is_still_restored() {
|
||||
const win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
let heldTimer;
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
if (!win.closed) {
|
||||
heldTimer?.stopHolding();
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
});
|
||||
|
||||
if (win.windowState != win.STATE_MINIMIZED) {
|
||||
await setSizeMode(win, "minimize");
|
||||
}
|
||||
|
||||
heldTimer = holdNextZeroTimeout(win);
|
||||
const restoring = promiseWindowRestoring(win);
|
||||
const restored = promiseWindowRestored(win);
|
||||
ss.setWindowState(win, JSON.stringify(getWindowState(win)), true);
|
||||
await restoring;
|
||||
heldTimer.stopHolding();
|
||||
|
||||
const sizeModeChanged = BrowserTestUtils.waitForEvent(win, "sizemodechange");
|
||||
heldTimer.run();
|
||||
await Promise.all([restored, sizeModeChanged]);
|
||||
|
||||
Assert.equal(
|
||||
win.windowState,
|
||||
win.STATE_NORMAL,
|
||||
"still applies saved state when the window was already minimized"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
@@ -3,13 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const BARPROP_NAMES = [
|
||||
"locationbar",
|
||||
"menubar",
|
||||
"personalbar",
|
||||
"scrollbars",
|
||||
"toolbar",
|
||||
];
|
||||
const BARPROP_NAMES = ["locationbar", "menubar", "personalbar", "toolbar"];
|
||||
|
||||
function testFeatures(win, test) {
|
||||
for (let name of BARPROP_NAMES) {
|
||||
@@ -43,14 +37,13 @@ add_task(async function testRestoredWindowFeatures() {
|
||||
locationbar: true,
|
||||
menubar: true,
|
||||
personalbar: true,
|
||||
scrollbars: true,
|
||||
toolbar: true,
|
||||
};
|
||||
const TESTS = [
|
||||
{
|
||||
url: "http://example.com/browser/" + DUMMY_PAGE,
|
||||
features: "menubar=0,resizable",
|
||||
barprops: { scrollbars: true },
|
||||
barprops: { locationbar: true },
|
||||
chromeFlags: Ci.nsIWebBrowserChrome.CHROME_WINDOW_RESIZE,
|
||||
unsetFlags: Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG,
|
||||
},
|
||||
@@ -58,14 +51,14 @@ add_task(async function testRestoredWindowFeatures() {
|
||||
url: "data:,", // title should be empty
|
||||
checkContentTitleEmpty: true,
|
||||
features: "location,resizable",
|
||||
barprops: { locationbar: true, scrollbars: true },
|
||||
barprops: { locationbar: true },
|
||||
chromeFlags: Ci.nsIWebBrowserChrome.CHROME_WINDOW_RESIZE,
|
||||
unsetFlags: Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG,
|
||||
},
|
||||
{
|
||||
url: "http://example.com/browser/" + DUMMY_PAGE,
|
||||
features: "dialog,resizable",
|
||||
barprops: { scrollbars: true },
|
||||
barprops: { locationbar: true },
|
||||
chromeFlags:
|
||||
Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG |
|
||||
Ci.nsIWebBrowserChrome.CHROME_WINDOW_RESIZE,
|
||||
|
||||
@@ -18,23 +18,23 @@ const HTTPSROOT = ROOT.replace(
|
||||
);
|
||||
|
||||
const { SessionSaver } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionSaver.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionSaver.sys.mjs"
|
||||
);
|
||||
const { SessionFile } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionFile.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionFile.sys.mjs"
|
||||
);
|
||||
const { TabState } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabState.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/TabState.sys.mjs"
|
||||
);
|
||||
const { TabStateFlusher } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs"
|
||||
);
|
||||
const { SessionStoreTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/SessionStoreTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const { PageWireframes } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/PageWireframes.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/PageWireframes.sys.mjs"
|
||||
);
|
||||
|
||||
const ss = SessionStore;
|
||||
|
||||
@@ -48,6 +48,10 @@ skip-if = [
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64'", # Bug 1727691
|
||||
]
|
||||
|
||||
["test_shutdown_flush_timeout.py"]
|
||||
|
||||
["test_splitview_hidden.py"]
|
||||
|
||||
["test_splitview_restore.py"]
|
||||
|
||||
["test_tabgroups_restore.py"]
|
||||
|
||||
@@ -156,7 +156,7 @@ class SessionStoreTestCase(WindowManagerMixin, MarionetteTestCase):
|
||||
null,
|
||||
AppConstants.BROWSER_CHROME_URL,
|
||||
"_blank",
|
||||
"chrome,dialog=no,titlebar,close,toolbar,location,personalbar=no,status,menubar=no,resizable,minimizable,scrollbars",
|
||||
"chrome,dialog=no,titlebar,close,toolbar,location,personalbar=no,status,menubar=no,resizable,minimizable",
|
||||
args
|
||||
);
|
||||
await new Promise(resolve => {
|
||||
|
||||
@@ -246,7 +246,7 @@ class TestNewTabOnRestoreNotSettingBased(SessionStoreTestCase):
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
const { SessionStore } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
SessionStore.restoreLastSession();
|
||||
"""
|
||||
@@ -294,10 +294,10 @@ class TestNewTabOnRestoreAfterCrash(SessionStoreTestCase):
|
||||
let [resolve] = arguments;
|
||||
Services.prefs.savePrefFile(Services.dirsvc.get("PrefF", Ci.nsIFile));
|
||||
const { TabStateFlusher } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs"
|
||||
);
|
||||
const { SessionSaver } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionSaver.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionSaver.sys.mjs"
|
||||
);
|
||||
(async () => {
|
||||
for (let win of Services.wm.getEnumerator("navigator:browser")) {
|
||||
@@ -318,7 +318,7 @@ class TestNewTabOnRestoreAfterCrash(SessionStoreTestCase):
|
||||
"""
|
||||
let [resolve] = arguments;
|
||||
const { SessionStore } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
SessionStore.promiseAllWindowsRestored.then(resolve);
|
||||
"""
|
||||
|
||||
@@ -58,7 +58,7 @@ class TestSessionRestoreClosedTabs(SessionStoreTestCase):
|
||||
let resolve = arguments[0];
|
||||
let tab = gBrowser.tabs[1];
|
||||
gBrowser.removeTab(tab);
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flush(tab).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -70,7 +70,7 @@ class TestSessionRestoreClosedTabs(SessionStoreTestCase):
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
let { SessionStore } = ChromeUtils.importESModule("resource:///modules/sessionstore/SessionStore.sys.mjs");
|
||||
let { SessionStore } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/SessionStore.sys.mjs");
|
||||
let state = JSON.parse(SessionStore.getBrowserState());
|
||||
return state.windows[0]._closedTabs.length;
|
||||
"""
|
||||
@@ -82,7 +82,7 @@ class TestSessionRestoreClosedTabs(SessionStoreTestCase):
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
let { SessionStore } = ChromeUtils.importESModule("resource:///modules/sessionstore/SessionStore.sys.mjs");
|
||||
let { SessionStore } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/SessionStore.sys.mjs");
|
||||
let state = JSON.parse(SessionStore.getBrowserState());
|
||||
return state.windows[0]._closedTabs[0].removeAfterRestore;
|
||||
"""
|
||||
@@ -130,7 +130,7 @@ class TestSessionRestoreClosedTabs(SessionStoreTestCase):
|
||||
let resolve = arguments[0];
|
||||
let tab = gBrowser.tabs[1];
|
||||
gBrowser.removeTab(tab);
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flush(tab).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -143,7 +143,7 @@ class TestSessionRestoreClosedTabs(SessionStoreTestCase):
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
function observeClosedTabsChange() {
|
||||
return new Promise(resolve => {
|
||||
|
||||
@@ -66,7 +66,7 @@ class AIWindowTestMixin:
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
function observeClosedObjectsChange() {
|
||||
return new Promise(resolve => {
|
||||
@@ -117,7 +117,7 @@ class SmartWindowDefaultMixin(AIWindowTestMixin):
|
||||
return self.marionette.execute_script(
|
||||
"""
|
||||
const { SessionStore } = ChromeUtils.importESModule(
|
||||
"resource:///modules/sessionstore/SessionStore.sys.mjs"
|
||||
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs"
|
||||
);
|
||||
return SessionStore.canRestoreLastSession;
|
||||
"""
|
||||
|
||||
@@ -95,7 +95,7 @@ class TestSessionRestoreManually(SessionStoreTestCase):
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
function observeClosedObjectsChange() {
|
||||
return new Promise(resolve => {
|
||||
@@ -129,7 +129,7 @@ class TestSessionRestoreManually(SessionStoreTestCase):
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
let state = SessionStore.getCurrentState()
|
||||
return state.windows[1]["height"]
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestSessionRestoreWithPinnedTabs(SessionStoreTestCase):
|
||||
"""
|
||||
let resolve = arguments[0];
|
||||
gBrowser.pinTab(gBrowser.tabs[0]);
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flush(gBrowser.tabs[0]).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ class TestSessionRestoreWithTabGroups(SessionStoreTestCase):
|
||||
let closedGroup = gBrowser.addTabGroup([gBrowser.tabs[1]], { id:"group-closed", label: "closed" });
|
||||
gBrowser.removeTabGroup(closedGroup);
|
||||
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -144,7 +144,7 @@ class TestSessionRestoreWithTabGroups(SessionStoreTestCase):
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
let group = gBrowser.addTabGroup([...gBrowser.tabs], { id: "group-to-save", label: "to-save" });
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(() => {
|
||||
group.saveAndClose();
|
||||
});
|
||||
@@ -181,7 +181,7 @@ class TestSessionRestoreWithTabGroups(SessionStoreTestCase):
|
||||
gBrowser.addTabGroup([gBrowser.tabs[3], gBrowser.tabs[4]], { id: "save-through-restore-1", label: "open-1" });
|
||||
gBrowser.addTabGroup([gBrowser.tabs[1], gBrowser.tabs[2]], { id: "save-through-restore-2", label: "open-2" });
|
||||
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -252,7 +252,7 @@ class TestSessionRestoreWithTabGroups(SessionStoreTestCase):
|
||||
gBrowser.addTabGroup([gBrowser.tabs[3], gBrowser.tabs[4]], { id: "not-saved-after-restore-1", label: "open-1" });
|
||||
gBrowser.addTabGroup([gBrowser.tabs[1], gBrowser.tabs[2]], { id: "not-saved-after-restore-2", label: "open-2" });
|
||||
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -97,7 +97,7 @@ class TestSessionRestore(SessionStoreTestCase):
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
let state = SessionStore.getCurrentState();
|
||||
return state.windows[0].sidebar.command;
|
||||
|
||||
@@ -95,7 +95,7 @@ class TestSessionRestore(SessionStoreTestCase):
|
||||
"""
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
SessionStore: "moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||
});
|
||||
let state = SessionStore.getCurrentState();
|
||||
return state.windows[0].sidebar.command;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# 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/.
|
||||
|
||||
import os
|
||||
import time
|
||||
from urllib.parse import quote
|
||||
|
||||
from marionette_harness import MarionetteTestCase, WindowManagerMixin
|
||||
|
||||
|
||||
def inline(doc):
|
||||
return f"data:text/html;charset=utf-8,{quote(doc)}"
|
||||
|
||||
|
||||
# The page blocks its content process for this long, which has to outlast the
|
||||
# loose timer's first beat, one second into the shutdown flush.
|
||||
CONTENT_BUSY_MS = 10000
|
||||
|
||||
# Give the navigation time to settle before the block starts, so that it is the
|
||||
# shutdown flush that gets stuck rather than the test's own setup.
|
||||
CONTENT_BUSY_DELAY_MS = 500
|
||||
|
||||
TIMED_OUT_PATTERN = r"looseTimer of \d+ timed out"
|
||||
|
||||
|
||||
class TestShutdownFlushTimeout(WindowManagerMixin, MarionetteTestCase):
|
||||
"""Shutdown races the window flushes against a loose timer, so that an
|
||||
unresponsive content process cannot stall quitting. This covers the timer
|
||||
winning that race, which only happens when its callback can reach the
|
||||
logger."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.marionette.enforce_gecko_prefs({
|
||||
"browser.sessionstore.loglevel": "Debug",
|
||||
"browser.sessionstore.log.appender.file.logOnSuccess": True,
|
||||
# The timer waits DELAY_CRASH_MS - 10000, so this brings it forward
|
||||
# to its first beat.
|
||||
"toolkit.asyncshutdown.crash_timeout": 10000,
|
||||
})
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
# Create a fresh profile for subsequent tests.
|
||||
self.marionette.restart(in_app=False, clean=True)
|
||||
finally:
|
||||
super().tearDown()
|
||||
|
||||
def getLogContents(self):
|
||||
profilePath = self.marionette.instance.profile.profile
|
||||
assert profilePath is not None
|
||||
dirPath = os.path.join(profilePath, "sessionstore-logs")
|
||||
if not os.path.isdir(dirPath):
|
||||
return ""
|
||||
contents = []
|
||||
for entry in os.scandir(dirPath):
|
||||
if entry.is_file():
|
||||
with open(entry.path) as f:
|
||||
contents.append(f.read())
|
||||
return "\n".join(contents)
|
||||
|
||||
def quitFromParent(self):
|
||||
with self.marionette.using_context("chrome"):
|
||||
self.marionette.execute_script(
|
||||
"Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);"
|
||||
)
|
||||
|
||||
def test_flush_timeout_is_logged(self):
|
||||
# The page blocks its own content process shortly after loading, so the
|
||||
# parent cannot collect its tab state and the timer wins the race.
|
||||
with self.marionette.using_context("content"):
|
||||
self.marionette.navigate(
|
||||
inline(
|
||||
"<script>"
|
||||
f"setTimeout(() => {{ const end = Date.now() + {CONTENT_BUSY_MS};"
|
||||
" while (Date.now() < end) {} }, "
|
||||
f"{CONTENT_BUSY_DELAY_MS});"
|
||||
"</script>"
|
||||
)
|
||||
)
|
||||
time.sleep((CONTENT_BUSY_DELAY_MS + 500) / 1000)
|
||||
|
||||
self.marionette.quit(callback=self.quitFromParent)
|
||||
|
||||
self.assertRegex(
|
||||
self.getLogContents(),
|
||||
TIMED_OUT_PATTERN,
|
||||
"The loose timer resolved the shutdown flush race",
|
||||
)
|
||||
|
||||
self.marionette.start_session()
|
||||
@@ -0,0 +1,201 @@
|
||||
# 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/.
|
||||
|
||||
# add this directory to the path
|
||||
import os
|
||||
import sys
|
||||
from urllib.parse import quote
|
||||
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
from session_store_test_case import SessionStoreTestCase
|
||||
|
||||
|
||||
def inline(doc):
|
||||
return f"data:text/html;charset=utf-8,{quote(doc)}"
|
||||
|
||||
|
||||
# Each list element represents a window of tabs loaded at
|
||||
# some testing URL
|
||||
DEFAULT_WINDOWS = set([
|
||||
# Window 1. Note the comma after the inline call -
|
||||
# this is Python's way of declaring a 1 item tuple.
|
||||
(
|
||||
inline("""<div">Lorem</div>"""),
|
||||
inline("""<div">Ipsum</div>"""),
|
||||
inline("""<div">Dolor</div>"""),
|
||||
inline("""<div">sit</div>"""),
|
||||
inline("""<div">amet</div>"""),
|
||||
),
|
||||
])
|
||||
|
||||
RETURN_HIDDEN_TAB_COUNT = """
|
||||
return gBrowser.tabs.reduce((count, t) => count + (t.hidden ? 1 : 0), 0)
|
||||
"""
|
||||
|
||||
|
||||
class TestHiddenTabsRestoreWithSplitView(SessionStoreTestCase):
|
||||
def setUp(self):
|
||||
super().setUp(
|
||||
startup_page=3,
|
||||
include_private=False,
|
||||
restore_on_demand=True,
|
||||
test_windows=DEFAULT_WINDOWS,
|
||||
)
|
||||
self.marionette.set_context("chrome")
|
||||
|
||||
def test_splitview_no_hidden_tabs(self):
|
||||
self.wait_for_windows(
|
||||
self.all_windows, "Not all requested windows have been opened"
|
||||
)
|
||||
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
let resolve = arguments[0];
|
||||
gBrowser.addTabSplitView([gBrowser.tabs[0], gBrowser.tabs[1]], {
|
||||
insertBefore: gBrowser.tabs[0],
|
||||
});
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
0,
|
||||
"No tabs are hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews.every(t => !t.hasAttribute('hidden'))"
|
||||
),
|
||||
"No split views are hidden",
|
||||
)
|
||||
|
||||
self.marionette.quit()
|
||||
self.marionette.start_session()
|
||||
self.marionette.set_context("chrome")
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
0,
|
||||
"No tabs are restored hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews.every(t => !t.hasAttribute('hidden'))"
|
||||
),
|
||||
"No restored split views are hidden",
|
||||
)
|
||||
|
||||
def test_splitview_both_hidden(self):
|
||||
"""
|
||||
Hiding one tab in a split view should hide both of the tabs and the
|
||||
split view container. They should be restored in the same state.
|
||||
"""
|
||||
self.wait_for_windows(
|
||||
self.all_windows, "Not all requested windows have been opened"
|
||||
)
|
||||
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
let resolve = arguments[0];
|
||||
gBrowser.addTabSplitView([gBrowser.tabs[0], gBrowser.tabs[1]], {
|
||||
insertBefore: gBrowser.tabs[0],
|
||||
});
|
||||
gBrowser.hideTab(gBrowser.tabs[0]);
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
2,
|
||||
"Two tabs are hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.tabs[0].hidden && gBrowser.tabs[1].hidden"
|
||||
),
|
||||
"The right tabs are hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews[0].hasAttribute('hidden')"
|
||||
),
|
||||
"The split view is hidden because both tabs in it are hidden",
|
||||
)
|
||||
|
||||
self.marionette.quit()
|
||||
self.marionette.start_session()
|
||||
self.marionette.set_context("chrome")
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
2,
|
||||
"Two tabs are restored hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.tabs[0].hidden && gBrowser.tabs[1].hidden"
|
||||
),
|
||||
"The right tabs are restored hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews[0].hasAttribute('hidden')"
|
||||
),
|
||||
"The split view is restored hidden",
|
||||
)
|
||||
|
||||
def test_splitview_in_collapsed_group_is_not_hidden(self):
|
||||
"""
|
||||
Bug 2063789: ensure split views that are invisible (e.g. in a collapsed
|
||||
group) but not actually hidden are restored not hidden.
|
||||
"""
|
||||
self.wait_for_windows(
|
||||
self.all_windows, "Not all requested windows have been opened"
|
||||
)
|
||||
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
let resolve = arguments[0];
|
||||
let splitview = gBrowser.addTabSplitView([gBrowser.tabs[0], gBrowser.tabs[1]], {
|
||||
insertBefore: gBrowser.tabs[0],
|
||||
});
|
||||
let group = gBrowser.addTabGroup([splitview, gBrowser.tabs[2]], { insertBefore: splitview });
|
||||
group.collapsed = true;
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
0,
|
||||
"No tabs are hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews.every(t => !t.hasAttribute('hidden'))"
|
||||
),
|
||||
"No split views are hidden",
|
||||
)
|
||||
|
||||
self.marionette.quit()
|
||||
self.marionette.start_session()
|
||||
self.marionette.set_context("chrome")
|
||||
|
||||
self.assertEqual(
|
||||
self.marionette.execute_script(RETURN_HIDDEN_TAB_COUNT),
|
||||
0,
|
||||
"No tabs are restored hidden",
|
||||
)
|
||||
self.assertTrue(
|
||||
self.marionette.execute_script(
|
||||
"return gBrowser.splitViews.every(t => !t.hasAttribute('hidden'))"
|
||||
),
|
||||
"No restored split views are hidden",
|
||||
)
|
||||
@@ -53,7 +53,7 @@ class TestAutoRestoreWithSplitView(SessionStoreTestCase):
|
||||
gBrowser.addTabSplitView([gBrowser.tabs[0], gBrowser.tabs[1]], {
|
||||
insertBefore: gBrowser.tabs[0],
|
||||
});
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -98,7 +98,7 @@ class TestAutoRestoreWithSplitView(SessionStoreTestCase):
|
||||
insertBefore: gBrowser.tabs[2],
|
||||
});
|
||||
gBrowser.selectedTab = gBrowser.tabs[2];
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
@@ -150,7 +150,7 @@ class TestAutoRestoreWithSplitView(SessionStoreTestCase):
|
||||
gBrowser.addTabSplitView([gBrowser.tabs[0], gBrowser.tabs[1]], {
|
||||
insertBefore: gBrowser.tabs[0],
|
||||
});
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("resource:///modules/sessionstore/TabStateFlusher.sys.mjs");
|
||||
let { TabStateFlusher } = ChromeUtils.importESModule("moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs");
|
||||
TabStateFlusher.flushWindow(gBrowser.documentGlobal).then(resolve);
|
||||
"""
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user