Merge branch 'dev' into library

This commit is contained in:
mr. m
2026-05-28 09:14:19 +02:00
committed by GitHub
194 changed files with 4743 additions and 597 deletions

View File

@@ -0,0 +1,18 @@
diff --git a/accessible/base/TextAttrs.cpp b/accessible/base/TextAttrs.cpp
index d2ce06bef67ecb6d6ccb798a62d7f2759dd9da18..fb4952df9aa54d4085a282dc269a48ad72979b8b 100644
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -237,11 +237,11 @@ bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame* aFrame,
TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame,
nsIFrame* aFrame)
: TTextAttr<nscolor>(!aFrame) {
- mRootNativeValue = aRootFrame->StyleText()->mColor.ToColor();
+ mRootNativeValue = aRootFrame->StyleText()->mColor.ToColor(aRootFrame);
mIsRootDefined = true;
if (aFrame) {
- mNativeValue = aFrame->StyleText()->mColor.ToColor();
+ mNativeValue = aFrame->StyleText()->mColor.ToColor(aFrame);
mIsDefined = true;
}
}

View File

@@ -0,0 +1,13 @@
diff --git a/accessible/windows/ia2/ia2AccessibleComponent.cpp b/accessible/windows/ia2/ia2AccessibleComponent.cpp
index 7837fdee3db339543f8b3d95dcb23ebe99aed8dc..207adf3ded9848b84ec89e94f80e8e02f161923c 100644
--- a/accessible/windows/ia2/ia2AccessibleComponent.cpp
+++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp
@@ -81,7 +81,7 @@ ia2AccessibleComponent::get_foreground(IA2Color* aForeground) {
if (!acc) return CO_E_OBJNOTCONNECTED;
nsIFrame* frame = acc->GetFrame();
- if (frame) *aForeground = frame->StyleText()->mColor.ToColor();
+ if (frame) *aForeground = frame->StyleText()->mColor.ToColor(frame);
return S_OK;
}

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
index 5905271a3343efa04b45f5d1a63bfca3de342755..af76922c1ba0b35a0072ec044f7d0860f9295d9d 100644
index 5905271a3343efa04b45f5d1a63bfca3de342755..37f57de0ad72271d4c6e188ab9841b23b95f08d0 100644
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
@@ -13,6 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
@@ -195,7 +195,7 @@ index 5905271a3343efa04b45f5d1a63bfca3de342755..af76922c1ba0b35a0072ec044f7d0860
+ win.gZenVerticalTabsManager._hasSetSingleToolbar &&
+ Services.prefs.getBoolPref("zen.view.overflow-webext-toolbar", true) &&
+ !win.gURLBar.hasAttribute("breakout-extend")) {
+ const availSelectors = ":is(#page-action-buttons, #zen-copy-url-button, .unified-extensions-item)";
+ const availSelectors = ":is(#page-action-buttons, #zen-copy-url-button, .unified-extensions-item, .urlbar-addon-page-action)";
+ const width = [
+ ...win.gURLBar._inputContainer.querySelectorAll(availSelectors),
+ ...win.document.getElementById("zen-overflow-extensions-list").querySelectorAll(availSelectors)

View File

@@ -793,6 +793,7 @@ const zenMissingKeyboardShortcutL10n = {
key_selectTab7: "zen-key-select-tab-7",
key_selectTab8: "zen-key-select-tab-8",
key_selectLastTab: "zen-key-select-tab-last",
key_duplicateTab: "customkeys-file-duplicate-tab",
key_showAllTabs: "zen-key-show-all-tabs",
key_gotoHistory: "zen-key-goto-history",
@@ -801,6 +802,7 @@ const zenMissingKeyboardShortcutL10n = {
key_redo: "zen-key-redo",
key_inspectorMac: "zen-key-inspector-mac",
key_findSelection: "zen-key-find-selection",
// Devtools
key_toggleToolbox: "zen-devtools-toggle-shortcut",
@@ -1124,7 +1126,7 @@ var gZenCKSSettings = {
this._hasSafed = false;
input.classList.remove(`${ZEN_CKS_INPUT_FIELD_CLASS}-invalid`);
input.classList.remove(`${ZEN_CKS_INPUT_FIELD_CLASS}-not-set`);
input.value = modifiers.toDisplayString() + shortcut;
input.value = modifiers.toDisplayString() + gZenKeyboardShortcutsManager.getKeyDisplay(shortcut);
this._latestValidKey = shortcut;
},
};

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js
index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c1a15b335 100644
index d1be14df27d76a191eaff05502c030fd68c46738..e9b5e90e39b594a6119081c8d707fb4a064fea9b 100644
--- a/browser/components/tabbrowser/content/tabgroup.js
+++ b/browser/components/tabbrowser/content/tabgroup.js
@@ -14,11 +14,11 @@
@@ -147,7 +147,7 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
});
}
@@ -478,13 +511,65 @@
@@ -478,13 +511,68 @@
* @returns {MozTabbrowserTab[]}
*/
get tabs() {
@@ -162,8 +162,9 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
+ tabsCollect.push(item);
+ if (gBrowser.isTabGroup(item)) {
+ tabsCollect.push(...item.tabs);
+ }
+ }
}
}
- return childrenArray.filter(node => node.matches("tab"));
+ return tabsCollect.filter(node => node.matches("tab"));
+ }
+
@@ -189,9 +190,8 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
+ result.push(labelContainer);
+ }
+ result.push(...item.childGroupsAndTabs);
}
}
- return childrenArray.filter(node => node.matches("tab"));
+ }
+ }
+ return result;
+ }
+
@@ -210,6 +210,9 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
+ return false;
+ }
+ }
+ if (this.pinned && gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs) {
+ return false;
+ }
+ return true;
+ }
+
@@ -218,7 +221,7 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
}
/**
@@ -592,7 +677,6 @@
@@ -592,7 +680,6 @@
);
} else {
if (tabOrSplitView.pinned) {
@@ -226,7 +229,7 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
}
let tabToMove =
this.ownerGlobal === tabOrSplitView.ownerGlobal
@@ -661,7 +745,7 @@
@@ -661,7 +748,7 @@
*/
on_click(event) {
let isToggleElement =
@@ -235,7 +238,7 @@ index d1be14df27d76a191eaff05502c030fd68c46738..30e8dda663df8e96dbed5fe5f12f828c
event.target === this.#overflowCountLabel;
if (isToggleElement && event.button === 0) {
event.preventDefault();
@@ -740,5 +824,6 @@
@@ -740,5 +827,6 @@
}
}

View File

@@ -1,8 +1,8 @@
diff --git a/browser/modules/URILoadingHelper.sys.mjs b/browser/modules/URILoadingHelper.sys.mjs
index ed6b9fda700b2b4b35836a77a4da953377a72f4b..22acedcf1006f994ec8b6bf8991b4202e12a6f39 100644
index bd2e54e914b171df9b8bcc7dcbc2388e9641f6c6..8b3cb6542bea3fb89e47adc93cb13f94447450e2 100644
--- a/browser/modules/URILoadingHelper.sys.mjs
+++ b/browser/modules/URILoadingHelper.sys.mjs
@@ -224,6 +224,7 @@ function openInWindow(url, params, sourceWindow) {
@@ -228,6 +228,7 @@ function openInWindow(url, params, sourceWindow) {
features,
sa
);
@@ -10,7 +10,7 @@ index ed6b9fda700b2b4b35836a77a4da953377a72f4b..22acedcf1006f994ec8b6bf8991b4202
}
function openInCurrentTab(targetBrowser, url, uriObj, params) {
@@ -541,7 +542,7 @@ export const URILoadingHelper = {
@@ -545,7 +546,7 @@ export const URILoadingHelper = {
// page. If a load request bounces off for the currently selected tab,
// we'll open a new tab instead.
let tab = w.gBrowser.getTabForBrowser(targetBrowser);
@@ -19,7 +19,7 @@ index ed6b9fda700b2b4b35836a77a4da953377a72f4b..22acedcf1006f994ec8b6bf8991b4202
where = "tab";
targetBrowser = null;
} else if (
@@ -974,7 +975,7 @@ export const URILoadingHelper = {
@@ -978,7 +979,7 @@ export const URILoadingHelper = {
ignoreQueryString || replaceQueryString,
ignoreFragmentWhenComparing
);
@@ -28,8 +28,8 @@ index ed6b9fda700b2b4b35836a77a4da953377a72f4b..22acedcf1006f994ec8b6bf8991b4202
for (let i = 0; i < browsers.length; i++) {
let browser = browsers[i];
let browserCompare = cleanURL(
@@ -1026,7 +1027,7 @@ export const URILoadingHelper = {
aSplitView.replaceTab(tabToReplace, tabToMove);
@@ -1034,7 +1035,7 @@ export const URILoadingHelper = {
}
aSplitView.ownerGlobal.focus();
} else {
- aWindow.gBrowser.tabContainer.selectedIndex = i;

View File

@@ -436,6 +436,7 @@
}
#zen-copy-current-url-button,
#share-tab-button,
#zen-site-data-header-share {
list-style-image: url("share.svg");
}
@@ -925,7 +926,7 @@
position: relative;
list-style-image: url("paintbrush.svg");
list-style-image: url("boost.svg");
& .toolbarbutton-text {
display: none;
@@ -938,6 +939,8 @@
& image {
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
width: 14px;
fill-opacity: 0.7;
}
}
@@ -1067,7 +1070,7 @@
}
#zen-boost-shuffle {
list-style-image: url("arrow-rotate-anticlockwise.svg");
list-style-image: url("dice.svg");
}
#zen-boost-css-picker {

View File

@@ -13,6 +13,7 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
@@ -37,6 +38,7 @@
* skin/classic/browser/zen-icons/desktop-notification-fill.svg (../shared/zen-icons/nucleo/desktop-notification-fill.svg)
* skin/classic/browser/zen-icons/desktop-notification.svg (../shared/zen-icons/nucleo/desktop-notification.svg)
* skin/classic/browser/zen-icons/developer.svg (../shared/zen-icons/nucleo/developer.svg)
* skin/classic/browser/zen-icons/dice.svg (../shared/zen-icons/nucleo/dice.svg)
* skin/classic/browser/zen-icons/downloads.svg (../shared/zen-icons/nucleo/downloads.svg)
* skin/classic/browser/zen-icons/drag-indicator.svg (../shared/zen-icons/nucleo/drag-indicator.svg)
* skin/classic/browser/zen-icons/duplicate-tab.svg (../shared/zen-icons/nucleo/duplicate-tab.svg)
@@ -102,26 +104,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -161,6 +163,7 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
@@ -185,6 +188,7 @@
* skin/classic/browser/zen-icons/desktop-notification-fill.svg (../shared/zen-icons/nucleo/desktop-notification-fill.svg)
* skin/classic/browser/zen-icons/desktop-notification.svg (../shared/zen-icons/nucleo/desktop-notification.svg)
* skin/classic/browser/zen-icons/developer.svg (../shared/zen-icons/nucleo/developer.svg)
* skin/classic/browser/zen-icons/dice.svg (../shared/zen-icons/nucleo/dice.svg)
* skin/classic/browser/zen-icons/downloads.svg (../shared/zen-icons/nucleo/downloads.svg)
* skin/classic/browser/zen-icons/drag-indicator.svg (../shared/zen-icons/nucleo/drag-indicator.svg)
* skin/classic/browser/zen-icons/duplicate-tab.svg (../shared/zen-icons/nucleo/duplicate-tab.svg)
@@ -250,26 +254,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -309,6 +313,7 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
@@ -333,6 +338,7 @@
* skin/classic/browser/zen-icons/desktop-notification-fill.svg (../shared/zen-icons/nucleo/desktop-notification-fill.svg)
* skin/classic/browser/zen-icons/desktop-notification.svg (../shared/zen-icons/nucleo/desktop-notification.svg)
* skin/classic/browser/zen-icons/developer.svg (../shared/zen-icons/nucleo/developer.svg)
* skin/classic/browser/zen-icons/dice.svg (../shared/zen-icons/nucleo/dice.svg)
* skin/classic/browser/zen-icons/downloads.svg (../shared/zen-icons/nucleo/downloads.svg)
* skin/classic/browser/zen-icons/drag-indicator.svg (../shared/zen-icons/nucleo/drag-indicator.svg)
* skin/classic/browser/zen-icons/duplicate-tab.svg (../shared/zen-icons/nucleo/duplicate-tab.svg)
@@ -398,26 +404,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -456,8 +462,8 @@
* skin/classic/browser/zen-icons/selectable/basket.svg (../shared/zen-icons/common/selectable/basket.svg)
* skin/classic/browser/zen-icons/selectable/bed.svg (../shared/zen-icons/common/selectable/bed.svg)
* skin/classic/browser/zen-icons/selectable/bell.svg (../shared/zen-icons/common/selectable/bell.svg)
* skin/classic/browser/zen-icons/selectable/book.svg (../shared/zen-icons/common/selectable/book.svg)
* skin/classic/browser/zen-icons/selectable/bookmark.svg (../shared/zen-icons/common/selectable/bookmark.svg)
* skin/classic/browser/zen-icons/selectable/book.svg (../shared/zen-icons/common/selectable/book.svg)
* skin/classic/browser/zen-icons/selectable/briefcase.svg (../shared/zen-icons/common/selectable/briefcase.svg)
* skin/classic/browser/zen-icons/selectable/brush.svg (../shared/zen-icons/common/selectable/brush.svg)
* skin/classic/browser/zen-icons/selectable/bug.svg (../shared/zen-icons/common/selectable/bug.svg)
@@ -519,8 +525,8 @@
* skin/classic/browser/zen-icons/selectable/shapes.svg (../shared/zen-icons/common/selectable/shapes.svg)
* skin/classic/browser/zen-icons/selectable/shirt.svg (../shared/zen-icons/common/selectable/shirt.svg)
* skin/classic/browser/zen-icons/selectable/skull.svg (../shared/zen-icons/common/selectable/skull.svg)
* skin/classic/browser/zen-icons/selectable/square.svg (../shared/zen-icons/common/selectable/square.svg)
* skin/classic/browser/zen-icons/selectable/squares.svg (../shared/zen-icons/common/selectable/squares.svg)
* skin/classic/browser/zen-icons/selectable/square.svg (../shared/zen-icons/common/selectable/square.svg)
* skin/classic/browser/zen-icons/selectable/star-1.svg (../shared/zen-icons/common/selectable/star-1.svg)
* skin/classic/browser/zen-icons/selectable/star.svg (../shared/zen-icons/common/selectable/star.svg)
* skin/classic/browser/zen-icons/selectable/stats-chart.svg (../shared/zen-icons/common/selectable/stats-chart.svg)

View File

@@ -0,0 +1,5 @@
#filter dumbComments emptyLines substitution
# 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/.
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="context-fill" fill-opacity="context-fill-opacity" viewBox="0 0 18 18"><path d="M5 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2M9.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2m-2.25 2.25a1 1 0 1 0 0-2 1 1 0 0 0 0 2M1 13.75v-7c.033-.705.349-1.488.805-1.945.456-.456 1.239-.773 1.945-.805h7c.706.033 1.488.349 1.945.805.456.456.773 1.239.805 1.945v7c-.033.705-.349 1.488-.805 1.945-.456.456-1.239.773-1.945.805h-7c-.706-.033-1.488-.349-1.945-.805-.456-.456-.773-1.239-.805-1.945m1.866.884c.267.267.485.399.884.366h7c.399.033.617-.099.884-.366s.399-.485.366-.884v-7c.033-.399-.099-.617-.366-.884s-.485-.399-.884-.366h-7c-.399-.033-.617.099-.884.366s-.399.485-.366.884v7c-.033.399.099.617.366.884m12.274-2.737a.75.75 0 0 0 .852-.632l.978-6.581c.071-.703-.127-1.524-.511-2.042-.384-.519-1.112-.946-1.805-1.082L7.73.53C7.191.469 6.557.562 6.11.783s-.897.66-1.167 1.092a.75.75 0 1 0 1.299.749c.129-.258.275-.37.531-.497.258-.127.437-.178.735-.114l6.924 1.03c.399.026.595.188.82.492s.323.538.232.928l-.978 6.581a.75.75 0 0 0 .632.852z"/></svg>

View File

@@ -0,0 +1,14 @@
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index ca400d3aed179ebef8e005206f29b419ae56afc4..4d4e56f4a222bd61dea82638f3e0b30fbe56a176 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1326,7 +1326,8 @@ Maybe<nscolor> CanvasRenderingContext2D::ParseColor(
RefPtr<const ComputedStyle> canvasStyle =
nsComputedDOMStyle::GetComputedStyle(mCanvasElement);
if (canvasStyle) {
- return Some(canvasStyle->StyleText()->mColor.ToColor());
+ return Some(canvasStyle->StyleText()->mColor.ToColor(
+ mCanvasElement->GetPrimaryFrame()));
}
}
return data.mColor;

View File

@@ -0,0 +1,13 @@
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 3374a88b9335de1659df548fe8c18610f675b336..540f22697e7b85bca2fd6d3fe952ed3944216e17 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -768,7 +768,7 @@ static void SerializeColorForHTMLCompatibility(const StyleAbsoluteColor& aColor,
// Raw StyleAbsoluteColor can have floats outside of 0-1 range e.g. when
// display-p3 color is converted to srgb, and ToColor guarantees to fit the
// values within the range.
- nscolor color = aColor.ToColor();
+ nscolor color = aColor.ToColor(nullptr);
aResult.Truncate();
aResult.AppendPrintf("#%02x%02x%02x", NS_GET_R(color), NS_GET_G(color),
NS_GET_B(color));

View File

@@ -0,0 +1,13 @@
diff --git a/editor/libeditor/HTMLAbsPositionEditor.cpp b/editor/libeditor/HTMLAbsPositionEditor.cpp
index 44bd8ba90e9828423742d768e64ad6204b3cf134..49d5c9512137ce28ac463223098515f6912452b1 100644
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp
+++ b/editor/libeditor/HTMLAbsPositionEditor.cpp
@@ -1001,7 +1001,7 @@ nsresult HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
static const uint8_t kBlackBgTrigger = 0xd0;
- auto color = style->StyleText()->mColor.ToColor();
+ auto color = style->StyleText()->mColor.ToColor(aElement.GetPrimaryFrame());
if (NS_GET_R(color) >= kBlackBgTrigger &&
NS_GET_G(color) >= kBlackBgTrigger &&
NS_GET_B(color) >= kBlackBgTrigger) {

View File

@@ -1,5 +1,5 @@
diff --git a/gfx/layers/AnimationInfo.cpp b/gfx/layers/AnimationInfo.cpp
index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..ef112715580b6bb7238e8f37bbe3133e187685dc 100644
index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..629fbdd748310c31aeb16b0a8d8e862a99314cc9 100644
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -14,6 +14,7 @@
@@ -10,12 +10,20 @@ index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..ef112715580b6bb7238e8f37bbe3133e
#include "nsIContent.h"
#include "nsLayoutUtils.h"
#include "nsRefreshDriver.h"
@@ -343,7 +344,7 @@ static void SetAnimatable(NonCustomCSSPropertyId aProperty,
@@ -341,9 +342,13 @@ static void SetAnimatable(NonCustomCSSPropertyId aProperty,
case eCSSProperty_background_color: {
// We don't support color animation on the compositor yet so that we can
// resolve currentColor at this moment.
nscolor foreground =
aFrame->Style()->GetVisitedDependentColor(&nsStyleText::mColor);
- nscolor foreground =
- aFrame->Style()->GetVisitedDependentColor(&nsStyleText::mColor);
- aAnimatable = aAnimationValue.GetColor(foreground);
+ aAnimatable = zen::nsZenBoostsBackend::FilterColorFromPresContext(aAnimationValue.GetColor(foreground), aFrame->PresContext());
+ nscolor foreground = aFrame->Style()->GetVisitedDependentColor(
+ &nsStyleText::mColor, nullptr);
+ nscolor resolved = aAnimationValue.GetColor(foreground);
+ aAnimatable = aAnimationValue.IsCurrentColor()
+ ? resolved
+ : zen::nsZenBoostsBackend::ResolveStyleColor(resolved,
+ aFrame);
break;
}
case eCSSProperty_opacity:

View File

@@ -0,0 +1,16 @@
diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp
index 6c19c572f06e8c4c97ce3f9dd390a32832e2f527..d11cbad2ee32a1507316809893e9c42a883e6c12 100644
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1743,8 +1743,9 @@ DeviceColor ToDeviceColor(nscolor aColor) {
return ToDeviceColor(sRGBColor::FromABGR(aColor));
}
-DeviceColor ToDeviceColor(const StyleAbsoluteColor& aColor) {
- return ToDeviceColor(aColor.ToColor());
+DeviceColor ToDeviceColor(const StyleAbsoluteColor& aColor,
+ const nsIFrame* aFrame) {
+ return ToDeviceColor(aColor.ToColor(aFrame));
}
sRGBColor ToSRGBColor(const StyleAbsoluteColor& aColor) {

View File

@@ -0,0 +1,23 @@
diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h
index 55f874429fd8cbb7a0a469eba33f6c777a5bc5f7..8cf0567d81fcae7413cee6df9471d1fa1738fc4a 100644
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -598,6 +598,9 @@ class ElementOrArray {
};
struct StyleAbsoluteColor;
+} // namespace mozilla
+class nsIFrame;
+namespace mozilla {
namespace gfx {
@@ -609,7 +612,7 @@ namespace gfx {
* applicable).
*/
DeviceColor ToDeviceColor(const sRGBColor&);
-DeviceColor ToDeviceColor(const StyleAbsoluteColor&);
+DeviceColor ToDeviceColor(const StyleAbsoluteColor&, const nsIFrame*);
DeviceColor ToDeviceColor(nscolor);
sRGBColor ToSRGBColor(const StyleAbsoluteColor&);

View File

@@ -0,0 +1,14 @@
diff --git a/image/AutoRestoreSVGState.h b/image/AutoRestoreSVGState.h
index be639a7b78c13c2d56be49a9690bf711ccaf0a8f..28bea58034ead1206d77521934e92d3a69bfd84b 100644
--- a/image/AutoRestoreSVGState.h
+++ b/image/AutoRestoreSVGState.h
@@ -47,6 +47,9 @@ class MOZ_STACK_CLASS AutoRestoreSVGState final {
}
return dom::PrefersColorSchemeOverride::None;
}());
+ pc->SetZenBoostsOverride(aSVGContext.GetZenBoostsAccent(),
+ aSVGContext.GetZenBoostsComplementaryRotation(),
+ aSVGContext.GetZenBoostsInverted());
}
aSVGDocumentWrapper->mIsDrawing = true;

View File

@@ -1,5 +1,5 @@
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
index b5930f71e362eb78f74888e1b33b2a6f9dbb4ea4..dc1ba0b462402f62e47fcb32e2d7cd1a671a7fd8 100644
index b5930f71e362eb78f74888e1b33b2a6f9dbb4ea4..2105911a18b64e210d3125fec1bfa8058ca07d4e 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -135,6 +135,7 @@
@@ -10,12 +10,13 @@ index b5930f71e362eb78f74888e1b33b2a6f9dbb4ea4..dc1ba0b462402f62e47fcb32e2d7cd1a
#include "nsAnimationManager.h"
#include "nsAutoLayoutPhase.h"
#include "nsCOMArray.h"
@@ -5572,7 +5573,7 @@ nscolor PresShell::GetDefaultBackgroundColorToDraw() const {
@@ -5572,7 +5573,8 @@ nscolor PresShell::GetDefaultBackgroundColorToDraw() const {
if (!mPresContext) {
return NS_RGB(255, 255, 255);
}
- return mPresContext->DefaultBackgroundColor();
+ return zen::nsZenBoostsBackend::FilterColorFromPresContext(mPresContext->DefaultBackgroundColor(), mPresContext);
+ return zen::nsZenBoostsBackend::ResolveStyleColor(
+ mPresContext->DefaultBackgroundColor(), GetRootFrame());
}
void PresShell::UpdateCanvasBackground() {

View File

@@ -0,0 +1,39 @@
diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h
index 13aa7141c8e5297d0dd6aa9bd78fd32f050e8123..149a89e928d354f116c54f71605830f5ec6b7f8a 100644
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -594,6 +594,22 @@ class nsPresContext : public nsISupports,
*/
void SetColorSchemeOverride(mozilla::dom::PrefersColorSchemeOverride);
+ // Zen boosts override. SVG images render in their own document, which has no
+ // BrowsingContext to carry the page's boost, so the host propagates it here.
+ void SetZenBoostsOverride(nscolor aAccent, float aComplementaryRotation,
+ bool aInverted) {
+ mZenBoostsOverrideAccent = aAccent;
+ mZenBoostsOverrideComplementaryRotation = aComplementaryRotation;
+ mZenBoostsOverrideInverted = aInverted;
+ mHasZenBoostsOverride = true;
+ }
+ bool HasZenBoostsOverride() const { return mHasZenBoostsOverride; }
+ nscolor ZenBoostsOverrideAccent() const { return mZenBoostsOverrideAccent; }
+ float ZenBoostsOverrideComplementaryRotation() const {
+ return mZenBoostsOverrideComplementaryRotation;
+ }
+ bool ZenBoostsOverrideInverted() const { return mZenBoostsOverrideInverted; }
+
/**
* Return the device's screen size in inches, for font size
* inflation.
@@ -1441,6 +1457,11 @@ class nsPresContext : public nsISupports,
mozilla::dom::PrefersColorSchemeOverride mOverriddenOrEmbedderColorScheme;
mozilla::StyleForcedColors mForcedColors;
+ nscolor mZenBoostsOverrideAccent = 0;
+ float mZenBoostsOverrideComplementaryRotation = 0.0f;
+ bool mZenBoostsOverrideInverted = false;
+ bool mHasZenBoostsOverride = false;
+
protected:
virtual ~nsPresContext();

View File

@@ -1,33 +0,0 @@
diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp
index 9d1c25c3834da50fd7dfa3a9583144f5817ee231..08b69a63ea3a8067861984fa2fcd25435c921c0d 100644
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -23,6 +23,7 @@
#include "nsLayoutUtils.h"
#include "nsPlaceholderFrame.h"
#include "nsSubDocumentFrame.h"
+#include "mozilla/nsZenBoostsBackend.h"
using namespace mozilla;
@@ -291,15 +292,20 @@ ViewportFrame::BuildDisplayListForViewTransitionsAndNACTopLayer(
}
}
+ bool isAnonContent = false;
if (dom::Element* container = doc->GetCustomContentContainer()) {
if (nsIFrame* frame = container->GetPrimaryFrame()) {
MOZ_ASSERT(frame->StyleDisplay()->mTopLayer != StyleTopLayer::None,
"ua.css should ensure this");
MOZ_ASSERT(frame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
+ isAnonContent = frame->ContentIsRootOfNativeAnonymousSubtree();
BuildDisplayListForTopLayerFrame(aBuilder, frame, &topLayerList);
}
}
+ if (auto zenBackend = zen::nsZenBoostsBackend::GetInstance()) {
+ zenBackend->mCurrentFrameIsAnonymousContent = isAnonContent;
+ }
return MaybeWrapTopLayerList(
aBuilder, uint16_t(TopLayerIndex::ViewTransitionsAndAnonymousContent),
topLayerList);

View File

@@ -0,0 +1,47 @@
diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp
index c27fec39f9e32e61f0e335e5880ce3e97074965b..7b4f7760dcf92ead74c9f89cfc7a067892af9e34 100644
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -349,7 +349,8 @@ class nsDisplaySelectionOverlay final : public nsPaintedDisplayItem {
nsDisplayListBuilder* aDisplayListBuilder) override;
NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
- static DeviceColor ComputeColorFromSelectionStyle(const ComputedStyle&);
+ static DeviceColor ComputeColorFromSelectionStyle(const ComputedStyle&,
+ const nsIFrame*);
static DeviceColor ApplyTransparencyIfNecessary(nscolor);
private:
@@ -371,9 +372,9 @@ DeviceColor nsDisplaySelectionOverlay::ApplyTransparencyIfNecessary(
}
DeviceColor nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(
- const ComputedStyle& aStyle) {
- return ApplyTransparencyIfNecessary(
- aStyle.GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor));
+ const ComputedStyle& aStyle, const nsIFrame* aFrame) {
+ return ApplyTransparencyIfNecessary(aStyle.GetVisitedDependentColor(
+ &nsStyleBackground::mBackgroundColor, aFrame));
}
void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
@@ -472,7 +473,8 @@ void nsContainerFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
ComputeHighlightSelectionStyle(sd->mHighlightData.mHighlightName)) {
aList->AppendNewToTopWithIndex<nsDisplaySelectionOverlay>(
aBuilder, this, index++,
- nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(*style));
+ nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(*style,
+ this));
}
}
@@ -480,7 +482,8 @@ void nsContainerFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
if (normal) {
DeviceColor color;
if (RefPtr<ComputedStyle> style = ComputeSelectionStyle(selectionValue)) {
- color = nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(*style);
+ color = nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(*style,
+ this);
} else {
LookAndFeel::ColorID colorID;
if (selectionValue == nsISelectionController::SELECTION_ON) {

View File

@@ -0,0 +1,13 @@
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 588b00d7ee115f0a7513e357af7ab5eee28311c1..bf07b69c7e7957e6e558403e069f16e2dec3cad0 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1008,7 +1008,7 @@ class nsIFrame : public nsQueryFrame {
/** Also forward GetVisitedDependentColor to the style */
template <typename T, typename S>
nscolor GetVisitedDependentColor(T S::* aField) {
- return mComputedStyle->GetVisitedDependentColor(aField);
+ return mComputedStyle->GetVisitedDependentColor(aField, this);
}
/**

View File

@@ -0,0 +1,13 @@
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c4ff60477e3061aeeecbdedb5ad8054d3808ab6e..40857d430eda576c4fca613857860f32abb39e2d 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1764,7 +1764,7 @@ void nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
const nsRect& aRect) {
// Set font and color
aRenderingContext.SetColor(
- sRGBColor::FromABGR(StyleText()->mColor.ToColor()));
+ sRGBColor::FromABGR(StyleText()->mColor.ToColor(this)));
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetInflatedFontMetricsForFrame(this);

View File

@@ -0,0 +1,13 @@
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index e7f7943a19d3ac71872d0a8439b6ed90e8fd423d..eb3e84fabc67d95b6d194b5aaf3aaef7c38480c0 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -6381,7 +6381,7 @@ void nsTextFrame::DrawSelectionDecorations(
computedStyleFromPseudo->StyleTextReset()->mTextDecorationStyle;
params.color =
computedStyleFromPseudo->StyleTextReset()
- ->mTextDecorationColor.CalcColor(*computedStyleFromPseudo);
+ ->mTextDecorationColor.CalcColor(*computedStyleFromPseudo, this);
params.decoration =
computedStyleFromPseudo->StyleTextReset()->mTextDecorationLine;
params.descentLimit = -1.f;

View File

@@ -0,0 +1,67 @@
diff --git a/layout/generic/nsTextPaintStyle.cpp b/layout/generic/nsTextPaintStyle.cpp
index 5d1bf44687e925aff67f44c8e0629f7f06e84e98..1fa60a4d91edc60ba733cefc5f73ab8b7684d02a 100644
--- a/layout/generic/nsTextPaintStyle.cpp
+++ b/layout/generic/nsTextPaintStyle.cpp
@@ -240,7 +240,7 @@ bool nsTextPaintStyle::GetTargetTextColor(nscolor* aForeColor) {
(mTargetTextPseudoStyle->HasAuthorSpecifiedTextColor() ||
mTargetTextPseudoStyle->HasAuthorSpecifiedBorderOrBackground())) {
*aForeColor = mTargetTextPseudoStyle->GetVisitedDependentColor(
- &nsStyleText::mWebkitTextFillColor);
+ &nsStyleText::mWebkitTextFillColor, mFrame);
return mTargetTextPseudoStyle->HasAuthorSpecifiedTextColor();
}
*aForeColor = LookAndFeel::Color(
@@ -257,7 +257,7 @@ bool nsTextPaintStyle::GetTargetTextBackgroundColor(nscolor* aBackColor) {
(mTargetTextPseudoStyle->HasAuthorSpecifiedTextColor() ||
mTargetTextPseudoStyle->HasAuthorSpecifiedBorderOrBackground())) {
*aBackColor = mTargetTextPseudoStyle->GetVisitedDependentColor(
- &nsStyleBackground::mBackgroundColor);
+ &nsStyleBackground::mBackgroundColor, mFrame);
return NS_GET_A(*aBackColor) != 0;
}
*aBackColor = LookAndFeel::Color(
@@ -295,7 +295,8 @@ bool nsTextPaintStyle::GetCustomHighlightTextColor(nsAtom* aHighlightName,
return false;
}
- *aForeColor = highlightStyle->GetVisitedDependentColor(&nsStyleText::mColor);
+ *aForeColor =
+ highlightStyle->GetVisitedDependentColor(&nsStyleText::mColor, mFrame);
return highlightStyle->HasAuthorSpecifiedTextColor();
}
@@ -317,7 +318,7 @@ bool nsTextPaintStyle::GetCustomHighlightBackgroundColor(nsAtom* aHighlightName,
}
*aBackColor = highlightStyle->GetVisitedDependentColor(
- &nsStyleBackground::mBackgroundColor);
+ &nsStyleBackground::mBackgroundColor, mFrame);
return NS_GET_A(*aBackColor) != 0;
}
@@ -466,19 +467,19 @@ bool nsTextPaintStyle::InitSelectionColorsAndShadow() {
// this is web content or chrome content. See bug 2029839.
if (!mFrame->PresContext()->Document()->ChromeRulesEnabled()) {
mSelectionBGColor = mSelectionPseudoStyle->GetVisitedDependentColor(
- &nsStyleBackground::mBackgroundColor);
- mSelectionTextColor =
- mSelectionPseudoStyle->GetVisitedDependentColor(&nsStyleText::mColor);
+ &nsStyleBackground::mBackgroundColor, mFrame);
+ mSelectionTextColor = mSelectionPseudoStyle->GetVisitedDependentColor(
+ &nsStyleText::mColor, mFrame);
return true;
}
if (nscolor bgColor = mSelectionPseudoStyle->GetVisitedDependentColor(
- &nsStyleBackground::mBackgroundColor);
+ &nsStyleBackground::mBackgroundColor, mFrame);
mSelectionPseudoStyle->HasAuthorSpecifiedTextColor() ||
NS_GET_A(bgColor) > 0) {
mSelectionBGColor = bgColor;
- mSelectionTextColor =
- mSelectionPseudoStyle->GetVisitedDependentColor(&nsStyleText::mColor);
+ mSelectionTextColor = mSelectionPseudoStyle->GetVisitedDependentColor(
+ &nsStyleText::mColor, mFrame);
return true;
}
}

View File

@@ -0,0 +1,13 @@
diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp
index befaf7fed81a486f61e1186775c138ce5473a057..c7eb36dc9fcd06f8641d2d1a974e75eb24e07669 100644
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1686,7 +1686,7 @@ void nsMathMLChar::PaintForeground(nsIFrame* aForFrame,
// Set color ...
nscolor fgColor = computedStyle->GetVisitedDependentColor(
- &nsStyleText::mWebkitTextFillColor);
+ &nsStyleText::mWebkitTextFillColor, aForFrame);
if (aIsSelected) {
// get color to use for selection from the look&feel object
fgColor = LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, aForFrame,

View File

@@ -0,0 +1,87 @@
diff --git a/layout/painting/nsCSSRendering.cpp b/layout/painting/nsCSSRendering.cpp
index a581b039a8681f7d8191edfad100d287af38592e..4cd3d6695a04a42d806c36f8d5a324cac9efda34 100644
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -598,7 +598,8 @@ void nsCSSRendering::ComputePixelRadii(const nsRectCornerRadii& aRadii,
}
}
-static Maybe<nsStyleBorder> GetBorderIfVisited(const ComputedStyle& aStyle) {
+static Maybe<nsStyleBorder> GetBorderIfVisited(const ComputedStyle& aStyle,
+ const nsIFrame* aFrame) {
Maybe<nsStyleBorder> result;
// Don't check RelevantLinkVisited here, since we want to take the
// same amount of time whether or not it's true.
@@ -611,7 +612,7 @@ static Maybe<nsStyleBorder> GetBorderIfVisited(const ComputedStyle& aStyle) {
auto& newBorder = result.ref();
for (const auto side : mozilla::AllPhysicalSides()) {
nscolor color = aStyle.GetVisitedDependentColor(
- nsStyleBorder::BorderColorFieldFor(side));
+ nsStyleBorder::BorderColorFieldFor(side), aFrame);
newBorder.BorderColorFor(side) = StyleColor::FromColor(color);
}
@@ -624,7 +625,7 @@ ImgDrawResult nsCSSRendering::PaintBorder(
ComputedStyle* aStyle, PaintBorderFlags aFlags, Sides aSkipSides) {
AUTO_PROFILER_LABEL("nsCSSRendering::PaintBorder", GRAPHICS);
- Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*aStyle);
+ Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*aStyle, aForFrame);
return PaintBorderWithStyleBorder(
aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea,
visitedBorder.refOr(*aStyle->StyleBorder()), aStyle, aFlags, aSkipSides);
@@ -634,7 +635,7 @@ Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRenderer(
nsPresContext* aPresContext, DrawTarget* aDrawTarget, nsIFrame* aForFrame,
const nsRect& aDirtyRect, const nsRect& aBorderArea, ComputedStyle* aStyle,
bool* aOutBorderIsEmpty, Sides aSkipSides) {
- Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*aStyle);
+ Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*aStyle, aForFrame);
return CreateBorderRendererWithStyleBorder(
aPresContext, aDrawTarget, aForFrame, aDirtyRect, aBorderArea,
visitedBorder.refOr(*aStyle->StyleBorder()), aStyle, aOutBorderIsEmpty,
@@ -649,7 +650,7 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) {
const auto* style = aForFrame->Style();
- Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*style);
+ Maybe<nsStyleBorder> visitedBorder = GetBorderIfVisited(*style, aForFrame);
return nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
aItem, aForFrame, aBorderArea, aBuilder, aResources, aSc, aManager,
aDisplayListBuilder, visitedBorder.refOr(*style->StyleBorder()));
@@ -785,7 +786,7 @@ static nsCSSBorderRenderer ConstructBorderRenderer(
// pull out styles, colors
for (const auto i : mozilla::AllPhysicalSides()) {
borderStyles[i] = aStyleBorder.GetBorderStyle(i);
- borderColors[i] = aStyleBorder.BorderColorFor(i).CalcColor(*aStyle);
+ borderColors[i] = aStyleBorder.BorderColorFor(i).CalcColor(*aStyle, aForFrame);
}
PrintAsFormatString(
@@ -1005,7 +1006,7 @@ nsCSSRendering::CreateBorderRendererForNonThemedOutline(
// This handles treating the initial color as 'currentColor'; if we
// ever want 'invert' back we'll need to do a bit of work here too.
nscolor outlineColor =
- aStyle->GetVisitedDependentColor(&nsStyleOutline::mOutlineColor);
+ aStyle->GetVisitedDependentColor(&nsStyleOutline::mOutlineColor, aForFrame);
nscolor outlineColors[4] = {outlineColor, outlineColor, outlineColor,
outlineColor};
@@ -2341,7 +2342,7 @@ static Maybe<nscolor> CalcScrollbarColor(nsIFrame* aFrame,
const auto& color = aKind == ScrollbarColorKind::Thumb
? colors.AsColors().thumb
: colors.AsColors().track;
- return Some(color.CalcColor(*scrollbarStyle));
+ return Some(color.CalcColor(*scrollbarStyle, aFrame));
}
static nscolor GetBackgroundColor(nsIFrame* aFrame,
@@ -2367,7 +2368,8 @@ static nscolor GetBackgroundColor(nsIFrame* aFrame,
default:
break;
}
- return aStyle->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
+ return aStyle->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor,
+ aFrame);
}
nscolor nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,

View File

@@ -0,0 +1,14 @@
diff --git a/layout/painting/nsCSSRenderingBorders.cpp b/layout/painting/nsCSSRenderingBorders.cpp
index fd2524fd78b1709363afda35e4b0d4320913d9ec..c5b90bc789cdd7f8b0b661ca99b8c7f4d01e6d68 100644
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3624,7 +3624,8 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
case StyleImage::Tag::Gradient: {
const StyleGradient& gradient = *mImageRenderer.GetGradientData();
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
- aForFrame->PresContext(), aForFrame->Style(), gradient, mImageSize);
+ aForFrame->PresContext(), aForFrame->Style(), aForFrame, gradient,
+ mImageSize);
wr::ExtendMode extendMode;
nsTArray<wr::GradientStop> stops;

View File

@@ -0,0 +1,78 @@
diff --git a/layout/painting/nsCSSRenderingGradients.cpp b/layout/painting/nsCSSRenderingGradients.cpp
index 80a9d36ca865bbcd090d7aa556270a698447b016..2b1e0a70ed7e6f975c51a0912598c7903552ab20 100644
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -667,7 +667,8 @@ static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
nsCSSGradientRenderer nsCSSGradientRenderer::Create(
nsPresContext* aPresContext, ComputedStyle* aComputedStyle,
- const StyleGradient& aGradient, const nsSize& aIntrinsicSize) {
+ const nsIFrame* aFrame, const StyleGradient& aGradient,
+ const nsSize& aIntrinsicSize) {
auto srcSize = CSSSize::FromAppUnits(aIntrinsicSize);
// Compute "gradient line" start and end relative to the intrinsic size of
@@ -704,6 +705,7 @@ nsCSSGradientRenderer nsCSSGradientRenderer::Create(
nsCSSGradientRenderer renderer;
renderer.mPresContext = aPresContext;
+ renderer.mFrame = aFrame;
renderer.mGradient = &aGradient;
renderer.mStops = std::move(stops);
renderer.mLineStart = {
@@ -992,9 +994,10 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
GradientStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
- bool aExtend, nsTArray<gfx::GradientStop>& aResult)
+ bool aExtend, nsTArray<gfx::GradientStop>& aResult,
+ const nsIFrame* aFrame)
: ColorStopInterpolator(aStops, aStyleColorInterpolationMethod,
- aExtend),
+ aExtend, aFrame),
mStops(aResult) {}
void CreateStop(float aPosition, gfx::DeviceColor aColor) {
mStops.AppendElement(gfx::GradientStop{aPosition, aColor});
@@ -1007,12 +1010,12 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
bool extend = !isRepeat && styleColorInterpolationMethod.hue ==
StyleHueInterpolationMethod::Longer;
GradientStopInterpolator interpolator(mStops, styleColorInterpolationMethod,
- extend, rawStops);
+ extend, rawStops, mFrame);
interpolator.CreateStops();
} else {
rawStops.SetLength(mStops.Length());
for (uint32_t i = 0; i < mStops.Length(); i++) {
- rawStops[i].color = ToDeviceColor(mStops[i].mColor);
+ rawStops[i].color = ToDeviceColor(mStops[i].mColor, mFrame);
rawStops[i].color.a *= aOpacity;
rawStops[i].offset = stopScale * (mStops[i].mPosition - stopOrigin);
}
@@ -1203,8 +1206,10 @@ class MOZ_STACK_CLASS WrColorStopInterpolator
WrColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
- float aOpacity, nsTArray<wr::GradientStop>& aResult, bool aExtend)
- : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod, aExtend),
+ float aOpacity, nsTArray<wr::GradientStop>& aResult, bool aExtend,
+ const nsIFrame* aFrame)
+ : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod, aExtend,
+ aFrame),
mResult(aResult),
mOpacity(aOpacity),
mOutputStop(0) {}
@@ -1284,12 +1289,12 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
styleColorInterpolationMethod.hue ==
StyleHueInterpolationMethod::Longer;
WrColorStopInterpolator interpolator(mStops, styleColorInterpolationMethod,
- aOpacity, aStops, extend);
+ aOpacity, aStops, extend, mFrame);
interpolator.CreateStops();
} else {
aStops.SetLength(mStops.Length());
for (uint32_t i = 0; i < mStops.Length(); i++) {
- aStops[i].color = wr::ToColorF(ToDeviceColor(mStops[i].mColor));
+ aStops[i].color = wr::ToColorF(ToDeviceColor(mStops[i].mColor, mFrame));
aStops[i].color.a *= aOpacity;
aStops[i].offset = (float)mStops[i].mPosition;
}

View File

@@ -0,0 +1,59 @@
diff --git a/layout/painting/nsCSSRenderingGradients.h b/layout/painting/nsCSSRenderingGradients.h
index 30f665f7cacabb15fb6a1656385c5936d42be48b..8c4c4147ee8ec6812e9418f95b7b7c0358dcb735 100644
--- a/layout/painting/nsCSSRenderingGradients.h
+++ b/layout/painting/nsCSSRenderingGradients.h
@@ -42,10 +42,11 @@ class MOZ_STACK_CLASS ColorStopInterpolator {
ColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
- bool aExtend)
+ bool aExtend, const nsIFrame* aFrame)
: mStyleColorInterpolationMethod(aStyleColorInterpolationMethod),
mStops(aStops),
- mExtend(aExtend) {}
+ mExtend(aExtend),
+ mFrame(aFrame) {}
void CreateStops() {
// This loop intentionally iterates extra stops at the beginning and end
@@ -96,7 +97,7 @@ class MOZ_STACK_CLASS ColorStopInterpolator {
Servo_InterpolateColor(mStyleColorInterpolationMethod,
&start.mColor, &end.mColor, progress);
static_cast<T*>(this)->CreateStop(float(position),
- gfx::ToDeviceColor(color));
+ gfx::ToDeviceColor(color, mFrame));
}
}
}
@@ -108,6 +109,7 @@ class MOZ_STACK_CLASS ColorStopInterpolator {
// which only matters if this is a CSS non-repeating gradient with
// StyleHueInterpolationMethod::Longer (only valid for hsl/hwb/lch/oklch).
bool mExtend;
+ const nsIFrame* mFrame;
// This could be made tunable, but at 1.0/128 the error is largely
// irrelevant, as WebRender re-encodes it to 128 pairs of stops.
@@ -126,6 +128,7 @@ class nsCSSGradientRenderer final {
*/
static nsCSSGradientRenderer Create(nsPresContext* aPresContext,
ComputedStyle* aComputedStyle,
+ const nsIFrame* aFrame,
const StyleGradient& aGradient,
const nsSize& aIntrinsiceSize);
@@ -173,6 +176,7 @@ class nsCSSGradientRenderer final {
private:
nsCSSGradientRenderer()
: mPresContext(nullptr),
+ mFrame(nullptr),
mGradient(nullptr),
mRadiusX(0.0),
mRadiusY(0.0),
@@ -192,6 +196,7 @@ class nsCSSGradientRenderer final {
const nsSize& aRepeatSize, bool aForceRepeatToCoverTiles);
nsPresContext* mPresContext;
+ const nsIFrame* mFrame;
const StyleGradient* mGradient;
nsTArray<ColorStop> mStops;
gfxPoint mLineStart, mLineEnd; // only for linear/radial gradients

View File

@@ -1,23 +0,0 @@
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
index 4488dc2025da64fbad0e0ec998793a476de640ef..82990853e7279723666635ab8d9a929ede3f3aca 100644
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -81,6 +81,7 @@
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/WebRenderScrollData.h"
+#include "mozilla/nsZenBoostsBackend.h"
#include "nsCSSProps.h"
#include "nsCSSRendering.h"
#include "nsCSSRenderingGradients.h"
@@ -1252,6 +1253,10 @@ void nsDisplayListBuilder::EnterPresShell(const nsIFrame* aReferenceFrame,
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
}
+ if (auto zenBackend = zen::nsZenBoostsBackend::GetInstance(); zenBackend && !mIsInChromePresContext) {
+ zenBackend->onPresShellEntered(pc->Document());
+ }
+
state->mTouchEventPrefEnabledDoc = dom::TouchEvent::PrefEnabled(docShell);
if (auto* vt = pc->Document()->GetActiveViewTransition()) {

View File

@@ -0,0 +1,49 @@
diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp
index 4acb7670e971024f9c63e48ff711bbdd1dc02301..518543f29f396d819a71edb984879de22f8434a8 100644
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -90,7 +90,7 @@ static already_AddRefed<imgIContainer> GetSymbolicIconImage(nsAtom* aName,
if (NS_WARN_IF(!XRE_IsParentProcess())) {
return nullptr;
}
- const auto fg = aFrame->StyleText()->mColor.ToColor();
+ const auto fg = aFrame->StyleText()->mColor.ToColor(aFrame);
auto key = std::make_tuple(aName, aScale, fg);
auto* cache = aFrame->GetProperty(SymbolicImageCacheProp());
if (!cache) {
@@ -567,7 +567,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
}
case StyleImage::Tag::Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
- aPresContext, mForFrame->Style(), *mGradientData, mSize);
+ aPresContext, mForFrame->Style(), mForFrame, *mGradientData, mSize);
renderer.Paint(*ctx, aDest, aFill, aRepeatSize, aSrc, aDirtyRect,
aOpacity);
@@ -644,7 +644,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
switch (mType) {
case StyleImage::Tag::Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
- aPresContext, mForFrame->Style(), *mGradientData, mSize);
+ aPresContext, mForFrame->Style(), mForFrame, *mGradientData, mSize);
renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aDest, aFill,
aRepeatSize, aSrc,
@@ -670,6 +670,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
nsPresContext::AppUnitsToIntCSSPixels(aDest.height)};
SVGImageContext svgContext(Some(destCSSSize));
+ SVGImageContext::MaybeStoreZenBoosts(svgContext,
+ *mForFrame->PresContext());
Maybe<ImageIntRegion> region;
const int32_t appUnitsPerDevPixel =
@@ -1076,7 +1078,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
if (mImage->IsGradient()) {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
- aPresContext, mForFrame->Style(), *mGradientData, mSize);
+ aPresContext, mForFrame->Style(), mForFrame, *mGradientData, mSize);
nsRect dest(nsPoint(0, 0), mSize);
renderer.Paint(aRenderingContext, dest, dest, mSize,
CSSIntRect::FromAppUnitsRounded(dest), dest, 1.0);

View File

@@ -0,0 +1,65 @@
diff --git a/layout/style/ComputedStyle.cpp b/layout/style/ComputedStyle.cpp
index 18308d7891aab4ff0542e774190abeed6aad7c59..453da8ffa14ee5f31fbce873721779cbadce240d 100644
--- a/layout/style/ComputedStyle.cpp
+++ b/layout/style/ComputedStyle.cpp
@@ -285,29 +285,32 @@ static nscolor GetVisitedDependentColorInternal(const ComputedStyle& aStyle,
}
static nscolor ExtractColor(const ComputedStyle& aStyle,
- const StyleAbsoluteColor& aColor) {
- return aColor.ToColor();
+ const StyleAbsoluteColor& aColor,
+ const nsIFrame* aFrame) {
+ return aColor.ToColor(aFrame);
}
static nscolor ExtractColor(const ComputedStyle& aStyle,
- const StyleColor& aColor) {
- return aColor.CalcColor(aStyle);
+ const StyleColor& aColor, const nsIFrame* aFrame) {
+ return aColor.CalcColor(aStyle, aFrame);
}
// Currently caret-color, the only property in the list which is a ColorOrAuto,
// always maps auto to currentcolor.
static nscolor ExtractColor(const ComputedStyle& aStyle,
- const StyleColorOrAuto& aColor) {
+ const StyleColorOrAuto& aColor,
+ const nsIFrame* aFrame) {
if (aColor.IsAuto()) {
- return ExtractColor(aStyle, StyleColor::CurrentColor());
+ return ExtractColor(aStyle, StyleColor::CurrentColor(), aFrame);
}
- return ExtractColor(aStyle, aColor.AsColor());
+ return ExtractColor(aStyle, aColor.AsColor(), aFrame);
}
static nscolor ExtractColor(const ComputedStyle& aStyle,
- const StyleSVGPaint& aPaintServer) {
+ const StyleSVGPaint& aPaintServer,
+ const nsIFrame* aFrame) {
return aPaintServer.kind.IsColor()
- ? ExtractColor(aStyle, aPaintServer.kind.AsColor())
+ ? ExtractColor(aStyle, aPaintServer.kind.AsColor(), aFrame)
: NS_RGBA(0, 0, 0, 0);
}
@@ -315,14 +318,14 @@ static nscolor ExtractColor(const ComputedStyle& aStyle,
#define GENERATE_VISITED_COLOR_TEMPLATE(name_, fields_) \
template <> \
nscolor ComputedStyle::GetVisitedDependentColor( \
- decltype(nsStyle##name_::MOZ_ARG_1 fields_) nsStyle##name_::* aField) \
- const { \
+ decltype(nsStyle##name_::MOZ_ARG_1 fields_) nsStyle##name_::* aField, \
+ const nsIFrame* aFrame) const { \
MOZ_ASSERT(MOZ_FOR_EACH(STYLE_FIELD, (nsStyle##name_, ), fields_) false, \
"Getting visited-dependent color for a field in nsStyle" #name_ \
" which is not listed in nsCSSVisitedDependentPropList.h"); \
return GetVisitedDependentColorInternal( \
- *this, [aField](const ComputedStyle& aStyle) { \
- return ExtractColor(aStyle, aStyle.Style##name_()->*aField); \
+ *this, [aField, aFrame](const ComputedStyle& aStyle) { \
+ return ExtractColor(aStyle, aStyle.Style##name_()->*aField, aFrame); \
}); \
}
FOR_EACH_VISITED_DEPENDENT_STYLE_STRUCT(GENERATE_VISITED_COLOR_TEMPLATE)

View File

@@ -0,0 +1,22 @@
diff --git a/layout/style/ComputedStyle.h b/layout/style/ComputedStyle.h
index 661ec439dea1bc59dbc4507c9788df8821ea9086..7aa21f5388d6e3b5f1a85e38acdd646254ca8b01 100644
--- a/layout/style/ComputedStyle.h
+++ b/layout/style/ComputedStyle.h
@@ -18,6 +18,7 @@
enum nsChangeHint : uint32_t;
class nsWindowSizes;
+class nsIFrame;
#define FORWARD_STRUCT(name_) struct nsStyle##name_;
FOR_EACH_STYLE_STRUCT(FORWARD_STRUCT, FORWARD_STRUCT)
@@ -338,7 +339,8 @@ class ComputedStyle {
* been listed in nsCSSVisitedDependentPropList.h.
*/
template <typename T, typename S>
- nscolor GetVisitedDependentColor(T S::* aField) const;
+ nscolor GetVisitedDependentColor(T S::* aField,
+ const nsIFrame* aFrame) const;
/**
* aColors should be a two element array of nscolor in which the first

View File

@@ -0,0 +1,13 @@
diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp
index 56a16d313a5d30d12edf1f94459db1027af87002..3722f2d6ce6c0864956fed2b00c71a3286edc674 100644
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1068,7 +1068,7 @@ void Gecko_SetFontPaletteOverride(
return;
}
aValues->mOverrides.AppendElement(gfx::FontPaletteValueSet::OverrideColor{
- uint32_t(aIndex), gfx::sRGBColor::FromABGR(aColor->ToColor())});
+ uint32_t(aIndex), gfx::sRGBColor::FromABGR(aColor->ToColor(nullptr))});
}
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,

View File

@@ -1,5 +1,5 @@
diff --git a/layout/style/StyleColor.cpp b/layout/style/StyleColor.cpp
index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..8dbfbb846b786d51af288989163aacfae12e787c 100644
index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..85a48f27251756c72db8ed03a673a18e96cf76f9 100644
--- a/layout/style/StyleColor.cpp
+++ b/layout/style/StyleColor.cpp
@@ -8,6 +8,7 @@
@@ -10,25 +10,46 @@ index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..8dbfbb846b786d51af288989163aacfa
namespace mozilla {
@@ -21,6 +22,8 @@ bool StyleColor::MaybeTransparent() const {
template <>
StyleAbsoluteColor StyleColor::ResolveColor(
const StyleAbsoluteColor& aForegroundColor) const {
+ auto ResolveColorInner = [this,
+ &aForegroundColor]() -> StyleAbsoluteColor {
if (IsAbsolute()) {
return AsAbsolute();
}
@@ -30,6 +33,8 @@ StyleAbsoluteColor StyleColor::ResolveColor(
}
@@ -34,23 +35,24 @@ StyleAbsoluteColor StyleColor::ResolveColor(
return Servo_ResolveColor(this, &aForegroundColor);
+ };
+ return zen::nsZenBoostsBackend::ResolveStyleColor(ResolveColorInner());
template <>
nscolor StyleColor::CalcColor(nscolor aColor) const {
- return ResolveColor(StyleAbsoluteColor::FromColor(aColor)).ToColor();
+ return ResolveColor(StyleAbsoluteColor::FromColor(aColor)).ToColor(nullptr);
}
template <>
@@ -68,10 +73,11 @@ nscolor StyleAbsoluteColor::ToColor() const {
nscolor StyleColor::CalcColor(
const StyleAbsoluteColor& aForegroundColor) const {
- return ResolveColor(aForegroundColor).ToColor();
+ return ResolveColor(aForegroundColor).ToColor(nullptr);
}
template <>
-nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const {
- return ResolveColor(aStyle.StyleText()->mColor).ToColor();
+nscolor StyleColor::CalcColor(const ComputedStyle& aStyle,
+ const nsIFrame* aFrame) const {
+ return ResolveColor(aStyle.StyleText()->mColor).ToColor(aFrame);
}
template <>
nscolor StyleColor::CalcColor(const nsIFrame* aFrame) const {
- return ResolveColor(aFrame->StyleText()->mColor).ToColor();
+ return ResolveColor(aFrame->StyleText()->mColor).ToColor(aFrame);
}
StyleAbsoluteColor StyleAbsoluteColor::ToColorSpace(
@@ -58,7 +60,7 @@ StyleAbsoluteColor StyleAbsoluteColor::ToColorSpace(
return Servo_ConvertColorSpace(this, aColorSpace);
}
-nscolor StyleAbsoluteColor::ToColor() const {
+nscolor StyleAbsoluteColor::ToColor(const nsIFrame* aFrame) const {
auto srgb = ToColorSpace(StyleColorSpace::Srgb);
// TODO(tlouw): Needs gamut mapping here. Right now we just hard clip the
@@ -68,10 +70,12 @@ nscolor StyleAbsoluteColor::ToColor() const {
auto green = std::clamp(srgb.components._1, 0.0f, 1.0f);
auto blue = std::clamp(srgb.components._2, 0.0f, 1.0f);
@@ -38,7 +59,8 @@ index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..8dbfbb846b786d51af288989163aacfa
nsStyleUtil::FloatToColorComponent(green),
nsStyleUtil::FloatToColorComponent(blue),
- nsStyleUtil::FloatToColorComponent(srgb.alpha));
+ nsStyleUtil::FloatToColorComponent(srgb.alpha)));
+ nsStyleUtil::FloatToColorComponent(srgb.alpha)),
+ aFrame);
}
} // namespace mozilla

View File

@@ -0,0 +1,13 @@
diff --git a/layout/style/StyleColorInlines.h b/layout/style/StyleColorInlines.h
index 332f715ca2a11c98afcb80a870da98c038a7e4f0..a5bddde67165fcb40d40b3aec76a9d19d8880d64 100644
--- a/layout/style/StyleColorInlines.h
+++ b/layout/style/StyleColorInlines.h
@@ -66,7 +66,7 @@ template <>
nscolor StyleColor::CalcColor(nscolor) const;
template <>
-nscolor StyleColor::CalcColor(const ComputedStyle&) const;
+nscolor StyleColor::CalcColor(const ComputedStyle&, const nsIFrame*) const;
template <>
nscolor StyleColor::CalcColor(const nsIFrame*) const;

View File

@@ -0,0 +1,13 @@
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index 80ca0cc08bc675359fbb09100eca43c8e3b9d413..d3ea525f6d84568c4e997a142bbfef6435d21034 100644
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2208,7 +2208,7 @@ nscolor nsStyleBackground::BackgroundColor(const nsIFrame* aFrame) const {
}
nscolor nsStyleBackground::BackgroundColor(const ComputedStyle* aStyle) const {
- return mBackgroundColor.CalcColor(*aStyle);
+ return mBackgroundColor.CalcColor(*aStyle, nullptr);
}
bool nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const {

View File

@@ -0,0 +1,13 @@
diff --git a/layout/svg/FilterInstance.cpp b/layout/svg/FilterInstance.cpp
index 499f824aaeed6ac014974ff11848cf40ac0bba09..bec724baf0ae97cd9dea59a1609d8ea9baaad715 100644
--- a/layout/svg/FilterInstance.cpp
+++ b/layout/svg/FilterInstance.cpp
@@ -1681,7 +1681,7 @@ nsresult FilterInstance::BuildPrimitivesForFilter(
// If we don't have a frame, use opaque black for shadows with unspecified
// shadow colors.
nscolor shadowFallbackColor =
- mTargetFrame ? mTargetFrame->StyleText()->mColor.ToColor()
+ mTargetFrame ? mTargetFrame->StyleText()->mColor.ToColor(mTargetFrame)
: NS_RGB(0, 0, 0);
CSSFilterInstance cssFilterInstance(aFilter, shadowFallbackColor,

View File

@@ -0,0 +1,13 @@
diff --git a/layout/svg/SVGContextPaint.cpp b/layout/svg/SVGContextPaint.cpp
index 3df8728978c1b48ca326c852feb0553091a99673..9f9096205c3dd3551c41c547a1aee667c0a51238 100644
--- a/layout/svg/SVGContextPaint.cpp
+++ b/layout/svg/SVGContextPaint.cpp
@@ -143,7 +143,7 @@ static void SetupInheritablePaint(const DrawTarget* aDrawTarget,
}
nscolor color = SVGUtils::GetFallbackOrPaintColor(
- *aFrame->Style(), aFillOrStroke, aDefaultFallbackColor);
+ *aFrame->Style(), aFillOrStroke, aDefaultFallbackColor, aFrame);
aTargetPaint.SetColor(color);
}

View File

@@ -0,0 +1,42 @@
diff --git a/layout/svg/SVGGradientFrame.cpp b/layout/svg/SVGGradientFrame.cpp
index 9c66d90fc0292abcab30c912968d3f84c0e181ff..aec0b2e48965729ccff19d632ac5e8fd04fd09eb 100644
--- a/layout/svg/SVGGradientFrame.cpp
+++ b/layout/svg/SVGGradientFrame.cpp
@@ -229,8 +229,9 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
SVGColorStopInterpolator(
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
- bool aExtend)
- : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod, aExtend),
+ bool aExtend, const nsIFrame* aFrame)
+ : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod, aExtend,
+ aFrame),
mGradient(aGradient) {}
void CreateStop(float aPosition, DeviceColor aColor) {
@@ -270,7 +271,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
if (nStops == 1 || GradientVectorLengthIsZero()) {
// The gradient paints a single colour, using the stop-color of the last
// gradient step if there are more than one.
- return do_AddRef(new gfxPattern(ToDeviceColor(stops.LastElement().mColor)));
+ return do_AddRef(
+ new gfxPattern(ToDeviceColor(stops.LastElement().mColor, aSource)));
}
// Get the transform list (if there is one). We do this after the returns
@@ -313,12 +315,13 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
static constexpr auto interpolationMethod = StyleColorInterpolationMethod{
StyleColorSpace::SrgbLinear, StyleHueInterpolationMethod::Shorter};
SVGColorStopInterpolator interpolator(gradient, stops, interpolationMethod,
- false);
+ false, aSource);
interpolator.CreateStops();
} else {
// setup standard sRGB stops
for (const auto& stop : stops) {
- gradient->AddColorStop(stop.mPosition, ToDeviceColor(stop.mColor));
+ gradient->AddColorStop(stop.mPosition,
+ ToDeviceColor(stop.mColor, aSource));
}
}

View File

@@ -0,0 +1,58 @@
diff --git a/layout/svg/SVGImageContext.cpp b/layout/svg/SVGImageContext.cpp
index ecbda963b75fb70b62885a0c8f7a517011a8d5dc..5f55f0a4174db830656d434b5295835ab18e6619 100644
--- a/layout/svg/SVGImageContext.cpp
+++ b/layout/svg/SVGImageContext.cpp
@@ -10,6 +10,7 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/ServoCSSParser.h"
#include "mozilla/StaticPrefs_svg.h"
+#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Document.h"
#include "nsIFrame.h"
#include "nsISVGPaintContext.h"
@@ -18,6 +19,19 @@
namespace mozilla {
+/* static */
+void SVGImageContext::MaybeStoreZenBoosts(SVGImageContext& aContext,
+ const nsPresContext& aPresContext) {
+ if (dom::Document* doc = aPresContext.Document()) {
+ if (dom::BrowsingContext* bc = doc->GetBrowsingContext()) {
+ bc = bc->Top();
+ aContext.SetZenBoosts(bc->ZenBoostsData(),
+ bc->ZenBoostsComplementaryRotation(),
+ bc->IsZenBoostsInverted());
+ }
+ }
+}
+
/* static */
void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext,
nsIFrame* aFromFrame,
@@ -43,6 +57,8 @@ void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext,
aContext.SetColorScheme(Some(scheme));
}
+ MaybeStoreZenBoosts(aContext, aPresContext);
+
const nsStyleSVG* style = aStyle.StyleSVG();
if (!style->ExposesContextProperties()) {
// Content must have '-moz-context-properties' set to the names of the
@@ -57,12 +73,14 @@ void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext,
if ((style->mMozContextProperties.bits & StyleContextPropertyBits::FILL) &&
style->mFill.kind.IsColor()) {
haveContextPaint = true;
- contextPaint->SetFill(style->mFill.kind.AsColor().CalcColor(aStyle));
+ contextPaint->SetFill(
+ style->mFill.kind.AsColor().CalcColor(aStyle, nullptr));
}
if ((style->mMozContextProperties.bits & StyleContextPropertyBits::STROKE) &&
style->mStroke.kind.IsColor()) {
haveContextPaint = true;
- contextPaint->SetStroke(style->mStroke.kind.AsColor().CalcColor(aStyle));
+ contextPaint->SetStroke(
+ style->mStroke.kind.AsColor().CalcColor(aStyle, nullptr));
}
if (style->mMozContextProperties.bits &
StyleContextPropertyBits::FILL_OPACITY) {

View File

@@ -0,0 +1,80 @@
diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h
index 159d9cbbd0711076ee6c2a71a3da04bd92a0102c..daefc40590c4d7d7fac9db25c6ec4ba2424dded5 100644
--- a/layout/svg/SVGImageContext.h
+++ b/layout/svg/SVGImageContext.h
@@ -6,6 +6,7 @@
#define LAYOUT_SVG_SVGIMAGECONTEXT_H_
#include "Units.h"
+#include "nsColor.h"
#include "mozilla/Maybe.h"
#include "mozilla/SVGContextPaint.h"
#include "mozilla/SVGPreserveAspectRatio.h"
@@ -63,6 +64,11 @@ class SVGImageContext {
nsISVGPaintContext* aPaintContext,
imgIContainer* aImgContainer);
+ // Carry the host document's Zen boost into the image context so the image
+ // renders with the same accent/inversion as the page.
+ static void MaybeStoreZenBoosts(SVGImageContext& aContext,
+ const nsPresContext& aPresContext);
+
const Maybe<CSSIntSize>& GetViewportSize() const { return mViewportSize; }
void SetViewportSize(const Maybe<CSSIntSize>& aSize) {
@@ -75,6 +81,21 @@ class SVGImageContext {
mColorScheme = aScheme;
}
+ // Zen boosts state carried from the host document so the image renders with
+ // the same boost. Part of the cache key below so boosted and unboosted
+ // renderings don't collide.
+ void SetZenBoosts(nscolor aAccent, float aComplementaryRotation,
+ bool aInverted) {
+ mZenBoostsAccent = aAccent;
+ mZenBoostsComplementaryRotation = aComplementaryRotation;
+ mZenBoostsInverted = aInverted;
+ }
+ nscolor GetZenBoostsAccent() const { return mZenBoostsAccent; }
+ float GetZenBoostsComplementaryRotation() const {
+ return mZenBoostsComplementaryRotation;
+ }
+ bool GetZenBoostsInverted() const { return mZenBoostsInverted; }
+
const Maybe<SVGPreserveAspectRatio>& GetPreserveAspectRatio() const {
return mPreserveAspectRatio;
}
@@ -107,7 +128,11 @@ class SVGImageContext {
return contextPaintIsEqual && mViewportSize == aOther.mViewportSize &&
mPreserveAspectRatio == aOther.mPreserveAspectRatio &&
- mColorScheme == aOther.mColorScheme;
+ mColorScheme == aOther.mColorScheme &&
+ mZenBoostsAccent == aOther.mZenBoostsAccent &&
+ mZenBoostsComplementaryRotation ==
+ aOther.mZenBoostsComplementaryRotation &&
+ mZenBoostsInverted == aOther.mZenBoostsInverted;
}
bool operator!=(const SVGImageContext&) const = default;
@@ -119,7 +144,9 @@ class SVGImageContext {
}
return HashGeneric(hash, mViewportSize.map(HashSize).valueOr(0),
mPreserveAspectRatio.map(HashPAR).valueOr(0),
- mColorScheme.map(HashColorScheme).valueOr(0));
+ mColorScheme.map(HashColorScheme).valueOr(0),
+ mZenBoostsAccent, mZenBoostsComplementaryRotation,
+ mZenBoostsInverted);
}
private:
@@ -138,6 +165,9 @@ class SVGImageContext {
Maybe<CSSIntSize> mViewportSize;
Maybe<SVGPreserveAspectRatio> mPreserveAspectRatio;
Maybe<ColorScheme> mColorScheme;
+ nscolor mZenBoostsAccent = 0;
+ float mZenBoostsComplementaryRotation = 0.0f;
+ bool mZenBoostsInverted = false;
};
} // namespace mozilla

View File

@@ -0,0 +1,28 @@
diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp
index 93f6f2a704734314586fa16b6a45b434f9c2304d..4503ee2b48be39bb2e61962316ef43ad292a7b27 100644
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -2662,9 +2662,9 @@ void SVGTextDrawPathCallbacks::ApplyOpacity(
sRGBColor& aColor, const StyleSVGPaint& aPaint,
const StyleSVGOpacity& aOpacity) const {
if (aPaint.kind.tag == StyleSVGPaintKind::Tag::Color) {
- aColor.a *=
- sRGBColor::FromABGR(aPaint.kind.AsColor().CalcColor(*mFrame->Style()))
- .a;
+ aColor.a *= sRGBColor::FromABGR(
+ aPaint.kind.AsColor().CalcColor(*mFrame->Style(), mFrame))
+ .a;
}
aColor.a *= SVGUtils::GetOpacity(aOpacity, mContextPaint);
}
@@ -5076,8 +5076,8 @@ bool SVGTextFrame::ShouldRenderAsPath(nsTextFrame* aFrame,
// It's possible nsTextFrame will support non-opaque shadows in the future,
// in which case this test can be removed.
if (style->mFill.kind.IsColor() && aFrame->StyleText()->HasTextShadow() &&
- NS_GET_A(style->mFill.kind.AsColor().CalcColor(*aFrame->Style())) !=
- 0xFF) {
+ NS_GET_A(style->mFill.kind.AsColor().CalcColor(*aFrame->Style(),
+ aFrame)) != 0xFF) {
return true;
}

View File

@@ -0,0 +1,60 @@
diff --git a/layout/svg/SVGUtils.cpp b/layout/svg/SVGUtils.cpp
index 93b73e1c665ea8e011af7026810db6cd23c8049b..004d1d0637d62fcde25a924df5392a7dc64f75dc 100644
--- a/layout/svg/SVGUtils.cpp
+++ b/layout/svg/SVGUtils.cpp
@@ -1154,23 +1154,23 @@ gfxRect SVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
/* static */
nscolor SVGUtils::GetFallbackOrPaintColor(
const ComputedStyle& aStyle, StyleSVGPaint nsStyleSVG::* aFillOrStroke,
- nscolor aDefaultContextFallbackColor) {
+ nscolor aDefaultContextFallbackColor, const nsIFrame* aFrame) {
const auto& paint = aStyle.StyleSVG()->*aFillOrStroke;
nscolor color;
switch (paint.kind.tag) {
case StyleSVGPaintKind::Tag::PaintServer:
color = paint.fallback.IsColor()
- ? paint.fallback.AsColor().CalcColor(aStyle)
+ ? paint.fallback.AsColor().CalcColor(aStyle, aFrame)
: NS_RGBA(0, 0, 0, 0);
break;
case StyleSVGPaintKind::Tag::ContextStroke:
case StyleSVGPaintKind::Tag::ContextFill:
color = paint.fallback.IsColor()
- ? paint.fallback.AsColor().CalcColor(aStyle)
+ ? paint.fallback.AsColor().CalcColor(aStyle, aFrame)
: aDefaultContextFallbackColor;
break;
default:
- color = paint.kind.AsColor().CalcColor(aStyle);
+ color = paint.kind.AsColor().CalcColor(aStyle, aFrame);
break;
}
if (const auto* styleIfVisited = aStyle.GetStyleIfVisited()) {
@@ -1184,7 +1184,8 @@ nscolor SVGUtils::GetFallbackOrPaintColor(
// another simple color.
if (paintIfVisited.kind.IsColor() && paint.kind.IsColor()) {
nscolor colors[2] = {
- color, paintIfVisited.kind.AsColor().CalcColor(*styleIfVisited)};
+ color,
+ paintIfVisited.kind.AsColor().CalcColor(*styleIfVisited, aFrame)};
return ComputedStyle::CombineVisitedColors(colors,
aStyle.RelevantLinkVisited());
}
@@ -1254,7 +1255,7 @@ void SVGUtils::MakeFillPatternFor(nsIFrame* aFrame, gfxContext* aContext,
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
sRGBColor color(sRGBColor::FromABGR(GetFallbackOrPaintColor(
- *aFrame->Style(), &nsStyleSVG::mFill, NS_RGB(0, 0, 0))));
+ *aFrame->Style(), &nsStyleSVG::mFill, NS_RGB(0, 0, 0), aFrame)));
color.a *= fillOpacity;
aOutPattern->InitColorPattern(ToDeviceColor(color));
}
@@ -1321,7 +1322,7 @@ void SVGUtils::MakeStrokePatternFor(nsIFrame* aFrame, gfxContext* aContext,
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
sRGBColor color(sRGBColor::FromABGR(GetFallbackOrPaintColor(
- *aFrame->Style(), &nsStyleSVG::mStroke, NS_RGBA(0, 0, 0, 0))));
+ *aFrame->Style(), &nsStyleSVG::mStroke, NS_RGBA(0, 0, 0, 0), aFrame)));
color.a *= strokeOpacity;
aOutPattern->InitColorPattern(ToDeviceColor(color));
}

View File

@@ -0,0 +1,13 @@
diff --git a/layout/svg/SVGUtils.h b/layout/svg/SVGUtils.h
index 1f1f7ad6b78e5c411651fee30bbbfeb784257e0a..28c7332aae411c4220bd00af08b491d31d2eb090 100644
--- a/layout/svg/SVGUtils.h
+++ b/layout/svg/SVGUtils.h
@@ -428,7 +428,7 @@ class SVGUtils final {
static nscolor GetFallbackOrPaintColor(
const ComputedStyle&, StyleSVGPaint nsStyleSVG::* aFillOrStroke,
- nscolor aDefaultContextFallbackColor);
+ nscolor aDefaultContextFallbackColor, const nsIFrame* aFrame);
static void MakeFillPatternFor(nsIFrame* aFrame, gfxContext* aContext,
GeneralPattern* aOutPattern,

View File

@@ -0,0 +1,13 @@
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp
index 7c39ea94392dc158656621dfbee1be72bbcd46f8..e2fe47662b92ac6fb7fe2177d1d2cdab500bb969 100644
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -4088,7 +4088,7 @@ static void GetColorAndStyle(const nsIFrame* aFrame, WritingMode aTableWM,
return;
}
*aColor = aFrame->Style()->GetVisitedDependentColor(
- nsStyleBorder::BorderColorFieldFor(physicalSide));
+ nsStyleBorder::BorderColorFieldFor(physicalSide), aFrame);
if (aWidth) {
*aWidth = styleData->GetComputedBorderWidth(physicalSide);

View File

@@ -0,0 +1,32 @@
diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp
index b6aa10336e7994c830e0326298820c3a534f8094..7747c52e5c5d227894d8f7fb377c65861dc51c4c 100644
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2865,7 +2865,8 @@ ImgDrawResult nsTreeBodyFrame::PaintCell(
const nsStyleBorder* borderStyle = lineContext->StyleBorder();
// Resolve currentcolor values against the treeline context
- nscolor color = borderStyle->mBorderLeftColor.CalcColor(*lineContext);
+ nscolor color =
+ borderStyle->mBorderLeftColor.CalcColor(*lineContext, this);
ColorPattern colorPatt(ToDeviceColor(color));
StyleBorderStyle style = borderStyle->GetBorderStyle(eSideLeft);
@@ -3300,7 +3301,7 @@ ImgDrawResult nsTreeBodyFrame::PaintText(
textRect.Deflate(bp);
// Set our color.
- ColorPattern color(ToDeviceColor(textContext->StyleText()->mColor));
+ ColorPattern color(ToDeviceColor(textContext->StyleText()->mColor, this));
// Draw decorations.
StyleTextDecorationLine decorations =
@@ -3340,7 +3341,7 @@ ImgDrawResult nsTreeBodyFrame::PaintText(
}
aRenderingContext.SetColor(
- sRGBColor::FromABGR(textContext->StyleText()->mColor.ToColor()));
+ sRGBColor::FromABGR(textContext->StyleText()->mColor.ToColor(this)));
nsLayoutUtils::DrawString(
this, *fontMet, &aRenderingContext, text.get(), text.Length(),
textRect.TopLeft() + nsPoint(0, baseline), cellContext);

View File

@@ -0,0 +1,30 @@
diff --git a/servo/ports/geckolib/cbindgen.toml b/servo/ports/geckolib/cbindgen.toml
index e9ae0149e80a241b2a32ce445deb923af2fac445..0dc5768ab8bf89f7d6c31ff4c7bd4bb805d64509 100644
--- a/servo/ports/geckolib/cbindgen.toml
+++ b/servo/ports/geckolib/cbindgen.toml
@@ -679,9 +679,9 @@ renaming_overrides_prefixing = true
nscolor CalcColor(const nsIFrame*) const;
/**
* Compute the final color, taking into account the foreground color from the
- * style.
+ * style. The frame, when supplied, is used to resolve Zen boosts.
*/
- nscolor CalcColor(const ComputedStyle&) const;
+ nscolor CalcColor(const ComputedStyle&, const nsIFrame*) const;
/**
* Compute the final color, making the argument the foreground color.
*/
@@ -704,9 +704,11 @@ renaming_overrides_prefixing = true
/**
* Convert this color to an nscolor. The color will be converted to sRGB first
- * if required.
+ * if required. The frame, when supplied, is used to resolve Zen boosts; pass
+ * the frame the color is being resolved for so boosts can be derived from its
+ * document, or null to skip boost resolution.
*/
- nscolor ToColor() const;
+ nscolor ToColor(const nsIFrame*) const;
"""
"OwnedSlice" = """

View File

@@ -0,0 +1,23 @@
diff --git a/widget/ScrollbarDrawing.cpp b/widget/ScrollbarDrawing.cpp
index fec73f8a8cbfbf952f1d14f1a4eb2b20f9b5aad4..375ef5654cf61e4dea102588679d2ac2060d299a 100644
--- a/widget/ScrollbarDrawing.cpp
+++ b/widget/ScrollbarDrawing.cpp
@@ -121,7 +121,7 @@ sRGBColor ScrollbarDrawing::ComputeScrollbarTrackColor(
const nsStyleUI* ui = aStyle.StyleUI();
if (ui->mScrollbarColor.IsColors()) {
return sRGBColor::FromABGR(
- ui->mScrollbarColor.AsColors().track.CalcColor(aStyle));
+ ui->mScrollbarColor.AsColors().track.CalcColor(aStyle, aFrame));
}
static constexpr sRGBColor sDefaultDarkTrackColor =
sRGBColor::FromU8(20, 20, 25, 77);
@@ -143,7 +143,8 @@ sRGBColor ScrollbarDrawing::ComputeScrollbarThumbColor(
const nsStyleUI* ui = aStyle.StyleUI();
if (ui->mScrollbarColor.IsColors()) {
return sRGBColor::FromABGR(ThemeColors::AdjustUnthemedScrollbarThumbColor(
- ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle), aElementState));
+ ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle, aFrame),
+ aElementState));
}
auto systemColor = [&] {

View File

@@ -0,0 +1,15 @@
diff --git a/widget/ScrollbarDrawingCocoa.cpp b/widget/ScrollbarDrawingCocoa.cpp
index f0dff9276f9880034c800413c4afc2400136b35a..1dd5b53bfda64e1d3b4c1870680fa1a43de0e6fb 100644
--- a/widget/ScrollbarDrawingCocoa.cpp
+++ b/widget/ScrollbarDrawingCocoa.cpp
@@ -61,8 +61,8 @@ static ScrollbarParams ComputeScrollbarParams(nsIFrame* aFrame,
if (ui->HasCustomScrollbars()) {
const auto& colors = ui->mScrollbarColor.AsColors();
params.isCustom = true;
- params.trackColor = colors.track.CalcColor(aStyle);
- params.faceColor = colors.thumb.CalcColor(aStyle);
+ params.trackColor = colors.track.CalcColor(aStyle, aFrame);
+ params.faceColor = colors.thumb.CalcColor(aStyle, aFrame);
}
return params;

View File

@@ -0,0 +1,22 @@
diff --git a/widget/ScrollbarDrawingWin11.cpp b/widget/ScrollbarDrawingWin11.cpp
index be059ca615d1e0281af64984cfc8121be2f6e305..6326c98b369d948052c3cb1df13c8cfaaa472f5c 100644
--- a/widget/ScrollbarDrawingWin11.cpp
+++ b/widget/ScrollbarDrawingWin11.cpp
@@ -78,7 +78,7 @@ sRGBColor ScrollbarDrawingWin11::ComputeScrollbarTrackColor(
const nsStyleUI* ui = aStyle.StyleUI();
if (ui->mScrollbarColor.IsColors()) {
return sRGBColor::FromABGR(
- ui->mScrollbarColor.AsColors().track.CalcColor(aStyle));
+ ui->mScrollbarColor.AsColors().track.CalcColor(aStyle, aFrame));
}
return aColors.IsDark() ? sRGBColor::FromU8(23, 23, 23, 255)
: sRGBColor::FromU8(240, 240, 240, 255);
@@ -94,7 +94,7 @@ sRGBColor ScrollbarDrawingWin11::ComputeScrollbarThumbColor(
const nscolor baseColor = [&] {
const nsStyleUI* ui = aStyle.StyleUI();
if (ui->mScrollbarColor.IsColors()) {
- return ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle);
+ return ui->mScrollbarColor.AsColors().thumb.CalcColor(aStyle, aFrame);
}
return aColors.IsDark() ? NS_RGBA(149, 149, 149, 255)
: NS_RGBA(133, 133, 133, 255);

View File

@@ -0,0 +1,56 @@
diff --git a/widget/Theme.cpp b/widget/Theme.cpp
index 766a8ca4bc6fcc98f719ad4f472b20bc1d198ac9..be4419cfafb55e5cac8f5de741185ee3cabc4722 100644
--- a/widget/Theme.cpp
+++ b/widget/Theme.cpp
@@ -18,6 +18,7 @@
#include "mozilla/RelativeLuminanceUtils.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/StaticPrefs_widget.h"
+#include "mozilla/nsZenBoostsBackend.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "nsCSSColorUtils.h"
#include "nsCSSRendering.h"
@@ -670,10 +671,15 @@ template <typename PaintBackendData>
void Theme::PaintTextField(PaintBackendData& aPaintData,
const LayoutDeviceRect& aRect,
const ElementState& aState, const Colors& aColors,
- DPIRatio aDpiRatio) {
+ DPIRatio aDpiRatio, const nsIFrame* aFrame) {
auto [backgroundColor, borderColor] =
ComputeTextfieldColors(aState, aColors, OutlineCoversBorder::Yes);
+ // The default field background comes from a theme/system color rather than a
+ // resolved style color, so apply Zen boosts here to match boosted content.
+ backgroundColor = sRGBColor::FromABGR(zen::nsZenBoostsBackend::ResolveStyleColor(
+ backgroundColor.ToABGR(), aFrame));
+
const CSSCoord radius = 2.0f;
ThemeDrawing::PaintRoundedRectWithRadius(aPaintData, aRect, backgroundColor,
@@ -690,9 +696,9 @@ template <typename PaintBackendData>
void Theme::PaintListbox(PaintBackendData& aPaintData,
const LayoutDeviceRect& aRect,
const ElementState& aState, const Colors& aColors,
- DPIRatio aDpiRatio) {
+ DPIRatio aDpiRatio, const nsIFrame* aFrame) {
// We happen to share style between text fields and list boxes.
- return PaintTextField(aPaintData, aRect, aState, aColors, aDpiRatio);
+ return PaintTextField(aPaintData, aRect, aState, aColors, aDpiRatio, aFrame);
}
template <typename PaintBackendData>
@@ -1158,10 +1164,12 @@ bool Theme::DoDrawWidgetBackground(PaintBackendData& aPaintData,
case StyleAppearance::Textfield:
case StyleAppearance::NumberInput:
case StyleAppearance::PasswordInput:
- PaintTextField(aPaintData, devPxRect, elementState, colors, dpiRatio);
+ PaintTextField(aPaintData, devPxRect, elementState, colors, dpiRatio,
+ aFrame);
break;
case StyleAppearance::Listbox:
- PaintListbox(aPaintData, devPxRect, elementState, colors, dpiRatio);
+ PaintListbox(aPaintData, devPxRect, elementState, colors, dpiRatio,
+ aFrame);
break;
case StyleAppearance::Menulist:
PaintMenulist(aPaintData, devPxRect, elementState, colors, dpiRatio);

19
src/widget/Theme-h.patch Normal file
View File

@@ -0,0 +1,19 @@
diff --git a/widget/Theme.h b/widget/Theme.h
index 4e0acbb25b9e39b712a2d96d8dee366dfdce4a01..9aa377ca9f0d7f96d938339d198b797ceebbc602 100644
--- a/widget/Theme.h
+++ b/widget/Theme.h
@@ -161,10 +161,12 @@ class Theme : protected nsNativeTheme, public nsITheme {
const ElementState&, DPIRatio);
template <typename PaintBackendData>
void PaintTextField(PaintBackendData&, const LayoutDeviceRect&,
- const ElementState&, const Colors&, DPIRatio);
+ const ElementState&, const Colors&, DPIRatio,
+ const nsIFrame*);
template <typename PaintBackendData>
void PaintListbox(PaintBackendData&, const LayoutDeviceRect&,
- const ElementState&, const Colors&, DPIRatio);
+ const ElementState&, const Colors&, DPIRatio,
+ const nsIFrame*);
template <typename PaintBackendData>
void PaintMenulist(PaintBackendData&, const LayoutDeviceRect&,
const ElementState&, const Colors&, DPIRatio);

View File

@@ -0,0 +1,13 @@
diff --git a/widget/ThemeColors.cpp b/widget/ThemeColors.cpp
index 0ac3a8cbb04258312cba20a89a23700c6fd1b49f..dfd5203c1a795fc14befa88a474f241dd16e9c8f 100644
--- a/widget/ThemeColors.cpp
+++ b/widget/ThemeColors.cpp
@@ -113,7 +113,7 @@ ThemeAccentColor::ThemeAccentColor(const ComputedStyle& aStyle,
}
MOZ_ASSERT(color.IsColor());
nscolor accentColor =
- ColorPalette::EnsureOpaque(color.AsColor().CalcColor(aStyle));
+ ColorPalette::EnsureOpaque(color.AsColor().CalcColor(aStyle, nullptr));
if (sRGBColor::FromABGR(accentColor) == mDefaultPalette->mAccent) {
return;
}

View File

@@ -65,6 +65,7 @@ export class nsZenBoostEditor {
once: true,
});
this.doc.getElementById("zenBoostWindow").setAttribute("editor", "boost");
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"none";
@@ -366,20 +367,22 @@ export class nsZenBoostEditor {
// being smaller than it should be
this._boostEditorWidth = this.editorWindow.outerWidth;
this.editorWindow.resizeTo(
this._codeEditorWidth,
this.editorWindow.outerHeight
);
if (openRightAligned) {
this.editorWindow.moveTo(
this.editorWindow.screenX - offset,
this.editorWindow.screenY
this.editorWindow.requestAnimationFrame(() => {
this.editorWindow.resizeTo(
this._codeEditorWidth,
this.editorWindow.outerHeight
);
}
if (openRightAligned) {
this.editorWindow.moveTo(
this.editorWindow.screenX - offset,
this.editorWindow.screenY
);
}
this.doc.getElementById("zen-boost-editor-root").style.display = "none";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"initial";
this.doc.getElementById("zen-boost-editor-root").style.display = "none";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"initial";
});
}
/**
@@ -397,20 +400,22 @@ export class nsZenBoostEditor {
}
windowElem.setAttribute("editor", "boost");
this.editorWindow.resizeTo(
this._boostEditorWidth,
this.editorWindow.outerHeight
);
if (openRightAligned) {
this.editorWindow.moveTo(
this.editorWindow.screenX + offset,
this.editorWindow.screenY
this.editorWindow.requestAnimationFrame(() => {
this.editorWindow.resizeTo(
this._boostEditorWidth,
this.editorWindow.outerHeight
);
}
if (openRightAligned) {
this.editorWindow.moveTo(
this.editorWindow.screenX + offset,
this.editorWindow.screenY
);
}
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"none";
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"none";
});
// Disable picker mode
this.disableAllPickers();
@@ -564,6 +569,9 @@ ${cssSelector} {
this.wasDragging = true;
event.preventDefault();
this.currentBoostData.changeWasMade = true;
this.updateButtonToggleVisuals();
if (this.dragTarget == "zen-boost-color-picker-dot-secondary") {
this.setSecondaryDotPos(event.clientX, event.clientY);
} else if (event.target.id != "zen-boost-magic-theme") {
@@ -670,20 +678,6 @@ ${cssSelector} {
panel.openPopup(event.target, "bottomcenter topcenter", 0, 2);
}
/**
* Resets the color picker dot to the default position (default state).
*/
resetDotPosition() {
const gradient = this.doc.querySelector(".zen-boost-color-picker-gradient");
const rect = gradient.getBoundingClientRect();
const padding = 50;
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const radius = (rect.width - padding) / 2;
this.setDotPos(centerX + radius / 1.25, centerY);
}
/**
* Handles clicks on the theme picker gradient or magic theme button.
* Updates the dot position or toggles auto-theme mode based on the click target.
@@ -695,14 +689,16 @@ ${cssSelector} {
this.currentBoostData.changeWasMade = true;
this.currentBoostData.enableColorBoost = true;
if (event.target.id == "zen-boost-magic-theme") {
this.currentBoostData.enableColorBoost = true;
this.currentBoostData.autoTheme = !this.currentBoostData.autoTheme;
this.updateButtonToggleVisuals();
this.updateCurrentBoost();
} else if (this.dragTarget != "zen-boost-color-picker-dot-secondary") {
this.setDotPos(event.clientX, event.clientY, !this.wasDragging);
}
this.updateButtonToggleVisuals();
this.wasDragging = false;
}
@@ -1310,6 +1306,23 @@ ${cssSelector} {
const resetBoost = this.doc.getElementById("zen-boost-edit-reset");
const popup = this.doc.getElementById("zenBoostContextMenu");
popup.addEventListener(
"popupshown",
() => {
// Don't give the user following options if the boost
// is not going to save / not currently saved (unchanged)
let shouldDisable = !this.currentBoostData.changeWasMade;
const items = [renameBoost, deleteBoost, resetBoost];
for (let item of items) {
if (shouldDisable) {
item.setAttribute("disabled", "");
} else {
item.removeAttribute("disabled");
}
}
},
{ once: true }
);
popup.openPopup(
event.target,
"bottomcenter topcenter",
@@ -1319,12 +1332,6 @@ ${cssSelector} {
false /* attributesOverride */,
event
);
// Don't give the user following options if the boost
// is not going to save / not currently saved (unchanged)
renameBoost.disabled = !this.currentBoostData.changeWasMade;
deleteBoost.disabled = !this.currentBoostData.changeWasMade;
resetBoost.disabled = !this.currentBoostData.changeWasMade;
}
/**
@@ -1566,44 +1573,32 @@ ${cssSelector} {
}
if (
this.currentBoostData.dotPos.x == null ||
this.currentBoostData.dotPos.y == null
) {
this.resetDotPosition();
} else {
// Test if the stored position is a non-normalized dot position
if (
this.currentBoostData.dotPos.x > 1 ||
this.currentBoostData.dotPos.x < 0 ||
this.currentBoostData.dotPos.y > 1 ||
this.currentBoostData.dotPos.y < 0
) {
// Normalize position
this.currentBoostData.dotPos.x =
this.currentBoostData.dotPos.x / rect.width;
this.currentBoostData.dotPos.y =
this.currentBoostData.dotPos.y / rect.height;
}
// Convert normalized position to relative position
const xPos = this.currentBoostData.dotPos.x * rect.width;
const yPos = this.currentBoostData.dotPos.y * rect.height;
dot.style.left = `${xPos}px`;
dot.style.top = `${yPos}px`;
}
if (
this.currentBoostData.secondaryDotPos?.x != null &&
this.currentBoostData.secondaryDotPos?.y != null
this.currentBoostData.dotPos.x > 1 ||
this.currentBoostData.dotPos.x < 0 ||
this.currentBoostData.dotPos.y > 1 ||
this.currentBoostData.dotPos.y < 0
) {
const xPosSec = this.currentBoostData.secondaryDotPos.x * rect.width;
const yPosSec = this.currentBoostData.secondaryDotPos.y * rect.height;
dotSec.style.left = `${xPosSec}px`;
dotSec.style.top = `${yPosSec}px`;
// Normalize position
this.currentBoostData.dotPos.x =
this.currentBoostData.dotPos.x / rect.width;
this.currentBoostData.dotPos.y =
this.currentBoostData.dotPos.y / rect.height;
}
// Convert normalized position to relative position
const xPos = this.currentBoostData.dotPos.x * rect.width;
const yPos = this.currentBoostData.dotPos.y * rect.height;
dot.style.left = `${xPos}px`;
dot.style.top = `${yPos}px`;
const xPosSec = this.currentBoostData.secondaryDotPos.x * rect.width;
const yPosSec = this.currentBoostData.secondaryDotPos.y * rect.height;
dotSec.style.left = `${xPosSec}px`;
dotSec.style.top = `${yPosSec}px`;
this.editorWindow._editor.setText(this.currentBoostData.customCSS || "");
this.updateFontButtonVisuals();

View File

@@ -115,11 +115,11 @@ class nsZenBoostsManager {
boostName: "My Boost",
dotAngleDeg: 0,
dotPos: { x: null, y: null },
dotPos: { x: 0.76, y: 0.66 },
dotDistance: 0,
secondaryDotAngleDegDelta: 55,
secondaryDotPos: { x: null, y: null },
secondaryDotPos: { x: 0.5, y: 0.81 },
brightness: 0.5,
saturation: 0.5,
@@ -312,6 +312,7 @@ class nsZenBoostsManager {
Services.obs.notifyObservers(null, "zen-boosts-active-change", { id });
this.#writeToDisk(this.registeredDomains);
this.#stylesManager.invalidateStyleForDomain(domain);
this.notify();
}
@@ -327,23 +328,23 @@ class nsZenBoostsManager {
if (domainEntry) {
if (domainEntry.boostEntries.has(id)) {
let unloadStyles = false;
if (domainEntry.activeBoostId === id) {
domainEntry.activeBoostId = null;
Services.obs.notifyObservers(null, "zen-boosts-active-change", {
id: null,
});
this.#stylesManager.invalidateStyleForDomain(domain);
this.notify(true);
unloadStyles = true;
} else {
domainEntry.activeBoostId = id;
Services.obs.notifyObservers(null, "zen-boosts-active-change", {
id,
});
this.#stylesManager.invalidateStyleForDomain(domain);
this.notify();
}
this.#writeToDisk(this.registeredDomains);
this.#stylesManager.invalidateStyleForDomain(domain);
this.notify(unloadStyles);
}
}
}
@@ -539,6 +540,12 @@ class nsZenBoostsManager {
const directoryPath = this.#cssPath;
const savePath = PathUtils.join(directoryPath, fileName);
if (!css || css.trim() === "") {
if (await IOUtils.exists(savePath)) {
await IOUtils.remove(savePath);
}
return;
}
await IOUtils.makeDirectory(directoryPath, { createAncestors: true });
await IOUtils.writeUTF8(savePath, css);
}
@@ -553,7 +560,8 @@ class nsZenBoostsManager {
const domainEntry = this.#getDomainEntry(domain);
if (domainEntry) {
return domainEntry.boostEntries.has(domainEntry.activeBoostId);
const boost = this.loadActiveBoostFromStore(domain);
return boost?.boostEntry.boostData.changeWasMade ?? false;
}
return false;

View File

@@ -26,6 +26,7 @@ export class ZapOverlay {
#dissolvePoolSize = 5;
#dissolveEffectPool = [];
#currentDissolveIndex = 0;
#onZapDoneClick = null;
/**
* @param {*} document Webpage document
@@ -77,10 +78,8 @@ export class ZapOverlay {
*/
#initializeElements() {
this.zapDoneButton = this.getElementById("zap-done");
this.zapDoneButton.addEventListener(
"click",
this.#disableZapMode.bind(this)
);
this.#onZapDoneClick = this.#disableZapMode.bind(this);
this.zapDoneButton.addEventListener("click", this.#onZapDoneClick);
this.#updateZappedList();
}
@@ -355,6 +354,12 @@ export class ZapOverlay {
dissolve.tearDown();
});
if (this.zapDoneButton && this.#onZapDoneClick) {
this.zapDoneButton.removeEventListener("click", this.#onZapDoneClick);
}
this.#onZapDoneClick = null;
this.zapDoneButton = null;
if (this.#content) {
try {
this.document.removeAnonymousContent(this.#content);

View File

@@ -70,6 +70,17 @@ export class ZenBoostsChild extends JSWindowActorChild {
static PREVENTABLE_SET = new Set(ZenBoostsChild.PREVENTABLE_EVENTS);
actorCreated() {
this.#applyBoostForPageIfAvailable();
}
didDestroy() {
if (this.#currentState === ZenBoostsChild.STATES.ZAP) {
this.disableZapMode();
}
this.#removeEventListeners();
}
/**
* Inverse of https://searchfox.org/firefox-main/rev/1a8c62b86277005f907151bc5389cf5c5091e76f/gfx/src/nsColor.h#23-27
*
@@ -179,28 +190,6 @@ export class ZenBoostsChild extends JSWindowActorChild {
return [h * 60, s, l];
}
/**
* Handles DOM events for the actor. Applies boost settings when a document
* element is inserted.
*
* @param {Event} event - The DOM event to handle.
*/
handleEvent(event) {
switch (event.type) {
case "unload":
if (this.#currentState === ZenBoostsChild.STATES.ZAP) {
this.disableZapMode();
}
this.#removeEventListeners();
break;
case "DOMWindowCreated":
this.#applyBoostForPageIfAvailable();
break;
default:
break;
}
}
handleZapEvent(event) {
if (ZenBoostsChild.ALL_EVENTS_SET.has(event.type)) {
this.#overlay.handleEvent(
@@ -322,13 +311,18 @@ export class ZenBoostsChild extends JSWindowActorChild {
return p;
}
get #hostWithoutPort() {
const host = this.browsingContext.topWindow?.location.host;
return host?.split(":")[0];
}
/**
* Aquires the boost data for this website
*
* @returns {object} Boost data for the current website
*/
getWebsiteBoost() {
const domain = this.browsingContext.topWindow?.location?.host;
const domain = this.#hostWithoutPort;
if (!domain) {
return null;
}
@@ -362,6 +356,14 @@ export class ZenBoostsChild extends JSWindowActorChild {
this.#loadStyleSheet(boost.styleSheet);
}
if (
boostData.sizeOverride &&
isFinite(boostData.sizeOverride) &&
boostData.sizeOverride !== 1
) {
browsingContext.fullZoom = boostData.sizeOverride;
}
browsingContext.isZenBoostsInverted = boostData.smartInvert;
if (boostData.enableColorBoost) {
let primaryColor;
@@ -384,17 +386,17 @@ export class ZenBoostsChild extends JSWindowActorChild {
// using the same modifiers as the color above
primaryColor = this.#buildBoostColor(
primaryGradientColor[0],
primaryGradientColor[1] * (1 - boostData.saturation),
0.1 + primaryGradientColor[2] * 0.9 * boostData.brightness,
1 - boostData.saturation,
0.1 + 0.9 * boostData.brightness,
boostData
);
} else {
primaryColor = this.#buildBoostColor(
boostData.dotAngleDeg,
/* already is [0, 1] */
boostData.dotDistance * (1 - boostData.saturation),
1 - boostData.saturation,
/* lightness range from [0.1, 0.9] */
0.1 + boostData.dotDistance * 0.8 * boostData.brightness,
0.1 + 0.9 * boostData.brightness,
boostData
);
}
@@ -484,7 +486,7 @@ export class ZenBoostsChild extends JSWindowActorChild {
}
addZapSelector(selector) {
const domain = this.browsingContext.topWindow?.location?.host;
const domain = this.#hostWithoutPort;
this.sendQuery("ZenBoost:ZapSelector", {
action: "add",
selector,
@@ -493,7 +495,7 @@ export class ZenBoostsChild extends JSWindowActorChild {
}
removeZapSelector(selector) {
const domain = this.browsingContext.topWindow?.location?.host;
const domain = this.#hostWithoutPort;
this.sendQuery("ZenBoost:ZapSelector", {
action: "remove",
selector,

View File

@@ -0,0 +1,121 @@
/* 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 "gtest/gtest.h"
#include "mozilla/nsZenBoostsBackend.h"
using zen::detail::FilterColorChannel;
using zen::detail::InvertColorChannel;
using zen::detail::PrecomputeAccent;
using zen::detail::RotateAccent;
namespace {
// A spread of representative input colors (opaque unless noted).
const nscolor kColors[] = {
NS_RGBA(255, 0, 0, 255), // pure red
NS_RGBA(0, 255, 0, 255), // pure green
NS_RGBA(0, 0, 255, 255), // pure blue
NS_RGBA(0, 0, 0, 255), // black
NS_RGBA(255, 255, 255, 255), // white
NS_RGBA(128, 128, 128, 255), // mid gray
NS_RGBA(18, 52, 86, 200), // arbitrary, semi-transparent
NS_RGBA(240, 17, 99, 1), // near-min alpha
};
// The accent stores the contrast/strength in its alpha byte
// (NS_GET_CONTRAST == NS_GET_A). 0 means "no tint".
zen::nsZenAccentOklab MakeAccent(uint8_t r, uint8_t g, uint8_t b,
uint8_t contrast) {
return PrecomputeAccent(NS_RGBA(r, g, b, contrast));
}
} // namespace
// The headline invariant: filtering must never change opacity. The whole
// pipeline overloads the alpha byte for contrast on the *accent*, but a
// filtered *content* color must keep its original alpha.
TEST(ZenBoostsColorFilter, PreservesAlpha)
{
const zen::nsZenAccentOklab accent = MakeAccent(80, 120, 200, 180);
const zen::nsZenAccentOklab complementary = RotateAccent(accent, 180.0f);
for (nscolor c : kColors) {
const nscolor out = FilterColorChannel(c, accent, complementary);
EXPECT_EQ(NS_GET_A(out), NS_GET_A(c)) << "alpha changed for input " << c;
}
}
// Fully transparent colors are invisible; the filter must pass them through
// untouched (and must not interpret their zero alpha as contrast).
TEST(ZenBoostsColorFilter, TransparentPassthrough)
{
const zen::nsZenAccentOklab accent = MakeAccent(80, 120, 200, 180);
const zen::nsZenAccentOklab complementary = RotateAccent(accent, 90.0f);
const nscolor transparent = NS_RGBA(255, 0, 0, 0);
EXPECT_EQ(FilterColorChannel(transparent, accent, complementary),
transparent);
EXPECT_EQ(InvertColorChannel(transparent), transparent);
}
// Same inputs must always yield the same output (no hidden global state in
// the math itself; the production cache lives outside these primitives).
TEST(ZenBoostsColorFilter, Deterministic)
{
const zen::nsZenAccentOklab accent = MakeAccent(33, 200, 90, 200);
const zen::nsZenAccentOklab complementary = RotateAccent(accent, 200.0f);
for (nscolor c : kColors) {
const nscolor a = FilterColorChannel(c, accent, complementary);
const nscolor b = FilterColorChannel(c, accent, complementary);
EXPECT_EQ(a, b);
EXPECT_EQ(InvertColorChannel(c), InvertColorChannel(c));
}
}
// A zero-contrast accent means "no boost strength": the color must come back
// essentially unchanged (allow +/-1 per channel for sRGB<->Oklab rounding).
TEST(ZenBoostsColorFilter, ZeroContrastIsNearIdentity)
{
const zen::nsZenAccentOklab accent = MakeAccent(200, 50, 50, 0);
const zen::nsZenAccentOklab complementary = RotateAccent(accent, 180.0f);
for (nscolor c : kColors) {
if (NS_GET_A(c) == 0) {
continue;
}
const nscolor out = FilterColorChannel(c, accent, complementary);
EXPECT_NEAR(NS_GET_R(out), NS_GET_R(c), 1);
EXPECT_NEAR(NS_GET_G(out), NS_GET_G(c), 1);
EXPECT_NEAR(NS_GET_B(out), NS_GET_B(c), 1);
EXPECT_EQ(NS_GET_A(out), NS_GET_A(c));
}
}
// Guards against a regression that turns the filter into a no-op: a strong
// accent applied to a neutral gray must actually move the color.
TEST(ZenBoostsColorFilter, StrongAccentActuallyTints)
{
const zen::nsZenAccentOklab accent = MakeAccent(20, 130, 240, 255);
const zen::nsZenAccentOklab complementary = RotateAccent(accent, 30.0f);
const nscolor gray = NS_RGBA(128, 128, 128, 255);
const nscolor out = FilterColorChannel(gray, accent, complementary);
const bool moved = NS_GET_R(out) != NS_GET_R(gray) ||
NS_GET_G(out) != NS_GET_G(gray) ||
NS_GET_B(out) != NS_GET_B(gray);
EXPECT_TRUE(moved) << "a full-strength accent should tint mid gray";
EXPECT_EQ(NS_GET_A(out), NS_GET_A(gray));
}
// Inversion must also preserve opacity.
TEST(ZenBoostsColorFilter, InvertPreservesAlpha)
{
for (nscolor c : kColors) {
EXPECT_EQ(NS_GET_A(InvertColorChannel(c)), NS_GET_A(c));
}
}

View File

@@ -0,0 +1,9 @@
# 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/.
UNIFIED_SOURCES += [
"TestZenBoostsColorFilter.cpp",
]
FINAL_LIBRARY = "xul-gtest"

View File

@@ -26,3 +26,7 @@ SOURCES += [
]
FINAL_LIBRARY = "xul"
TEST_DIRS += [
"gtest",
]

View File

@@ -38,18 +38,6 @@ void BrowsingContext::WalkPresContexts(Callback&& aCallback) {
});
}
static void RefreshBoostCacheIfMatchesCurrent(BrowsingContext* aChanged) {
auto* backend = zen::nsZenBoostsBackend::GetInstance();
if (!backend) {
return;
}
auto current = backend->GetCurrentBrowsingContext();
if (!current || current->Top() != aChanged) {
return;
}
backend->RefreshCachedBoostState();
}
/**
* @brief Called when the ZenBoostsData field is set on a browsing context.
* Triggers a restyle if the boost data has changed.
@@ -61,7 +49,6 @@ void BrowsingContext::DidSet(FieldIndex<IDX_ZenBoostsData>,
if (ZenBoostsData() == aOldValue) {
return;
}
RefreshBoostCacheIfMatchesCurrent(this);
PresContextAffectingFieldChanged();
TRIGGER_PRES_CONTEXT_RESTYLE();
}
@@ -79,7 +66,6 @@ void BrowsingContext::DidSet(FieldIndex<IDX_ZenBoostsComplementaryRotation>,
if (ZenBoostsComplementaryRotation() == aOldValue) {
return;
}
RefreshBoostCacheIfMatchesCurrent(this);
PresContextAffectingFieldChanged();
TRIGGER_PRES_CONTEXT_RESTYLE();
}
@@ -95,7 +81,6 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsZenBoostsInverted>,
if (IsZenBoostsInverted() == aOldValue) {
return;
}
RefreshBoostCacheIfMatchesCurrent(this);
PresContextAffectingFieldChanged();
TRIGGER_PRES_CONTEXT_RESTYLE();
}

View File

@@ -4,12 +4,16 @@
#include <cmath>
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include "nsZenBoostsBackend.h"
#include "nsIXULRuntime.h"
#include "nsPresContext.h"
#include "nsIFrame.h"
#include "nsIContent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
@@ -21,6 +25,8 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Element.h"
#include "mozilla/PseudoStyleType.h"
#include "mozilla/StaticPrefs_zen.h"
@@ -29,9 +35,6 @@
#define INVERT_CHANNEL_FLOOR() \
(mozilla::StaticPrefs::zen_boosts_invert_channel_floor_AtStartup())
#define SHOULD_APPLY_BOOSTS_TO_ANONYMOUS_CONTENT() \
(!mozilla::StaticPrefs::zen_boosts_disable_on_anonymous_content_AtStartup())
#if defined(__clang__) || defined(__GNUC__)
# define ZEN_HOT_FUNCTION __attribute__((hot))
#else
@@ -48,10 +51,6 @@ namespace zen {
NS_IMPL_ISUPPORTS0(nsZenBoostsBackend)
nsZenAccentOklab nsZenBoostsBackend::mCachedAccent{0};
nsZenAccentOklab nsZenBoostsBackend::mCachedComplementary{0};
float nsZenBoostsBackend::mCachedComplementaryRotationDeg = 0.0f;
namespace {
/**
@@ -83,17 +82,43 @@ static inline float linearToSrgb(float c) {
static inline float fastCbrt(float x) {
if (x == 0.0f) return 0.0f;
float a = std::abs(x);
union {
float f;
uint32_t i;
} u = {a};
u.i = u.i / 3 + 0x2a504a2e;
float y = u.f;
// Bit-level initial guess. Use memcpy rather than a union to avoid the
// undefined behaviour of type-punning through a union member in C++.
uint32_t i;
std::memcpy(&i, &a, sizeof(i));
i = i / 3 + 0x2a504a2e;
float y;
std::memcpy(&y, &i, sizeof(y));
y = (2.0f * y + a / (y * y)) * (1.0f / 3.0f);
y = (2.0f * y + a / (y * y)) * (1.0f / 3.0f);
return x < 0.0f ? -y : y;
}
/**
* @brief sRGB(0..255) -> linear lookup table. The filter only ever feeds
* integer 8-bit channels through srgbToLinear, so the 256 possible results
* are precomputed once instead of calling std::pow three times per color on
* the per-color hot path. Built lazily on first use; the function-local
* static makes initialization thread-safe.
*/
static inline const std::array<float, 256>& SrgbLinearTable() {
static const std::array<float, 256> kTable = [] {
std::array<float, 256> table{};
for (int i = 0; i < 256; ++i) {
table[i] = srgbToLinear(i * (1.0f / 255.0f));
}
return table;
}();
return kTable;
}
/**
* @brief Linearizes an 8-bit sRGB channel via the precomputed table.
*/
static inline float srgbToLinear8(uint8_t aChannel) {
return SrgbLinearTable()[aChannel];
}
/**
* @brief Precomputes the Oklab values for a given accent color. This allows us
* to efficiently apply the accent color as a filter to other colors without
@@ -107,13 +132,9 @@ ZEN_HOT_FUNCTION
inline static auto zenPrecomputeAccent(nscolor aAccentColor) {
constexpr float inv255 = 1.0f / 255.0f;
const float r = NS_GET_R(aAccentColor) * inv255;
const float g = NS_GET_G(aAccentColor) * inv255;
const float b = NS_GET_B(aAccentColor) * inv255;
const float lr = srgbToLinear(r);
const float lg = srgbToLinear(g);
const float lb = srgbToLinear(b);
const float lr = srgbToLinear8(NS_GET_R(aAccentColor));
const float lg = srgbToLinear8(NS_GET_G(aAccentColor));
const float lb = srgbToLinear8(NS_GET_B(aAccentColor));
const float l_ =
fastCbrt(0.4122214708f * lr + 0.5363325363f * lg + 0.0514459929f * lb);
@@ -156,6 +177,45 @@ inline static nsZenAccentOklab zenRotateAccent(const nsZenAccentOklab& aBase,
};
}
/**
* @brief Small round-robin cache of precomputed accents. Painting several
* boosted tabs with different accents interleaved would otherwise recompute
* the Oklab base accent (with cbrt) and the rotated complementary accent on
* every single color. Keyed by the accent nscolor and the complementary hue
* rotation. Main-thread only (same threading assumption as the per-color
* paint path it serves).
*/
struct AccentCacheEntry {
nscolor accentNS = 0;
float rotationDeg = 0.0f;
bool valid = false;
nsZenAccentOklab accent{};
nsZenAccentOklab complementary{};
};
static constexpr size_t kAccentCacheSize = 4;
static AccentCacheEntry sAccentCache[kAccentCacheSize];
static size_t sAccentCacheNext = 0;
ZEN_HOT_FUNCTION
static const AccentCacheEntry& GetCachedAccent(nscolor aAccentNS,
float aRotationDeg) {
for (const auto& entry : sAccentCache) {
if (entry.valid && entry.accentNS == aAccentNS &&
entry.rotationDeg == aRotationDeg) {
return entry;
}
}
AccentCacheEntry& slot = sAccentCache[sAccentCacheNext];
sAccentCacheNext = (sAccentCacheNext + 1) % kAccentCacheSize;
slot.accentNS = aAccentNS;
slot.rotationDeg = aRotationDeg;
slot.accent = zenPrecomputeAccent(aAccentNS);
slot.complementary = zenRotateAccent(slot.accent, aRotationDeg);
slot.valid = true;
return slot;
}
/**
* @brief Applies a duotone color filter to transform an original color toward
* one of two accent colors. The original color's perceived lightness decides
@@ -183,10 +243,10 @@ inline static nsZenAccentOklab zenRotateAccent(const nsZenAccentOklab& aBase,
constexpr float inv255 = 1.0f / 255.0f;
const float blendFactor = contrast * inv255;
// sRGB -> linear
const float lr = srgbToLinear(NS_GET_R(aOriginalColor) * inv255);
const float lg = srgbToLinear(NS_GET_G(aOriginalColor) * inv255);
const float lb = srgbToLinear(NS_GET_B(aOriginalColor) * inv255);
// sRGB -> linear (8-bit channels via the precomputed table)
const float lr = srgbToLinear8(NS_GET_R(aOriginalColor));
const float lg = srgbToLinear8(NS_GET_G(aOriginalColor));
const float lb = srgbToLinear8(NS_GET_B(aOriginalColor));
// Linear RGB -> LMS -> cube root -> Oklab (fused)
const float l_ =
@@ -300,40 +360,83 @@ inline static nscolor zenInvertColorChannel(nscolor aColor) {
const auto gShifted = sum - gInv;
const auto bShifted = sum - bInv;
// Compress the channel range into [FLOOR, 255] so dark inversions are
// lifted while light inversions are left untouched. This preserves hue
// since all three channels are scaled by the same factor.
// If the resulting color is light, leave it untouched: mixing in the floor
// would raise its lowest channel and wash the color out toward grey. Only
// dark results get the floor lift, which keeps them off pure black.
const auto luma = (rShifted * 54 + gShifted * 183 + bShifted * 19) >> 8;
if (luma > 127) {
return NS_RGBA(static_cast<uint8_t>(rShifted),
static_cast<uint8_t>(gShifted),
static_cast<uint8_t>(bShifted), a);
}
// Compress the dark channel range into [FLOOR, 255] so dark inversions are
// lifted off pure black. This preserves hue since all three channels are
// scaled by the same factor.
const auto channelFloor = INVERT_CHANNEL_FLOOR();
const uint32_t range = 255 - channelFloor;
const auto lift = [channelFloor, range](uint8_t c) -> uint8_t {
return static_cast<uint8_t>(channelFloor + (c * range) / 255);
};
return NS_RGBA(lift(rShifted), lift(gShifted), lift(bShifted), a);
}
/**
* @brief Retrieves the current boost data from the browsing context. When
* called without aPresContext, reads the precomputed cache populated on
* presshell entry; otherwise resolves from the supplied PresContext.
* @brief Whether the given frame belongs to anonymous content that boosts must
* not touch (devtools highlighters, screenshots, the boosts overlays
* themselves, and other native-anonymous UI such as scrollbars). A null frame
* gives no document to anchor the boost on, so it is treated the same way.
* Author-facing content that happens to be native-anonymous is not exempt:
* UA-widget form-control internals (including the text the user types into an
* input), and pseudo-elements such as ::before/::after/::marker/::placeholder.
*/
ZEN_HOT_FUNCTION
inline static void GetZenBoostsDataFromBrowsingContext(
ZenBoostData* aData, float* aComplementaryRotation, bool* aIsInverted,
nsPresContext* aPresContext = nullptr) {
auto zenBoosts = nsZenBoostsBackend::GetInstance();
if (!zenBoosts || (zenBoosts->mCurrentFrameIsAnonymousContent &&
!SHOULD_APPLY_BOOSTS_TO_ANONYMOUS_CONTENT())) {
inline static bool IsBoostExemptFrame(const nsIFrame* aFrame) {
if (!aFrame) {
return true;
}
const nsIContent* content = aFrame->GetContent();
if (!content || !content->IsInNativeAnonymousSubtree()) {
return false;
}
// Form-control internals (and media controls) live in UA-widget shadow
// trees; the text typed into an input is author content and should be
// boosted. Classic native-anonymous UI (scrollbars, devtools) has no
// containing shadow and falls through to the pseudo-element check below.
if (content->GetContainingShadow()) {
return false;
}
const nsIContent* root = content->GetClosestNativeAnonymousSubtreeRoot();
return !root || !root->IsElement() ||
!mozilla::PseudoStyle::IsPseudoElement(
root->AsElement()->GetPseudoElementType());
}
/**
* @brief Retrieves the boost data for the document the given frame belongs to.
* Resolves from the frame's PresContext -> Document -> top BrowsingContext,
* which carries the accent/inversion fields.
*/
ZEN_HOT_FUNCTION
inline static void GetZenBoostsDataForFrame(const nsIFrame* aFrame,
ZenBoostData* aData,
float* aComplementaryRotation,
bool* aIsInverted) {
nsPresContext* presContext = aFrame->PresContext();
if (!presContext) {
return;
}
if (!aPresContext) {
*aData = zenBoosts->mCachedCurrentAccent;
*aComplementaryRotation = zenBoosts->mCachedCurrentComplementaryRotation;
*aIsInverted = zenBoosts->mCachedCurrentInverted;
// SVG images render in their own document with no BrowsingContext; the host
// propagates its boost onto the image document's PresContext instead.
if (presContext->HasZenBoostsOverride()) {
*aData = presContext->ZenBoostsOverrideAccent();
*aComplementaryRotation =
presContext->ZenBoostsOverrideComplementaryRotation();
*aIsInverted = presContext->ZenBoostsOverrideInverted();
return;
}
mozilla::dom::BrowsingContext* browsingContext = nullptr;
if (auto document = aPresContext->Document()) {
const mozilla::dom::BrowsingContext* browsingContext = nullptr;
if (auto document = presContext->Document()) {
browsingContext = document->GetBrowsingContext();
}
if (!browsingContext) {
@@ -347,6 +450,32 @@ inline static void GetZenBoostsDataFromBrowsingContext(
} // namespace
namespace detail {
// Thin forwarders that give unit tests access to the pure color math without
// pulling in the singleton / BrowsingContext. They are defined here, after the
// anonymous namespace, so they can reach those file-local implementations.
nsZenAccentOklab PrecomputeAccent(nscolor aAccentColor) {
return zenPrecomputeAccent(aAccentColor);
}
nsZenAccentOklab RotateAccent(const nsZenAccentOklab& aBase,
float aRotationDeg) {
return zenRotateAccent(aBase, aRotationDeg);
}
nscolor FilterColorChannel(nscolor aOriginalColor,
const nsZenAccentOklab& aAccent,
const nsZenAccentOklab& aComplementary) {
return zenFilterColorChannel(aOriginalColor, aAccent, aComplementary);
}
nscolor InvertColorChannel(nscolor aColor) {
return zenInvertColorChannel(aColor);
}
} // namespace detail
static mozilla::StaticRefPtr<nsZenBoostsBackend> sZenBoostsBackend;
auto nsZenBoostsBackend::GetInstance() -> nsZenBoostsBackend* {
@@ -362,68 +491,34 @@ auto nsZenBoostsBackend::GetInstance() -> nsZenBoostsBackend* {
return sZenBoostsBackend.get();
}
auto nsZenBoostsBackend::onPresShellEntered(mozilla::dom::Document* aDocument)
-> void {
if (auto displayDoc = aDocument->GetDisplayDocument()) {
onPresShellEntered(displayDoc);
return;
[[nodiscard]] ZEN_HOT_FUNCTION auto nsZenBoostsBackend::ResolveStyleColor(
nscolor aColor, const nsIFrame* aFrame) -> nscolor {
if (NS_GET_A(aColor) == 0) {
// Skip processing fully transparent colors since they won't be visible and
// we want to avoid unnecessary computations. This also prevents issues with
// using the alpha channel for contrast information in the accent color.
return aColor;
}
// Note that aDocument can be null when entering anonymous content frames.
// We explicitly do this to prevent applying boosts to anonymous content, such
// as devtools or screenshots.
mozilla::dom::BrowsingContext* browsingContext =
aDocument ? aDocument->GetBrowsingContext() : nullptr;
if (!browsingContext) {
return;
// Boosts are only supported in content; GetInstance() is null in the parent
// process, which keeps the browser chrome from being tinted.
if (!GetInstance() || IsBoostExemptFrame(aFrame)) {
return aColor;
}
mCurrentBrowsingContext = browsingContext;
RefreshCachedBoostState();
}
auto nsZenBoostsBackend::RefreshCachedBoostState() -> void {
if (!mCurrentBrowsingContext) {
mCachedCurrentAccent = 0;
mCachedCurrentComplementaryRotation = 0.0f;
mCachedCurrentInverted = false;
return;
}
auto top = mCurrentBrowsingContext->Top();
mCachedCurrentAccent = top->ZenBoostsData();
mCachedCurrentComplementaryRotation = top->ZenBoostsComplementaryRotation();
mCachedCurrentInverted = top->IsZenBoostsInverted();
}
[[nodiscard]] ZEN_HOT_FUNCTION auto
nsZenBoostsBackend::FilterColorFromPresContext(nscolor aColor,
nsPresContext* aPresContext)
-> nscolor {
ZenBoostData accentNS = 0;
float complementaryRotation = 0.0f;
bool invertColors = false;
GetZenBoostsDataFromBrowsingContext(&accentNS, &complementaryRotation,
&invertColors, aPresContext);
GetZenBoostsDataForFrame(aFrame, &accentNS, &complementaryRotation,
&invertColors);
if (accentNS) {
if (mCachedAccent.accentNS != accentNS) {
mCachedAccent = zenPrecomputeAccent(accentNS);
// Trigger a recompute of the complementary accent since
// it depends on the base accent.
mCachedComplementary.accentNS = 0;
}
// Derive the complementary accent by rotating the base accent's hue by the
// boost's complementary rotation. Cached so the per-color hot path only
// recomputes it when the base accent or rotation changes.
if (mCachedComplementary.accentNS != accentNS ||
mCachedComplementaryRotationDeg != complementaryRotation) {
mCachedComplementary =
zenRotateAccent(mCachedAccent, complementaryRotation);
mCachedComplementaryRotationDeg = complementaryRotation;
}
// Apply a filter-like tint:
// Resolve (and cache) the base + complementary accent for this accent and
// complementary rotation. Apply a filter-like tint:
// - Preserve the original color's perceived luminance
// - Map hue/chroma toward the base or complementary accent depending on
// the original color's lightness
// - Keep the original alpha
aColor = zenFilterColorChannel(aColor, mCachedAccent, mCachedComplementary);
const AccentCacheEntry& cached =
GetCachedAccent(accentNS, complementaryRotation);
aColor = zenFilterColorChannel(aColor, cached.accent, cached.complementary);
}
if (invertColors) {
aColor = zenInvertColorChannel(aColor);
@@ -431,21 +526,4 @@ nsZenBoostsBackend::FilterColorFromPresContext(nscolor aColor,
return aColor;
}
[[nodiscard]] ZEN_HOT_FUNCTION auto nsZenBoostsBackend::ResolveStyleColor(
mozilla::StyleAbsoluteColor aColor) -> mozilla::StyleAbsoluteColor {
const auto resultColor = FilterColorFromPresContext(aColor.ToColor());
return mozilla::StyleAbsoluteColor::FromColor(resultColor);
}
[[nodiscard]] ZEN_HOT_FUNCTION auto nsZenBoostsBackend::ResolveStyleColor(
nscolor aColor) -> nscolor {
if (NS_GET_A(aColor) == 0) {
// Skip processing fully transparent colors since they won't be visible and
// we want to avoid unnecessary computations. This also prevents issues with
// using the alpha channel for contrast information in the accent color.
return aColor;
}
return FilterColorFromPresContext(aColor);
}
} // namespace zen

View File

@@ -9,7 +9,11 @@
#include "nsISupportsImpl.h"
#include "nsPresContext.h"
#include "mozilla/RefPtr.h"
class nsIFrame;
namespace mozilla::dom {
class BrowsingContext;
}
#define ZEN_BOOSTS_BACKEND_CONTRACTID "@mozilla.org/zen/boosts-backend;1"
@@ -23,6 +27,19 @@ struct nsZenAccentOklab {
float contrastFactor;
};
namespace detail {
// Pure color-math primitives, exposed for unit testing. These have no
// dependency on the singleton, the BrowsingContext, or the process type, so
// they can be exercised directly from gtest.
nsZenAccentOklab PrecomputeAccent(nscolor aAccentColor);
nsZenAccentOklab RotateAccent(const nsZenAccentOklab& aBase,
float aRotationDeg);
nscolor FilterColorChannel(nscolor aOriginalColor,
const nsZenAccentOklab& aAccent,
const nsZenAccentOklab& aComplementary);
nscolor InvertColorChannel(nscolor aColor);
} // namespace detail
class nsZenBoostsBackend final : public nsISupports {
public:
NS_DECL_ISUPPORTS
@@ -30,81 +47,28 @@ class nsZenBoostsBackend final : public nsISupports {
explicit nsZenBoostsBackend() = default;
/**
* Indicates whether the current frame being rendered is for anonymous
* content.
*/
bool mCurrentFrameIsAnonymousContent = false;
/**
* @brief Resolve a StyleAbsoluteColor to take into account Zen boosts.
* @brief Resolve a color to take into account Zen boosts. This is the single
* place style colors are filtered; it is reached for every style color via
* StyleAbsoluteColor::ToColor. Do not add a second StyleColor::ResolveColor
* filter on top of this or colors get filtered multiple times (which also
* makes resting colors disagree with composited transition endpoints).
*
* The boost state is derived from the frame the color is being resolved for:
* its document's top BrowsingContext carries the accent/inversion data. When
* @p aFrame is null, or belongs to anonymous content (devtools, screenshots,
* the boosts overlays themselves), the color is returned unfiltered.
* @param aColor The color to resolve.
* @param aFrame The frame the color is being resolved for, or null.
* @return The resolved color with Zen boost filters applied, or the original
* color if no boost is active.
* @see StyleColor::ResolveColor for reference.
* @see StyleAbsoluteColor::ToColor for reference.
*/
static auto ResolveStyleColor(mozilla::StyleAbsoluteColor aColor)
-> mozilla::StyleAbsoluteColor;
/**
* @see ResolveStyleColor for reference.
*/
static auto ResolveStyleColor(nscolor aColor) -> nscolor;
/**
* @brief Filter a color based on the current Zen boost settings.
* @param aColor The color to filter.
* @param aPresContext The presentation context to use for filtering.
* @return The filtered color.
*/
static auto FilterColorFromPresContext(nscolor aColor,
nsPresContext* aPresContext = nullptr)
static auto ResolveStyleColor(nscolor aColor, const nsIFrame* aFrame)
-> nscolor;
/**
* @brief Called when a presshell is entered during rendering.
* @param aDocument The document associated with the presshell being entered.
*/
auto onPresShellEntered(mozilla::dom::Document* aDocument) -> void;
/**
* @brief Refresh the cached boost state from the current top BrowsingContext.
* Called from onPresShellEntered and from BrowsingContext::DidSet hooks when
* the underlying boost fields change.
*/
auto RefreshCachedBoostState() -> void;
[[nodiscard]]
inline auto GetCurrentBrowsingContext() const {
return mCurrentBrowsingContext;
}
/**
* Cached boost data for the current top BrowsingContext, refreshed on
* presshell entry and on DidSet hooks. Read by the per-color hot path so
* that boost-off pages don't pay for a BrowsingContext walk on every color
* resolve.
*/
ZenBoostData mCachedCurrentAccent = 0;
// Hue rotation in degrees applied to the base accent to derive the
// complementary accent. Zero means the complementary accent equals the base
// accent (the duotone collapses to a single-accent tint).
float mCachedCurrentComplementaryRotation = 0.0f;
bool mCachedCurrentInverted = false;
private:
~nsZenBoostsBackend() = default;
/**
* The presshell of the current document being rendered.
*/
RefPtr<mozilla::dom::BrowsingContext> mCurrentBrowsingContext;
static nsZenAccentOklab mCachedAccent;
// Base accent with its Oklab hue rotated by mCachedComplementaryRotationDeg,
// recomputed only when the base accent or rotation changes.
static nsZenAccentOklab mCachedComplementary;
static float mCachedComplementaryRotationDeg;
public:
/**
* @brief Get the singleton instance of the ZenBoostsBackend.

View File

@@ -132,18 +132,18 @@
<html:input id="zen-boost-color-saturation" type="range" min="0" max="1" value="0.5" step="0.01"/>
</vbox>
</panel>
</popupset>
<menupopup id="zenBoostContextMenu">
<menuitem data-l10n-id="zen-boost-edit-rename" id="zen-boost-edit-rename" command="cmd_zenBoostEditName" />
<menuitem data-l10n-id="zen-boost-edit-shuffle" id="zen-boost-edit-shuffle" command="cmd_zenBoostShuffle" />
<menuitem data-l10n-id="zen-boost-edit-reset" id="zen-boost-edit-reset" command="cmd_zenBoostReset" />
<menuseparator/>
<menuitem data-l10n-id="zen-boost-load" id="zen-boost-load" command="cmd_zenBoostLoad" />
<menuitem data-l10n-id="zen-boost-save" id="zen-boost-save" command="cmd_zenBoostSave" />
<menuseparator/>
<menuitem data-l10n-id="zen-boost-edit-delete" id="zen-boost-edit-delete" command="cmd_zenBoostDelete" />
</menupopup>
<menupopup id="zenBoostContextMenu">
<menuitem data-l10n-id="zen-boost-edit-rename" id="zen-boost-edit-rename" command="cmd_zenBoostEditName" />
<menuitem data-l10n-id="zen-boost-edit-shuffle" id="zen-boost-edit-shuffle" command="cmd_zenBoostShuffle" />
<menuitem data-l10n-id="zen-boost-edit-reset" id="zen-boost-edit-reset" command="cmd_zenBoostReset" />
<menuseparator/>
<menuitem data-l10n-id="zen-boost-load" id="zen-boost-load" command="cmd_zenBoostLoad" />
<menuitem data-l10n-id="zen-boost-save" id="zen-boost-save" command="cmd_zenBoostSave" />
<menuseparator/>
<menuitem data-l10n-id="zen-boost-edit-delete" id="zen-boost-edit-delete" command="cmd_zenBoostDelete" />
</menupopup>
</popupset>
<commandset id="zenBoostCommandSet">
<command id="cmd_zenBoostEditName"

View File

@@ -11,6 +11,19 @@
}
appearance: none;
border: none;
min-height: 582px;
max-height: 582px;
}
#zenBoostWindow[editor="boost"] {
min-width: 184px;
max-width: 184px;
}
#zenBoostWindow[editor="code"] {
min-width: 452px;
max-width: 452px;
}
.source-editor-frame {
@@ -106,9 +119,6 @@ body {
& button {
border-radius: 6px;
@media (-moz-platform: macos) {
border-radius: 10px;
}
padding: 0 !important;
min-width: fit-content !important;
@@ -229,9 +239,9 @@ body {
}
#zen-boost-filter-wrapper {
padding: 20px;
padding: 16px;
gap: 14px;
padding-top: 10px;
padding-top: 6px;
background-color: #fcfcfe;
@@ -543,6 +553,7 @@ body {
height: 26px;
width: 26px;
transform-origin: center center;
aspect-ratio: 1;
&:hover {
background-color: #9a9a9a30;

View File

@@ -1358,6 +1358,7 @@ window.gZenVerticalTabsManager = {
if (!this._hasSetSingleToolbar) {
buttonsTarget.append(this._topButtonsSeparatorElement);
}
this._hasSetSingleToolbar = true;
for (const button of elements) {
this.appendCustomizableItem(this._topButtonsSeparatorElement, button);
}
@@ -1381,7 +1382,6 @@ window.gZenVerticalTabsManager = {
titlebar.parentNode.moveBefore(navBar, titlebar);
}
document.documentElement.setAttribute("zen-single-toolbar", true);
this._hasSetSingleToolbar = true;
} else if (this._hasSetSingleToolbar) {
this._hasSetSingleToolbar = false;
// Do the opposite
@@ -1510,7 +1510,7 @@ window.gZenVerticalTabsManager = {
this.navigatorToolbox.after(splitter);
window.dispatchEvent(new Event("resize"));
if (!isCompactMode) {
gZenCompactModeManager.getAndApplySidebarWidth();
gZenCompactModeManager.getAndApplySidebarWidth({});
}
gZenUIManager.updateTabsToolbar();
this.rebuildURLBarMenus();

View File

@@ -8,7 +8,6 @@
@import url("chrome://browser/content/zen-styles/zen-panels/dialog.css");
:root {
--panel-subview-body-padding: 2px 0;
--arrowpanel-menuitem-border-radius: 5px;
--arrowpanel-menuitem-margin: var(--uc-arrowpanel-menuitem-margin-block) var(--uc-arrowpanel-menuitem-margin-inline);
--arrowpanel-menuitem-padding-block: 8px;
@@ -68,8 +67,7 @@ panel {
}
.widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text,
.subviewbutton:not(#appMenu-zoom-controls > .subviewbutton) > .toolbarbutton-icon + .toolbarbutton-text,
#appMenu-fxa-label2 > vbox {
.subviewbutton:not(#appMenu-zoom-controls > .subviewbutton) > .toolbarbutton-icon + .toolbarbutton-text {
padding-inline-start: var(--uc-arrowpanel-menuicon-margin-inline);
}
@@ -88,17 +86,6 @@ panel {
white-space: nowrap;
}
/* Firefox profile avatar in appmenu */
#appMenu-fxa-label2::before {
content: "";
display: -moz-box;
height: var(--size-item-small);
width: var(--size-item-small);
background: var(--avatar-image-url) 0/16px;
scale: 1.25;
border-radius: 99px;
}
/* disable proton account separator */
#appMenu-fxa-separator {
border-image: none;
@@ -108,10 +95,6 @@ panel {
padding-block: 0;
}
#appMenu-fxa-status2:not([fxastatus]) > #appMenu-fxa-label2 {
margin-inline-end: calc(var(--arrowpanel-menuitem-padding-inline) * -1);
}
/* zoom controls */
#appMenu-zoom-controls {
border-top: 1px solid var(--panel-separator-color);

View File

@@ -167,7 +167,7 @@
--toolbarbutton-hover-background: var(--zen-toolbar-element-bg-hover) !important;
--zen-toolbar-button-size: 16px;
@media (-moz-platform: macos) {
--zen-toolbar-button-size: 18px;
--zen-toolbar-button-size: 17px;
}
/* Using a semitransparent background preserves the tinting from the backdrop.

View File

@@ -67,8 +67,9 @@ if (!Services.appinfo.inSafeMode) {
child: {
esModuleURI: "resource:///actors/ZenBoostsChild.sys.mjs",
events: {
// Needed to let the actor be created, please don't remove
// without checking if boosts still work without it, thanks <3
DOMWindowCreated: {},
unload: {},
},
},
allFrames: true,

View File

@@ -169,7 +169,15 @@
} else {
document.documentElement.removeAttribute("zen-no-padding");
if (domFullscreen) {
window.windowUtils.flushLayoutWithoutThrottledAnimations();
const selectedBrowser = gBrowser.selectedBrowser;
selectedBrowser.style.paddingRight = "0.5px";
window.addEventListener(
"MozAfterPaint",
() => {
selectedBrowser.style.paddingRight = "";
},
{ once: true }
);
}
}
},

View File

@@ -724,6 +724,7 @@ window.gZenCompactModeManager = {
} else {
if (attr === "zen-has-hover") {
element.removeAttribute("zen-has-implicit-hover");
gURLBar.updateTextOverflow();
}
element.removeAttribute(attr);
// Only remove if none of the verified attributes are present

View File

@@ -725,7 +725,7 @@
.changeWorkspaceShortcut(
isNearLeftEdge ? -1 : 1,
false,
/* Disable wrapping */ true
/* Disable wrapping */ false
)
.then(spaceChanged => {
this.#onSpaceChanged(spaceChanged, dt);

View File

@@ -1566,7 +1566,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const tabsContainer = group.groupContainer;
tabsContainer.removeAttribute("hidden");
tabsContainer.style.overflow = "hidden";
tabsContainer.style.overflowY = "hidden";
const groupStart = group.groupStartElement;
const itemsToShow = this.#normalizeGroupItems(group.childGroupsAndTabs);
@@ -1615,7 +1615,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
const afterMarginTop = () => {
tabsContainer.style.overflow = "";
tabsContainer.style.overflowY = "";
if (group.hasAttribute("has-active")) {
const activeTabs = group.activeTabs;
const folders = new Map();
@@ -1859,14 +1859,14 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const tabsContainer = currentGroup.groupContainer;
const groupStart = currentGroup.groupStartElement;
tabsContainer.style.overflow = "clip";
tabsContainer.style.overflowY = "clip";
if (tabsContainer.hasAttribute("hidden")) {
tabsContainer.removeAttribute("hidden");
}
const afterMarginTop = () => {
tabsContainer.style.overflow = "";
tabsContainer.style.overflowY = "";
};
animations.push(
@@ -1972,7 +1972,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const heightContainer = expand
? 0
: this.#calculateHeightShift(tabsContainer, []);
tabsContainer.style.overflow = "clip";
tabsContainer.style.overflowY = "clip";
this.#createAnimation(
groupStart,

View File

@@ -35,7 +35,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
// Arc animation configuration
#ARC_CONFIG = Object.freeze({
ARC_STEPS: 80, // Browser interpolates between keyframes natively
MAX_ARC_HEIGHT: 25,
MAX_ARC_HEIGHT: 20,
ARC_HEIGHT_RATIO: 0.2, // Arc height = distance * ratio (capped at MAX_ARC_HEIGHT)
});

View File

@@ -32,7 +32,6 @@ const KEYCODE_MAP = {
TAB: "VK_TAB",
ENTER: "VK_RETURN",
ESCAPE: "VK_ESCAPE",
SPACE: "VK_SPACE",
ARROWLEFT: "VK_LEFT",
ARROWRIGHT: "VK_RIGHT",
ARROWUP: "VK_UP",
@@ -44,6 +43,10 @@ const KEYCODE_MAP = {
SCROLL_LOCK: "VK_SCROLL",
};
const REVERSE_KEYCODE_MAP = Object.fromEntries(
Object.entries(KEYCODE_MAP).map(([k, v]) => [v, k])
);
const defaultKeyboardGroups = {
windowAndTabManagement: [
"zen-window-new-shortcut",
@@ -430,11 +433,14 @@ class KeyShortcut {
if (this.#keycode) {
key.setAttribute("keycode", this.#keycode);
key.removeAttribute("key");
} else {
} else if (this.#key) {
// note to "mr. macos": Better use setAttribute, because without it, there's a
// risk of malforming the XUL element.
key.setAttribute("key", this.#key);
key.removeAttribute("keycode");
} else {
key.removeAttribute("key");
key.removeAttribute("keycode");
}
key.setAttribute("group", this.#group);
@@ -553,16 +559,21 @@ class KeyShortcut {
};
}
toDisplayString() {
let str = this.#modifiers.toDisplayString();
if (this.#key) {
str += this.#key.toUpperCase();
} else if (this.#keycode) {
static keyToDisplayString(key, keycode) {
let str = "";
if (key) {
switch (key) {
case " ":
str += AppConstants.platform == "macosx" ? "␣" : "Space";
break;
default:
str += key.toUpperCase();
}
} else if (keycode) {
// Get the key from the value
for (let [key, value] of Object.entries(KEYCODE_MAP)) {
if (value == this.#keycode) {
const normalizedKey = key.toLowerCase();
for (let [k, value] of Object.entries(KEYCODE_MAP)) {
if (value == keycode) {
const normalizedKey = k.toLowerCase();
switch (normalizedKey) {
case "arrowleft":
str += "←";
@@ -582,18 +593,23 @@ class KeyShortcut {
case "enter":
str += AppConstants.platform == "macosx" ? "↩" : "Enter";
break;
case "space":
str += AppConstants.platform == "macosx" ? "␣" : "Space";
break;
default:
str += normalizedKey;
}
break;
}
}
} else {
}
return str;
}
toDisplayString() {
if (!this.#key && !this.#keycode) {
return "";
}
let str = this.#modifiers.toDisplayString();
str += KeyShortcut.keyToDisplayString(this.#key, this.#keycode);
return str;
}
@@ -832,7 +848,7 @@ class nsZenKeyboardShortcutsLoader {
}
class nsZenKeyboardShortcutsVersioner {
static LATEST_KBS_VERSION = 18;
static LATEST_KBS_VERSION = 19;
constructor() {}
@@ -1228,6 +1244,18 @@ class nsZenKeyboardShortcutsVersioner {
);
}
if (version < 19) {
// Migrate from version 18 to 19.
// Disable "key_duplicateTab" since we already had "cmd_zenDuplicateTab" before Firefox 151.
for (let shortcut of data) {
if (shortcut.getID() == "key_duplicateTab") {
shortcut.shouldBeEmpty = true;
shortcut.setDisabled(true);
break;
}
}
}
return data;
}
}
@@ -1500,9 +1528,11 @@ window.gZenKeyboardShortcutsManager = {
continue;
}
const keyNameOrCode = targetShortcut.getKeyNameOrCode();
const key = REVERSE_KEYCODE_MAP[keyNameOrCode] ?? keyNameOrCode;
if (
targetShortcut.getModifiers().equals(modifiers) &&
targetShortcut.getKeyNameOrCode()?.toLowerCase() == realShortcut
key?.toLowerCase() == realShortcut
) {
return {
hasConflicts: true,
@@ -1541,4 +1571,22 @@ window.gZenKeyboardShortcutsManager = {
}
return null;
},
getKeyDisplay(shortcut) {
if (shortcut == "") {
return "";
}
let key = shortcut;
let keycode = "";
for (let kc of Object.keys(KEYCODE_MAP)) {
if (kc == shortcut.toUpperCase()) {
keycode = KEYCODE_MAP[kc];
key = "";
break;
}
}
return KeyShortcut.keyToDisplayString(key, keycode);
},
};

View File

@@ -1534,7 +1534,14 @@ class nsZenWindowSync {
window.removeEventListener(eventName, this);
}
delete window.gZenWindowSync;
this.#moveAllActiveTabsToOtherWindowsForClose(window);
const { promise, resolve } = Promise.withResolvers();
this.#docShellSwitchPromise = promise;
try {
this.#moveAllActiveTabsToOtherWindowsForClose(window);
} catch (e) {
console.error(`Error moving active tabs to other windows on close:`, e);
}
resolve();
}
on_WindowCloseAndBrowserFlushed(aBrowsers) {
@@ -1657,7 +1664,9 @@ class nsZenWindowSync {
this.#runOnAllWindows(window, win => {
const targetTab = this.getItemFromWindow(win, tab.id);
if (targetTab && win.gZenViewSplitter) {
win.gZenViewSplitter.removeTabFromGroup(targetTab);
win.gZenViewSplitter.removeTabFromGroup(targetTab, undefined, {
changeTab: false,
});
}
});
}

View File

@@ -219,7 +219,7 @@ class nsZenWorkspaceCreation extends MozXULElement {
document.getElementById("nav-bar").style.visibility = "collapse";
}
this.style.visibility = "visible";
gZenCompactModeManager.getAndApplySidebarWidth();
gZenCompactModeManager.getAndApplySidebarWidth({});
this.resolveInitialized();
let animation = gZenUIManager.motion.animate(
this.elementsToAnimate,
@@ -261,6 +261,7 @@ class nsZenWorkspaceCreation extends MozXULElement {
}
async onCancelButtonCommand() {
document.documentElement.removeAttribute("zen-creating-workspace");
await gZenWorkspaces.changeWorkspaceWithID(this.previousWorkspaceId);
}

View File

@@ -926,11 +926,7 @@ class nsZenWorkspaces {
if (gZenUIManager.testingEnabled || !this.workspaceEnabled) {
return;
}
// note: We cant access `gZenVerticalTabsManager._canReplaceNewTab` this early
if (
isEmpty &&
Services.prefs.getBoolPref("zen.urlbar.replace-newtab", true)
) {
if (isEmpty) {
tab._markedForReplacement = true;
this._tabToRemoveForEmpty = tab;
} else {
@@ -1741,13 +1737,26 @@ class nsZenWorkspaces {
const otherContainersEssentials = document.querySelectorAll(
`#zen-essentials .zen-workspace-tabs-section`
);
let nextSpaceIdx;
const spaceLen = workspaces.length;
if (offsetPixels > 0) {
nextSpaceIdx = (workspaceIndex - 1 + spaceLen) % spaceLen;
} else if (offsetPixels < 0) {
nextSpaceIdx = (workspaceIndex + 1) % spaceLen;
} else {
nextSpaceIdx = workspaceIndex;
}
const workspaceContextId = workspace.containerTabId;
const nextWorkspaceContextId =
workspaces[workspaceIndex + (offsetPixels > 0 ? -1 : 1)]?.containerTabId;
const nextWorkspaceContextId = workspaces[nextSpaceIdx]?.containerTabId;
for (const otherWorkspace of workspaces) {
const element = this.workspaceElement(otherWorkspace.uuid);
const newTransform =
-(workspaceIndex - workspaces.indexOf(otherWorkspace)) * 100;
let diff = workspaces.indexOf(otherWorkspace) - workspaceIndex;
if (diff > Math.floor(spaceLen / 2)) {
diff -= spaceLen;
} else if (diff < -Math.floor(spaceLen / 2)) {
diff += spaceLen;
}
const newTransform = diff * 100;
element.style.transform = `translateX(${newTransform + offsetPixels / 2}%)`;
}
// Hide other essentials with different containerTabId
@@ -1781,8 +1790,7 @@ class nsZenWorkspaces {
}
if (offsetPixels) {
// Find the next workspace we are scrolling to
const nextWorkspace =
workspaces[workspaceIndex + (offsetPixels > 0 ? -1 : 1)];
const nextWorkspace = workspaces[nextSpaceIdx];
if (nextWorkspace) {
const {
gradient: nextGradient,
@@ -1892,10 +1900,17 @@ class nsZenWorkspaces {
this._animatingChange = true;
const animations = [];
const workspaces = this.getWorkspaces();
const spaceLen = workspaces.length;
const newWorkspaceIndex = workspaces.findIndex(
w => w.uuid === newWorkspace.uuid
);
const isGoingLeft = newWorkspaceIndex <= previousWorkspaceIndex;
let diff = newWorkspaceIndex - previousWorkspaceIndex;
if (diff > Math.floor(spaceLen / 2)) {
diff -= spaceLen;
} else if (diff < -Math.floor(spaceLen / 2)) {
diff += spaceLen;
}
const isGoingLeft = diff < 0;
const clonedEssentials = [];
if (shouldAnimate && this.shouldAnimateEssentials && previousWorkspace) {
for (const workspace of workspaces) {
@@ -1974,19 +1989,23 @@ class nsZenWorkspaces {
const elementWorkspaceIndex = workspaces.findIndex(
w => w.uuid === elementWorkspaceId
);
const offset = -(newWorkspaceIndex - elementWorkspaceIndex) * 100;
let offset = elementWorkspaceIndex - newWorkspaceIndex;
if (offset > Math.floor(spaceLen / 2)) {
offset -= spaceLen;
} else if (offset < -Math.floor(spaceLen / 2)) {
offset += spaceLen;
}
offset = offset * 100;
const newTransform = `translateX(${offset}%)`;
// Only animate the workspace that is coming in, to avoid having multiple workspaces
// animating off-screen at the same time which can cause performance issues. With an off
// set of 1 or -1, so we animate the current workspace and the next one.
const goingLeft = newWorkspaceIndex < previousWorkspaceIndex;
const willBeVisible =
(goingLeft &&
elementWorkspaceIndex >= newWorkspaceIndex &&
elementWorkspaceIndex <= previousWorkspaceIndex) ||
(!goingLeft &&
elementWorkspaceIndex <= newWorkspaceIndex &&
elementWorkspaceIndex >= previousWorkspaceIndex);
const totalDistance = Math.abs(diff);
const distanceToElement = isGoingLeft
? (previousWorkspaceIndex - elementWorkspaceIndex + spaceLen) % spaceLen
: (elementWorkspaceIndex - previousWorkspaceIndex + spaceLen) %
spaceLen;
const willBeVisible = distanceToElement <= totalDistance;
if (shouldAnimate) {
if (!willBeVisible) {
element.style.transform = newTransform;

View File

@@ -314,6 +314,8 @@
/* mark: workspace element */
zen-workspace {
--toolbar-color: var(--toolbox-textcolor) !important;
flex-direction: column;
width: calc(100% + var(--zen-toolbox-padding) * 2);
position: absolute;

View File

@@ -2294,7 +2294,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
// Unsplit the tab and exit from the drag view
this.dropZone?.removeAttribute("enabled");
this.disableTabRearrangeView(event);
this.removeTabFromSplit(browserContainer);
this.removeTabFromSplit(event, browserContainer);
return true;
}
return false;

View File

@@ -702,6 +702,10 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
return tab;
});
if (!fromDifferentWindow) {
// See gh-13796 and gh-12156
ownedTabs = ownedTabs.reverse();
}
movingTabs = [...ownedTabs];
if (fromDifferentWindow) {
gBrowser.addRangeToMultiSelectedTabs(

View File

@@ -8,5 +8,6 @@ support-files = [
]
["browser_boost_selector_basic.js"]
["browser_boost_selector_escaping.js"]
["browser_boost_selector_invalid.js"]
["browser_boost_selector_nthchild.js"]

View File

@@ -0,0 +1,94 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Covers code paths the basic/invalid/nthchild tests don't:
// - getIdentification() running ids/classes through CSS.escape()
// - the ancestor-disambiguation while-loop in traverse(), which only runs
// when the exact path still matches more than one element.
add_task(async function test_getSelectionPath_escapesSpecialChars() {
const doc = document.implementation.createHTMLDocument("TestEscape");
const container = doc.createElement("div");
// Characters that are invalid in a CSS selector unless escaped.
container.id = "with.dot:and#hash";
const target = doc.createElement("span");
target.className = "foo:bar baz.qux";
target.textContent = "target";
container.appendChild(target);
doc.body.appendChild(container);
const component = new SelectorComponent(doc, null, [], () => {});
const path = component.getSelectionPath(doc, 0, target);
ok(path, "A path should be generated for an element with special chars");
// The unescaped raw strings must not leak into the selector verbatim.
ok(
!path.includes("with.dot:and#hash"),
"Raw unescaped id must not appear in the selector"
);
// The generated selector must be valid and resolve back to the target.
let matched;
try {
matched = doc.querySelectorAll(path);
} catch (e) {
ok(false, `Generated selector should be parseable, got: ${e}`);
return;
}
ok(
Array.from(matched).includes(target),
"Escaped selector must still match the original element"
);
Assert.equal(
matched.length,
1,
"Selector should uniquely identify the element"
);
});
add_task(async function test_getSelectionPath_disambiguatesAncestors() {
const doc = document.implementation.createHTMLDocument("TestAncestors");
// Two structurally identical subtrees. The leaf elements carry no id/class,
// so disambiguation must climb ancestors until the path is unique. The two
// wrappers differ only by id, forcing the ancestor-walk loop in traverse().
const makeBranch = wrapperId => {
const wrapper = doc.createElement("section");
wrapper.id = wrapperId;
const mid = doc.createElement("div");
const leaf = doc.createElement("span");
leaf.textContent = "leaf";
mid.appendChild(leaf);
wrapper.appendChild(mid);
doc.body.appendChild(wrapper);
return leaf;
};
const leafA = makeBranch("branch-a");
const leafB = makeBranch("branch-b");
const component = new SelectorComponent(doc, null, [], () => {});
for (const [leaf, label] of [
[leafA, "branch-a"],
[leafB, "branch-b"],
]) {
const path = component.getSelectionPath(doc, 0, leaf);
ok(path, `Path generated for the leaf under ${label}`);
const matched = doc.querySelectorAll(path);
Assert.equal(
matched.length,
1,
`Selector for the ${label} leaf must be unique despite an identical sibling subtree`
);
ok(
matched[0] === leaf,
`Selector must resolve to the correct ${label} leaf, not the other branch`
);
}
});

View File

@@ -81,6 +81,49 @@ const globalActionsTemplate = [
return !tab.hasAttribute("zen-empty-tab") && tab.pinned;
},
},
{
label: "New Boost",
icon: "chrome://browser/skin/zen-icons/boost.svg",
isAvailable: window => {
if (!isNotEmptyTab(window)) {
return false;
}
// Keep this action consistent with the rest of the Boosts UI.
if (!Services.prefs.getBoolPref("zen.boosts.enabled", false)) {
return false;
}
const uri = window.gBrowser.currentURI;
return !!uri?.schemeIs && (uri.schemeIs("http") || uri.schemeIs("https"));
},
command: window => {
const uri = window.gBrowser.currentURI;
if (!uri?.schemeIs || !(uri.schemeIs("http") || uri.schemeIs("https"))) {
return;
}
let domain = "";
try {
domain = uri.host;
} catch {
return;
}
if (!domain) {
return;
}
const { gZenBoostsManager } = ChromeUtils.importESModule(
"resource:///modules/zen/boosts/ZenBoostsManager.sys.mjs"
);
const boost = gZenBoostsManager.createNewBoost(domain);
if (!boost) {
return;
}
gZenBoostsManager.openBoostWindow(window, boost, uri);
},
},
{
label: "Next Space",
command: "cmd_zenWorkspaceForward",