Compare commits

..

5 Commits

Author SHA1 Message Date
mr. m
0541ac2ad0 closes #14331: Refactor SR to support container tab forcing 2026-06-22 12:13:52 +02:00
Bernhard
183c583841 gh-14320: fix workspace change icon picker state when opening (gh-14321)
The picker reset its page with a smooth scrollIntoView while the popup
was hiding, and positioned the page before the popup was laid out, so it
could animate/jump on open. Reset instantly on popupshown (after layout)
instead, and drop the on-hide scroll so there's no visible animation.
2026-06-21 21:43:44 +02:00
fen4flo
40080a25dc gh-11245: Fix tab placement with Move Tab / Space Routing (gh-14324)
Fixes #11245
2026-06-21 15:18:02 +02:00
Connor Griffin
733061fbe3 gh-11766: Fixed video fullscreen not working while in glance (gh-14272)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-06-21 11:20:37 +02:00
Andrey Bochkarev
61e631902c gh-14131: Prevent sidebar from flickering when moving a tab (gh-14293)
Co-authored-by: mr. m <mr.m@tuta.com>
2026-06-20 17:18:41 +02:00
28 changed files with 254 additions and 6984 deletions

View File

@@ -10,6 +10,7 @@
"build": "surfer build",
"build:ui": "surfer build --ui",
"start": "cd engine && python3 ./mach run --noprofile",
"start:debug": "npm start -- --jsdebugger --wait-for-jsdebugger",
"start:bloat": "XPCOM_MEM_BLOAT_LOG=1 npm start",
"import": "npm run ffprefs && npm run import:dumps && surfer import",
"import:dumps": "python3 scripts/update_service_dumps.py",

View File

@@ -95,9 +95,6 @@
- name: browser.search.widget.new
value: true
- name: layout.css.corner-shape.enabled
value: true
# Disabled from https://searchfox.org/firefox-main/rev/d6bfff43852356ca98af848b4705d37f8d41856f/modules/libpref/init/StaticPrefList.yaml#2008
# Only enabled for windows, doesn't really fit inside Zen.
- name: browser.startup.preXulSkeletonUI

View File

@@ -131,10 +131,10 @@
</box>
<html:input type="range" value="0.4" step="0.001" id="PanelUI-zen-gradient-generator-opacity"
#ifdef XP_MACOSX
max="0.8"
max="0.9"
min="0.30"
#else
max="0.8"
max="0.9"
min="0.25"
#endif
/>

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f3682852f8a52bd 100644
index 08b5b56e069d038d72c87355920c4ce8a55ed805..99b3de9a7be5cd5fd73c0b9dbbe265655d7171ce 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -511,6 +511,7 @@
@@ -285,22 +285,21 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} = {}
) {
// all callers of addTab that pass a params object need to pass
@@ -3347,10 +3438,25 @@
@@ -3347,10 +3438,24 @@
);
}
+ const beforeRouteResult = window.gZenSpaceRoutingManager.onBeforeAddTab(uriString, { skipRoute, pinned, tabGroup, fromExternal }, window);
+ const beforeRouteResult = window.gZenSpaceRoutingManager.onBeforeAddTab(uriString, { skipRoute, pinned, tabGroup, fromExternal, zenWorkspaceId }, window);
+ if (beforeRouteResult.shouldEarlyExit) {
+ return null;
+ }
+
+ let hasZenDefaultUserContextId = false;
+ let zenForcedWorkspaceId = undefined;
+ if (beforeRouteResult.isRouteFound && typeof userContextId !== "undefined") {
+ userContextId = beforeRouteResult.userContextId;
+ hasZenDefaultUserContextId = true;
+ } else if (typeof gZenWorkspaces !== "undefined" && !_forZenEmptyTab) {
+ [userContextId, hasZenDefaultUserContextId, zenForcedWorkspaceId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal);
+ [userContextId, hasZenDefaultUserContextId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal);
+ }
+
if (!UserInteraction.running("browser.tabs.opening", window)) {
@@ -311,7 +310,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// If we're opening a foreground tab, set the owner by default.
ownerTab ??= inBackground ? null : this.selectedTab;
@@ -3358,6 +3464,7 @@
@@ -3358,6 +3463,7 @@
if (this.selectedTab.owner) {
this.selectedTab.owner = null;
}
@@ -319,7 +318,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// Find the tab that opened this one, if any. This is used for
// determining positioning, and inherited attributes such as the
@@ -3410,6 +3517,22 @@
@@ -3410,6 +3516,18 @@
noInitialLabel,
skipBackgroundNotify,
});
@@ -328,10 +327,6 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
+ }
+ if (zenWorkspaceId) {
+ t.setAttribute("zen-workspace-id", zenWorkspaceId);
+ t.setAttribute("change-workspace", "")
+ } else if (zenForcedWorkspaceId !== undefined) {
+ t.setAttribute("zen-workspace-id", zenForcedWorkspaceId);
+ t.setAttribute("change-workspace", "")
+ }
+ if (_forZenEmptyTab) {
+ t.setAttribute("zen-empty-tab", "true");
@@ -342,7 +337,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (insertTab) {
// Insert the tab into the tab container in the correct position.
this.#insertTabAtIndex(t, {
@@ -3418,6 +3541,7 @@
@@ -3418,6 +3536,7 @@
ownerTab,
openerTab,
pinned,
@@ -350,7 +345,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
bulkOrderedOpen,
tabGroup: tabGroup ?? openerTab?.group,
});
@@ -3436,6 +3560,7 @@
@@ -3436,6 +3555,7 @@
openWindowInfo,
skipLoad,
triggeringRemoteType,
@@ -358,7 +353,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}));
if (focusUrlBar) {
@@ -3560,6 +3685,12 @@
@@ -3560,6 +3680,12 @@
}
}
@@ -371,7 +366,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// Additionally send pinned tab events
if (pinned) {
this.#notifyPinnedStatus(t);
@@ -3570,6 +3701,15 @@
@@ -3570,6 +3696,15 @@
if (!inBackground) {
this.selectedTab = t;
}
@@ -387,7 +382,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
return t;
}
@@ -3802,6 +3942,7 @@
@@ -3802,6 +3937,7 @@
isAdoptingGroup = false,
isUserTriggered = false,
telemetryUserCreateSource = "unknown",
@@ -395,7 +390,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} = {}
) {
if (
@@ -3812,9 +3953,6 @@
@@ -3812,9 +3948,6 @@
!this.isSplitViewWrapper(tabOrSplitView)
)
) {
@@ -405,7 +400,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
if (!color) {
@@ -3835,9 +3973,14 @@
@@ -3835,9 +3968,14 @@
label,
isAdoptingGroup
);
@@ -422,7 +417,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
);
group.addTabs(tabsAndSplitViews);
@@ -3958,7 +4101,7 @@
@@ -3958,7 +4096,7 @@
}
this.#handleTabMove(tab, () =>
@@ -431,7 +426,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
);
}
@@ -4044,6 +4187,7 @@
@@ -4044,6 +4182,7 @@
color: group.color,
insertBefore: newTabs[0],
isAdoptingGroup: true,
@@ -439,7 +434,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
});
}
@@ -4254,6 +4398,7 @@
@@ -4254,6 +4393,7 @@
openWindowInfo,
skipLoad,
triggeringRemoteType,
@@ -447,7 +442,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
) {
// If we don't have a preferred remote type (or it is `NOT_REMOTE`), and
@@ -4323,6 +4468,7 @@
@@ -4323,6 +4463,7 @@
openWindowInfo,
name,
skipLoad,
@@ -455,7 +450,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
});
}
@@ -4536,9 +4682,9 @@
@@ -4536,9 +4677,9 @@
}
// Add a new tab if needed.
@@ -467,7 +462,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let url = "about:blank";
if (tabData.entries?.length) {
@@ -4575,8 +4721,10 @@
@@ -4575,8 +4716,10 @@
insertTab: false,
skipLoad: true,
preferredRemoteType,
@@ -479,7 +474,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (select) {
tabToSelect = tab;
}
@@ -4598,7 +4746,8 @@
@@ -4598,7 +4741,8 @@
this.pinTab(tab);
// Then ensure all the tab open/pinning information is sent.
this._fireTabOpen(tab, {});
@@ -489,7 +484,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let { groupId } = tabData;
const tabGroup = tabGroupWorkingData.get(groupId);
// if a tab refers to a tab group we don't know, skip any group
@@ -4618,7 +4767,10 @@
@@ -4618,7 +4762,10 @@
tabGroup.stateData.id,
tabGroup.stateData.color,
tabGroup.stateData.collapsed,
@@ -501,7 +496,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
);
tabsFragment.appendChild(tabGroup.node);
}
@@ -4673,9 +4825,21 @@
@@ -4673,9 +4820,21 @@
// to remove the old selected tab.
if (tabToSelect) {
let leftoverTab = this.selectedTab;
@@ -523,7 +518,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (tabs.length > 1 || !tabs[0].selected) {
this._updateTabsAfterInsert();
@@ -4866,11 +5030,14 @@
@@ -4866,11 +5025,14 @@
if (ownerTab) {
tab.owner = ownerTab;
}
@@ -539,7 +534,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (
!bulkOrderedOpen &&
((openerTab &&
@@ -4882,7 +5049,7 @@
@@ -4882,7 +5044,7 @@
let lastRelatedTab =
openerTab && this._lastRelatedTabMap.get(openerTab);
let previousTab = lastRelatedTab || openerTab || this.selectedTab;
@@ -548,7 +543,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
tabGroup = previousTab.group;
}
if (
@@ -4898,7 +5065,7 @@
@@ -4898,7 +5060,7 @@
previousTab.splitview
) + 1;
} else if (previousTab.visible) {
@@ -557,7 +552,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} else if (previousTab == FirefoxViewHandler.tab) {
elementIndex = 0;
}
@@ -4926,14 +5093,14 @@
@@ -4926,14 +5088,14 @@
}
// Ensure index is within bounds.
if (tab.pinned) {
@@ -576,7 +571,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (pinned && !itemAfter?.pinned) {
itemAfter = null;
@@ -4950,7 +5117,7 @@
@@ -4950,7 +5112,7 @@
this.tabContainer._invalidateCachedTabs();
@@ -585,7 +580,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (
(this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
this.isSplitViewWrapper(itemAfter)
@@ -4981,7 +5148,11 @@
@@ -4981,7 +5143,11 @@
const tabContainer = pinned
? this.tabContainer.pinnedTabsContainer
: this.tabContainer;
@@ -597,7 +592,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
if (tab.group?.collapsed) {
@@ -4996,6 +5167,7 @@
@@ -4996,6 +5162,7 @@
if (pinned) {
this._updateTabBarForPinnedTabs();
}
@@ -605,7 +600,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
TabBarVisibility.update();
}
@@ -5544,6 +5716,7 @@
@@ -5544,6 +5711,7 @@
telemetrySource,
} = {}
) {
@@ -613,7 +608,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
// can be considered equivalent to closing the window.
if (
@@ -5633,6 +5806,7 @@
@@ -5633,6 +5801,7 @@
if (lastToClose) {
this.removeTab(lastToClose, aParams);
}
@@ -621,7 +616,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} catch (e) {
console.error(e);
}
@@ -5678,6 +5852,14 @@
@@ -5678,6 +5847,14 @@
return;
}
@@ -636,7 +631,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let isVisibleTab = aTab.visible;
// We have to sample the tab width now, since _beginRemoveTab might
// end up modifying the DOM in such a way that aTab gets a new
@@ -5685,6 +5867,9 @@
@@ -5685,6 +5862,9 @@
// state).
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
let isLastTab = this.#isLastTabInWindow(aTab);
@@ -646,7 +641,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (
!this._beginRemoveTab(aTab, {
closeWindowFastpath: true,
@@ -5696,13 +5881,14 @@
@@ -5696,13 +5876,14 @@
telemetrySource,
})
) {
@@ -662,7 +657,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let lockTabSizing =
!this.tabContainer.verticalMode &&
!aTab.pinned &&
@@ -5733,7 +5919,13 @@
@@ -5733,7 +5914,13 @@
// We're not animating, so we can cancel the animation stopwatch.
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
aTab._closeTimeAnimTimerId = null;
@@ -677,7 +672,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
return;
}
@@ -5867,7 +6059,7 @@
@@ -5867,7 +6054,7 @@
closeWindowWithLastTab != null
? closeWindowWithLastTab
: !window.toolbar.visible ||
@@ -686,7 +681,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (closeWindow) {
// We've already called beforeunload on all the relevant tabs if we get here,
@@ -5891,6 +6083,7 @@
@@ -5891,6 +6078,7 @@
newTab = true;
}
@@ -694,7 +689,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
aTab._endRemoveArgs = [closeWindow, newTab];
// swapBrowsersAndCloseOther will take care of closing the window without animation.
@@ -5931,13 +6124,7 @@
@@ -5931,13 +6119,7 @@
aTab._mouseleave();
if (newTab) {
@@ -709,7 +704,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} else {
TabBarVisibility.update();
}
@@ -6070,6 +6257,7 @@
@@ -6070,6 +6252,7 @@
this.tabs[i]._tPos = i;
}
@@ -717,7 +712,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (!this._windowIsClosing) {
// update tab close buttons state
this.tabContainer._updateCloseButtons();
@@ -6255,6 +6443,7 @@
@@ -6255,6 +6438,7 @@
memory_after: await getTotalMemoryUsage(),
time_to_unload_in_ms: timeElapsed,
});
@@ -725,7 +720,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
/**
@@ -6300,6 +6489,7 @@
@@ -6300,6 +6484,7 @@
}
let excludeTabs = new Set(aExcludeTabs);
@@ -733,7 +728,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// If this tab has a successor, it should be selectable, since
// hiding or closing a tab removes that tab as a successor.
@@ -6312,15 +6502,22 @@
@@ -6312,15 +6497,22 @@
!excludeTabs.has(aTab.owner) &&
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
) {
@@ -758,7 +753,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let tab = this.tabContainer.findNextTab(aTab, {
direction: 1,
filter: _tab => remainingTabs.includes(_tab),
@@ -6334,7 +6531,7 @@
@@ -6334,7 +6526,7 @@
}
if (tab) {
@@ -767,7 +762,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
// If no qualifying visible tab was found, see if there is a tab in
@@ -6355,7 +6552,7 @@
@@ -6355,7 +6547,7 @@
});
}
@@ -776,7 +771,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
_blurTab(aTab) {
@@ -6366,7 +6563,7 @@
@@ -6366,7 +6558,7 @@
* @returns {boolean}
* False if swapping isn't permitted, true otherwise.
*/
@@ -785,7 +780,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// Do not allow transfering a private tab to a non-private window
// and vice versa.
if (
@@ -6420,6 +6617,7 @@
@@ -6420,6 +6612,7 @@
// fire the beforeunload event in the process. Close the other
// window if this was its last tab.
if (
@@ -793,7 +788,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
!remoteBrowser._beginRemoveTab(aOtherTab, {
adoptedByTab: aOurTab,
closeWindowWithLastTab: true,
@@ -6431,7 +6629,7 @@
@@ -6431,7 +6624,7 @@
// If this is the last tab of the window, hide the window
// immediately without animation before the docshell swap, to avoid
// about:blank being painted.
@@ -802,7 +797,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (closeWindow) {
let win = aOtherTab.documentGlobal;
win.windowUtils.suppressAnimation(true);
@@ -6565,11 +6763,13 @@
@@ -6565,11 +6758,13 @@
}
// Finish tearing down the tab that's going away.
@@ -816,7 +811,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
this.setTabTitle(aOurTab);
@@ -6771,10 +6971,10 @@
@@ -6771,10 +6966,10 @@
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
}
@@ -829,7 +824,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
aTab.selected ||
aTab.closing ||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
@@ -6834,7 +7034,8 @@
@@ -6834,7 +7029,8 @@
* @param {object} [aOptions={}]
* Key-value pairs that will be serialized into the features string.
*/
@@ -839,7 +834,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (this.tabs.length == 1) {
return null;
}
@@ -6851,7 +7052,7 @@
@@ -6851,7 +7047,7 @@
// tell a new window to take the "dropped" tab
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
args.appendElement(aTab.splitview ?? aTab);
@@ -848,7 +843,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
private: PrivateBrowsingUtils.isWindowPrivate(window),
features: Object.entries(aOptions)
.map(([key, value]) => `${key}=${value}`)
@@ -6859,6 +7060,8 @@
@@ -6859,6 +7055,8 @@
openerWindow: window,
args,
});
@@ -857,7 +852,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
/**
@@ -6971,7 +7174,7 @@
@@ -6971,7 +7169,7 @@
* `true` if element is a `<tab-group>`
*/
isTabGroup(element) {
@@ -866,7 +861,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
/**
@@ -7056,8 +7259,8 @@
@@ -7056,8 +7254,8 @@
}
// Don't allow mixing pinned and unpinned tabs.
@@ -877,7 +872,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} else {
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
}
@@ -7103,8 +7306,8 @@
@@ -7103,8 +7301,8 @@
this.#handleTabMove(
element,
() => {
@@ -888,7 +883,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
neighbor = neighbor.group;
}
if (neighbor?.splitview) {
@@ -7115,6 +7318,12 @@
@@ -7115,6 +7313,12 @@
return;
}
}
@@ -901,7 +896,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
if (movingForwards && neighbor) {
neighbor.after(element);
@@ -7173,23 +7382,31 @@
@@ -7173,23 +7377,31 @@
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
if (this.isTabGroupLabel(targetElement)) {
targetElement = targetElement.group;
@@ -939,7 +934,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
} else if (!element.pinned && targetElement && targetElement.pinned) {
// If the caller asks to move an unpinned element next to a pinned
// tab, move the unpinned element to be the first unpinned element
@@ -7202,12 +7419,35 @@
@@ -7202,12 +7414,35 @@
// move the tab group right before the first unpinned tab.
// 4. Moving a tab group and the first unpinned tab is grouped:
// move the tab group right before the first unpinned tab's tab group.
@@ -976,7 +971,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// We want to include the splitview wrapper if it's the targetElement, but
// not in the case where we want to reverse tabs within the same splitview.
@@ -7216,6 +7456,7 @@
@@ -7216,6 +7451,7 @@
}
let getContainer = () =>
@@ -984,7 +979,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
element.pinned
? this.tabContainer.pinnedTabsContainer
: this.tabContainer;
@@ -7224,11 +7465,15 @@
@@ -7224,11 +7460,15 @@
element,
() => {
if (moveBefore) {
@@ -1001,7 +996,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
},
metricsContext
@@ -7302,11 +7547,15 @@
@@ -7302,11 +7542,15 @@
* @param {TabMetricsContext} [metricsContext]
*/
moveTabToExistingGroup(aTab, aGroup, metricsContext) {
@@ -1020,7 +1015,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
if (aTab.group && aTab.group.id === aGroup.id) {
return;
@@ -7378,6 +7627,7 @@
@@ -7378,6 +7622,7 @@
let state = {
tabIndex: tab._tPos,
@@ -1028,7 +1023,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
};
if (tab.visible) {
state.elementIndex = tab.elementIndex;
@@ -7409,7 +7659,7 @@
@@ -7409,7 +7654,7 @@
let changedSplitView =
previousTabState.splitViewId != currentTabState.splitViewId;
@@ -1037,7 +1032,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
tab.dispatchEvent(
new CustomEvent("TabMove", {
bubbles: true,
@@ -7456,6 +7706,10 @@
@@ -7456,6 +7701,10 @@
moveActionCallback();
@@ -1048,7 +1043,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// Clear tabs cache after moving nodes because the order of tabs may have
// changed.
this.tabContainer._invalidateCachedTabs();
@@ -7506,7 +7760,22 @@
@@ -7506,7 +7755,22 @@
* @returns {object}
* The new tab in the current window, null if the tab couldn't be adopted.
*/
@@ -1072,7 +1067,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
// Swap the dropped tab with a new one we create and then close
// it in the other window (making it seem to have moved between
// windows). We also ensure that the tab we create to swap into has
@@ -7549,6 +7818,8 @@
@@ -7549,6 +7813,8 @@
}
params.skipLoad = true;
let newTab = this.addWebTab("about:blank", params);
@@ -1081,7 +1076,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
aTab.container.tabDragAndDrop.finishAnimateTabMove();
@@ -8259,7 +8530,7 @@
@@ -8259,7 +8525,7 @@
// preventDefault(). It will still raise the window if appropriate.
return;
}
@@ -1090,7 +1085,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
window.focus();
aEvent.preventDefault();
}
@@ -8276,7 +8547,6 @@
@@ -8276,7 +8542,6 @@
on_TabGroupCollapse(aEvent) {
aEvent.target.tabs.forEach(tab => {
@@ -1098,7 +1093,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
});
}
@@ -8630,7 +8900,9 @@
@@ -8630,7 +8895,9 @@
let filter = this._tabFilters.get(tab);
if (filter) {
@@ -1108,7 +1103,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
let listener = this._tabListeners.get(tab);
if (listener) {
@@ -9435,6 +9707,7 @@
@@ -9435,6 +9702,7 @@
aWebProgress.isTopLevel
) {
this.mTab.setAttribute("busy", "true");
@@ -1116,7 +1111,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
gBrowser._tabAttrModified(this.mTab, ["busy"]);
this.mTab._notselectedsinceload = !this.mTab.selected;
}
@@ -9515,6 +9788,7 @@
@@ -9515,6 +9783,7 @@
// known defaults. Note we use the original URL since about:newtab
// redirects to a prerendered page.
const shouldRemoveFavicon =
@@ -1124,7 +1119,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
!this.mBrowser.mIconURL &&
!ignoreBlank &&
!(originalLocation.spec in FAVICON_DEFAULTS);
@@ -9689,13 +9963,6 @@
@@ -9689,13 +9958,6 @@
this.mBrowser.originalURI = aRequest.originalURI;
}
@@ -1138,7 +1133,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f368285
}
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
@@ -10587,7 +10854,8 @@ var TabContextMenu = {
@@ -10587,7 +10849,8 @@ var TabContextMenu = {
);
contextUnpinSelectedTabs.hidden =
!this.contextTab.pinned || !this.multiselected;

View File

@@ -1,8 +1,23 @@
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9ea21b6f6 100644
index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..b9a1cfe3a4a5035d9b06b0b3826a97c52cfcb39e 100644
--- a/browser/components/tabbrowser/content/tabs.js
+++ b/browser/components/tabbrowser/content/tabs.js
@@ -220,7 +220,7 @@
@@ -197,8 +197,12 @@
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_sidebarPositionStart",
- "sidebar.position_start",
- true
+ "zen.tabs.vertical.right-side",
+ true,
+ null,
+ newValue => {
+ return !newValue;
+ }
);
if (gMultiProcessBrowser) {
@@ -220,7 +224,7 @@
this.tooltip = "tabbrowser-tab-tooltip";
@@ -11,7 +26,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.tabDragAndDrop.init();
}
@@ -444,7 +444,7 @@
@@ -444,7 +448,7 @@
// and we're not hitting the scroll buttons.
if (
event.button != 0 ||
@@ -20,7 +35,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
event.composedTarget.localName == "toolbarbutton"
) {
return;
@@ -525,7 +525,6 @@
@@ -525,7 +529,6 @@
});
}
} else if (isTabGroupLabel(event.target)) {
@@ -28,7 +43,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} else if (
event.originalTarget.closest("scrollbox") &&
!Services.prefs.getBoolPref(
@@ -561,6 +560,9 @@
@@ -561,6 +564,9 @@
}
on_keydown(event) {
@@ -38,7 +53,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
let { altKey, shiftKey } = event;
let [accel, nonAccel] =
AppConstants.platform == "macosx"
@@ -755,7 +757,6 @@
@@ -755,7 +761,6 @@
this._updateCloseButtons();
if (!this.#animatingGroups.size) {
@@ -46,7 +61,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
}
document
@@ -822,7 +823,7 @@
@@ -822,7 +827,7 @@
}
get newTabButton() {
@@ -55,7 +70,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
}
get verticalMode() {
@@ -838,6 +839,7 @@
@@ -838,6 +843,7 @@
}
get overflowing() {
@@ -63,7 +78,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
return this.hasAttribute("overflow");
}
@@ -851,29 +853,56 @@
@@ -851,29 +857,56 @@
if (pinnedChildren?.at(-1)?.id == "pinned-tabs-container-periphery") {
pinnedChildren.pop();
}
@@ -93,7 +108,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
+ } else if (!isTab(tab)) {
+ tabs.splice(i, 1);
+ }
}
+ }
+ };
+ expandTabs(pinnedTabs);
+ expandTabs(unpinnedChildren);
@@ -114,7 +129,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
+ // remove the separator from the list
+ allTabs.splice(i, 1);
+ i--;
+ }
}
+ i++;
}
-
@@ -130,7 +145,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
}
get allSplitViews() {
@@ -958,29 +987,28 @@
@@ -958,29 +991,28 @@
return this.#focusableItems;
}
@@ -170,7 +185,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.#focusableItems = focusableItems;
return this.#focusableItems;
@@ -993,6 +1021,7 @@
@@ -993,6 +1025,7 @@
* focusable (ex, we don't want the splitview container to be focusable, only its children).
*/
get dragAndDropElements() {
@@ -178,7 +193,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
if (this.#dragAndDropElements) {
return this.#dragAndDropElements;
}
@@ -1063,6 +1092,7 @@
@@ -1063,6 +1096,7 @@
_invalidateCachedTabs() {
this.#allTabs = null;
this._invalidateCachedVisibleTabs();
@@ -186,7 +201,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
}
_invalidateCachedVisibleTabs() {
@@ -1082,7 +1112,8 @@
@@ -1082,7 +1116,8 @@
isContainerVerticalPinnedGrid(tab) {
return (
@@ -196,7 +211,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.verticalMode &&
this.hasAttribute("expanded") &&
!this.expandOnHover
@@ -1176,7 +1207,7 @@
@@ -1176,7 +1211,7 @@
if (node == null) {
// We have a container for non-tab elements at the end of the scrollbox.
@@ -205,7 +220,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
}
node.before(tab);
@@ -1271,7 +1302,7 @@
@@ -1271,7 +1306,7 @@
// There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and
// for when the tab strip is overflowed (which is shared by vertical and horizontal tabs);
// Attach the long click popup to all of them.
@@ -214,7 +229,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
const newTab2 = this.newTabButton;
const newTabVertical = document.getElementById(
"vertical-tabs-newtab-button"
@@ -1376,8 +1407,10 @@
@@ -1376,8 +1411,10 @@
*/
_handleTabSelect(aInstant) {
let selectedTab = this.selectedItem;
@@ -225,7 +240,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
selectedTab._notselectedsinceload = false;
}
@@ -1386,7 +1419,7 @@
@@ -1386,7 +1423,7 @@
* @param {boolean} [shouldScrollInstantly=false]
*/
#ensureTabIsVisible(tab, shouldScrollInstantly = false) {
@@ -234,7 +249,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
if (arrowScrollbox?.overflowing) {
arrowScrollbox.ensureElementIsVisible(tab, shouldScrollInstantly);
}
@@ -1513,7 +1546,7 @@
@@ -1513,7 +1550,7 @@
}
_notifyBackgroundTab(aTab) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
diff --git a/servo/components/style/values/generics/border.rs b/servo/components/style/values/generics/border.rs
--- a/servo/components/style/values/generics/border.rs
+++ b/servo/components/style/values/generics/border.rs
@@ -296,9 +296,9 @@
pub fn all(s: S) -> Self {
Self {
top_left: s.clone(),
top_right: s.clone(),
bottom_right: s.clone(),
- bottom_left: s.clone(),
+ bottom_left: s,
}
}
}

View File

@@ -1,38 +0,0 @@
diff --git a/gfx/wr/glsl-to-cxx/src/hir.rs b/gfx/wr/glsl-to-cxx/src/hir.rs
--- a/gfx/wr/glsl-to-cxx/src/hir.rs
+++ b/gfx/wr/glsl-to-cxx/src/hir.rs
@@ -3531,10 +3531,11 @@
None,
Type::new(Float),
vec![Type::new(Vec2)],
);
declare_function(state, "pow", None, Type::new(Vec3), vec![Type::new(Vec3)]);
+ declare_function(state, "pow", None, Type::new(Vec2), vec![Type::new(Vec2)]);
declare_function(state, "pow", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp2", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log2", None, Type::new(Float), vec![Type::new(Float)]);
diff --git a/gfx/wr/swgl/src/glsl.h b/gfx/wr/swgl/src/glsl.h
--- a/gfx/wr/swgl/src/glsl.h
+++ b/gfx/wr/swgl/src/glsl.h
@@ -800,10 +800,18 @@
Float pow(Float x, Float y) {
return if_then_else((x == 0) | (x == 1), x, approx_pow2(approx_log2(x) * y));
}
+vec2 pow(vec2 a, vec2 b) {
+ return vec2(pow(a.x, b.x), pow(a.y, b.y));
+}
+
+vec2_scalar pow(vec2_scalar a, vec2_scalar b) {
+ return vec2_scalar(pow(a.x, b.x), pow(a.y, b.y));
+}
+
#define exp __glsl_exp
SI float exp(float x) { return expf(x); }
Float exp(Float y) {

View File

@@ -1,19 +0,0 @@
diff --git a/gfx/wr/swgl/src/glsl.h b/gfx/wr/swgl/src/glsl.h
--- a/gfx/wr/swgl/src/glsl.h
+++ b/gfx/wr/swgl/src/glsl.h
@@ -1611,10 +1611,14 @@
vec3_scalar make_vec3(const vec2_scalar& v, float z) {
return vec3_scalar{v.x, v.y, z};
}
+vec3_scalar make_vec3(float x, const vec2_scalar& v) {
+ return vec3_scalar{x, v.x, v.y};
+}
+
vec3_scalar make_vec3(float x, float y, float z) {
return vec3_scalar{x, y, z};
}
vec3_scalar make_vec3(int32_t x, int32_t y, float z) {

View File

@@ -1,22 +0,0 @@
diff --git a/gfx/wr/swgl/src/glsl.h b/gfx/wr/swgl/src/glsl.h
--- a/gfx/wr/swgl/src/glsl.h
+++ b/gfx/wr/swgl/src/glsl.h
@@ -1599,10 +1599,17 @@
x += a.x;
y += a.y;
z += a.z;
return *this;
}
+
+ vec3& operator*=(Float a) {
+ x *= a;
+ y *= a;
+ z *= a;
+ return *this;
+ }
};
vec3_scalar force_scalar(const vec3& v) {
return vec3_scalar{force_scalar(v.x), force_scalar(v.y), force_scalar(v.z)};
}

View File

@@ -1,20 +0,0 @@
diff --git a/gfx/wr/swgl/src/glsl.h b/gfx/wr/swgl/src/glsl.h
--- a/gfx/wr/swgl/src/glsl.h
+++ b/gfx/wr/swgl/src/glsl.h
@@ -469,10 +469,15 @@
vec2_scalar_ref& operator=(const vec2_scalar& a) {
x = a.x;
y = a.y;
return *this;
}
+ vec2_scalar_ref& operator+=(vec2_scalar a) {
+ x += a.x;
+ y += a.y;
+ return *this;
+ }
vec2_scalar_ref& operator*=(vec2_scalar a) {
x *= a.x;
y *= a.y;
return *this;
}

View File

@@ -1,67 +0,0 @@
diff --git a/gfx/wr/glsl-to-cxx/src/hir.rs b/gfx/wr/glsl-to-cxx/src/hir.rs
--- a/gfx/wr/glsl-to-cxx/src/hir.rs
+++ b/gfx/wr/glsl-to-cxx/src/hir.rs
@@ -3537,10 +3537,12 @@
declare_function(state, "pow", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "exp2", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log", None, Type::new(Float), vec![Type::new(Float)]);
declare_function(state, "log2", None, Type::new(Float), vec![Type::new(Float)]);
+ declare_function(state, "isnan", None, Type::new(Bool), vec![Type::new(Float)]);
+ declare_function(state, "isinf", None, Type::new(Bool), vec![Type::new(Float)]);
for t in &[Float, Vec2] {
// recip is non-standard
declare_function(
state,
"recip",
diff --git a/gfx/wr/swgl/src/glsl.h b/gfx/wr/swgl/src/glsl.h
--- a/gfx/wr/swgl/src/glsl.h
+++ b/gfx/wr/swgl/src/glsl.h
@@ -205,10 +205,46 @@
#else
return (Float){sqrtf(v.x), sqrtf(v.y), sqrtf(v.z), sqrtf(v.w)};
#endif
}
+// NOTE: the Bool type is actually int under the hood,
+// and is used for bitwise return value masking in the
+// generated code ("ret_mask" variable).
+//
+// The ret_mask is initialized to -1 (0xffffffff), and
+// is then subsequently masked with condition results.
+//
+// If we use the boolean result directly here (0 or 1),
+// the bitwise AND ends up removing just one bit from
+// the mask, and it doesn't work.
+//
+// Taking the negative transforms 1 (single bit) into -1
+// (all bits 1), and correctly broadcasts the boolean
+// result into all bits of the ret_mask.
+//
+// If the condition is false, 0 becomes -0 which is the
+// same bit pattern for integers (all bits 0).
+
+SI Bool isnan(Float v) {
+ return (Bool){
+ -(fpclassify(v.x) == FP_NAN),
+ -(fpclassify(v.y) == FP_NAN),
+ -(fpclassify(v.z) == FP_NAN),
+ -(fpclassify(v.w) == FP_NAN)
+ };
+}
+
+SI Bool isinf(Float v) {
+ return (Bool){
+ -(fpclassify(v.x) == FP_INFINITE),
+ -(fpclassify(v.y) == FP_INFINITE),
+ -(fpclassify(v.z) == FP_INFINITE),
+ -(fpclassify(v.w) == FP_INFINITE)
+ };
+}
+
SI float recip(float x) {
#if USE_SSE2
return _mm_cvtss_f32(_mm_rcp_ss(_mm_set_ss(x)));
#else
return 1.0f / x;

View File

@@ -1,49 +0,0 @@
diff --git a/gfx/wr/webrender/res/debug.glsl b/gfx/wr/webrender/res/debug.glsl
new file mode 100644
--- /dev/null
+++ b/gfx/wr/webrender/res/debug.glsl
@@ -0,0 +1,43 @@
+/* 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/. */
+
+// Display a signed distance field as color
+//
+// It will be orange outside the shape (positive distance), and blue
+// inside (negative distance).
+//
+// Color will cycle every 10px.
+//
+// The shape outline (distance = 0) is drawn as a thin white outline.
+//
+// NaNs and infinite values will be drawn as red and yellow respectively.
+//
+// Example usage:
+//
+// #include debug
+//
+// void main(void) {
+// float d = compute_some_distance_in_pixels(...);
+// oFragColor = debug_sdf(d);
+// }
+//
+vec4 debug_sdf(float d) {
+ if (isnan(d)) {
+ return vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ if (isinf(d)) {
+ return vec4(1.0, 1.0, 0.0, 1.0);
+ }
+
+ vec3 color = (d > 0.0) ? vec3(0.9, 0.6, 0.3) : vec3(0.6, 0.8, 1.0);
+ color *= 1.0 - exp(-0.32 * abs(d));
+ color *= fract(d / 10.0) * 0.4 + 0.6;
+#ifdef SWGL
+ // SWGL doesn't support smoothstep() for now
+ color = mix(color, vec3(1.0), step(abs(d), 2.0));
+#else
+ color = mix(color, vec3(1.0), smoothstep(2.0, 0.0, abs(d)));
+#endif
+ return vec4(color, 1.0);
+}

View File

@@ -1,456 +0,0 @@
diff --git a/gfx/wr/wrench/reftests/clip/clip-superellipse.png b/gfx/wr/wrench/reftests/clip/clip-superellipse.png
new file mode 100644
index 0000000000000000000000000000000000000000..4470f8b707c255bc3e4eb026368945267ee895e6
GIT binary patch
literal 7953
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
G@_zvPNe@N<
literal 0
Hc$@<O00001
diff --git a/gfx/wr/wrench/reftests/clip/clip-superellipse.yaml b/gfx/wr/wrench/reftests/clip/clip-superellipse.yaml
new file mode 100644
--- /dev/null
+++ b/gfx/wr/wrench/reftests/clip/clip-superellipse.yaml
@@ -0,0 +1,174 @@
+---
+root:
+ items:
+ - type: clip
+ id: 100
+ complex:
+ - rect: [20, 20, 100, 100]
+ radius:
+ top-left: [32, 16]
+ top-right: [32, 16]
+ bottom-right: [32, 16]
+ bottom-left: [32, 16]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ - type: clip-chain
+ id: 200
+ clips: [100]
+ - type: rect
+ bounds: [20, 20, 100, 100]
+ color: red
+ clip-chain: 200
+
+ - type: clip
+ id: 101
+ complex:
+ - rect: [130, 20, 100, 100]
+ radius:
+ top-left: [32, 16]
+ top-right: [32, 16]
+ bottom-right: [32, 16]
+ bottom-left: [32, 16]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ clip-mode: clip-out
+ - type: clip-chain
+ id: 201
+ clips: [101]
+ - type: rect
+ bounds: [130, 20, 100, 100]
+ color: green
+ clip-chain: 201
+
+ - type: clip
+ id: 102
+ complex:
+ - rect: [20, 130, 100, 100]
+ radius:
+ top-left: [16, 32]
+ top-right: [16, 32]
+ bottom-right: [16, 32]
+ bottom-left: [16, 32]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ - type: clip-chain
+ id: 202
+ clips: [102]
+ - type: rect
+ bounds: [20, 130, 100, 100]
+ color: red
+ clip-chain: 202
+
+ - type: clip
+ id: 103
+ complex:
+ - rect: [130, 130, 100, 100]
+ radius:
+ top-left: [16, 32]
+ top-right: [16, 32]
+ bottom-right: [16, 32]
+ bottom-left: [16, 32]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ clip-mode: clip-out
+ - type: clip-chain
+ id: 203
+ clips: [103]
+ - type: rect
+ bounds: [130, 130, 100, 100]
+ color: green
+ clip-chain: 203
+
+ - type: clip
+ id: 104
+ complex:
+ - rect: [20, 240, 100, 100]
+ radius:
+ top-left: [128, 32]
+ top-right: [128, 32]
+ bottom-right: [128, 32]
+ bottom-left: [128, 32]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ - type: clip-chain
+ id: 204
+ clips: [104]
+ - type: rect
+ bounds: [20, 240, 100, 100]
+ color: red
+ clip-chain: 204
+
+ - type: clip
+ id: 105
+ complex:
+ - rect: [130, 240, 100, 100]
+ radius:
+ top-left: [128, 32]
+ top-right: [128, 32]
+ bottom-right: [128, 32]
+ bottom-left: [128, 32]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ clip-mode: clip-out
+ - type: clip-chain
+ id: 205
+ clips: [105]
+ - type: rect
+ bounds: [130, 240, 100, 100]
+ color: green
+ clip-chain: 205
+
+ - type: clip
+ id: 106
+ complex:
+ - rect: [20, 350, 100, 100]
+ radius:
+ top-left: [32, 128]
+ top-right: [32, 128]
+ bottom-right: [32, 128]
+ bottom-left: [32, 128]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ - type: clip-chain
+ id: 206
+ clips: [106]
+ - type: rect
+ bounds: [20, 350, 100, 100]
+ color: red
+ clip-chain: 206
+
+ - type: clip
+ id: 107
+ complex:
+ - rect: [130, 350, 100, 100]
+ radius:
+ top-left: [32, 128]
+ top-right: [32, 128]
+ bottom-right: [32, 128]
+ bottom-left: [32, 128]
+ shape-top-left: 0.5
+ shape-top-right: +Inf
+ shape-bottom-left: -2.1
+ shape-bottom-right: 0
+ clip-mode: clip-out
+ - type: clip-chain
+ id: 207
+ clips: [107]
+ - type: rect
+ bounds: [130, 350, 100, 100]
+ color: green
+ clip-chain: 207
diff --git a/gfx/wr/wrench/reftests/clip/reftest.list b/gfx/wr/wrench/reftests/clip/reftest.list
--- a/gfx/wr/wrench/reftests/clip/reftest.list
+++ b/gfx/wr/wrench/reftests/clip/reftest.list
@@ -1,8 +1,9 @@
platform(linux,mac) == border-with-rounded-clip.yaml border-with-rounded-clip.png
fuzzy-if(platform(swgl),1,4) == clip-mode.yaml clip-mode.png
fuzzy-if(platform(swgl),1,80) == clip-ellipse.yaml clip-ellipse.png
+fuzzy-if(platform(android),128,200) fuzzy-if(platform(swgl),1,350) == clip-superellipse.yaml clip-superellipse.png
fuzzy(1,1000) platform(linux,mac) == clip-45-degree-rotation.yaml clip-45-degree-rotation-ref.png
== clip-3d-transform.yaml clip-3d-transform-ref.yaml
fuzzy(1,4) == clip-corner-overlap.yaml clip-corner-overlap-ref.yaml
== custom-clip-chain-node-ancestors.yaml custom-clip-chain-node-ancestors-ref.yaml
== fixed-position-clipping.yaml fixed-position-clipping-ref.yaml
diff --git a/gfx/wr/wrench/reftests/mask/reftest.list b/gfx/wr/wrench/reftests/mask/reftest.list
--- a/gfx/wr/wrench/reftests/mask/reftest.list
+++ b/gfx/wr/wrench/reftests/mask/reftest.list
@@ -14,5 +14,6 @@
platform(linux,mac) == checkerboard.yaml checkerboard.png
skip_on(android,device) fuzzy(2,1900) == checkerboard.yaml checkerboard-tiling.yaml # Fails on a Pixel2
== missing-mask.yaml missing-mask-ref.yaml
platform(linux) == scaled-filter-raster-root.yaml scaled-filter-raster-root.png
platform(linux,mac) == mask-multiple-coord-systems.yaml mask-multiple-coord-systems.png
+fuzzy(1,10) fuzzy-if(platform(swgl),5,100) == shaped-corners.yaml shaped-corners.png
diff --git a/gfx/wr/wrench/reftests/mask/shaped-corners.png b/gfx/wr/wrench/reftests/mask/shaped-corners.png
new file mode 100644
index 0000000000000000000000000000000000000000..0599a1f93a7d3564c6da950908fe495c98216f7c
GIT binary patch
literal 2026
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
TV>Bg#Z@5WtKp0!@_p|UHon4m#
literal 0
Hc$@<O00001
diff --git a/gfx/wr/wrench/reftests/mask/shaped-corners.yaml b/gfx/wr/wrench/reftests/mask/shaped-corners.yaml
new file mode 100644
--- /dev/null
+++ b/gfx/wr/wrench/reftests/mask/shaped-corners.yaml
@@ -0,0 +1,12 @@
+---
+root:
+ items:
+ - type: clip
+ id: 2
+ complex:
+ - rect: [10, 10, 200, 200]
+ radius: [200, 200, 200, 200, 8.2, 0, -2.8, +Inf]
+ - type: rect
+ clip-chain: [2]
+ bounds: [10, 10, 200, 200]
+ color: blue
diff --git a/gfx/wr/wrench/src/yaml_helper.rs b/gfx/wr/wrench/src/yaml_helper.rs
--- a/gfx/wr/wrench/src/yaml_helper.rs
+++ b/gfx/wr/wrench/src/yaml_helper.rs
@@ -206,10 +206,12 @@
impl YamlHelper for Yaml {
fn as_f32(&self) -> Option<f32> {
match *self {
Yaml::Integer(iv) => Some(iv as f32),
Yaml::Real(ref sv) => f32::from_str(sv.as_str()).ok(),
+ Yaml::String(ref sv) if sv == "+Inf" => Some(f32::INFINITY),
+ Yaml::String(ref sv) if sv == "-Inf" => Some(f32::NEG_INFINITY),
_ => None,
}
}
fn as_force_f32(&self) -> Option<f32> {
@@ -483,24 +485,48 @@
shape_top_right: 1.0,
shape_bottom_left: 1.0,
shape_bottom_right: 1.0,
})
}
+ Yaml::Array(ref array) if array.len() == 8 => {
+ let top_left = array[0].as_border_radius_component();
+ let top_right = array[1].as_border_radius_component();
+ let bottom_left = array[2].as_border_radius_component();
+ let bottom_right = array[3].as_border_radius_component();
+ let shape_top_left = array[4].as_f32().unwrap();
+ let shape_top_right = array[5].as_f32().unwrap();
+ let shape_bottom_left = array[6].as_f32().unwrap();
+ let shape_bottom_right = array[7].as_f32().unwrap();
+ Some(BorderRadius {
+ top_left,
+ top_right,
+ bottom_left,
+ bottom_right,
+ shape_top_left,
+ shape_top_right,
+ shape_bottom_left,
+ shape_bottom_right,
+ })
+ }
Yaml::Hash(_) => {
let top_left = self["top-left"].as_border_radius_component();
let top_right = self["top-right"].as_border_radius_component();
let bottom_left = self["bottom-left"].as_border_radius_component();
let bottom_right = self["bottom-right"].as_border_radius_component();
+ let shape_top_left = self["shape-top-left"].as_f32().unwrap_or(1.0);
+ let shape_top_right = self["shape-top-right"].as_f32().unwrap_or(1.0);
+ let shape_bottom_left = self["shape-bottom-left"].as_f32().unwrap_or(1.0);
+ let shape_bottom_right = self["shape-bottom-right"].as_f32().unwrap_or(1.0);
Some(BorderRadius {
top_left,
top_right,
bottom_left,
bottom_right,
- shape_top_left: 1.0,
- shape_top_right: 1.0,
- shape_bottom_left: 1.0,
- shape_bottom_right: 1.0,
+ shape_top_left,
+ shape_top_right,
+ shape_bottom_left,
+ shape_bottom_right,
})
}
_ => {
panic!("Invalid border radius specified: {:?}", self);
}

View File

@@ -1,592 +0,0 @@
diff --git a/gfx/wr/webrender/res/border_shared.glsl b/gfx/wr/webrender/res/border_shared.glsl
new file mode 100644
--- /dev/null
+++ b/gfx/wr/webrender/res/border_shared.glsl
@@ -0,0 +1,47 @@
+/* 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/. */
+
+#include gpu_buffer
+
+#define SEGMENT_TOP_LEFT 0
+#define SEGMENT_TOP_RIGHT 1
+#define SEGMENT_BOTTOM_RIGHT 2
+#define SEGMENT_BOTTOM_LEFT 3
+#define SEGMENT_LEFT 4
+#define SEGMENT_TOP 5
+#define SEGMENT_RIGHT 6
+#define SEGMENT_BOTTOM 7
+
+#ifdef WR_VERTEX_SHADER
+
+PER_INSTANCE in vec2 aTaskOrigin;
+PER_INSTANCE in int aFlags;
+PER_INSTANCE in int aGpuDataAddress;
+PER_INSTANCE in vec4 aClipParams1;
+PER_INSTANCE in vec4 aClipParams2;
+
+struct BorderInstanceGpuData {
+ vec4 rect;
+ vec4 color0;
+ vec4 color1;
+ vec2 widths;
+ vec2 radii;
+ float shape;
+};
+
+BorderInstanceGpuData fetch_gpu_data(int index) {
+ BorderInstanceGpuData data;
+
+ vec4 texels[5] = fetch_from_gpu_buffer_5f(index);
+ data.rect = texels[0];
+ data.color0 = texels[1];
+ data.color1 = texels[2];
+ data.widths = texels[3].xy;
+ data.radii = texels[3].zw;
+ data.shape = texels[4].x;
+
+ return data;
+}
+
+#endif
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
@@ -1,10 +1,10 @@
/* 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/. */
-#include shared,rect,ellipse
+#include shared,rect,border_shared,ellipse
// For edges, the colors are the same. For corners, these
// are the colors of each edge making up the corner.
flat varying mediump vec4 vColor00;
flat varying mediump vec4 vColor01;
@@ -44,19 +44,10 @@
flat varying mediump vec4 vClipParams2;
// Local space position
varying highp vec2 vPos;
-#define SEGMENT_TOP_LEFT 0
-#define SEGMENT_TOP_RIGHT 1
-#define SEGMENT_BOTTOM_RIGHT 2
-#define SEGMENT_BOTTOM_LEFT 3
-#define SEGMENT_LEFT 4
-#define SEGMENT_TOP 5
-#define SEGMENT_RIGHT 6
-#define SEGMENT_BOTTOM 7
-
// Border styles as defined in webrender_api/types.rs
#define BORDER_STYLE_NONE 0
#define BORDER_STYLE_SOLID 1
#define BORDER_STYLE_DOUBLE 2
#define BORDER_STYLE_DOTTED 3
@@ -72,20 +63,10 @@
#define CLIP_DASH_EDGE 2
#define CLIP_DOT 3
#ifdef WR_VERTEX_SHADER
-PER_INSTANCE in vec2 aTaskOrigin;
-PER_INSTANCE in vec4 aRect;
-PER_INSTANCE in vec4 aColor0;
-PER_INSTANCE in vec4 aColor1;
-PER_INSTANCE in int aFlags;
-PER_INSTANCE in vec2 aWidths;
-PER_INSTANCE in vec2 aRadii;
-PER_INSTANCE in vec4 aClipParams1;
-PER_INSTANCE in vec4 aClipParams2;
-
vec2 get_outer_corner_scale(int segment) {
vec2 p;
switch (segment) {
case SEGMENT_TOP_LEFT:
@@ -153,16 +134,18 @@
return result;
}
void main(void) {
+ BorderInstanceGpuData data = fetch_gpu_data(aGpuDataAddress);
+
int segment = aFlags & 0xff;
int style0 = (aFlags >> 8) & 0xff;
int style1 = (aFlags >> 16) & 0xff;
int clip_mode = (aFlags >> 24) & 0x0f;
- vec2 size = aRect.zw - aRect.xy;
+ vec2 size = data.rect.zw - data.rect.xy;
vec2 outer_scale = get_outer_corner_scale(segment);
vec2 outer = outer_scale * size;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
// Set some flags used by the FS to determine the
@@ -176,19 +159,19 @@
edge_axis = ivec2(0, 1);
edge_reference = outer;
break;
case SEGMENT_TOP_RIGHT:
edge_axis = ivec2(1, 0);
- edge_reference = vec2(outer.x - aWidths.x, outer.y);
+ edge_reference = vec2(outer.x - data.widths.x, outer.y);
break;
case SEGMENT_BOTTOM_RIGHT:
edge_axis = ivec2(0, 1);
- edge_reference = outer - aWidths;
+ edge_reference = outer - data.widths;
break;
case SEGMENT_BOTTOM_LEFT:
edge_axis = ivec2(1, 0);
- edge_reference = vec2(outer.x, outer.y - aWidths.y);
+ edge_reference = vec2(outer.x, outer.y - data.widths.y);
break;
case SEGMENT_TOP:
case SEGMENT_BOTTOM:
edge_axis = ivec2(1, 1);
break;
@@ -199,23 +182,23 @@
}
vSegmentClipMode = vec2(float(segment), float(clip_mode));
vStyleEdgeAxis = vec4(float(style0), float(style1), float(edge_axis.x), float(edge_axis.y));
- vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
+ vPartialWidths = vec4(data.widths / 3.0, data.widths / 2.0);
vPos = size * aPosition.xy;
- vec4[2] color0 = get_colors_for_side(aColor0, style0);
+ vec4[2] color0 = get_colors_for_side(data.color0, style0);
vColor00 = color0[0];
vColor01 = color0[1];
- vec4[2] color1 = get_colors_for_side(aColor1, style1);
+ vec4[2] color1 = get_colors_for_side(data.color1, style1);
vColor10 = color1[0];
vColor11 = color1[1];
- vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
- vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
- vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
- vEdgeReference = vec4(edge_reference, edge_reference + aWidths);
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
+ vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
+ 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;
// For the case of dot and dash clips, optimize the number of pixels that
// are hit to just include the dot itself.
@@ -234,17 +217,17 @@
// This is a gross approximation which works out because dashes don't have
// a strong curvature and we will overshoot by inflating the geometry by
// this amount on each side (sqrt(2) * length(dash) would be enough and we
// compute 2 * approx_length(dash)).
float dash_length = length(aClipParams1.xy - aClipParams2.xy);
- float width = max(aWidths.x, aWidths.y);
+ float width = max(data.widths.x, data.widths.y);
// expand by a small amout for AA just like we do for dots.
vec2 r = vec2(max(dash_length, width)) + 2.0;
vPos = clamp(vPos, center - r, center + r);
}
- gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
+ gl_Position = uTransform * vec4(aTaskOrigin + data.rect.xy + vPos, 0.0, 1.0);
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 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
@@ -1,10 +1,10 @@
/* 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/. */
-#include shared,rect,ellipse
+#include shared,rect,border_shared,ellipse
#define DONT_MIX 0
#define MIX_AA 1
#define MIX_NO_AA 2
@@ -37,27 +37,12 @@
flat varying highp vec2 vVerticalClipRadii;
// Local space position
varying highp vec2 vPos;
-#define SEGMENT_TOP_LEFT 0
-#define SEGMENT_TOP_RIGHT 1
-#define SEGMENT_BOTTOM_RIGHT 2
-#define SEGMENT_BOTTOM_LEFT 3
-
#ifdef WR_VERTEX_SHADER
-PER_INSTANCE in vec2 aTaskOrigin;
-PER_INSTANCE in vec4 aRect;
-PER_INSTANCE in vec4 aColor0;
-PER_INSTANCE in vec4 aColor1;
-PER_INSTANCE in int aFlags;
-PER_INSTANCE in vec2 aWidths;
-PER_INSTANCE in vec2 aRadii;
-PER_INSTANCE in vec4 aClipParams1;
-PER_INSTANCE in vec4 aClipParams2;
-
vec2 get_outer_corner_scale(int segment) {
vec2 p;
switch (segment) {
case SEGMENT_TOP_LEFT:
@@ -80,15 +65,17 @@
return p;
}
void main(void) {
+ BorderInstanceGpuData data = fetch_gpu_data(aGpuDataAddress);
+
int segment = aFlags & 0xff;
bool do_aa = ((aFlags >> 24) & 0xf0) != 0;
vec2 outer_scale = get_outer_corner_scale(segment);
- vec2 size = aRect.zw - aRect.xy;
+ vec2 size = data.rect.zw - data.rect.xy;
vec2 outer = outer_scale * size;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
int mix_colors;
switch (segment) {
@@ -105,15 +92,15 @@
}
vMixColors.x = mix_colors;
vPos = size * aPosition.xy;
- vColor0 = aColor0;
- vColor1 = aColor1;
- vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
- vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
- vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
+ vColor0 = data.color0;
+ vColor1 = data.color1;
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
+ vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
+ vColorLine = vec4(outer, data.widths.y * -clip_sign.y, data.widths.x * clip_sign.x);
vec2 horizontal_clip_sign = vec2(-clip_sign.x, clip_sign.y);
vHorizontalClipCenter_Sign = vec4(aClipParams1.xy +
horizontal_clip_sign * aClipParams1.zw,
horizontal_clip_sign);
@@ -123,11 +110,11 @@
vVerticalClipCenter_Sign = vec4(aClipParams2.xy +
vertical_clip_sign * aClipParams2.zw,
vertical_clip_sign);
vVerticalClipRadii = aClipParams2.zw;
- gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
+ gl_Position = uTransform * vec4(aTaskOrigin + data.rect.xy + vPos, 0.0, 1.0);
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
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
@@ -6,13 +6,14 @@
use api::{NormalBorder as ApiNormalBorder, RepeatMode};
use api::units::*;
use crate::clip::ClipNodeId;
use crate::ellipse::Ellipse;
use euclid::vec2;
+use crate::renderer::GpuBufferBuilderF;
use crate::scene_building::SceneBuilder;
use crate::spatial_tree::SpatialNodeIndex;
-use crate::gpu_types::{BorderInstance, BorderSegment, BrushFlags};
+use crate::gpu_types::{BorderInstance, BorderInstanceGpuData, BorderSegment, BrushFlags};
use crate::prim_store::{BorderSegmentInfo, BrushSegment, NinePatchDescriptor};
use crate::prim_store::borders::NormalBorderPrim;
use crate::util::{lerp, RectHelpers};
use crate::internal_types::LayoutPrimitiveInfo;
use crate::segment::EdgeMask;
@@ -125,10 +126,11 @@
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BorderSegmentCacheKey {
pub size: LayoutSizeAu,
pub radius: LayoutSizeAu,
+ pub shape: u32,
pub side0: BorderSideAu,
pub side1: BorderSideAu,
pub segment: BorderSegment,
pub do_aa: bool,
pub h_adjacent_corner_outer: LayoutPointAu,
@@ -762,10 +764,11 @@
),
border.left,
border.top,
LayoutSize::new(widths.left, widths.top),
border.radius.top_left,
+ border.radius.shape_top_left,
BorderSegment::TopLeft,
EdgeMask::TOP | EdgeMask::LEFT,
rect.top_right(),
border.radius.top_right,
rect.bottom_left(),
@@ -789,10 +792,11 @@
),
border.top,
border.right,
LayoutSize::new(widths.right, widths.top),
border.radius.top_right,
+ border.radius.shape_top_right,
BorderSegment::TopRight,
EdgeMask::TOP | EdgeMask::RIGHT,
rect.min,
border.radius.top_left,
rect.max,
@@ -816,10 +820,11 @@
),
border.right,
border.bottom,
LayoutSize::new(widths.right, widths.bottom),
border.radius.bottom_right,
+ border.radius.shape_bottom_right,
BorderSegment::BottomRight,
EdgeMask::BOTTOM | EdgeMask::RIGHT,
rect.bottom_left(),
border.radius.bottom_left,
rect.top_right(),
@@ -843,10 +848,11 @@
),
border.bottom,
border.left,
LayoutSize::new(widths.left, widths.bottom),
border.radius.bottom_left,
+ border.radius.shape_bottom_left,
BorderSegment::BottomLeft,
EdgeMask::BOTTOM | EdgeMask::LEFT,
rect.max,
border.radius.bottom_right,
rect.min,
@@ -881,30 +887,37 @@
color1: ColorF,
segment: BorderSegment,
instances: &mut Vec<BorderInstance>,
widths: DeviceSize,
radius: DeviceSize,
+ shape: f32,
do_aa: bool,
h_adjacent_corner_outer: DevicePoint,
h_adjacent_corner_radius: DeviceSize,
v_adjacent_corner_outer: DevicePoint,
v_adjacent_corner_radius: DeviceSize,
+ gpu_buffer_builder: &mut GpuBufferBuilderF,
) {
let base_flags = (segment as i32) |
((style0 as i32) << 8) |
((style1 as i32) << 16) |
((do_aa as i32) << 28);
- let base_instance = BorderInstance {
- task_origin: DevicePoint::zero(),
+ let instance_gpu_data = BorderInstanceGpuData {
local_rect: task_rect,
- flags: base_flags,
color0: color0.premultiplied(),
color1: color1.premultiplied(),
widths,
radius,
+ shape
+ };
+
+ 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)
};
match segment {
BorderSegment::TopLeft |
BorderSegment::TopRight |
@@ -1018,10 +1031,11 @@
non_overlapping_rect: LayoutRect,
side0: BorderSide,
side1: BorderSide,
widths: LayoutSize,
radius: LayoutSize,
+ shape: f32,
segment: BorderSegment,
edge_flags: EdgeMask,
h_adjacent_corner_outer: LayoutPoint,
h_adjacent_corner_radius: LayoutSize,
v_adjacent_corner_outer: LayoutPoint,
@@ -1137,10 +1151,11 @@
do_aa,
side0: side0.into(),
side1: side1.into(),
segment,
radius: radius.to_au(),
+ shape: shape.to_bits(),
size: widths.to_au(),
h_adjacent_corner_outer: (h_corner_outer - image_rect.min).to_point().to_au(),
h_adjacent_corner_radius: h_corner_radius.to_au(),
v_adjacent_corner_outer: (v_corner_outer - image_rect.min).to_point().to_au(),
v_adjacent_corner_radius: v_corner_radius.to_au(),
@@ -1200,10 +1215,11 @@
cache_key: BorderSegmentCacheKey {
do_aa,
side0: side.into(),
side1: side.into(),
radius: LayoutSizeAu::zero(),
+ shape: 0,
size: size.to_au(),
segment,
h_adjacent_corner_outer: LayoutPointAu::zero(),
h_adjacent_corner_radius: LayoutSizeAu::zero(),
v_adjacent_corner_outer: LayoutPointAu::zero(),
@@ -1217,10 +1233,11 @@
pub fn build_border_instances(
cache_key: &BorderSegmentCacheKey,
cache_size: DeviceIntSize,
border: &ApiNormalBorder,
scale: LayoutToDeviceScale,
+ gpu_buffer_builder: &mut GpuBufferBuilderF,
) -> Vec<BorderInstance> {
let mut instances = Vec::new();
let (side0, side1, flip0, flip1) = match cache_key.segment {
BorderSegment::Left => (&border.left, &border.left, false, false),
@@ -1247,10 +1264,11 @@
let color0 = side0.border_color(flip0);
let color1 = side1.border_color(flip1);
let widths = (LayoutSize::from_au(cache_key.size) * scale).ceil();
let radius = (LayoutSize::from_au(cache_key.radius) * scale).ceil();
+ let shape = f32::from_bits(cache_key.shape);
let h_corner_outer = (LayoutPoint::from_au(cache_key.h_adjacent_corner_outer) * scale).round();
let h_corner_radius = (LayoutSize::from_au(cache_key.h_adjacent_corner_radius) * scale).ceil();
let v_corner_outer = (LayoutPoint::from_au(cache_key.v_adjacent_corner_outer) * scale).round();
let v_corner_radius = (LayoutSize::from_au(cache_key.v_adjacent_corner_radius) * scale).ceil();
@@ -1263,15 +1281,17 @@
color1,
cache_key.segment,
&mut instances,
widths,
radius,
+ shape,
border.do_aa,
h_corner_outer,
h_corner_radius,
v_corner_outer,
v_corner_radius,
+ gpu_buffer_builder,
);
instances
}
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,22 +192,40 @@
Top,
Right,
Bottom,
}
+pub struct BorderInstanceGpuData {
+ pub local_rect: DeviceRect,
+ pub color0: PremultipliedColorF,
+ pub color1: PremultipliedColorF,
+ pub widths: DeviceSize,
+ pub radius: DeviceSize,
+ pub shape: f32,
+}
+
+impl BorderInstanceGpuData {
+ pub fn write(&self, gpu_buffer_builder: &mut GpuBufferBuilderF) -> GpuBufferAddress {
+ let mut writer = gpu_buffer_builder.write_blocks(5);
+ 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, 0.0, 0.0, 0.0]);
+
+ writer.finish()
+ }
+}
+
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BorderInstance {
pub task_origin: DevicePoint,
- pub local_rect: DeviceRect,
- pub color0: PremultipliedColorF,
- pub color1: PremultipliedColorF,
pub flags: i32,
- pub widths: DeviceSize,
- pub radius: DeviceSize,
+ pub gpu_data_address: GpuBufferAddress,
pub clip_params: [f32; 8],
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
diff --git a/gfx/wr/webrender/src/prim_store/borders.rs b/gfx/wr/webrender/src/prim_store/borders.rs
--- a/gfx/wr/webrender/src/prim_store/borders.rs
+++ b/gfx/wr/webrender/src/prim_store/borders.rs
@@ -230,19 +230,20 @@
false, // TODO(gw): We don't calculate opacity for borders yet!
RenderTaskParent::Surface,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
&mut frame_state.surface_builder,
- &mut |rg_builder, _| {
+ &mut |rg_builder, gpu_buffer_builder| {
rg_builder.add().init(RenderTask::new_dynamic(
cache_size,
RenderTaskKind::new_border_segment(
build_border_instances(
&segment.cache_key,
cache_size,
&self.border,
scale,
+ gpu_buffer_builder,
)
),
))
}
);
diff --git a/gfx/wr/webrender/src/renderer/vertex.rs b/gfx/wr/webrender/src/renderer/vertex.rs
--- a/gfx/wr/webrender/src/renderer/vertex.rs
+++ b/gfx/wr/webrender/src/renderer/vertex.rs
@@ -63,16 +63,12 @@
pub const BORDER: VertexDescriptor = VertexDescriptor {
vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
instance_attributes: &[
VertexAttribute::f32x2("aTaskOrigin"),
- VertexAttribute::f32x4("aRect"),
- VertexAttribute::f32x4("aColor0"),
- VertexAttribute::f32x4("aColor1"),
VertexAttribute::i32("aFlags"),
- VertexAttribute::f32x2("aWidths"),
- VertexAttribute::f32x2("aRadii"),
+ VertexAttribute::gpu_buffer_address("aGpuDataAddress"),
VertexAttribute::f32x4("aClipParams1"),
VertexAttribute::f32x4("aClipParams2"),
],
};

View File

@@ -2,24 +2,6 @@
// 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/.
[
{
"type": "phabricator",
"ids": [
"D296935",
"D303334",
"D297660",
"D304517",
"D306773",
"D306774",
"D306775",
"D306776",
"D306777",
"D306778",
"D306779"
],
"name": "Corner shape support"
},
{
"type": "phabricator",
"id": "D299584",

View File

@@ -6,29 +6,29 @@ import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components
// prettier-ignore
const SVG_ICONS = [
"airplane.svg", "american-football.svg", "baseball.svg", "basket.svg",
"bed.svg", "bell.svg", "bookmark.svg", "book.svg",
"briefcase.svg", "brush.svg", "bug.svg", "build.svg",
"cafe.svg", "call.svg", "card.svg", "chat.svg",
"checkbox.svg", "circle.svg", "cloud.svg", "code.svg",
"coins.svg", "construct.svg", "cutlery.svg", "egg.svg",
"extension-puzzle.svg", "eye.svg", "fast-food.svg", "fish.svg",
"flag.svg", "flame.svg", "flask.svg", "folder.svg",
"game-controller.svg", "globe-1.svg", "globe.svg", "grid-2x2.svg",
"grid-3x3.svg", "heart.svg", "ice-cream.svg", "image.svg",
"inbox.svg", "key.svg", "layers.svg", "leaf.svg",
"lightning.svg", "location.svg", "lock-closed.svg", "logo-rss.svg",
"logo-usd.svg", "mail.svg", "map.svg", "megaphone.svg",
"moon.svg", "music.svg", "navigate.svg", "nuclear.svg",
"page.svg", "palette.svg", "paw.svg", "people.svg",
"pizza.svg", "planet.svg", "present.svg", "rocket.svg",
"school.svg", "shapes.svg", "shirt.svg", "skull.svg",
"squares.svg", "square.svg", "star-1.svg", "star.svg",
"stats-chart.svg", "sun.svg", "tada.svg", "terminal.svg",
"ticket.svg", "time.svg", "trash.svg", "triangle.svg",
"video.svg", "volume-high.svg", "wallet.svg", "warning.svg",
"water.svg", "weight.svg",
];
"airplane.svg", "american-football.svg", "baseball.svg", "basket.svg",
"bed.svg", "bell.svg", "bookmark.svg", "book.svg",
"briefcase.svg", "brush.svg", "bug.svg", "build.svg",
"cafe.svg", "call.svg", "card.svg", "chat.svg",
"checkbox.svg", "circle.svg", "cloud.svg", "code.svg",
"coins.svg", "construct.svg", "cutlery.svg", "egg.svg",
"extension-puzzle.svg", "eye.svg", "fast-food.svg", "fish.svg",
"flag.svg", "flame.svg", "flask.svg", "folder.svg",
"game-controller.svg", "globe-1.svg", "globe.svg", "grid-2x2.svg",
"grid-3x3.svg", "heart.svg", "ice-cream.svg", "image.svg",
"inbox.svg", "key.svg", "layers.svg", "leaf.svg",
"lightning.svg", "location.svg", "lock-closed.svg", "logo-rss.svg",
"logo-usd.svg", "mail.svg", "map.svg", "megaphone.svg",
"moon.svg", "music.svg", "navigate.svg", "nuclear.svg",
"page.svg", "palette.svg", "paw.svg", "people.svg",
"pizza.svg", "planet.svg", "present.svg", "rocket.svg",
"school.svg", "shapes.svg", "shirt.svg", "skull.svg",
"squares.svg", "square.svg", "star-1.svg", "star.svg",
"stats-chart.svg", "sun.svg", "tada.svg", "terminal.svg",
"ticket.svg", "time.svg", "trash.svg", "triangle.svg",
"video.svg", "volume-high.svg", "wallet.svg", "warning.svg",
"water.svg", "weight.svg",
];
class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
#panel;
@@ -47,6 +47,7 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
init() {
this.#panel = document.getElementById("PanelUI-zen-emojis-picker");
this.#panel.addEventListener("popupshowing", this);
this.#panel.addEventListener("popupshown", this);
this.#panel.addEventListener("popuphidden", this);
this.#panel.addEventListener("command", this);
this.searchInput.addEventListener("input", this);
@@ -57,6 +58,9 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
case "popupshowing":
this.#onPopupShowing(event);
break;
case "popupshown":
this.#onPopupShown(event);
break;
case "popuphidden":
this.#onPopupHidden(event);
break;
@@ -103,17 +107,20 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
return document.getElementById("PanelUI-zen-emojis-picker-search");
}
#changePage(toSvg = false) {
#changePage(toSvg = false, { animate = true } = {}) {
const pages = document.getElementById("PanelUI-zen-emojis-picker-pages");
const itemToScroll = toSvg
? this.svgList
: document
.getElementById("PanelUI-zen-emojis-picker-pages")
.querySelector('[emojis="true"]');
itemToScroll.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "start",
});
: pages.querySelector('[emojis="true"]');
if (animate) {
itemToScroll.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "start",
});
} else {
pages.scrollLeft = toSvg ? itemToScroll.offsetLeft : 0;
}
const button = document.getElementById(
`PanelUI-zen-emojis-picker-change-${toSvg ? "svg" : "emojis"}`
);
@@ -180,9 +187,6 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
});
emojiList.appendChild(item);
}
setTimeout(() => {
this.searchInput.focus();
}, 500);
}
const svgList = this.svgList;
for (const icon of SVG_ICONS) {
@@ -199,14 +203,23 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
}
}
#onPopupShown(event) {
if (event.target !== this.#panel) {
return;
}
const allowEmojis = !this.#panel.hasAttribute("only-svg-icons");
if (allowEmojis) {
this.searchInput.focus({ preventScroll: true });
}
this.#changePage(false, { animate: false });
}
#onPopupHidden(event) {
if (event.target !== this.#panel) {
return;
}
this.#clearEmojis();
this.#changePage(false);
const emojiList = this.emojiList;
emojiList.innerHTML = "";

View File

@@ -185,7 +185,7 @@
.toolbarbutton-1:not(#tabs-newtab-button),
.urlbar-page-action,
.identity-box-button {
--tab-border-radius: 8px;
--tab-border-radius: 6px;
--toolbarbutton-border-radius: var(--tab-border-radius);
--toolbarbutton-padding-inner: 6px;
--toolbarbutton-padding-outer: 1px;

View File

@@ -213,8 +213,6 @@
--toolbarbutton-border-radius: 6px;
--urlbar-margin-inline: 1px !important;
--zen-squircle-value: 1.4;
--tab-icon-overlay-stroke: light-dark(white, black) !important;
--tab-close-button-padding: 4px !important;
@@ -345,9 +343,3 @@
}
%include zen-buttons.css
@media (-moz-pref('layout.css.corner-shape.enabled')) {
*:not(.no-squircles) {
corner-shape: superellipse(var(--zen-squircle-value));
}
}

View File

@@ -723,8 +723,11 @@
const { isNearLeftEdge, isNearRightEdge } =
this.#shouldSwitchSpace(event);
if (isNearLeftEdge || isNearRightEdge) {
if (!this.#changeSpaceTimer) {
if (!this.#changeSpaceTimer && !this.#isOutOfWindow) {
this.#changeSpaceTimer = setTimeout(() => {
if (this.#isOutOfWindow) {
return;
}
this.clearDragOverVisuals();
gZenWorkspaces
.changeWorkspaceShortcut(
@@ -956,8 +959,10 @@
if (ownerGlobal?.gZenCompactModeManager) {
// Sometimes, dragend doesn't always get called when dragging
// to different windows, see gh-8643.
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
requestAnimationFrame(() => {
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
});
}
this.clearSpaceSwitchTimer();
gZenFolders.highlightGroupOnDragOver(null);

View File

@@ -53,6 +53,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
#setupEventListeners() {
window.addEventListener("TabClose", this.onTabClose.bind(this));
window.addEventListener("TabSelect", this.onLocationChange.bind(this));
window.addEventListener(
"MozDOMFullscreen:Entered",
this.onFullscreenEntered.bind(this)
);
document
.getElementById("tabbrowser-tabpanels")
@@ -1414,6 +1418,23 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
}
}
/**
* Handle DOM Fullscreen request while inside glance
*
* @param {Event} event - The MozDOMFullscreen:Entered event
*/
onFullscreenEntered(event) {
const browser = this.#currentBrowser;
if (!browser) {
return;
}
if (event.target === browser) {
this.fullyOpenGlance();
}
}
/**
* Manage tab close for glance tabs
*

View File

@@ -41,11 +41,11 @@
&:hover {
background: light-dark(rgb(41, 41, 41), rgb(204, 204, 204));
scale: 1.02;
scale: 1.05;
}
&:hover:active {
scale: 0.98;
scale: 0.95;
}
& label {

View File

@@ -4,8 +4,8 @@
<html:template id="zen-glance-sidebar-template">
<vbox class="zen-glance-sidebar-container">
<toolbarbutton class="no-squircles zen-glance-sidebar-close toolbarbutton-1" command="cmd_zenGlanceClose" data-l10n-id="zen-general-confirm" />
<toolbarbutton class="no-squircles zen-glance-sidebar-open toolbarbutton-1" command="cmd_zenGlanceExpand" />
<toolbarbutton class="no-squircles zen-glance-sidebar-split toolbarbutton-1" command="cmd_zenGlanceSplit" />
<toolbarbutton class="zen-glance-sidebar-close toolbarbutton-1" command="cmd_zenGlanceClose" data-l10n-id="zen-general-confirm" />
<toolbarbutton class="zen-glance-sidebar-open toolbarbutton-1" command="cmd_zenGlanceExpand" />
<toolbarbutton class="zen-glance-sidebar-split toolbarbutton-1" command="cmd_zenGlanceSplit" />
</vbox>
</html:template>

View File

@@ -3,6 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { JSONFile } from "resource://gre/modules/JSONFile.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"shouldForceContainerTabsToWorkspace",
"zen.workspaces.force-container-workspace",
false
);
class nsZenSpaceRoutingManager {
#file = null;
@@ -62,6 +72,37 @@ class nsZenSpaceRoutingManager {
}
}
if (!isRouteFound) {
let tabSpaceId = options.zenWorkspaceId;
let spaceManager = win.gZenWorkspaces;
if (lazy.shouldForceContainerTabsToWorkspace) {
// In case its undefined, to make it into an integer.
const tabContainerId = options.userContextId || 0;
const currentSpace = spaceManager.getActiveWorkspaceFromCache();
console.log("[ZenSpaceRouting] Tab is opening with userContextId", tabContainerId, "and active space has containerTabId", currentSpace.containerTabId);
if (tabContainerId !== currentSpace.containerTabId) {
const targetWorkspace = spaceManager.getWorkspaces().find(
workspace => workspace.containerTabId === tabContainerId
);
if (targetWorkspace) {
tabSpaceId = targetWorkspace.uuid;
}
}
}
// Add support for zen.workspaces.force-container-workspace in SR,
// instead of using the old implementation. Lets create a temporary route
// for this tab, so that it will be routed to the correct space.
if (tabSpaceId && tabSpaceId !== spaceManager.activeWorkspace) {
const targetWorkspace = spaceManager.getWorkspaceFromId(tabSpaceId);
if (targetWorkspace) {
userContextId = targetWorkspace.containerTabId;
isRouteFound = true;
targetWorkspaceName = targetWorkspace.name;
targetRoute = tabSpaceId;
}
}
}
return {
shouldEarlyExit: false,
userContextId,
@@ -167,8 +208,8 @@ class nsZenSpaceRoutingManager {
break;
default: {
const workspaces = win?.gZenWorkspaces;
const targetWorkspace = workspaces?.getWorkspaceFromId?.(targetRoute);
const workspaces = win.gZenWorkspaces;
const targetWorkspace = workspaces.getWorkspaceFromId(targetRoute);
if (targetWorkspace) {
workspaces.moveTabToWorkspace(newTab, targetWorkspace.uuid);

View File

@@ -106,12 +106,6 @@ class nsZenWorkspaces {
"zen.workspaces.wrap-around-navigation",
true
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"shouldForceContainerTabsToWorkspace",
"zen.workspaces.force-container-workspace",
true
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"shouldOpenNewTabIfLastUnpinnedTabIsClosed",
@@ -788,11 +782,6 @@ class nsZenWorkspaces {
window.addEventListener("TabUnpinned", tabUpdateListener);
window.addEventListener("aftercustomization", tabUpdateListener);
window.addEventListener("TabSelect", this.onLocationChange.bind(this));
window.addEventListener(
"TabBrowserInserted",
this.onTabBrowserInserted.bind(this)
);
this.updateWorkspacesChangeContextMenu();
})();
}
@@ -1506,19 +1495,27 @@ class nsZenWorkspaces {
continue;
}
const newtabPlacement = Services.prefs.getBoolPref(
"zen.view.show-newtab-button-top",
false
);
const insertElement = newtabPlacement
? container.firstChild
: container.lastChild;
if (container) {
if (tab.group?.hasAttribute("split-view-group")) {
gBrowser.zenHandleTabMove(tab.group, () => {
for (const subTab of tab.group.tabs) {
subTab.setAttribute("zen-workspace-id", workspaceID);
}
container.insertBefore(tab.group, container.lastChild);
container.insertBefore(tab.group, insertElement);
});
continue;
}
gBrowser.zenHandleTabMove(tab, () => {
tab.setAttribute("zen-workspace-id", workspaceID);
container.insertBefore(tab, container.lastChild);
container.insertBefore(tab, insertElement);
});
}
// also change glance tab if it's the same tab
@@ -2786,44 +2783,6 @@ class nsZenWorkspaces {
}
}
async onTabBrowserInserted(event) {
let tab = event.originalTarget;
const isEssential = tab.getAttribute("zen-essential") === "true";
const workspaceID = tab.getAttribute("zen-workspace-id");
if (!this.workspaceEnabled || isEssential) {
return;
}
if (workspaceID) {
if (
tab.hasAttribute("change-workspace") &&
this.moveTabToWorkspace(tab, workspaceID)
) {
this.lastSelectedWorkspaceTabs[workspaceID] =
gZenGlanceManager.getTabOrGlanceParent(tab);
tab.removeAttribute("change-workspace");
const workspace = this.getWorkspaceFromId(workspaceID);
setTimeout(() => {
this.changeWorkspace(workspace);
}, 0);
}
return;
}
let activeWorkspace = this.getActiveWorkspace();
if (!activeWorkspace) {
return;
}
if (tab.hasAttribute("zen-workspace-id")) {
const tabWorkspaceId = tab.getAttribute("zen-workspace-id");
this.moveTabToWorkspace(tab, tabWorkspaceId);
await this.changeWorkspaceWithID(tabWorkspaceId);
} else {
tab.setAttribute("zen-workspace-id", activeWorkspace.uuid);
}
}
#changeToEmptyTab() {
const isEmpty = gBrowser.selectedTab.hasAttribute("zen-empty-tab");
gZenCompactModeManager.sidebar.toggleAttribute(
@@ -3009,7 +2968,7 @@ class nsZenWorkspaces {
getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal) {
if (!this.workspaceEnabled) {
return [userContextId, false, undefined];
return [userContextId, false];
}
if (
@@ -3017,27 +2976,7 @@ class nsZenWorkspaces {
triggeringPrincipal.isAddonOrExpandedAddonPrincipal &&
typeof userContextId === "undefined"
) {
return [userContextId, false, undefined];
}
if (
this.shouldForceContainerTabsToWorkspace &&
typeof userContextId !== "undefined" &&
this._workspaceCache &&
!fromExternal
) {
// Find all workspaces that match the given userContextId
const matchingWorkspaces = this._workspaceCache.filter(
workspace => workspace.containerTabId === userContextId
);
// Check if exactly one workspace matches
if (matchingWorkspaces.length === 1) {
const workspace = matchingWorkspaces[0];
if (workspace.uuid !== this.getActiveWorkspaceFromCache().uuid) {
return [userContextId, true, workspace.uuid];
}
}
return [userContextId, false];
}
const activeWorkspace = this.getActiveWorkspaceFromCache();
@@ -3048,9 +2987,9 @@ class nsZenWorkspaces {
typeof userContextId !== "undefined" &&
userContextId !== activeWorkspaceUserContextId
) {
return [userContextId, false, undefined];
return [userContextId, false];
}
return [activeWorkspaceUserContextId, true, undefined];
return [activeWorkspaceUserContextId, true];
}
getTabsToExclude(aTab) {

View File

@@ -31,7 +31,6 @@
& toolbarbutton {
margin: 0;
max-width: 28px;
border-radius: var(--toolbarbutton-border-radius);
height: 28px;
display: flex;
justify-content: center;

View File

@@ -235,7 +235,7 @@
}
@media (-moz-platform: macos) {
--border-radius-medium: 14px;
--border-radius-medium: 12px;
--tab-border-radius: 8px;
}
@@ -1232,8 +1232,6 @@
background: var(--zen-essential-tab-selected-bg);
margin: var(--zen-essential-bg-margin);
border-radius: calc(var(--border-radius-medium) - var(--zen-essential-bg-margin));
/* stylelint-disable-next-line property-no-unknown */
corner-shape: var(--zen-squircle-value);
position: absolute;
inset: 0;
z-index: 0;