Compare commits

...

16 Commits

Author SHA1 Message Date
mr. m
5383737b23 no-bug: Fixed boosts window not resizing back properly (gh-14007) 2026-06-04 00:38:39 +02:00
mr. m
b812bff07e no-bug: Change wine build download (gh-14002) 2026-06-03 12:04:25 +02:00
Rishab Shah
e04e910a6f no-bug: bypass workspace container coercion for extension-opened tabs (gh-14001)
Co-authored-by: pokeshah <89949620+pokeshah@users.noreply.github.com>
2026-06-03 11:06:16 +02:00
Ashvin Jangid
bf365f8043 gh-13439: Implement dark mode boosts panel (gh-13979) 2026-06-02 15:47:37 +02:00
mr. m
0a45b82a6c no-bug: Sync upstream Firefox to version 151.0.3 (gh-13991)
This PR syncs the upstream Firefox to version 151.0.3.

*  All patches applied cleanly.

@mr-cheffy please review and merge this PR.

---------

Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-06-02 15:47:19 +02:00
mr. m
2311e183f1 gh-13745: Disable desktop launcher for windows (gh-13987) 2026-06-02 11:16:29 +02:00
mr. m
8ea65cba48 gh-12112: Fixed auto focus for new windows not working (gh-13976) 2026-06-01 12:24:16 +02:00
mr. m
45075e2fbc gh-13439: Add tests coverage for boosts (gh-13977) 2026-06-01 11:24:45 +02:00
sporocyst
64e2e49a00 gh-13941: Fixed boost button viable when non-effective, CSS part (gh-13975)
Signed-off-by: sporocyst <sporocyst.tw@gmail.com>
2026-06-01 10:59:41 +02:00
fen4flo
feca914821 gh-13949: Secondary dot snapping to center in a new Boost (gh-13965)
Co-authored-by: mr. m <mr.m@tuta.com>
Signed-off-by: fen4flo <75260616+FlorianButz@users.noreply.github.com>
2026-05-31 15:53:33 +02:00
fen4flo
c7818fe355 gh-13839: Fix icons when using custom fonts (gh-13956)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-05-30 21:10:37 +02:00
mr. m
2c59265249 gh-13745: Fixed nightly being installed accidentally (gh-13964) 2026-05-30 20:54:55 +02:00
NHClaessens
193d004a37 gh-10594: Change conditional for triggering padding bump (gh-13959) 2026-05-30 17:35:40 +02:00
sporocyst
072d874f78 gh-13941: Fixed boost button viable when non-effective (gh-13953) 2026-05-30 12:26:20 +02:00
mr. m
7aa0ca05ec gh-13947: Fixed loading bar appearing on dom fullscreen (gh-13954) 2026-05-30 11:55:36 +02:00
Ashvin Jangid
d76fa13edd gh-13923: fix empty keyboard shortcut label caused by key_duplicateTab (gh-13924) 2026-05-28 18:33:29 +02:00
97 changed files with 1914 additions and 322 deletions

View File

@@ -129,7 +129,7 @@ jobs:
token: ${{ secrets.DEPLOY_KEY }}
commit-message: "chore: Sync upstream to `Firefox ${{ steps.build-data.outputs.version }}`"
branch: "chore/upstream-sync"
title: "no-bug: Sync upstream Firefox to version ${{ steps.build-data.outputs.version }}"
title: "no-bug: Sync upstream Firefox to version `${{ steps.build-data.outputs.version }}`"
body: |
This PR syncs the upstream Firefox to version ${{ steps.build-data.outputs.version }}.

View File

@@ -154,7 +154,7 @@ jobs:
zlib1g-dev \
aria2
echo Setup wine
aria2c "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.cache.level-1.toolchains.v3.linux64-wine.latest/artifacts/public%2Fbuild%2Fwine.tar.zst" -o wine.tar.zst
aria2c "https://firefox-ci-tc.services.mozilla.com/api/queue/v1/task/dQz_aHy8Rl-Lt0xf2WlrMw/artifacts/public/build/wine.tar.zst" -o wine.tar.zst
tar --zstd -xf wine.tar.zst -C ~/win-cross
rm wine.tar.zst
echo Setup Visual Studio

View File

@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
### Firefox Versions
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.2`! 🚀
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.2`!
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.3`! 🚀
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.3`!
### Contributing

View File

@@ -1 +1 @@
05272df13c2e4f435b4e0a706715f302b09ef829
5c4d14a559bf26eb4ab3e136d2084310ebe51ac0

View File

@@ -16,9 +16,9 @@ if test "$ZEN_CROSS_COMPILING"; then
CROSS_COMPILE=1
if test "$SURFER_COMPAT" = "aarch64"; then
export WIN32_REDIST_DIR="$(echo ~)/win-cross/vs2026/VC/Redist/MSVC/14.50.35710/arm64/Microsoft.VC145.CRT"
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/arm64/Microsoft.VC145.CRT"
else
export WIN32_REDIST_DIR="$(echo ~)/win-cross/vs2026/VC/Redist/MSVC/14.50.35710/x64/Microsoft.VC145.CRT"
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/x64/Microsoft.VC145.CRT"
fi
fi

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Trieu el selector
zen-boost-css-inspector =
.tooltiptext = Obre l'inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brillantor
zen-bootst-color-original-saturation = Saturació original
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brillantor
zen-boost-color-original-saturation = Saturació original
zen-add-zap-helper = Feu clic als elements de la pàgina per <b>amagar-los</b>
zen-remove-zap-helper = ← Feu clic per mostrar
zen-select-this = Insereix un selector per a això

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Selektor auswählen
zen-boost-css-inspector =
.tooltiptext = Inspektor öffnen
zen-bootst-color-contrast = Kontrast
zen-bootst-color-brightness = Helligkeit
zen-bootst-color-original-saturation = Ausgangssättigung
zen-boost-color-contrast = Kontrast
zen-boost-color-brightness = Helligkeit
zen-boost-color-original-saturation = Ausgangssättigung
zen-add-zap-helper = Klicke auf Elemente auf der Seite, um sie mit <b>Zap</b> zu markieren
zen-remove-zap-helper = ← Erneut klicken zum Wiederherstellen
zen-select-this = Selektor für dieses Element einfügen

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Escoger selector
zen-boost-css-inspector =
.tooltiptext = Abrir inspector
zen-bootst-color-contrast = Contraste
zen-bootst-color-brightness = Brillo
zen-bootst-color-original-saturation = Saturación original
zen-boost-color-contrast = Contraste
zen-boost-color-brightness = Brillo
zen-boost-color-original-saturation = Saturación original
zen-add-zap-helper = Haga clic en los elementos de la página para <b>borrarlos</b>
zen-remove-zap-helper = ← Clic para deshacer
zen-select-this = Insertar selector para esto

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Choisir le sélecteur
zen-boost-css-inspector =
.tooltiptext = Ouvrir l'inspecteur
zen-bootst-color-contrast = Contraste
zen-bootst-color-brightness = Luminosité
zen-bootst-color-original-saturation = Saturation originale
zen-boost-color-contrast = Contraste
zen-boost-color-brightness = Luminosité
zen-boost-color-original-saturation = Saturation originale
zen-add-zap-helper = Cliquez sur des éléments de la page pour les <b>zapper</b>
zen-remove-zap-helper = ← Cliquez pour démasquer
zen-select-this = Insérer un sélecteur pour ceci

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Roghnóir Roghnaigh
zen-boost-css-inspector =
.tooltiptext = Oscail an Cigire
zen-bootst-color-contrast = Codarsnacht
zen-bootst-color-brightness = Gile
zen-bootst-color-original-saturation = Sáithiú Bunaidh
zen-boost-color-contrast = Codarsnacht
zen-boost-color-brightness = Gile
zen-boost-color-original-saturation = Sáithiú Bunaidh
zen-add-zap-helper = Cliceáil ar eilimintí ar an leathanach chun iad a <b>Zapáil</b>
zen-remove-zap-helper = ← Cliceáil chun Dízipáil
zen-select-this = Cuir roghnóir isteach don seo

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = ניגודיות
zen-bootst-color-brightness = בהירות
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = ניגודיות
zen-boost-color-brightness = בהירות
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Vizsgáló megnyitása
zen-bootst-color-contrast = Kontraszt
zen-bootst-color-brightness = Fényerő
zen-bootst-color-original-saturation = Eredeti szaturáció
zen-boost-color-contrast = Kontraszt
zen-boost-color-brightness = Fényerő
zen-boost-color-original-saturation = Eredeti szaturáció
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Veljari
zen-boost-css-inspector =
.tooltiptext = Opna rýni
zen-bootst-color-contrast = Birtuskil
zen-bootst-color-brightness = Birtustig
zen-bootst-color-original-saturation = Upprunaleg litmettun
zen-boost-color-contrast = Birtuskil
zen-boost-color-brightness = Birtustig
zen-boost-color-original-saturation = Upprunaleg litmettun
zen-add-zap-helper = Smelltu á atriði á síðunni til að <b>einangra</b> þau (zap)
zen-remove-zap-helper = ← Smelltu til að taka úr einangrun
zen-select-this = Setja inn veljara fyrir þetta

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = セレクターを選択
zen-boost-css-inspector =
.tooltiptext = インスペクタを開く
zen-bootst-color-contrast = コントラスト
zen-bootst-color-brightness = 明るさ
zen-bootst-color-original-saturation = 元の彩度
zen-boost-color-contrast = コントラスト
zen-boost-color-brightness = 明るさ
zen-boost-color-original-saturation = 元の彩度
zen-add-zap-helper = <b>Zap</b> にページ上の要素をクリックします
zen-remove-zap-helper = ←クリックして解除
zen-select-this = このセレクターを挿入

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = 선택자 선택
zen-boost-css-inspector =
.tooltiptext = 검사기 열기
zen-bootst-color-contrast = 대비
zen-bootst-color-brightness = 밝기
zen-bootst-color-original-saturation = 원본 채도
zen-boost-color-contrast = 대비
zen-boost-color-brightness = 밝기
zen-boost-color-original-saturation = 원본 채도
zen-add-zap-helper = 페이지 내의 요소를 클릭해서 <b>날려</b>버리세요
zen-remove-zap-helper = ← 클릭하여 되살리기
zen-select-this = 이 요소의 선택자 삽입

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Kontrastas
zen-bootst-color-brightness = Šviesumas
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Kontrastas
zen-boost-color-brightness = Šviesumas
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Velgselektor
zen-boost-css-inspector =
.tooltiptext = Åpne inspektør
zen-bootst-color-contrast = Kontrast
zen-bootst-color-brightness = Lysstyrke
zen-bootst-color-original-saturation = Opprinnelig fargemetning
zen-boost-color-contrast = Kontrast
zen-boost-color-brightness = Lysstyrke
zen-boost-color-original-saturation = Opprinnelig fargemetning
zen-add-zap-helper = Klikk elementer på siden for å <b>Zappe</b> dem
zen-remove-zap-helper = ← Klikk for å avzappe
zen-select-this = Sett inn slektor for dette

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Wybierz selektor
zen-boost-css-inspector =
.tooltiptext = Otwórz Inspektor
zen-bootst-color-contrast = Kontrast
zen-bootst-color-brightness = Jasność
zen-bootst-color-original-saturation = Oryginalne nasycenie
zen-boost-color-contrast = Kontrast
zen-boost-color-brightness = Jasność
zen-boost-color-original-saturation = Oryginalne nasycenie
zen-add-zap-helper = Kliknij elementy na stronie, aby je <b>ukryć</b>
zen-remove-zap-helper = ← Kliknij, aby cofnąć ukrycie
zen-select-this = Wstaw selektor dla tego elementu

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Ferramenta de Seleção
zen-boost-css-inspector =
.tooltiptext = Abrir Inspetor
zen-bootst-color-contrast = Contraste
zen-bootst-color-brightness = Brilho
zen-bootst-color-original-saturation = Saturação Original
zen-boost-color-contrast = Contraste
zen-boost-color-brightness = Brilho
zen-boost-color-original-saturation = Saturação Original
zen-add-zap-helper = Clique em elementos da página para dar um <b>Zap</b> neles
zen-remove-zap-helper = Clique para Deszapar
zen-select-this = Inserir seletor para isto

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Välj väljare
zen-boost-css-inspector =
.tooltiptext = Öppna inspektör
zen-bootst-color-contrast = Kontrast
zen-bootst-color-brightness = Ljusstyrka
zen-bootst-color-original-saturation = Ursprunglig mättnad
zen-boost-color-contrast = Kontrast
zen-boost-color-brightness = Ljusstyrka
zen-boost-color-original-saturation = Ursprunglig mättnad
zen-add-zap-helper = Klicka på element på sidan för att <b>zappa</b> dem
zen-remove-zap-helper = ← Klicka för att avzappa
zen-select-this = Infoga väljare för detta

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Pick Selector
zen-boost-css-inspector =
.tooltiptext = Open Inspector
zen-bootst-color-contrast = Contrast
zen-bootst-color-brightness = Brightness
zen-bootst-color-original-saturation = Original Saturation
zen-boost-color-contrast = Contrast
zen-boost-color-brightness = Brightness
zen-boost-color-original-saturation = Original Saturation
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
zen-remove-zap-helper = ← Click to Unzap
zen-select-this = Insert selector for this

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Seçici seç
zen-boost-css-inspector =
.tooltiptext = Denetleyiciyi aç
zen-bootst-color-contrast = Kontrast
zen-bootst-color-brightness = Parlaklık
zen-bootst-color-original-saturation = Orijinal doygunluk
zen-boost-color-contrast = Kontrast
zen-boost-color-brightness = Parlaklık
zen-boost-color-original-saturation = Orijinal doygunluk
zen-add-zap-helper = Sayfadaki ögelere tıklayarak onları <b>Zap</b> ile kaldırın
zen-remove-zap-helper = ← Unzap için tıklayın
zen-select-this = Bu öge için seçici ekle

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Вибір селектора
zen-boost-css-inspector =
.tooltiptext = Відкрити інспектора
zen-bootst-color-contrast = Контраст
zen-bootst-color-brightness = Яскравість
zen-bootst-color-original-saturation = Оригінальна насиченість
zen-boost-color-contrast = Контраст
zen-boost-color-brightness = Яскравість
zen-boost-color-original-saturation = Оригінальна насиченість
zen-add-zap-helper = Клацніть на елементи на сторінці, щоби <b>сховати</b> їх
zen-remove-zap-helper = ← Клацніть, аби знову показати
zen-select-this = Вставити селектор для цього

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = Chọn phần tử
zen-boost-css-inspector =
.tooltiptext = Mở trình kiểm tra
zen-bootst-color-contrast = Độ tương phản
zen-bootst-color-brightness = Độ sáng
zen-bootst-color-original-saturation = Độ bão hòa gốc
zen-boost-color-contrast = Độ tương phản
zen-boost-color-brightness = Độ sáng
zen-boost-color-original-saturation = Độ bão hòa gốc
zen-add-zap-helper = Nhấp vào các phần tử trên trang để <b>Khử</b> chúng
zen-remove-zap-helper = ← Nhấp để khôi phục
zen-select-this = Nhập bộ chọn cho phần tử này

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = 选取选择器
zen-boost-css-inspector =
.tooltiptext = 打开查看器
zen-bootst-color-contrast = 对比度
zen-bootst-color-brightness = 亮度
zen-bootst-color-original-saturation = 初始饱和度
zen-boost-color-contrast = 对比度
zen-boost-color-brightness = 亮度
zen-boost-color-original-saturation = 初始饱和度
zen-add-zap-helper = 点击页面上的元素以将其<b>屏蔽</b>
zen-remove-zap-helper = ← 点击以取消屏蔽
zen-select-this = 插入此元素的选择器

View File

@@ -29,9 +29,9 @@ zen-boost-css-picker =
.tooltiptext = 汲取選擇器
zen-boost-css-inspector =
.tooltiptext = 開啟檢測器
zen-bootst-color-contrast = 對比
zen-bootst-color-brightness = 亮度
zen-bootst-color-original-saturation = 飽和度
zen-boost-color-contrast = 對比
zen-boost-color-brightness = 亮度
zen-boost-color-original-saturation = 飽和度
zen-add-zap-helper = 選擇要 <b>Zap</b>的元素
zen-remove-zap-helper = ← 按此取消zap
zen-select-this = 加入此元素的選擇器

View File

@@ -28,7 +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",
"test:gtest": "cd engine && ./mach gtest Zen*",
"ffprefs": "cd tools/ffprefs && cargo run --bin ffprefs -- ../../",
"lc": "surfer license-check",
"lc:fix": "surfer license-check --fix",

View File

@@ -825,6 +825,7 @@ var zenIgnoreKeyboardShortcutIDs = [
"key_enterFullScreen_compat",
"key_exitFullScreen_old",
"key_exitFullScreen_compat",
"key_duplicateTab",
];
var zenIgnoreKeyboardShortcutL10n = [

View File

@@ -281,7 +281,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
+ let hasZenDefaultUserContextId = false;
+ let zenForcedWorkspaceId = undefined;
+ if (typeof gZenWorkspaces !== "undefined" && !_forZenEmptyTab) {
+ [userContextId, hasZenDefaultUserContextId, zenForcedWorkspaceId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal);
+ [userContextId, hasZenDefaultUserContextId, zenForcedWorkspaceId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal);
+ }
+
if (!UserInteraction.running("browser.tabs.opening", window)) {

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e6463b45191 100644
index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..c166b7de23c35716bf8c51b6b9c72f771f0a75a8 100644
--- a/browser/components/urlbar/content/UrlbarInput.mjs
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
@@ -98,6 +98,13 @@ const lazy = XPCOMUtils.declareLazy({
@@ -132,15 +132,17 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
// Enable the animation only after the first extend call to ensure it
// doesn't run when opening a new window.
if (!this.hasAttribute("breakout-extend-animate")) {
@@ -2891,6 +2966,27 @@ ${
@@ -2891,6 +2966,29 @@ ${
return;
}
+ if (this._zenHandleUrlbarClose) {
+ this._zenHandleUrlbarClose();
+ } else if (!this._untrimmedValue || this.searchMode) {
+ } else if (!this._untrimmedValue || this.searchMode || this.window.gZenVerticalTabsManager._hasSetSingleToolbar) {
+ // Restore the current page URL when the urlbar is empty on blur
+ this.handleRevert();
+ this.window.requestAnimationFrame(() => {
+ this.handleRevert();
+ });
+ }
+
+ // Arc like URLbar: Blur the input on exit
@@ -160,7 +162,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
this.removeAttribute("breakout-extend");
this.#updateTextboxPosition();
}
@@ -2921,7 +3017,7 @@ ${
@@ -2921,7 +3019,7 @@ ${
forceUnifiedSearchButtonAvailable = false
) {
let prevState = this.getAttribute("pageproxystate");
@@ -169,7 +171,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
this.setAttribute("pageproxystate", state);
this._inputContainer.setAttribute("pageproxystate", state);
this._identityBox?.setAttribute("pageproxystate", state);
@@ -3198,10 +3294,12 @@ ${
@@ -3198,10 +3296,12 @@ ${
return;
}
this.style.top = px(
@@ -182,7 +184,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
);
}
@@ -3260,9 +3358,10 @@ ${
@@ -3260,9 +3360,10 @@ ${
return;
}
@@ -194,7 +196,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
);
this.style.setProperty(
"--urlbar-height",
@@ -3768,6 +3867,7 @@ ${
@@ -3768,6 +3869,7 @@ ${
}
_toggleActionOverride(event) {
@@ -202,7 +204,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
if (
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
event.keyCode == KeyEvent.DOM_VK_ALT ||
@@ -3880,8 +3980,8 @@ ${
@@ -3880,8 +3982,8 @@ ${
if (!this.#isAddressbar) {
return val;
}
@@ -213,7 +215,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
: val;
// Only trim value if the directionality doesn't change to RTL and we're not
// showing a strikeout https protocol.
@@ -4180,6 +4280,7 @@ ${
@@ -4180,6 +4282,7 @@ ${
resultDetails = null,
browser = this.window.gBrowser.selectedBrowser
) {
@@ -221,7 +223,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
if (this.#isAddressbar) {
this.#prepareAddressbarLoad(
url,
@@ -4291,6 +4392,10 @@ ${
@@ -4291,6 +4394,10 @@ ${
}
reuseEmpty = true;
}
@@ -232,7 +234,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
if (
where == "tab" &&
reuseEmpty &&
@@ -4298,6 +4403,9 @@ ${
@@ -4298,6 +4405,9 @@ ${
) {
where = "current";
}
@@ -242,7 +244,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
return where;
}
@@ -4552,6 +4660,7 @@ ${
@@ -4552,6 +4662,7 @@ ${
this.setResultForCurrentValue(null);
this.handleCommand();
this.controller.clearLastQueryContextCache();
@@ -250,7 +252,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
this._suppressStartQuery = false;
});
@@ -4559,7 +4668,6 @@ ${
@@ -4559,7 +4670,6 @@ ${
contextMenu.addEventListener("popupshowing", () => {
// Close the results pane when the input field contextual menu is open,
// because paste and go doesn't want a result selection.
@@ -258,7 +260,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
let controller =
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
@@ -4715,7 +4823,11 @@ ${
@@ -4715,7 +4825,11 @@ ${
if (!engineName && !source && !this.hasAttribute("searchmode")) {
return;
}
@@ -271,7 +273,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
if (this._searchModeIndicatorTitle) {
this._searchModeIndicatorTitle.textContent = "";
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
@@ -5031,6 +5143,7 @@ ${
@@ -5031,6 +5145,7 @@ ${
this.document.l10n.setAttributes(
this.inputField,
@@ -279,7 +281,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
l10nId,
l10nId == "urlbar-placeholder-with-name"
? { name: engineName }
@@ -5156,6 +5269,11 @@ ${
@@ -5156,6 +5271,11 @@ ${
}
_on_click(event) {
@@ -291,7 +293,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
switch (event.target) {
case this.inputField:
case this._inputContainer:
@@ -5242,7 +5360,7 @@ ${
@@ -5242,7 +5362,7 @@ ${
}
}
@@ -300,7 +302,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
this.view.autoOpen({ event });
} else {
if (this._untrimOnFocusAfterKeydown) {
@@ -5282,9 +5400,16 @@ ${
@@ -5282,9 +5402,16 @@ ${
}
_on_mousedown(event) {
@@ -318,7 +320,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
if (
event.composedTarget != this.inputField &&
event.composedTarget != this._inputContainer
@@ -5294,6 +5419,10 @@ ${
@@ -5294,6 +5421,10 @@ ${
this.focusedViaMousedown = !this.focused;
this.#preventClickSelectsAll = this.focused;
@@ -329,7 +331,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
// Keep the focus status, since the attribute may be changed
// upon calling this.focus().
@@ -5329,7 +5458,7 @@ ${
@@ -5329,7 +5460,7 @@ ${
}
// Don't close the view when clicking on a tab; we may want to keep the
// view open on tab switch, and the TabSelect event arrived earlier.
@@ -338,7 +340,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
break;
}
@@ -5636,7 +5765,7 @@ ${
@@ -5636,7 +5767,7 @@ ${
// When we are in actions search mode we can show more results so
// increase the limit.
let maxResults =

View File

@@ -520,7 +520,8 @@
list-style-image: url("permissions-fill.svg");
}
&[boosting] image {
color: var(--color-accent-primary);
fill-opacity: 1 !important;
color: var(--zen-sidebar-themed-icon-fill);
list-style-image: url("permissions-fill.svg");
}
@@ -537,7 +538,9 @@
display: flex;
width: 100%;
height: 100%;
color: var(--color-accent-primary);
color: var(--zen-sidebar-themed-icon-fill);
-moz-context-properties: fill;
fill: currentColor;
list-style-image: url("chrome://browser/content/zen-images/boost-indicator.svg");
transform: translateX(-20%);
z-index: 0;

View File

@@ -1,8 +1,8 @@
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d232f392d47 100644
index 0f5dab192533aa42df97ee3bd4176a9f44d4d568..d45ad2409f6d36106fce5a380545aaae9397ae84 100644
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -22,6 +22,7 @@ def check_moz_app_id(moz_app_id, build_project):
@@ -20,6 +20,7 @@ def check_moz_app_id(moz_app_id, build_project):
project_flag(
env="MOZ_APP_VENDOR",
@@ -10,7 +10,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
nargs=1,
help='Used for application.ini\'s "Vendor" field, which also impacts profile location and user-visible fields',
)
@@ -35,6 +36,7 @@ project_flag(
@@ -33,6 +34,7 @@ project_flag(
project_flag(
"MOZ_APP_PROFILE",
@@ -18,7 +18,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
nargs=1,
help='Used for application.ini\'s "Profile" field, which controls profile location',
)
@@ -86,10 +88,13 @@ option(
@@ -84,10 +86,13 @@ option(
)
set_config("MOZ_INCLUDE_SOURCE_INFO", True, when="MOZ_INCLUDE_SOURCE_INFO")
@@ -33,7 +33,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
help="Set distribution-specific id",
)
set_config("MOZ_DISTRIBUTION_ID", depends("--with-distribution-id")(lambda v: v[0]))
@@ -931,9 +936,9 @@ set_config("MOZ_SYSTEM_AV1", True, when="--with-system-av1")
@@ -874,9 +879,9 @@ set_config("MOZ_SYSTEM_AV1", True, when="--with-system-av1")
option("--disable-jxl", help="Disable jxl image support")
@@ -46,7 +46,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
return True
@@ -2070,7 +2075,7 @@ set_define("A11Y_LOG", True, when=a11y_log)
@@ -2028,7 +2033,7 @@ set_define("A11Y_LOG", True, when=a11y_log)
# ==============================================================
@depends(milestone)
def require_signing(milestone):
@@ -55,7 +55,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
option(
@@ -3903,7 +3908,7 @@ with only_when(compile_environment):
@@ -3912,7 +3917,7 @@ with only_when(compile_environment):
return "Mozilla"
elif target.os == "Android":
return ".mozilla"
@@ -64,3 +64,12 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
option(
"--with-user-appdir",
@@ -4325,7 +4330,7 @@ with only_when(target_is_windows):
@depends(target.abi)
def desktop_launcher_enabled(abi):
- return abi == "msvc"
+ return False # See gh-13745
set_config("DESKTOP_LAUNCHER_ENABLED", True, when=desktop_launcher_enabled)
set_define("DESKTOP_LAUNCHER_ENABLED", True, when=desktop_launcher_enabled)

View File

@@ -82,7 +82,7 @@ export class nsZenBoostStyles {
if (fontCase != "" || fontFamily != "") {
style += `/* Text Format */\n`;
style += `body * {\n`;
style += `body *:not(.google-symbols, gf-load-icon-font, mat-icon, .google-material-icons) {\n`;
style += `${fontFamily}\n`;
style += `${fontCase}\n`;
style += `}\n`;

View File

@@ -44,6 +44,7 @@ export class nsZenBoostEditor {
this.lastDotSetPos = { x: 0, y: 0 };
this.currentBoostData = null;
this.boostInfo = null;
this.isDarkMode = this.openerWindow.gZenThemePicker.isDarkMode;
this.killOtherEditorInstances();
@@ -52,6 +53,7 @@ export class nsZenBoostEditor {
});
this.init();
this.initColorScheme();
this.initColorPicker();
this.initFonts();
this.loadBoost(domain);
@@ -184,6 +186,17 @@ export class nsZenBoostEditor {
}
}
/**
* Initializes the color scheme of the editor window based on the current theme (dark or light mode)
*/
initColorScheme() {
if (this.isDarkMode) {
this.doc.documentElement.style.colorScheme = "dark";
} else {
this.doc.documentElement.style.colorScheme = "light";
}
}
/**
* Initializes the code editor for the css editor
*/
@@ -205,7 +218,7 @@ export class nsZenBoostEditor {
const editor = new Editor({
mode: Editor.modes.css,
lineNumbers: true,
theme: "default", // default is light theme
theme: "mozilla",
readOnly: false,
gutters: ["CodeMirror-linenumbers"],
});
@@ -361,12 +374,6 @@ export class nsZenBoostEditor {
}
windowElem.setAttribute("editor", "code");
// Store the old boost editor width.
// The window needs the outer width which includes
// window chrome. This results in the window
// being smaller than it should be
this._boostEditorWidth = this.editorWindow.outerWidth;
this.editorWindow.requestAnimationFrame(() => {
this.editorWindow.resizeTo(
this._codeEditorWidth,
@@ -400,7 +407,11 @@ export class nsZenBoostEditor {
}
windowElem.setAttribute("editor", "boost");
this.editorWindow.requestAnimationFrame(() => {
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"none";
this.editorWindow.promiseDocumentFlushed(() => {
this.editorWindow.resizeTo(
this._boostEditorWidth,
this.editorWindow.outerHeight
@@ -411,10 +422,6 @@ export class nsZenBoostEditor {
this.editorWindow.screenY
);
}
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
this.doc.getElementById("zen-boost-code-editor-root").style.display =
"none";
});
// Disable picker mode
@@ -824,13 +831,19 @@ ${cssSelector} {
const dotSec = this.doc.querySelector(
"#zen-boost-color-picker-dot-secondary"
);
const dotDistance = this.currentBoostData.dotDistance;
const dotAngleDeg = this.currentBoostData.dotAngleDeg;
const secondaryDotAngleDelta =
this.currentBoostData.secondaryDotAngleDegDelta ?? 0;
dot.style.setProperty(
"--zen-theme-picker-dot-color",
`hsl(${this.currentBoostData.dotAngleDeg}deg, ${this.currentBoostData.dotDistance * 100}%, 55%)`
`hsl(${dotAngleDeg}deg, ${dotDistance * 100}%, 55%)`
);
dotSec.style.setProperty(
"--zen-theme-picker-dot-color",
`hsl(${this.currentBoostData.dotAngleDeg + this.currentBoostData.secondaryDotAngleDegDelta}deg, ${this.currentBoostData.dotDistance * 100}%, 20%)`
`hsl(${dotAngleDeg + secondaryDotAngleDelta}deg, ${dotDistance * 100}%, 20%)`
);
}
@@ -854,22 +867,23 @@ ${cssSelector} {
const centerY = rect.top + rect.height / 2;
const radius = (rect.width - padding) / 2;
const dotDistance = this.currentBoostData.dotDistance;
const primaryDotAngleDeg = this.currentBoostData.dotAngleDeg;
let angle = null;
if (!pixelX || !pixelY) {
if (pixelX == null || pixelY == null) {
pixelX = centerX;
pixelY = centerY;
angle = this.currentBoostData.secondaryDotAngleDegDelta;
} else {
angle = Math.atan2(pixelY - centerY, pixelX - centerX);
pixelX =
centerX + Math.cos(angle) * this.currentBoostData.dotDistance * radius;
pixelY =
centerY + Math.sin(angle) * this.currentBoostData.dotDistance * radius;
pixelX = centerX + Math.cos(angle) * dotDistance * radius;
pixelY = centerY + Math.sin(angle) * dotDistance * radius;
}
// Rad to degree
this.currentBoostData.secondaryDotAngleDegDelta =
((angle * 180) / Math.PI + 100 - this.currentBoostData.dotAngleDeg) % 360;
((angle * 180) / Math.PI + 100 - primaryDotAngleDeg) % 360;
if (this.currentBoostData.secondaryDotAngleDegDelta < 0) {
this.currentBoostData.secondaryDotAngleDegDelta += 360;
}
@@ -902,14 +916,19 @@ ${cssSelector} {
const cx = rect.width / 2;
const cy = rect.height / 2;
const dotDistance = this.currentBoostData.dotDistance;
const dotAngleDeg = this.currentBoostData.dotAngleDeg;
const secondaryDotAngleDelta =
this.currentBoostData.secondaryDotAngleDegDelta ?? 0;
// Updating the circle size to match the distance of the point
const circle = this.doc.querySelector(".zen-boost-color-picker-circle");
circle.setAttribute("animated", "false");
circle.style.width = `${this.currentBoostData.dotDistance * radius * 2}px`;
circle.style.height = `${this.currentBoostData.dotDistance * radius * 2}px`;
circle.style.width = `${dotDistance * radius * 2}px`;
circle.style.height = `${dotDistance * radius * 2}px`;
const dotColor = `hsl(${this.currentBoostData.dotAngleDeg}deg, ${this.currentBoostData.dotDistance * 100}%, 55%)`;
const dotColorSec = `hsl(${this.currentBoostData.dotAngleDeg + this.currentBoostData.secondaryDotAngleDegDelta}deg, ${this.currentBoostData.dotDistance * 100}%, 20%)`;
const dotColor = `hsl(${dotAngleDeg}deg, ${dotDistance * 100}%, 55%)`;
const dotColorSec = `hsl(${dotAngleDeg + secondaryDotAngleDelta}deg, ${dotDistance * 100}%, 20%)`;
this.updateArcFill(cx, cy, radius, dotColor, dotColorSec);
}
@@ -1154,12 +1173,6 @@ ${cssSelector} {
invertButton.classList.remove("zen-boost-button-active");
}
if (this.currentBoostData.smartInvert) {
invertButton.classList.add("zen-boost-button-active");
} else {
invertButton.classList.remove("zen-boost-button-active");
}
if (!this.currentBoostData.enableColorBoost) {
disableButton.classList.add("zen-boost-button-active-transparent");
} else {

View File

@@ -114,9 +114,12 @@ class nsZenBoostsManager {
boostData: {
boostName: "My Boost",
dotAngleDeg: 0,
/* These initial values depend on
each other. Changing one means having to
recalculate all of them manually. */
dotAngleDeg: 131.61,
dotPos: { x: 0.76, y: 0.66 },
dotDistance: 0,
dotDistance: 0.91,
secondaryDotAngleDegDelta: 55,
secondaryDotPos: { x: 0.5, y: 0.81 },

View File

@@ -0,0 +1,104 @@
/* 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::AccentCacheSize;
using zen::detail::EnsureCachedAccent;
using zen::detail::IsAccentCached;
using zen::detail::ResetAccentCache;
namespace {
class ZenBoostsAccentCache : public ::testing::Test {
protected:
void SetUp() override { ResetAccentCache(); }
void TearDown() override { ResetAccentCache(); }
};
constexpr nscolor kAccentA = NS_RGBA(80, 120, 200, 200);
constexpr nscolor kAccentB = NS_RGBA(200, 80, 80, 200);
constexpr nscolor kAccentC = NS_RGBA(80, 200, 120, 200);
constexpr nscolor kAccentD = NS_RGBA(200, 200, 80, 200);
constexpr nscolor kAccentE = NS_RGBA(120, 80, 200, 200);
} // namespace
TEST_F(ZenBoostsAccentCache, SizeIsAtLeastFour) {
EXPECT_GE(AccentCacheSize(), 4u);
}
TEST_F(ZenBoostsAccentCache, EmptyAfterReset) {
EnsureCachedAccent(kAccentA, 0.0f);
ResetAccentCache();
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
}
TEST_F(ZenBoostsAccentCache, SameKeyIsCachedAfterEnsure) {
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
EnsureCachedAccent(kAccentA, 0.0f);
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
}
// Keying on accent alone would silently serve a stale complementary accent
// when the rotation changes.
TEST_F(ZenBoostsAccentCache, DifferentRotationOccupiesDistinctEntry) {
EnsureCachedAccent(kAccentA, 0.0f);
EnsureCachedAccent(kAccentA, 90.0f);
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentA, 90.0f));
}
TEST_F(ZenBoostsAccentCache, DifferentAccentOccupiesDistinctEntry) {
EnsureCachedAccent(kAccentA, 30.0f);
EnsureCachedAccent(kAccentB, 30.0f);
EXPECT_TRUE(IsAccentCached(kAccentA, 30.0f));
EXPECT_TRUE(IsAccentCached(kAccentB, 30.0f));
}
TEST_F(ZenBoostsAccentCache, RoundRobinEvictsOldestEntry) {
ASSERT_EQ(AccentCacheSize(), 4u);
EnsureCachedAccent(kAccentA, 0.0f);
EnsureCachedAccent(kAccentB, 0.0f);
EnsureCachedAccent(kAccentC, 0.0f);
EnsureCachedAccent(kAccentD, 0.0f);
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentD, 0.0f));
EnsureCachedAccent(kAccentE, 0.0f);
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentD, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentE, 0.0f));
}
// A cache hit must not consume a fresh slot, otherwise repeated paints with
// the same accent would evict their own neighbours.
TEST_F(ZenBoostsAccentCache, RepeatEnsureDoesNotChurnTheCache) {
ASSERT_EQ(AccentCacheSize(), 4u);
EnsureCachedAccent(kAccentA, 0.0f);
EnsureCachedAccent(kAccentB, 0.0f);
EnsureCachedAccent(kAccentC, 0.0f);
for (int i = 0; i < 16; ++i) {
EnsureCachedAccent(kAccentA, 0.0f);
}
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
EnsureCachedAccent(kAccentD, 0.0f);
EnsureCachedAccent(kAccentE, 0.0f);
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
}

View File

@@ -0,0 +1,42 @@
/* 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::nsZenBoostsBackend;
namespace {
const nscolor kResolveColors[] = {
NS_RGBA(0, 0, 0, 255), NS_RGBA(255, 255, 255, 255),
NS_RGBA(128, 128, 128, 255), NS_RGBA(255, 0, 0, 255),
NS_RGBA(0, 255, 0, 255), NS_RGBA(0, 0, 255, 255),
NS_RGBA(40, 44, 52, 255), NS_RGBA(248, 248, 248, 255),
NS_RGBA(20, 22, 28, 255), NS_RGBA(80, 80, 80, 200),
NS_RGBA(240, 17, 99, 1), NS_RGBA(0, 0, 0, 0),
};
} // namespace
// Removing the null-frame guard would crash chrome-process callers that
// legitimately pass nullptr (canvas getComputedStyle, font-palette binding,
// the StyleColor(nscolor)/StyleColor(StyleAbsoluteColor) overloads).
TEST(ZenBoostsResolveStyleColor, NullFrameIsIdentity)
{
for (nscolor c : kResolveColors) {
EXPECT_EQ(nsZenBoostsBackend::ResolveStyleColor(c, nullptr), c);
}
}
TEST(ZenBoostsResolveStyleColor, NullFrameIsIdempotent)
{
for (nscolor c : kResolveColors) {
nscolor once = nsZenBoostsBackend::ResolveStyleColor(c, nullptr);
nscolor twice = nsZenBoostsBackend::ResolveStyleColor(once, nullptr);
EXPECT_EQ(once, c);
EXPECT_EQ(twice, c);
}
}

View File

@@ -3,7 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
"TestZenBoostsAccentCache.cpp",
"TestZenBoostsColorFilter.cpp",
"TestZenBoostsResolveStyleColor.cpp",
]
FINAL_LIBRARY = "xul-gtest"

View File

@@ -450,11 +450,9 @@ inline static void GetZenBoostsDataForFrame(const nsIFrame* aFrame,
} // namespace
#ifdef ENABLE_TESTS
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);
}
@@ -474,7 +472,33 @@ nscolor InvertColorChannel(nscolor aColor) {
return zenInvertColorChannel(aColor);
}
size_t AccentCacheSize() { return kAccentCacheSize; }
void ResetAccentCache() {
for (auto& entry : sAccentCache) {
entry.valid = false;
entry.accentNS = 0;
entry.rotationDeg = 0.0f;
}
sAccentCacheNext = 0;
}
bool IsAccentCached(nscolor aAccentNS, float aRotationDeg) {
for (const auto& entry : sAccentCache) {
if (entry.valid && entry.accentNS == aAccentNS &&
entry.rotationDeg == aRotationDeg) {
return true;
}
}
return false;
}
void EnsureCachedAccent(nscolor aAccentNS, float aRotationDeg) {
(void)GetCachedAccent(aAccentNS, aRotationDeg);
}
} // namespace detail
#endif // ENABLE_TESTS
static mozilla::StaticRefPtr<nsZenBoostsBackend> sZenBoostsBackend;

View File

@@ -27,10 +27,9 @@ struct nsZenAccentOklab {
float contrastFactor;
};
#ifdef ENABLE_TESTS
// Test-only forwarders into the file-local color math and accent cache.
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);
@@ -38,7 +37,13 @@ nscolor FilterColorChannel(nscolor aOriginalColor,
const nsZenAccentOklab& aAccent,
const nsZenAccentOklab& aComplementary);
nscolor InvertColorChannel(nscolor aColor);
size_t AccentCacheSize();
void ResetAccentCache();
bool IsAccentCached(nscolor aAccentNS, float aRotationDeg);
void EnsureCachedAccent(nscolor aAccentNS, float aRotationDeg);
} // namespace detail
#endif // ENABLE_TESTS
class nsZenBoostsBackend final : public nsISupports {
public:

View File

@@ -5,11 +5,10 @@
*/
#zen-boost-advanced-color-options-panel {
color-scheme: light;
--panel-padding: 15px;
& p {
color: #3a3a3b;
color: var(--zen-boosts-primary-color);
}
& input {

View File

@@ -34,14 +34,6 @@
<link rel="stylesheet" href="chrome://browser/content/zen-styles/zen-advanced-color-options.css" />
<link rel="localization" href="browser/zen-boosts.ftl"/>
<!-- Loading in the window module -->
<script>
const { nsZenBoostEditor } = ChromeUtils.importESModule( "resource:///modules/zen/boosts/ZenBoostsEditor.mjs" );
window.addEventListener("load", () => {
window.boostEditor = new nsZenBoostEditor(document, window.domain, window, window.openerWindow);
});
</script>
</head>
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox flex="1" id="zen-boost-editor-root">
@@ -120,15 +112,15 @@
<popupset id="mainPopupSet">
<panel type="arrow" popupalign="topmiddle" id="zen-boost-advanced-color-options-panel">
<vbox>
<p data-l10n-id="zen-bootst-color-contrast"></p>
<p data-l10n-id="zen-boost-color-contrast"></p>
<html:input id="zen-boost-color-contrast" type="range" min="0.05" max="0.9" value="0.75" step="0.01"/>
</vbox>
<vbox>
<p data-l10n-id="zen-bootst-color-brightness"></p>
<p data-l10n-id="zen-boost-color-brightness"></p>
<html:input id="zen-boost-color-brightness" type="range" min="0" max="1" value="0.5" step="0.01"/>
</vbox>
<vbox>
<p data-l10n-id="zen-bootst-color-original-saturation"></p>
<p data-l10n-id="zen-boost-color-original-saturation"></p>
<html:input id="zen-boost-color-saturation" type="range" min="0" max="1" value="0.5" step="0.01"/>
</vbox>
</panel>
@@ -164,5 +156,10 @@
<command id="cmd_zenBoostDelete"
oncommand="window.boostEditor.deleteBoost();" />
</commandset>
<script>
const { nsZenBoostEditor } = ChromeUtils.importESModule( "resource:///modules/zen/boosts/ZenBoostsEditor.mjs" );
window.boostEditor = new nsZenBoostEditor(document, window.domain, window, window.openerWindow);
</script>
</html:body>
</html>

View File

@@ -5,10 +5,33 @@
*/
#zenBoostWindow {
/* For the mica effect we want a white tint */
@media not (-moz-platform: linux) {
color-scheme: light;
}
--zen-boosts-primary-background: light-dark(#fcfcfe, #171717);
--zen-boosts-secondary-background: light-dark(#f6f6f8, #1c1c1e);
--zen-boosts-mica-background: light-dark(#f6f6f8c0, #1c1c1ec0);
--zen-boosts-primary-color: light-dark(#3a3a3b, #f3f3f3);
--zen-boosts-secondary-color: light-dark(#727272, #b1b1b1);
--zen-boosts-button-background: light-dark(#ebebed, #262626);
--mod-button-c1: light-dark(#ebebed, #262626);
--mod-button-c2: light-dark(#ebebed, #262626);
--zen-boosts-active-button-background: light-dark(#3a3a3a, #cccccc);
--zen-boosts-active-button-hover-background: light-dark(#5b5b5c, #c9c9c9);
--zen-boosts-active-button-color: light-dark(#fcfcfe, #1c1c1e);
--zen-boosts-back-button-hover-background: light-dark(#e3e3e6, #3a3a3a);
--zen-boosts-magic-theme-background: light-dark(white, #3a3a3a);
--zen-boosts-magic-theme-active-background: light-dark(#3a3a3a, white);
--zen-boosts-font-wrapper-background: light-dark(white, #262626);
--zen-boosts-primary-border-color: light-dark(#ededef, #3a3a3a);
--zen-boosts-color-picker-background: light-dark(#fbfbfdea, #1c1c1eea);
--zen-boosts-color-picker-pattern-color: light-dark(#e3e9e4, #3a3a3a);
appearance: none;
border: none;
@@ -40,12 +63,12 @@
width: 100%;
height: 40px;
background-color: #f6f6f8;
background-color: var(--zen-boosts-secondary-background);
@media (-moz-windows-mica) {
background-color: #f6f6f8c0;
background-color: var(--zen-boosts-mica-background);
}
border: solid 0 #ededef;
border: solid 0 var(--zen-boosts-primary-border-color);
border-bottom-width: 1px;
}
@@ -58,6 +81,9 @@
margin-left: 4px;
border-radius: 8px;
-moz-context-properties: fill;
fill: var(--zen-boosts-primary-color);
opacity: 0.75;
background-color: transparent;
@@ -79,12 +105,12 @@
width: 100%;
height: 60px;
background-color: #f6f6f8;
background-color: var(--zen-boosts-secondary-background);
@media (-moz-windows-mica) {
background-color: #f6f6f8c0;
background-color: var(--zen-boosts-mica-background);
}
border: solid 0 #ededef;
border: solid 0 var(--zen-boosts-primary-border-color);
border-top-width: 1px;
display: flex;
@@ -113,6 +139,7 @@ body {
user-select: none;
width: 100%;
min-height: 582px;
height: 100%;
padding: 0;
margin: 0;
@@ -148,7 +175,7 @@ body {
}
.subviewbutton {
color: #3a3a3b;
color: var(--zen-boosts-primary-color);
}
#zen-boost-editor-view {
@@ -166,11 +193,11 @@ body {
min-height: 40px;
max-height: 40px;
align-items: center;
background-color: #f6f6f8;
border: solid 1px #e7e7e7ab;
background-color: var(--zen-boosts-secondary-background);
border: solid 1px var(--zen-boosts-primary-border-color);
@media (-moz-windows-mica) {
background-color: #f6f6f8c0;
background-color: var(--zen-boosts-mica-background);
border: none;
}
@@ -232,6 +259,7 @@ body {
padding: 2px;
& button {
color: var(--zen-boosts-primary-color) !important;
padding: auto;
margin: auto;
background-color: transparent;
@@ -243,7 +271,7 @@ body {
gap: 14px;
padding-top: 6px;
background-color: #fcfcfe;
background-color: var(--zen-boosts-primary-background);
-moz-window-dragging: drag;
& > * {
@@ -328,7 +356,7 @@ body {
border-radius: 12px;
}
background-color: #ebebed;
background-color: var(--zen-boosts-button-background);
transition:
0.4s background-color cubic-bezier(0.075, 0.82, 0.165, 1),
@@ -348,7 +376,7 @@ body {
}
#zen-boost-case:not([case-mode="none"]) {
background-color: #ebebed;
background-color: var(--zen-boosts-button-background);
font-weight: 600 !important;
}
@@ -373,7 +401,7 @@ body {
font-size: 8pt;
text-indent: 2px;
vertical-align: middle;
color: #3a3a3b;
color: var(--zen-boosts-primary-color);
justify-content: center;
}
@@ -397,12 +425,16 @@ body {
}
.zen-boost-button-active {
background-color: #3a3a3a;
color: #fcfcfe;
background-color: var(--zen-boosts-active-button-background);
color: var(--zen-boosts-active-button-color);
&#zen-boost-magic-theme {
background-color: var(--zen-boosts-magic-theme-active-background);
}
}
.zen-boost-button-active:hover {
background-color: #5b5b5c;
background-color: var(--zen-boosts-active-button-hover-background);
}
.zen-boost-button-active-transparent {
@@ -430,12 +462,13 @@ body {
}
&:not(.zen-boost-button-active) {
background: white;
background: var(--zen-boosts-magic-theme-background);
color: var(--zen-boosts-primary-color);
}
}
.footer {
background-color: #F6F6F8;
background-color: var(--zen-boosts-secondary-background);
padding: 20px;
}
@@ -471,7 +504,7 @@ body {
transition: 0.2s opacity ease-in-out;
color: #727272;
color: var(--zen-boosts-secondary-color);
background: none;
font-size: 9pt;
@@ -490,7 +523,7 @@ body {
&[has-selection="true"] {
opacity: 1;
background-color: #ebebed;
background-color: var(--zen-boosts-button-background);
}
}
@@ -513,7 +546,7 @@ body {
#zen-boost-font-wrapper {
box-shadow: 0 2px 6px rgba(0,0,0,.15);
background-color: #ffffff;
background-color: var(--zen-boosts-font-wrapper-background);
border-radius: 6px;
@media (-moz-platform: macos) {
@@ -564,35 +597,35 @@ body {
@property --mod-button-c1 {
syntax: "<color>";
inherits: false;
initial-value: #ebebed;
inherits: true;
initial-value: transparent;
}
@property --mod-button-c2 {
syntax: "<color>";
inherits: false;
initial-value: #ebebed;
inherits: true;
initial-value: transparent;
}
.mod-button[mode="orange"] {
color: #e3e9e4;
--mod-button-c1: #ffbb5d;
--mod-button-c2: #ffa01d;
--mod-button-c1: light-dark(#ffbb5d, #c37a3f);
--mod-button-c2: light-dark(#ffa01d, #9f5a2a);
}
.mod-button[mode="orange-red"] {
color: #e3e9e4;
--mod-button-c1: #ff8758;
--mod-button-c2: #ff5b1b;
--mod-button-c1: light-dark(#ff8758, #bd6048);
--mod-button-c2: light-dark(#ff5b1b, #9b422b);
}
.mod-button[mode="red"] {
color: #e3e9e4;
--mod-button-c1: #ff595f;
--mod-button-c2: #ff121b;
--mod-button-c1: light-dark(#ff595f, #b94a50);
--mod-button-c2: light-dark(#ff121b, #95272e);
}
.mod-button[mode="blue"] {
color: #e3e9e4;
--mod-button-c1: #6650fc;
--mod-button-c2: #4125ff;
--mod-button-c1: light-dark(#6650fc, #5d56ca);
--mod-button-c2: light-dark(#4125ff, #453aa9);
}
.mod-button[mode] {
background: linear-gradient(180deg, var(--mod-button-c1) 0%, var(--mod-button-c2) 100%) border-box;
@@ -608,7 +641,7 @@ body {
background-color: transparent;
&:hover {
background-color: #e3e3e6;
background-color: var(--zen-boosts-back-button-hover-background);
}
}
@@ -635,17 +668,17 @@ body {
z-index: 2;
background: #fbfbfdea;
background: var(--zen-boosts-color-picker-background);
background-position: -23px -23px;
backdrop-filter: saturate(2) blur(15px);
background-size: 6px 6px;
background-image: radial-gradient(#e3e9e4, 1px, transparent 0);
background-image: radial-gradient(var(--zen-boosts-color-picker-pattern-color), 1px, transparent 0);
@media (-moz-platform: macos) {
background-size: 4px 4px;
background-image: radial-gradient(#e3e9e4 0.5px, transparent 0);
background-image: radial-gradient(var(--zen-boosts-color-picker-pattern-color) 0.5px, transparent 0);
}
}

View File

@@ -16,6 +16,12 @@
}
#select-component {
--zen-boosts-selector-background: light-dark(#f5f7fb, #27272a);
--zen-boosts-selector-preview-background: light-dark(#e0e2e63d, #27272a3d);
--zen-boosts-selector-preview-color: light-dark(rgb(76, 78, 80), rgb(207, 200, 200));
--zen-boosts-selector-button-color: light-dark(#dadada, #f1f1f1);
--zen-boosts-selector-outline-color: light-dark(#e0e2e6ae, #474749);
width: min-content;
font-family: system-ui;
@@ -29,7 +35,7 @@
position: fixed;
z-index: 9999;
background-color: #f5f7fb;
background-color: var(--zen-boosts-selector-background);
margin: 4px;
border-radius: 12px;
@@ -126,17 +132,29 @@
width: 250px !important;
--related-elements-value: 100%;
background: linear-gradient(to top, rgb(247, 66, 0), rgb(245, 134, 86));
background: linear-gradient(
to top,
light-dark(#ff5b1b, #9b422b),
light-dark(#ff8758, #bd6048)
);
border: none;
color: #dadada;
color: var(--zen-boosts-selector-button-color);
box-shadow: 0 0 15px #00000052;
&:hover {
box-shadow: 0 0 14px #00000066;
background:
linear-gradient(to right, transparent var(--related-elements-value), gray var(--related-elements-value)),
linear-gradient(to top, rgb(247, 66, 0), rgb(245, 134, 86));
linear-gradient(
to right,
transparent var(--related-elements-value),
light-dark(gray, #363636) var(--related-elements-value)
),
linear-gradient(
to top,
light-dark(#ff5b1b, #9b422b),
light-dark(#ff8758, #bd6048)
);
@media not (-moz-platform: windows) {
box-shadow: 0 0 20px #00000077;
@@ -147,30 +165,34 @@
#select-this {
appearance: none;
background: linear-gradient(0deg, rgba(246, 27, 25, 1) 0%, rgba(254, 67, 59, 1) 100%);
background: linear-gradient(
0deg,
light-dark(#ff121b, #95272e),
light-dark(#ff595f, #b94a50)
);
border: none;
color: #dadada;
color: var(--zen-boosts-selector-button-color);
box-shadow: 0 0 15px #00000052;
}
#select-cancel {
appearance: none;
background: rgb(90, 94, 100);
@media (-moz-platform: macos) {
background: linear-gradient(0deg, rgba(81, 83, 85, 1) 0%, rgba(108, 110, 112, 1) 100%);
}
background: linear-gradient(
0deg,
light-dark(#525355, #373739) 0%,
light-dark(#6c6e70, #4b4c4e) 100%
);
border: none;
color: #dadada;
color: var(--zen-boosts-selector-button-color);
box-shadow: 0 0 15px #00000052;
}
#selector-preview {
background-color: #e0e2e63d;
outline: 1px solid #e0e2e6ae;
background-color: var(--zen-boosts-selector-preview-background);
outline: 1px solid var(--zen-boosts-selector-outline-color);
width: 100%;
height: 34px;
text-indent: 18px;
@@ -182,7 +204,7 @@
#selector-element-preview-text {
font-family: Arial, Helvetica, sans-serif;
font-size: 9pt;
color: rgb(76, 78, 80);
color: var(--zen-boosts-selector-preview-color);
}
#hover-div {

View File

@@ -495,7 +495,7 @@
border-radius: 99px;
width: var(--size-item-large);
height: var(--size-item-large);
background: var(--button-background-color-primary);
background: var(--zen-sidebar-themed-icon-fill);
opacity: 0.6;
transition:
transform 0.12s ease-in-out,
@@ -540,6 +540,10 @@
& toolbarbutton {
margin: 0;
&[disabled] {
visibility: hidden;
}
}
}
@@ -621,7 +625,7 @@
color: var(--button-primary-color);
&::before {
background: var(--button-background-color-primary);
background: var(--zen-sidebar-themed-icon-fill);
}
}
@@ -786,4 +790,8 @@
@media not -moz-pref("zen.view.enable-loading-indicator") {
display: none;
}
:root[inDOMFullscreen="true"] & {
display: none;
}
}

View File

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

View File

@@ -861,6 +861,7 @@ class nsZenWorkspaces {
"Selecting empty tab because startup page didnt select a valid tab"
);
this.selectEmptyTab();
initialTabWasEmpty = true;
}
this.log("Removing empty tab added by startup page");
this._removedByStartupPage = true;
@@ -2978,11 +2979,18 @@ class nsZenWorkspaces {
// Tab browser utilities
getContextIdIfNeeded(userContextId, fromExternal) {
getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal) {
if (!this.workspaceEnabled) {
return [userContextId, false, undefined];
}
if (
triggeringPrincipal &&
triggeringPrincipal.isAddonOrExpandedAddonPrincipal
) {
return [userContextId, false, undefined];
}
if (
this.shouldForceContainerTabsToWorkspace &&
typeof userContextId !== "undefined" &&

View File

@@ -322,7 +322,6 @@ zen-workspace {
height: 100%;
overflow: hidden;
color: var(--toolbox-textcolor);
will-change: transform;
@media not (prefers-reduced-motion: reduce) {
transition: padding-top 0.1s;

View File

@@ -1131,7 +1131,6 @@
transition:
max-height 0.3s ease-out,
grid-template-columns 0.3s ease-out;
will-change: transform;
opacity: 1;
--min-essentials-width-wrap: calc(var(--tab-min-height) + 4px);
grid-template-columns: repeat(auto-fit, minmax(max(23.7%, var(--min-essentials-width-wrap)), 1fr));

View File

@@ -8,6 +8,41 @@ support-files = [
]
["browser_boost_selector_basic.js"]
["browser_boost_selector_escaping.js"]
["browser_boost_selector_invalid.js"]
["browser_boost_selector_nthchild.js"]
["browser_boosts_animation.js"]
["browser_boosts_background.js"]
["browser_boosts_border.js"]
["browser_boosts_gradient.js"]
["browser_boosts_inline_svg.js"]
["browser_boosts_input_text.js"]
["browser_boosts_invert.js"]
["browser_boosts_outline.js"]
["browser_boosts_placeholder.js"]
["browser_boosts_pseudo_before.js"]
["browser_boosts_shadow.js"]
["browser_boosts_svg_background_image.js"]
["browser_boosts_svg_image.js"]
["browser_boosts_svg_linear_gradient.js"]
["browser_boosts_svg_use_sprite.js"]
["browser_boosts_text_color.js"]

View File

@@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// The compositor animation path in AnimationInfo.cpp resolves a colour with
// the host frame, then either takes it as-is (currentColor keyframe) or
// passes it through ResolveStyleColor (absolute keyframe). Both paths must
// end up at the same boosted colour as the static equivalent. We pin a
// background-color animation at 50% via animation-delay and compare against
// a static element that holds the interpolated colour.
add_task(async function animated_background_is_boosted() {
// Paused-at-50% animation between #000 and #fff → mid grey at the sampled
// time. We compare against a static rgb(128,128,128) swatch and require
// both to land at the same colour after boost.
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
.swatch { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
#static { background-color: rgb(128, 128, 128); }
@keyframes fade { from { background-color: black; } to { background-color: white; } }
#animated {
background-color: black;
animation: fade 4s linear infinite;
animation-delay: -2s;
animation-play-state: paused;
}
</style>
<div id="static" class="swatch"></div>
<div id="animated" class="swatch"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const staticBoosted = await pixelInElement(browser, "#static");
const animBoosted = await pixelInElement(browser, "#animated");
Assert.ok(
pixelsClose(staticBoosted, animBoosted, 6),
`animated and static mid-grey must land at the same boosted colour; ` +
`static=${JSON.stringify(staticBoosted)} animated=${JSON.stringify(
animBoosted
)}`
);
});
});

View File

@@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Verifies that activating a boost on a tab moves the painted colour of a
// plain CSS `background-color` block. Catches regressions where the per-color
// boost in StyleAbsoluteColor::ToColor or CalcColor is bypassed for
// backgrounds, and the gap that would surface if nsCSSRendering ever stopped
// passing the frame through GetVisitedDependentColor.
add_task(async function bg_color_is_tinted() {
const html = `
<style>
html, body { margin: 0; padding: 0; }
#bg { width: 200px; height: 200px; background-color: rgb(120, 120, 120); }
</style>
<div id="bg"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, { accent: 0 });
const baseline = await pixelInElement(browser, "#bg");
Assert.equal(baseline.r, 120, "baseline R is the literal background");
Assert.equal(baseline.g, 120, "baseline G is the literal background");
Assert.equal(baseline.b, 120, "baseline B is the literal background");
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelInElement(browser, "#bg");
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`boost should tint the background; got baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
// Sanity: clear the boost and the painted colour returns home.
await setBoost(browser, { accent: 0 });
const cleared = await pixelInElement(browser, "#bg");
Assert.ok(
pixelsClose(cleared, baseline, 2),
`clearing boost should restore original; got ${JSON.stringify(cleared)}`
);
});
});

View File

@@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Borders go through nsCSSRendering::ComputeBorderColors → CalcColor with the
// frame, so the boost should reach them. Use a thick solid border and sample
// inside the border band (which is fully the border colour) rather than the
// element interior.
add_task(async function border_color_is_tinted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#b { width: 200px; height: 200px; margin: 50px;
background: white;
border: 30px solid rgb(120, 120, 120); }
</style>
<div id="b"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// Sample a point inside the top border band: x = centre of element, y just
// below the top edge (well inside the 30px-wide border).
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#b").getBoundingClientRect();
return {
x: Math.round(r.left + r.width / 2),
y: Math.round(r.top + 15),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsClose(baseline, { r: 120, g: 120, b: 120 }, 5),
`baseline border colour ≈ rgb(120,120,120); got ${JSON.stringify(baseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`border colour should be tinted; baseline=${JSON.stringify(baseline)} ` +
`boosted=${JSON.stringify(boosted)}`
);
});
});

View File

@@ -0,0 +1,83 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// CSS linear-gradient stops are resolved via the nsCSSGradientRenderer +
// ColorStopInterpolator path, which threads the frame down into
// gfxUtils::ToDeviceColor(StyleAbsoluteColor, frame). If that threading
// regresses, gradient stops paint without the boost while everything else
// around them gets tinted — a particularly visible regression.
add_task(async function linear_gradient_stops_are_boosted() {
// Use a two-stop horizontal gradient so a sample near the left edge is
// dominated by the first stop and a sample near the right edge by the
// second. The element is sized 400×200 so we have generous sample regions.
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#g { width: 400px; height: 200px;
background: linear-gradient(to right,
rgb(180, 60, 60),
rgb(60, 60, 180)); }
</style>
<div id="g"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// Sample 5% in (mostly first stop) and 95% in (mostly last stop).
const points = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#g").getBoundingClientRect();
return {
left: {
x: Math.round(r.left + r.width * 0.05),
y: Math.round(r.top + r.height / 2),
},
right: {
x: Math.round(r.left + r.width * 0.95),
y: Math.round(r.top + r.height / 2),
},
};
});
await setBoost(browser, { accent: 0 });
const leftBaseline = await pixelAt(browser, points.left.x, points.left.y);
const rightBaseline = await pixelAt(
browser,
points.right.x,
points.right.y
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const leftBoosted = await pixelAt(browser, points.left.x, points.left.y);
const rightBoosted = await pixelAt(browser, points.right.x, points.right.y);
Assert.ok(
pixelsDiffer(leftBaseline, leftBoosted, 3),
`left gradient stop must tint; baseline=${JSON.stringify(
leftBaseline
)} boosted=${JSON.stringify(leftBoosted)}`
);
Assert.ok(
pixelsDiffer(rightBaseline, rightBoosted, 3),
`right gradient stop must tint; baseline=${JSON.stringify(
rightBaseline
)} boosted=${JSON.stringify(rightBoosted)}`
);
// The two stops must remain distinguishable after boost — otherwise the
// gradient has flattened, which would be a separate regression (e.g.,
// ToDeviceColor losing per-stop frame context and collapsing to a single
// tinted value).
Assert.ok(
pixelsDiffer(leftBoosted, rightBoosted, 8),
`boosted gradient endpoints collapsed; left=${JSON.stringify(
leftBoosted
)} right=${JSON.stringify(rightBoosted)}`
);
});
});

View File

@@ -0,0 +1,106 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// The "twice" diagnostic: paint an inline SVG fill and a CSS background-color
// with the *same* source colour, side by side. Under boost they must end up
// painted with the same boosted colour. If the SVG sample comes out
// noticeably more saturated / further from the baseline than the CSS one, the
// SVG paint path is applying the boost twice (the symptom you reported).
add_task(async function inline_svg_fill_matches_css_bg_under_boost() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#div, #svg { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
#div { background-color: rgb(51, 54, 57); }
</style>
<div id="div"></div>
<svg id="svg" width="200" height="200" viewBox="0 0 200 200">
<rect width="200" height="200" fill="rgb(51, 54, 57)"/>
</svg>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, { accent: 0 });
const divBaseline = await pixelInElement(browser, "#div");
const svgBaseline = await pixelInElement(browser, "#svg");
// Sanity: both paint the same source colour before any boost.
Assert.ok(
pixelsClose(divBaseline, svgBaseline, 2),
`pre-boost div/svg should already match; div=${JSON.stringify(
divBaseline
)} svg=${JSON.stringify(svgBaseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const divBoosted = await pixelInElement(browser, "#div");
const svgBoosted = await pixelInElement(browser, "#svg");
Assert.ok(
pixelsDiffer(divBaseline, divBoosted, 3),
"div background must be tinted under boost (sanity)"
);
Assert.ok(
pixelsDiffer(svgBaseline, svgBoosted, 3),
"SVG fill must be tinted under boost (sanity)"
);
// Headline assertion: the SVG fill and the CSS background, both starting
// from rgb(51, 54, 57) on the same page, must land at the same colour
// after the boost. A larger gap is the "filtered twice" symptom.
Assert.ok(
pixelsClose(divBoosted, svgBoosted, 4),
`SVG fill drifted from CSS background under boost — likely double-` +
`applied boost on the SVG path. div=${JSON.stringify(
divBoosted
)} svg=${JSON.stringify(svgBoosted)}`
);
});
});
// Same comparison but with `fill="currentColor"` — your reported case. The SVG
// inherits `color` and resolves it via the path frame; the CSS swatch resolves
// via its own frame. Both must land in the same place after one boost pass.
add_task(async function inline_svg_currentcolor_matches_css_under_boost() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
.row { color: rgb(51, 54, 57); }
#div, #svg { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
#div { background-color: currentColor; }
</style>
<div class="row">
<div id="div"></div>
<svg id="svg" width="200" height="200" viewBox="0 0 200 200"
fill="currentColor">
<rect width="200" height="200"/>
</svg>
</div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const divBoosted = await pixelInElement(browser, "#div");
const svgBoosted = await pixelInElement(browser, "#svg");
Assert.ok(
pixelsClose(divBoosted, svgBoosted, 4),
`SVG currentColor fill must match the same-colour CSS swatch after ` +
`boost. div=${JSON.stringify(divBoosted)} svg=${JSON.stringify(
svgBoosted
)}`
);
});
});

View File

@@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// The editor content of <input> / <textarea> sits in a UA-widget shadow tree;
// the boost-exemption logic must treat it as author content. To get a clean
// sample we use textarea (more text area, no themed background overdraw on
// the sample point) with an explicit colour so we know the baseline.
add_task(async function input_text_is_boosted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
textarea {
appearance: none; /* avoid theme repainting over our sample */
background: white;
color: rgb(40, 44, 52);
font: 200px/1 system-ui, sans-serif;
border: none;
padding: 0 20px;
width: 600px;
height: 240px;
}
</style>
<textarea id="t">█</textarea>`;
// Full-block U+2588 again — the centre pixel is the solid foreground colour.
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// The block character sits near the start of the textarea content box.
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#t").getBoundingClientRect();
// Estimate the block's centre: x ≈ left padding + half a glyph width;
// y ≈ vertical centre of the line box.
return {
x: Math.round(r.left + 120),
y: Math.round(r.top + 120),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`editor text must tint with boost; baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
});
});

View File

@@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Invert mode: white must come out dark, black must come out light. A double-
// invert regression (invert applied twice somewhere in the paint pipeline)
// looks like "white stays white" / "black stays black" — which is exactly
// what this test guards.
add_task(async function invert_flips_lightness() {
const html = `
<style>
html, body { margin: 0; padding: 0; }
.swatch { width: 200px; height: 200px; display: inline-block; }
#white { background: white; }
#black { background: black; }
</style>
<div id="white" class="swatch"></div>
<div id="black" class="swatch"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, { accent: 0, inverted: false });
const whiteOff = await pixelInElement(browser, "#white");
const blackOff = await pixelInElement(browser, "#black");
Assert.greater(pxLuma(whiteOff), 240, "baseline white is bright");
Assert.less(pxLuma(blackOff), 16, "baseline black is dark");
await setBoost(browser, { accent: 0, inverted: true });
const whiteOn = await pixelInElement(browser, "#white");
const blackOn = await pixelInElement(browser, "#black");
Assert.less(
pxLuma(whiteOn),
pxLuma(whiteOff),
"white must darken under invert; double-invert would leave it bright"
);
Assert.greater(
pxLuma(blackOn),
pxLuma(blackOff),
"black must lighten under invert (and stay off pure black via the floor)"
);
});
});

View File

@@ -0,0 +1,54 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// CSS `outline` is painted by nsCSSRendering with its own color path. Pin
// that it gets the boost: a thick solid outline must tint when the page is
// boosted (just like a border does), and the sample point inside the outline
// band must move noticeably.
add_task(async function outline_color_is_tinted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#o { width: 200px; height: 200px; margin: 60px;
background: white;
outline: 30px solid rgb(120, 120, 120);
outline-offset: 0; }
</style>
<div id="o"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// Sample inside the outline band on the left side of the element.
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#o").getBoundingClientRect();
return {
x: Math.round(r.left - 15),
y: Math.round(r.top + r.height / 2),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsClose(baseline, { r: 120, g: 120, b: 120 }, 5),
`baseline outline ≈ rgb(120,120,120); got ${JSON.stringify(baseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`outline must tint; baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
});
});

View File

@@ -0,0 +1,57 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// `::placeholder` is an element-backed pseudo inside a text-control's UA
// widget shadow tree. The boost-exemption logic must un-exempt it the same
// way it does the editor's typed text. Use a solid-block character as the
// placeholder so we get a clean foreground sample.
add_task(async function placeholder_is_boosted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
input {
appearance: none;
background: white;
color: rgb(40, 44, 52);
font: 200px/1 system-ui, sans-serif;
border: none;
padding: 0 20px;
width: 600px;
height: 260px;
}
input::placeholder { color: rgb(40, 44, 52); opacity: 1; }
</style>
<input id="i" placeholder="█">`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#i").getBoundingClientRect();
// The placeholder block sits near the left of the input.
return {
x: Math.round(r.left + 120),
y: Math.round(r.top + 130),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`::placeholder must tint with boost; baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
});
});

View File

@@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Generated content (::before/::after) lives in a native-anonymous subtree,
// so IsBoostExemptFrame has historically over-exempted it. This test pins the
// fix: an inline-block ::before with a solid background-color must take the
// page's tint just like a regular element.
add_task(async function pseudo_before_is_boosted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#host::before {
content: "";
display: inline-block;
width: 200px;
height: 200px;
background-color: rgb(120, 120, 120);
}
</style>
<div id="host"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// ::before sits inside the host: sample inside its area (start of host).
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#host").getBoundingClientRect();
return {
x: Math.round(r.left + 100),
y: Math.round(r.top + 100),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsClose(baseline, { r: 120, g: 120, b: 120 }, 4),
`baseline ::before colour ≈ rgb(120,120,120); got ${JSON.stringify(
baseline
)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`::before background must tint with the boost; baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
});
});

View File

@@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// box-shadow is the property where the "alpha byte is contrast for accents but
// must stay opacity for content colours" invariant is most visible. We render
// a thick, fully-opaque box-shadow on a white background and verify (a) it's
// tinted by the boost and (b) the sampled pixel's alpha — after compositing —
// is not the accent's contrast byte bleeding through.
add_task(async function box_shadow_is_tinted_alpha_preserved() {
// Use a solid (alpha = 1.0) shadow colour so we can sample inside the shadow
// band on a white background without dealing with partial transparency.
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#s { width: 100px; height: 100px; margin: 80px; background: white;
box-shadow: 0 80px 0 0 rgb(80, 80, 80); }
</style>
<div id="s"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
const point = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#s").getBoundingClientRect();
// 40px inside the 80px tall shadow band that lives below the box.
return {
x: Math.round(r.left + r.width / 2),
y: Math.round(r.bottom + 40),
};
});
await setBoost(browser, { accent: 0 });
const baseline = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsClose(baseline, { r: 80, g: 80, b: 80 }, 5),
`baseline shadow ≈ rgb(80,80,80); got ${JSON.stringify(baseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelAt(browser, point.x, point.y);
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`box-shadow colour should be tinted; baseline=${JSON.stringify(
baseline
)} boosted=${JSON.stringify(boosted)}`
);
// The compositor combines RGB only; the rendered pixel from drawWindow is
// always alpha=255 because the canvas backing is opaque. The real
// alpha-preservation invariant is enforced as a gtest on the filter
// primitive (TestZenBoostsColorFilter.ShadowAlphaPreserved). Here we just
// assert the visible pixel isn't pathological (e.g., turned transparent).
Assert.equal(boosted.a, 255, "composited shadow pixel has full alpha");
});
});

View File

@@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// `background-image: url(*.svg)` goes through nsImageRenderer's WebRender
// blob path, which is a separate code path from the <img> case. Verify that
// path also has the boost propagated: a div whose background is an SVG image
// must tint just like a div with a CSS background-color of the same value.
add_task(async function svg_background_image_is_boosted() {
const svgSrc = encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">` +
`<rect width="200" height="200" fill="rgb(120, 120, 120)"/>` +
`</svg>`
);
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#css, #bg { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
#css { background-color: rgb(120, 120, 120); }
#bg { background-image: url('data:image/svg+xml;charset=utf-8,${svgSrc}');
background-size: 200px 200px; background-repeat: no-repeat; }
</style>
<div id="css"></div>
<div id="bg"></div>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
for (let i = 0; i < 4; i++) {
await waitForRepaint(browser);
}
await setBoost(browser, { accent: 0 });
const cssBaseline = await pixelInElement(browser, "#css");
const bgBaseline = await pixelInElement(browser, "#bg");
Assert.ok(
pixelsClose(cssBaseline, bgBaseline, 3),
`baseline mismatch: css=${JSON.stringify(
cssBaseline
)} bg-image=${JSON.stringify(bgBaseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const cssBoosted = await pixelInElement(browser, "#css");
const bgBoosted = await pixelInElement(browser, "#bg");
Assert.ok(
pixelsDiffer(bgBaseline, bgBoosted, 3),
"background-image SVG must tint under boost"
);
Assert.ok(
pixelsClose(cssBoosted, bgBoosted, 4),
`SVG background-image must match CSS background-color after boost. ` +
`css=${JSON.stringify(cssBoosted)} bg=${JSON.stringify(bgBoosted)}`
);
});
});

View File

@@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// SVG used as an image (<img src=*.svg>) renders inside its own image document
// with no BrowsingContext, so the boost must be propagated through the
// SVGImageContext + AutoRestoreSVGState plumbing onto the image document's
// PresContext. Compare the painted colour of an <img>-rendered SVG to an
// inline <svg> with the same fill — both should land at the same boosted
// colour after one pass.
add_task(async function svg_as_img_matches_inline_under_boost() {
const svgSrc = encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">` +
`<rect width="200" height="200" fill="rgb(120, 120, 120)"/>` +
`</svg>`
);
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#img, #inline { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
</style>
<img id="img" src="data:image/svg+xml;charset=utf-8,${svgSrc}">
<svg id="inline" width="200" height="200" viewBox="0 0 200 200">
<rect width="200" height="200" fill="rgb(120, 120, 120)"/>
</svg>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
// SVG images are loaded async; give the <img> a few frames to paint.
for (let i = 0; i < 4; i++) {
await waitForRepaint(browser);
}
await setBoost(browser, { accent: 0 });
const imgBaseline = await pixelInElement(browser, "#img");
const inlineBaseline = await pixelInElement(browser, "#inline");
Assert.ok(
pixelsClose(imgBaseline, inlineBaseline, 3),
`baseline mismatch between <img>-svg and inline svg: img=` +
`${JSON.stringify(imgBaseline)} inline=${JSON.stringify(inlineBaseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const imgBoosted = await pixelInElement(browser, "#img");
const inlineBoosted = await pixelInElement(browser, "#inline");
Assert.ok(
pixelsDiffer(imgBaseline, imgBoosted, 3),
"<img>-rendered SVG must tint under boost"
);
Assert.ok(
pixelsClose(imgBoosted, inlineBoosted, 4),
`<img>-rendered SVG must match inline SVG after boost. img=` +
`${JSON.stringify(imgBoosted)} inline=${JSON.stringify(inlineBoosted)}`
);
});
});

View File

@@ -0,0 +1,71 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// SVG paint-server gradients (<linearGradient>) go through SVGGradientFrame
// which threads the host frame into ToDeviceColor for each stop. Coverage
// here pins that threading: a paint-server gradient must tint stops the same
// way a CSS gradient does.
add_task(async function svg_linear_gradient_stops_are_boosted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
</style>
<svg id="g" width="400" height="200" viewBox="0 0 400 200">
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="rgb(180, 60, 60)"/>
<stop offset="100%" stop-color="rgb(60, 60, 180)"/>
</linearGradient>
</defs>
<rect width="400" height="200" fill="url(#grad)"/>
</svg>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
const points = await SpecialPowers.spawn(browser, [], () => {
const r = content.document.querySelector("#g").getBoundingClientRect();
return {
left: {
x: Math.round(r.left + r.width * 0.05),
y: Math.round(r.top + r.height / 2),
},
right: {
x: Math.round(r.left + r.width * 0.95),
y: Math.round(r.top + r.height / 2),
},
};
});
await setBoost(browser, { accent: 0 });
const leftBaseline = await pixelAt(browser, points.left.x, points.left.y);
const rightBaseline = await pixelAt(
browser,
points.right.x,
points.right.y
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const leftBoosted = await pixelAt(browser, points.left.x, points.left.y);
const rightBoosted = await pixelAt(browser, points.right.x, points.right.y);
Assert.ok(
pixelsDiffer(leftBaseline, leftBoosted, 3),
"SVG <linearGradient> first stop must tint"
);
Assert.ok(
pixelsDiffer(rightBaseline, rightBoosted, 3),
"SVG <linearGradient> last stop must tint"
);
Assert.ok(
pixelsDiffer(leftBoosted, rightBoosted, 8),
"SVG <linearGradient> stops must stay distinguishable after boost"
);
});
});

View File

@@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Inline <use href="#symbol"> clones the symbol's content into a shadow tree.
// The clone is native-anonymous, so IsBoostExemptFrame must NOT exempt it
// (that's what the GetContainingShadow carve-out is for). Compare against a
// direct inline rect with the same fill — both must land at the same boosted
// colour, demonstrating the use-clone isn't being skipped.
add_task(async function svg_use_clone_is_boosted_like_direct_inline() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
.swatch { width: 200px; height: 200px; display: inline-block;
vertical-align: top; }
</style>
<svg width="0" height="0" style="position:absolute">
<symbol id="sym" viewBox="0 0 200 200">
<rect width="200" height="200" fill="rgb(120, 120, 120)"/>
</symbol>
</svg>
<svg id="direct" class="swatch" viewBox="0 0 200 200">
<rect width="200" height="200" fill="rgb(120, 120, 120)"/>
</svg>
<svg id="used" class="swatch" viewBox="0 0 200 200">
<use href="#sym"/>
</svg>`;
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, { accent: 0 });
const directBaseline = await pixelInElement(browser, "#direct");
const usedBaseline = await pixelInElement(browser, "#used");
Assert.ok(
pixelsClose(directBaseline, usedBaseline, 3),
`baseline mismatch between direct and used; direct=${JSON.stringify(
directBaseline
)} used=${JSON.stringify(usedBaseline)}`
);
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const directBoosted = await pixelInElement(browser, "#direct");
const usedBoosted = await pixelInElement(browser, "#used");
Assert.ok(
pixelsDiffer(usedBaseline, usedBoosted, 3),
"<use>-cloned content must tint under boost (use-shadow not exempt)"
);
Assert.ok(
pixelsClose(directBoosted, usedBoosted, 4),
`<use> clone must match direct inline rect after boost. direct=` +
`${JSON.stringify(directBoosted)} used=${JSON.stringify(usedBoosted)}`
);
});
});

View File

@@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Verifies that text colour is tinted under a boost. Uses a large solid-colour
// glyph and samples at its geometric centre, where the rendered pixel is fully
// the foreground colour (no anti-aliased blend with the background).
add_task(async function text_color_is_tinted() {
const html = `
<style>
html, body { margin: 0; padding: 0; background: white; }
#t { color: rgb(40, 44, 52); font: 200px/1 system-ui, sans-serif;
display: inline-block; padding: 0 20px; }
</style>
<span id="t">█</span>`;
// Full-block U+2588 fills its glyph cell with the foreground colour, so the
// centre pixel is a clean sample of the painted text colour.
await BrowserTestUtils.withNewTab(dataUrl(html), async browser => {
await waitForRepaint(browser);
await setBoost(browser, { accent: 0 });
const baseline = await pixelInElement(browser, "#t");
await setBoost(browser, {
accent: PAGE_ACCENT,
complementaryRotation: PAGE_COMPLEMENTARY_ROTATION,
});
const boosted = await pixelInElement(browser, "#t");
Assert.ok(
pixelsDiffer(baseline, boosted, 3),
`text colour should be tinted; baseline=${JSON.stringify(baseline)} ` +
`boosted=${JSON.stringify(boosted)}`
);
// The text was clearly darker than white before the boost, and the boost
// preserves perceived luminance roughly, so it must stay darker than its
// (white) background afterwards. A broken filter that inverts the
// luminance direction would flip this.
const bg = await pixelAt(browser, 5, 5);
Assert.greater(
pxLuma(bg),
pxLuma(boosted),
"boosted text must remain darker than its boosted white background"
);
});
});

View File

@@ -5,3 +5,108 @@
const { SelectorComponent } = ChromeUtils.importESModule(
"resource:///modules/zen/boosts/ZenSelectorComponent.sys.mjs"
);
// --- Boost pixel-level test helpers --------------------------------------
//
// Used by browser_boosts_*.js. Each helper documents what regression in the
// boost paint paths it's meant to catch.
// Construct an nscolor in Firefox's ABGR encoding from RGB + the alpha byte.
// The boost backend reuses the alpha byte as the accent's contrast/strength
// (see NS_GET_CONTRAST in nsZenBoostsBackend.cpp), so for boost activation
// use `contrast` as the fourth arg with a typical value of 200.
function nsRGBA(r, g, b, a = 255) {
return (((a >>> 0) << 24) | (b << 16) | (g << 8) | r) >>> 0;
}
// Two animation frames is enough for a BC-field-triggered restyle + repaint
// to settle in our tests; the DidSet handlers in nsZenBCOverrides.cpp
// dispatch a RecascadeSubtree + visual hint that's processed by the next
// refresh tick.
async function waitForRepaint(browser) {
await SpecialPowers.spawn(browser, [], async () => {
await new Promise(r => content.requestAnimationFrame(r));
await new Promise(r => content.requestAnimationFrame(r));
});
}
// Apply (or clear) a boost on the tab's top-level content BrowsingContext.
// Passing accent = 0 clears the boost so a test can sample a no-boost
// baseline and a boosted state on the same loaded page.
async function setBoost(
browser,
{ accent = 0, complementaryRotation = 0, inverted = false } = {}
) {
const bc = browser.browsingContext;
bc.zenBoostsData = accent;
bc.zenBoostsComplementaryRotation = complementaryRotation;
bc.isZenBoostsInverted = inverted;
await waitForRepaint(browser);
}
// Read the RGBA pixel at content coordinates (x, y). Runs in the content
// process so drawWindow targets the real painted output of the tab.
async function pixelAt(browser, x, y) {
return SpecialPowers.spawn(browser, [x, y], async (px, py) => {
const w = content.innerWidth;
const h = content.innerHeight;
const canvas = content.document.createElementNS(
"http://www.w3.org/1999/xhtml",
"canvas"
);
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
ctx.drawWindow(content, 0, 0, w, h, "rgba(0,0,0,0)");
const data = ctx.getImageData(px, py, 1, 1).data;
return { r: data[0], g: data[1], b: data[2], a: data[3] };
});
}
// Sample the centre of the element matching |selector|.
async function pixelInElement(browser, selector) {
const point = await SpecialPowers.spawn(browser, [selector], sel => {
const el = content.document.querySelector(sel);
if (!el) {
throw new Error(`No element matches selector: ${sel}`);
}
const r = el.getBoundingClientRect();
return {
x: Math.round(r.left + r.width / 2),
y: Math.round(r.top + r.height / 2),
};
});
return pixelAt(browser, point.x, point.y);
}
// Coarse RGB-distance threshold for "the colour clearly changed". The boost's
// duotone moves channels by tens of units even for a modest accent; tolerance
// 3 is comfortably below that while ignoring sub-pixel/anti-aliasing noise.
function pixelsDiffer(a, b, tol = 3) {
return (
Math.abs(a.r - b.r) > tol ||
Math.abs(a.g - b.g) > tol ||
Math.abs(a.b - b.b) > tol
);
}
function pixelsClose(a, b, tol = 3) {
return !pixelsDiffer(a, b, tol);
}
// BT.601-ish perceived luminance, integer-valued. Matches the coefficients
// used by InvertColorChannel in the backend, so a test expressing "X stays
// darker than Y after boost" maps to what the user actually perceives.
function pxLuma({ r, g, b }) {
return (r * 54 + g * 183 + b * 19) >> 8;
}
function dataUrl(html) {
return "data:text/html;charset=utf-8," + encodeURIComponent(html);
}
// A "page accent" colour used across the property tests. Strong enough to
// move a mid-grey by tens of units per channel; rotation kept small so the
// duotone stays cohesive.
const PAGE_ACCENT = nsRGBA(80, 120, 200, /*contrast*/ 200);
const PAGE_COMPLEMENTARY_ROTATION = 30;

View File

@@ -14,6 +14,8 @@ support-files = [
["browser_issue_10455.js"]
["browser_issue_12112.js"]
["browser_issue_8699.js"]
["browser_issue_9900.js"]

View File

@@ -4,16 +4,24 @@
"use strict";
add_task(async function test_Issue_10455() {
debugger;
await SpecialPowers.pushPrefEnv({
set: [["browser.tabs.closeWindowWithLastTab", true]],
set: [
["browser.tabs.closeWindowWithLastTab", true],
["zen.testing.enabled", false],
["zen.window-sync.enabled", false],
],
});
debugger;
let newWindow = await BrowserTestUtils.openNewBrowserWindow();
await newWindow.gZenWorkspaces.promiseInitialized;
const unloadEvent = BrowserTestUtils.waitForEvent(newWindow, "unload");
Assert.equal(
newWindow.gBrowser.tabs.length,
3,
"New window should have three tabs"
);
newWindow.BrowserCommands.closeTabOrWindow();
newWindow.BrowserCommands.closeTabOrWindow();
await unloadEvent;
@@ -22,14 +30,23 @@ add_task(async function test_Issue_10455() {
});
add_task(async function test_Issue_10455_Dont_Close() {
debugger;
await SpecialPowers.pushPrefEnv({
set: [["browser.tabs.closeWindowWithLastTab", false]],
set: [
["browser.tabs.closeWindowWithLastTab", false],
["zen.testing.enabled", false],
["zen.window-sync.enabled", false],
],
});
let newWindow = await BrowserTestUtils.openNewBrowserWindow();
await newWindow.gZenWorkspaces.promiseInitialized;
Assert.equal(
newWindow.gBrowser.tabs.length,
3,
"New window should have three tabs"
);
newWindow.BrowserCommands.closeTabOrWindow();
newWindow.BrowserCommands.closeTabOrWindow();
Assert.strictEqual(
newWindow.gBrowser.tabs.length,

View File

@@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [["zen.urlbar.replace-newtab", false]],
});
registerCleanupFunction(async () => {
await SpecialPowers.popPrefEnv();
});
});
add_task(
async function test_focuses_urlbar_on_startup_without_replace_newtab() {
await gZenWorkspaces.promiseInitialized;
Assert.ok(
!gZenVerticalTabsManager._canReplaceNewTab,
"Precondition: zen.urlbar.replace-newtab is disabled"
);
const originalTab = gBrowser.selectedTab;
const originalOpenLocation = window.openLocation;
const originalTestingEnabled = gZenUIManager.testingEnabled;
let openLocationCalls = 0;
window.openLocation = () => {
openLocationCalls++;
};
// selectStartPage() and selectEmptyTab() are both no-ops while testing mode
// is enabled; temporarily disable it to exercise the real startup path.
gZenUIManager.testingEnabled = false;
// The tab the startup page leaves selected, which Zen wants to replace.
const tabToRemove = BrowserTestUtils.addTab(gBrowser, "about:blank", {
skipAnimation: true,
});
gBrowser.selectedTab = tabToRemove;
gZenWorkspaces._tabToRemoveForEmpty = tabToRemove;
delete gZenWorkspaces._tabToSelect;
delete gZenWorkspaces._shouldOverrideTabs;
delete gZenWorkspaces._initialTab;
try {
await gZenWorkspaces.selectStartPage();
await TestUtils.waitForCondition(
() => openLocationCalls > 0,
"openLocation() should be called to focus the address bar"
);
Assert.equal(
openLocationCalls,
1,
"The address bar was focused via openLocation()"
);
Assert.ok(
!gBrowser.selectedTab.hasAttribute("zen-empty-tab"),
"A fallback homepage tab is selected (no zen-empty-tab attribute), so " +
"the focus decision came from initialTabWasEmpty, not shownEmptyTab"
);
Assert.ok(
!gBrowser.tabs.includes(tabToRemove),
"The empty tab added by the startup page was removed"
);
} finally {
window.openLocation = originalOpenLocation;
gZenUIManager.testingEnabled = originalTestingEnabled;
delete gZenWorkspaces._tabToRemoveForEmpty;
// Remove any tab created by the startup path, then restore the original.
for (const tab of [...gBrowser.tabs]) {
if (tab !== originalTab && !tab.hasAttribute("zen-empty-tab")) {
BrowserTestUtils.removeTab(tab);
}
}
if (!originalTab.closing) {
gBrowser.selectedTab = originalTab;
}
}
}
);

View File

@@ -5,7 +5,10 @@
add_task(async function test_Private_Mode() {
await SpecialPowers.pushPrefEnv({
set: [["privacy.userContext.enabled", true]],
set: [
["privacy.userContext.enabled", true],
["zen.testing.enabled", false],
],
});
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({
@@ -13,6 +16,11 @@ add_task(async function test_Private_Mode() {
});
await privateWindow.gZenWorkspaces.promiseInitialized;
Assert.ok(
privateWindow.gBrowser.selectedTab.hasAttribute("zen-empty-tab"),
"Private window should start with a zen empty tab"
);
await BrowserTestUtils.closeWindow(privateWindow);
await SpecialPowers.popPrefEnv();
});

View File

@@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
prefs = ["browser.urlbar.closeOnWindowBlur=false"]
support-files = [
"head.js",
"!/browser/components/urlbar/tests/browser/head.js",

View File

@@ -9,27 +9,24 @@ ChromeUtils.defineESModuleGetters(this, {
add_task(async function test_Selection_Remains_Double_Toolbar() {
await goToMultipleLayouts(async () => {
const untrimmedValue = "https://example.com";
const untrimmedValue = "https://example.com/";
let trimmedValue = UrlbarTestUtils.trimURL(untrimmedValue);
gURLBar._setValue(untrimmedValue, {
allowTrim: true,
valueIsTyped: false,
});
gURLBar.blur();
await SimpleTest.promiseFocus(window);
Assert.equal(gURLBar.value, trimmedValue, "Value has been trimmed");
await selectWithMouseDrag(100, 200);
await BrowserTestUtils.withNewTab(untrimmedValue, async () => {
Assert.equal(gURLBar.value, trimmedValue, "Value has been trimmed");
await selectWithMouseDrag(10, 20);
Assert.greater(gURLBar.selectionStart, 0, "Selection start is positive.");
Assert.greater(
gURLBar.selectionEnd,
gURLBar.selectionStart,
"Selection is not empty."
);
Assert.greater(gURLBar.selectionStart, 0, "Selection start is positive.");
Assert.greater(
gURLBar.selectionEnd,
gURLBar.selectionStart,
"Selection is not empty."
);
Assert.equal(gURLBar.value, untrimmedValue, `Value should be untrimmed`);
Assert.equal(gURLBar.value, untrimmedValue, `Value should be untrimmed`);
gURLBar.handleRevert();
gURLBar.view.close();
gURLBar.handleRevert();
gURLBar.view.close();
});
});
});

View File

@@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.defineESModuleGetters(this, {
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs",
});
const PAGE_URL = "https://example.com/";
const TYPED_VALUE = "zen blur revert test";
async function typeIntoUrlbar() {
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: TYPED_VALUE,
fireInputEvent: true,
});
Assert.equal(
gURLBar.value,
TYPED_VALUE,
"The typed value is present while the address bar is focused"
);
}
add_task(async function test_single_toolbar_reverts_typed_value_on_blur() {
await TestUtils.waitForCondition(
() => gZenVerticalTabsManager._hasSetSingleToolbar,
"The default layout should be single-toolbar"
);
await BrowserTestUtils.withNewTab(PAGE_URL, async () => {
await typeIntoUrlbar();
await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur());
await SimpleTest.promiseFocus(window);
await new Promise(resolve => setTimeout(resolve));
await TestUtils.waitForCondition(
() => gURLBar.value !== TYPED_VALUE,
"The address bar should revert away from the typed value on blur"
);
Assert.ok(
gURLBar.value.includes("example.com"),
`Reverted to the page URL (got "${gURLBar.value}")`
);
Assert.notEqual(
gURLBar.value,
TYPED_VALUE,
"Single-toolbar blur did not retain the typed value"
);
});
gURLBar.handleRevert();
});
add_task(async function test_double_toolbar_keeps_typed_value_on_blur() {
await SpecialPowers.pushPrefEnv({
set: [["zen.view.use-single-toolbar", false]],
});
await TestUtils.waitForCondition(
() => !gZenVerticalTabsManager._hasSetSingleToolbar,
"The layout should switch to double-toolbar"
);
await BrowserTestUtils.withNewTab(PAGE_URL, async () => {
await typeIntoUrlbar();
await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur());
await SimpleTest.promiseFocus(window);
Assert.equal(
gURLBar.value,
TYPED_VALUE,
"Double-toolbar blur keeps the typed value (no forced revert)"
);
});
gURLBar.handleRevert();
await SpecialPowers.popPrefEnv();
});

View File

@@ -250,12 +250,12 @@ export class nsZenSiteDataPanel {
const boostButton = this.document.getElementById("zen-site-data-boost");
if (!canBoostSite) {
boostButton.removeAttribute("boosting");
}
if (!canBoostSite) {
boostButton.setAttribute("disabled", "true");
return;
}
boostButton.removeAttribute("disabled");
if (lazy.gZenBoostsManager.registeredBoostForDomain(domain)) {
boostButton.setAttribute("boosting", "true");
} else {

View File

@@ -5,8 +5,8 @@
"binaryName": "zen",
"version": {
"product": "firefox",
"version": "151.0.2",
"candidate": "151.0.2",
"version": "151.0.3",
"candidate": "151.0.3",
"candidateBuild": 1
},
"buildOptions": {
@@ -20,7 +20,7 @@
"brandShortName": "Zen",
"brandFullName": "Zen Browser",
"release": {
"displayVersion": "1.20.1b",
"displayVersion": "1.20.2b",
"github": {
"repo": "zen-browser/desktop"
},
@@ -54,4 +54,4 @@
"licenseType": "MPL-2.0"
},
"updateHostname": "updates.zen-browser.app"
}
}