mirror of
https://github.com/zen-browser/desktop.git
synced 2026-05-20 12:01:27 +00:00
no-bug: Add polish to finished boosts implementation (gh-13762)
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
"surfer": "surfer",
|
||||
"test": "python3 scripts/run_tests.py",
|
||||
"test:dbg": "python3 scripts/run_tests.py --jsdebugger --debug-on-failure",
|
||||
"test:gtest": "cd engine && ./mach gtest",
|
||||
"ffprefs": "cd tools/ffprefs && cargo run --bin ffprefs -- ../../",
|
||||
"lc": "surfer license-check",
|
||||
"lc:fix": "surfer license-check --fix",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
- name: zen.boosts.enabled
|
||||
value: "@IS_TWILIGHT@"
|
||||
value: true
|
||||
|
||||
- name: zen.boosts.dissolve-on-zap
|
||||
value: true
|
||||
|
||||
@@ -924,7 +924,7 @@
|
||||
|
||||
position: relative;
|
||||
|
||||
list-style-image: url("paintbrush.svg");
|
||||
list-style-image: url("boost.svg");
|
||||
|
||||
& .toolbarbutton-text {
|
||||
display: none;
|
||||
@@ -937,6 +937,8 @@
|
||||
& image {
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
width: 14px;
|
||||
fill-opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,7 +1068,7 @@
|
||||
}
|
||||
|
||||
#zen-boost-shuffle {
|
||||
list-style-image: url("arrow-rotate-anticlockwise.svg");
|
||||
list-style-image: url("dice.svg");
|
||||
}
|
||||
|
||||
#zen-boost-css-picker {
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
* 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/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark.svg (../shared/zen-icons/nucleo/bookmark.svg)
|
||||
* skin/classic/browser/zen-icons/boost.svg (../shared/zen-icons/nucleo/boost.svg)
|
||||
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
|
||||
* skin/classic/browser/zen-icons/brackets-curly.svg (../shared/zen-icons/nucleo/brackets-curly.svg)
|
||||
* skin/classic/browser/zen-icons/camera-blocked.svg (../shared/zen-icons/nucleo/camera-blocked.svg)
|
||||
* skin/classic/browser/zen-icons/camera-fill.svg (../shared/zen-icons/nucleo/camera-fill.svg)
|
||||
@@ -37,6 +37,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 +103,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,13 +162,13 @@
|
||||
* 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/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark.svg (../shared/zen-icons/nucleo/bookmark.svg)
|
||||
* skin/classic/browser/zen-icons/boost.svg (../shared/zen-icons/nucleo/boost.svg)
|
||||
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
|
||||
* skin/classic/browser/zen-icons/brackets-curly.svg (../shared/zen-icons/nucleo/brackets-curly.svg)
|
||||
* skin/classic/browser/zen-icons/camera-blocked.svg (../shared/zen-icons/nucleo/camera-blocked.svg)
|
||||
* skin/classic/browser/zen-icons/camera-fill.svg (../shared/zen-icons/nucleo/camera-fill.svg)
|
||||
@@ -185,6 +186,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 +252,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,13 +311,13 @@
|
||||
* 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/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
|
||||
* skin/classic/browser/zen-icons/bookmark.svg (../shared/zen-icons/nucleo/bookmark.svg)
|
||||
* skin/classic/browser/zen-icons/boost.svg (../shared/zen-icons/nucleo/boost.svg)
|
||||
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
|
||||
* skin/classic/browser/zen-icons/brackets-curly.svg (../shared/zen-icons/nucleo/brackets-curly.svg)
|
||||
* skin/classic/browser/zen-icons/camera-blocked.svg (../shared/zen-icons/nucleo/camera-blocked.svg)
|
||||
* skin/classic/browser/zen-icons/camera-fill.svg (../shared/zen-icons/nucleo/camera-fill.svg)
|
||||
@@ -333,6 +335,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 +401,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)
|
||||
@@ -453,8 +456,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)
|
||||
@@ -516,8 +519,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)
|
||||
|
||||
5
src/browser/themes/shared/zen-icons/nucleo/dice.svg
Normal file
5
src/browser/themes/shared/zen-icons/nucleo/dice.svg
Normal 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>
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/gfx/layers/AnimationInfo.cpp b/gfx/layers/AnimationInfo.cpp
|
||||
index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..ef112715580b6bb7238e8f37bbe3133e187685dc 100644
|
||||
index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..38bfbcfcaf0c791ee817aafbd24b1cad67974e62 100644
|
||||
--- a/gfx/layers/AnimationInfo.cpp
|
||||
+++ b/gfx/layers/AnimationInfo.cpp
|
||||
@@ -14,6 +14,7 @@
|
||||
@@ -10,12 +10,22 @@ index 1d330056bd7a4e89aac5e5296a3c164fb42b5c42..ef112715580b6bb7238e8f37bbe3133e
|
||||
#include "nsIContent.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
@@ -343,7 +344,7 @@ static void SetAnimatable(NonCustomCSSPropertyId aProperty,
|
||||
@@ -343,7 +344,17 @@ static void SetAnimatable(NonCustomCSSPropertyId aProperty,
|
||||
// resolve currentColor at this moment.
|
||||
nscolor foreground =
|
||||
aFrame->Style()->GetVisitedDependentColor(&nsStyleText::mColor);
|
||||
- aAnimatable = aAnimationValue.GetColor(foreground);
|
||||
+ aAnimatable = zen::nsZenBoostsBackend::FilterColorFromPresContext(aAnimationValue.GetColor(foreground), aFrame->PresContext());
|
||||
+ nscolor resolved = aAnimationValue.GetColor(foreground);
|
||||
+ // |foreground| is already boost-resolved through
|
||||
+ // StyleAbsoluteColor::ToColor, so a currentColor keyframe is already
|
||||
+ // filtered; only absolute keyframe colors still need the boost applied
|
||||
+ // here, exactly once, so the composited transition endpoint matches the
|
||||
+ // resting/static paint and doesn't snap when the transition ends.
|
||||
+ aAnimatable =
|
||||
+ aAnimationValue.IsCurrentColor()
|
||||
+ ? resolved
|
||||
+ : zen::nsZenBoostsBackend::FilterColorFromPresContext(
|
||||
+ resolved, aFrame->PresContext());
|
||||
break;
|
||||
}
|
||||
case eCSSProperty_opacity:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/layout/style/StyleColor.cpp b/layout/style/StyleColor.cpp
|
||||
index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..8dbfbb846b786d51af288989163aacfae12e787c 100644
|
||||
index 95c7ae6abea5032bef0466e8d59d212374d7a4d0..3b2118e224141f5151a31ac663dfbe17864ef182 100644
|
||||
--- a/layout/style/StyleColor.cpp
|
||||
+++ b/layout/style/StyleColor.cpp
|
||||
@@ -8,6 +8,7 @@
|
||||
@@ -10,25 +10,7 @@ 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(
|
||||
}
|
||||
|
||||
return Servo_ResolveColor(this, &aForegroundColor);
|
||||
+ };
|
||||
+ return zen::nsZenBoostsBackend::ResolveStyleColor(ResolveColorInner());
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -68,10 +73,11 @@ nscolor StyleAbsoluteColor::ToColor() const {
|
||||
@@ -68,10 +69,11 @@ 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);
|
||||
|
||||
|
||||
@@ -539,6 +539,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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -322,13 +322,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 +367,7 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
||||
this.#loadStyleSheet(boost.styleSheet);
|
||||
}
|
||||
|
||||
browsingContext.fullZoom = boostData.sizeOverride;
|
||||
browsingContext.isZenBoostsInverted = boostData.smartInvert;
|
||||
if (boostData.enableColorBoost) {
|
||||
let primaryColor;
|
||||
@@ -484,7 +490,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 +499,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,
|
||||
|
||||
121
src/zen/boosts/gtest/TestZenBoostsColorFilter.cpp
Normal file
121
src/zen/boosts/gtest/TestZenBoostsColorFilter.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
9
src/zen/boosts/gtest/moz.build
Normal file
9
src/zen/boosts/gtest/moz.build
Normal 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"
|
||||
@@ -26,3 +26,7 @@ SOURCES += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
TEST_DIRS += [
|
||||
"gtest",
|
||||
]
|
||||
|
||||
@@ -43,7 +43,7 @@ static void RefreshBoostCacheIfMatchesCurrent(BrowsingContext* aChanged) {
|
||||
if (!backend) {
|
||||
return;
|
||||
}
|
||||
auto current = backend->GetCurrentBrowsingContext();
|
||||
RefPtr<BrowsingContext> current = backend->GetCurrentBrowsingContext();
|
||||
if (!current || current->Top() != aChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "nsZenBoostsBackend.h"
|
||||
|
||||
@@ -48,10 +50,6 @@ namespace zen {
|
||||
|
||||
NS_IMPL_ISUPPORTS0(nsZenBoostsBackend)
|
||||
|
||||
nsZenAccentOklab nsZenBoostsBackend::mCachedAccent{0};
|
||||
nsZenAccentOklab nsZenBoostsBackend::mCachedComplementary{0};
|
||||
float nsZenBoostsBackend::mCachedComplementaryRotationDeg = 0.0f;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
@@ -83,17 +81,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 +131,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 +176,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 +242,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_ =
|
||||
@@ -347,6 +406,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* {
|
||||
@@ -376,18 +461,25 @@ auto nsZenBoostsBackend::onPresShellEntered(mozilla::dom::Document* aDocument)
|
||||
if (!browsingContext) {
|
||||
return;
|
||||
}
|
||||
mCurrentBrowsingContext = browsingContext;
|
||||
mCurrentBrowsingContextId = browsingContext->Id();
|
||||
RefreshCachedBoostState();
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::BrowsingContext>
|
||||
nsZenBoostsBackend::GetCurrentBrowsingContext() const {
|
||||
return mozilla::dom::BrowsingContext::Get(mCurrentBrowsingContextId);
|
||||
}
|
||||
|
||||
auto nsZenBoostsBackend::RefreshCachedBoostState() -> void {
|
||||
if (!mCurrentBrowsingContext) {
|
||||
RefPtr<mozilla::dom::BrowsingContext> current =
|
||||
mozilla::dom::BrowsingContext::Get(mCurrentBrowsingContextId);
|
||||
if (!current) {
|
||||
mCachedCurrentAccent = 0;
|
||||
mCachedCurrentComplementaryRotation = 0.0f;
|
||||
mCachedCurrentInverted = false;
|
||||
return;
|
||||
}
|
||||
auto top = mCurrentBrowsingContext->Top();
|
||||
auto top = current->Top();
|
||||
mCachedCurrentAccent = top->ZenBoostsData();
|
||||
mCachedCurrentComplementaryRotation = top->ZenBoostsComplementaryRotation();
|
||||
mCachedCurrentInverted = top->IsZenBoostsInverted();
|
||||
@@ -397,33 +489,27 @@ auto nsZenBoostsBackend::RefreshCachedBoostState() -> void {
|
||||
nsZenBoostsBackend::FilterColorFromPresContext(nscolor aColor,
|
||||
nsPresContext* aPresContext)
|
||||
-> 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;
|
||||
}
|
||||
ZenBoostData accentNS = 0;
|
||||
float complementaryRotation = 0.0f;
|
||||
bool invertColors = false;
|
||||
GetZenBoostsDataFromBrowsingContext(&accentNS, &complementaryRotation,
|
||||
&invertColors, aPresContext);
|
||||
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,20 +517,8 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
#include "nsPresContext.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mozilla::dom {
|
||||
class BrowsingContext;
|
||||
}
|
||||
|
||||
#define ZEN_BOOSTS_BACKEND_CONTRACTID "@mozilla.org/zen/boosts-backend;1"
|
||||
|
||||
@@ -23,6 +30,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
|
||||
@@ -36,17 +56,15 @@ class nsZenBoostsBackend final : public nsISupports {
|
||||
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).
|
||||
* @param aColor The color to resolve.
|
||||
* @return The resolved color with Zen boost filters applied, or the original
|
||||
* color if no boost is active.
|
||||
* @see StyleColor::ResolveColor for reference.
|
||||
*/
|
||||
static auto ResolveStyleColor(mozilla::StyleAbsoluteColor aColor)
|
||||
-> mozilla::StyleAbsoluteColor;
|
||||
|
||||
/**
|
||||
* @see ResolveStyleColor for reference.
|
||||
* @see StyleAbsoluteColor::ToColor for reference.
|
||||
*/
|
||||
static auto ResolveStyleColor(nscolor aColor) -> nscolor;
|
||||
|
||||
@@ -73,10 +91,13 @@ class nsZenBoostsBackend final : public nsISupports {
|
||||
*/
|
||||
auto RefreshCachedBoostState() -> void;
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto GetCurrentBrowsingContext() const {
|
||||
return mCurrentBrowsingContext;
|
||||
}
|
||||
/**
|
||||
* Resolves the current top BrowsingContext from its stored id. May return
|
||||
* null if it has since been discarded. Not on the per-color hot path; the
|
||||
* hot path uses the mCachedCurrent* fields instead.
|
||||
*/
|
||||
[[nodiscard]] already_AddRefed<mozilla::dom::BrowsingContext>
|
||||
GetCurrentBrowsingContext() const;
|
||||
|
||||
/**
|
||||
* Cached boost data for the current top BrowsingContext, refreshed on
|
||||
@@ -95,15 +116,12 @@ class nsZenBoostsBackend final : public nsISupports {
|
||||
~nsZenBoostsBackend() = default;
|
||||
|
||||
/**
|
||||
* The presshell of the current document being rendered.
|
||||
* Id of the top BrowsingContext of the current document being rendered.
|
||||
* Stored as an id rather than a strong RefPtr so the process-wide singleton
|
||||
* does not keep a navigated-away BrowsingContext (and its subtree) alive
|
||||
* until the next presshell entry.
|
||||
*/
|
||||
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;
|
||||
uint64_t mCurrentBrowsingContextId = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -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"]
|
||||
|
||||
94
src/zen/tests/boosts/browser_boost_selector_escaping.js
Normal file
94
src/zen/tests/boosts/browser_boost_selector_escaping.js
Normal 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`
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user