From 7f00a16d6d6f9f31261ee81dffc23d3f5d36d739 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:14:38 +0200 Subject: [PATCH 001/149] gh-12973: Fixed compact mode toggle being always checked (gh-12977) --- src/zen/common/styles/zen-omnibox.css | 2 +- src/zen/compact-mode/ZenCompactMode.mjs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index 8b8bc51e5..ba321e429 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -268,7 +268,7 @@ background-color: var(--zen-urlbar-background-transparent, var(--zen-urlbar-background-base)) !important; box-shadow: 0 30px 140px -15px light-dark(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.6)) !important; backdrop-filter: none !important; - outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)) !important; + outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.2)) !important; outline-offset: var(--zen-urlbar-outline-offset) !important; /* stylelint-disable-next-line media-query-no-invalid */ diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index c0c40036b..19b0abd68 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -590,7 +590,7 @@ window.gZenCompactModeManager = { if (!toggle) { return; } - toggle.setAttribute("checked", this.preference); + toggle.toggleAttribute("checked", this.preference); const hideTabBar = this.canHideSidebar; const hideToolbar = this.canHideToolbar; @@ -600,9 +600,9 @@ window.gZenCompactModeManager = { const sidebarItem = document.getElementById(idName + "sidebar"); const toolbarItem = document.getElementById(idName + "toolbar"); const bothItem = document.getElementById(idName + "both"); - sidebarItem.setAttribute("checked", !hideBoth && hideTabBar); - toolbarItem.setAttribute("checked", !hideBoth && hideToolbar); - bothItem.setAttribute("checked", hideBoth); + sidebarItem.toggleAttribute("checked", !hideBoth && hideTabBar); + toolbarItem.toggleAttribute("checked", !hideBoth && hideToolbar); + bothItem.toggleAttribute("checked", hideBoth); }, _removeOpenStateOnUnifiedExtensions() { From ec2864902ce7120146b4fa2fdef6f6fea754c09b Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:32:27 +0200 Subject: [PATCH 002/149] gh-8206: Respect reduce motion more and dont block switch animations (gh-12980) --- src/zen/common/modules/ZenUIManager.mjs | 1 + src/zen/spaces/ZenSpaceCreation.mjs | 70 +++++++++++++------------ src/zen/spaces/ZenSpaceManager.mjs | 24 +++++++-- src/zen/tabs/zen-tabs/vertical-tabs.css | 12 +++-- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/zen/common/modules/ZenUIManager.mjs b/src/zen/common/modules/ZenUIManager.mjs index c5b64643d..5a3826d2f 100644 --- a/src/zen/common/modules/ZenUIManager.mjs +++ b/src/zen/common/modules/ZenUIManager.mjs @@ -1014,6 +1014,7 @@ window.gZenVerticalTabsManager = { animateItemOpen(aItem) { if ( + gReduceMotion || !gZenUIManager.motion || !aItem || !gZenUIManager._hasLoadedDOM || diff --git a/src/zen/spaces/ZenSpaceCreation.mjs b/src/zen/spaces/ZenSpaceCreation.mjs index 69b8316cf..18243b48d 100644 --- a/src/zen/spaces/ZenSpaceCreation.mjs +++ b/src/zen/spaces/ZenSpaceCreation.mjs @@ -199,25 +199,27 @@ class nsZenWorkspaceCreation extends MozXULElement { this.style.visibility = "visible"; gZenCompactModeManager.getAndApplySidebarWidth(); this.resolveInitialized(); - gZenUIManager.motion - .animate( - this.elementsToAnimate, - { - y: [20, 0], - opacity: [0, 1], - filter: ["blur(2px)", "blur(0)"], - }, - { - duration: 0.6, - type: "spring", - bounce: 0, - delay: gZenUIManager.motion.stagger(0.05, { startDelay: 0.2 }), - } - ) - .then(() => { - this.inputName.focus(); - gZenWorkspaces.workspaceElement(this.workspaceId).hidden = false; - }); + let animation = gZenUIManager.motion.animate( + this.elementsToAnimate, + { + y: [20, 0], + opacity: [0, 1], + filter: ["blur(2px)", "blur(0)"], + }, + { + duration: 0.6, + type: "spring", + bounce: 0, + delay: gZenUIManager.motion.stagger(0.05, { startDelay: 0.2 }), + } + ); + if (gReduceMotion) { + animation.complete(); + } + animation.then(() => { + this.inputName.focus(); + gZenWorkspaces.workspaceElement(this.workspaceId).hidden = false; + }); }); } @@ -303,20 +305,22 @@ class nsZenWorkspaceCreation extends MozXULElement { } async #cleanup() { - await gZenUIManager.motion.animate( - this.elementsToAnimate.reverse(), - { - y: [0, 20], - opacity: [1, 0], - filter: ["blur(0)", "blur(2px)"], - }, - { - duration: 0.4, - type: "spring", - bounce: 0, - delay: gZenUIManager.motion.stagger(0.05), - } - ); + if (!gReduceMotion) { + await gZenUIManager.motion.animate( + this.elementsToAnimate.reverse(), + { + y: [0, 20], + opacity: [1, 0], + filter: ["blur(0)", "blur(2px)"], + }, + { + duration: 0.4, + type: "spring", + bounce: 0, + delay: gZenUIManager.motion.stagger(0.05), + } + ); + } document.getElementById("zen-sidebar-splitter").style.pointerEvents = ""; diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs index 6b8dd64d1..b58acc44f 100644 --- a/src/zen/spaces/ZenSpaceManager.mjs +++ b/src/zen/spaces/ZenSpaceManager.mjs @@ -44,6 +44,10 @@ class nsZenWorkspaces { _workspaceCache = []; #lastScrollTime = 0; + #currentSpaceSwitchContext = { + promise: null, + animations: [], + }; bookmarkMenus = [ "PlacesToolbar", @@ -1631,9 +1635,18 @@ class nsZenWorkspaces { } async changeWorkspace(workspace, ...args) { - if (!this.workspaceEnabled || this.#inChangingWorkspace) { + if (!this.workspaceEnabled) { return; } + this.#currentSpaceSwitchContext.animations.forEach(animation => { + animation.complete(); + }); + await this.#currentSpaceSwitchContext.promise; + let { resolve, promise } = Promise.withResolvers(); + this.#currentSpaceSwitchContext = { + promise, + animations: [], + }; this.#inChangingWorkspace = true; try { this.log("Changing workspace to", workspace?.uuid); @@ -1642,10 +1655,11 @@ class nsZenWorkspaces { console.error("gZenWorkspaces: Error changing workspace", e); } this.#inChangingWorkspace = false; + resolve(); } _cancelSwipeAnimation() { - this._animateTabs(this.getActiveWorkspaceFromCache(), true); + this.#animateTabs(this.getActiveWorkspaceFromCache(), true); } async #performWorkspaceChange( @@ -1923,7 +1937,7 @@ class nsZenWorkspaces { } /* eslint-disable complexity */ - async _animateTabs( + async #animateTabs( newWorkspace, shouldAnimate, tabToSelect = null, @@ -2253,12 +2267,14 @@ class nsZenWorkspaces { let promiseTimeout = new Promise(resolve => setTimeout(resolve, kGlobalAnimationDuration * 1000 + 50) ); + this.#currentSpaceSwitchContext.animations = animations; // See issue https://github.com/zen-browser/desktop/issues/9334, we need to add // some sort of timeout to the animation promise, just in case it gets stuck. // We are doing a race between the timeout and the animations finishing. await Promise.race([Promise.all(animations), promiseTimeout]).catch( console.error ); + this.#currentSpaceSwitchContext.animations = []; document.documentElement.removeAttribute("animating-background"); if (shouldAnimate) { for (const cloned of clonedEssentials) { @@ -2420,7 +2436,7 @@ class nsZenWorkspaces { gZenUIManager.tabsWrapper.scrollbarWidth = "none"; this.workspaceIcons.activeIndex = workspace.uuid; - await this._animateTabs( + await this.#animateTabs( workspace, !onInit && !this._animatingChange, tabToSelect, diff --git a/src/zen/tabs/zen-tabs/vertical-tabs.css b/src/zen/tabs/zen-tabs/vertical-tabs.css index 027a1997c..6fd06719a 100644 --- a/src/zen/tabs/zen-tabs/vertical-tabs.css +++ b/src/zen/tabs/zen-tabs/vertical-tabs.css @@ -310,11 +310,13 @@ } & .tabbrowser-tab { - &, - & .tab-content > image { - transition: - scale 0.2s ease, - var(--zen-tabbox-element-indent-transition); + @media not (prefers-reduced-motion: reduce) { + &, + & .tab-content > image { + transition: + scale 0.2s ease, + var(--zen-tabbox-element-indent-transition); + } } :root[zen-sidebar-expanded="true"] &:not([zen-glance-tab]) { From 8fec3702f461d1c43492c30d56979dc004682fac Mon Sep 17 00:00:00 2001 From: Rugved_018 Date: Sun, 29 Mar 2026 19:14:03 +0530 Subject: [PATCH 003/149] gh-12104: Fix notification tabs overlap (gh-12965) Co-authored-by: mr. m --- src/zen/common/modules/ZenStartup.mjs | 13 ++++---- src/zen/common/styles/zen-omnibox.css | 26 --------------- .../common/styles/zen-single-components.css | 33 +++++++++++++++++++ 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/zen/common/modules/ZenStartup.mjs b/src/zen/common/modules/ZenStartup.mjs index e9c7fa1c6..bfa20f596 100644 --- a/src/zen/common/modules/ZenStartup.mjs +++ b/src/zen/common/modules/ZenStartup.mjs @@ -46,14 +46,13 @@ class ZenStartup { } newContainer.appendChild(node); } - // Fix notification deck - const deckTemplate = document.getElementById( - "tab-notification-deck-template" - ); - if (deckTemplate) { - document.getElementById("zen-appcontent-wrapper").prepend(deckTemplate); - } + const deckTemplate = + document.getElementById("tab-notification-deck-template") || + document.getElementById("tab-notification-deck"); + + // overlap and interaction issues with vertical tabs + document.getElementById("browser").prepend(deckTemplate); gZenWorkspaces.init(); setTimeout(() => { diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index ba321e429..fa6171568 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -404,32 +404,6 @@ min-width: 26px; } -/* Notification Stack */ - -.notificationbox-stack { - background: transparent; - - &[notificationside="top"] { - position: fixed; - bottom: calc(var(--zen-element-separation) * 1.5); - right: calc(var(--zen-element-separation) * 1.5); - width: fit-content; - max-width: 30rem !important; - z-index: 9999; - - & notification-message { - background: color-mix(in srgb, var(--zen-colors-tertiary) 70%, transparent 30%); - backdrop-filter: blur(10px); - border: 1px solid var(--arrowpanel-border-color); - border-radius: var(--zen-border-radius); - - &::before { - display: none; - } - } - } -} - #nav-bar, #zen-sidebar-top-buttons { min-height: var(--zen-toolbar-height) !important; diff --git a/src/zen/common/styles/zen-single-components.css b/src/zen/common/styles/zen-single-components.css index 8d7d17f0f..f40e64210 100644 --- a/src/zen/common/styles/zen-single-components.css +++ b/src/zen/common/styles/zen-single-components.css @@ -650,3 +650,36 @@ gap: 4px; } } + + +/* Notification Stack */ + +.notificationbox-stack { + background: transparent; + + &[notificationside="top"] { + position: fixed; + bottom: calc(var(--zen-element-separation) * 1.5); + right: calc(var(--zen-element-separation) * 1.5); + + :root[zen-right-side="true"] & { + right: auto; + left: calc(var(--zen-element-separation) * 1.5); + } + + width: fit-content; + max-width: 30rem !important; + z-index: 9999; + + & notification-message { + background: color-mix(in srgb, var(--zen-colors-tertiary) 70%, transparent 30%); + backdrop-filter: blur(10px); + border: 1px solid var(--arrowpanel-border-color); + border-radius: var(--zen-border-radius); + + &::before { + display: none; + } + } + } +} From 595f236a7a83e45e1b0ced7deaafc84f2d41dca6 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 29 Mar 2026 18:59:15 +0200 Subject: [PATCH 004/149] gh-12989: Make split command use context tabs (gh-12990) --- src/zen/split-view/ZenViewSplitter.mjs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zen/split-view/ZenViewSplitter.mjs b/src/zen/split-view/ZenViewSplitter.mjs index 40d0053f9..85afd37d6 100644 --- a/src/zen/split-view/ZenViewSplitter.mjs +++ b/src/zen/split-view/ZenViewSplitter.mjs @@ -1237,7 +1237,12 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature { * Splits the selected tabs. */ contextSplitTabs() { - const tabs = window.gBrowser.selectedTabs; + let tabs; + if (TabContextMenu.contextTab.multiselected) { + tabs = gBrowser.selectedTabs; + } else { + tabs = [TabContextMenu.contextTab]; + } // If any is already in a split view, we unsplit them first if (tabs.some(tab => tab.splitView)) { for (const tab of tabs) { From 3fd89a93f5dda8ac55a6b499da0ffbe2b8aa6c6a Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 29 Mar 2026 19:20:11 +0200 Subject: [PATCH 005/149] no-bug: Move live folder context menu item to the toolbar menu (gh-12991) --- .../base/content/zen-panels/popups.inc | 17 ----------------- src/zen/common/modules/ZenUIManager.mjs | 2 +- src/zen/compact-mode/ZenCompactMode.mjs | 2 +- src/zen/folders/ZenFolders.mjs | 19 ++++++++++++++++++- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/browser/base/content/zen-panels/popups.inc b/src/browser/base/content/zen-panels/popups.inc index c79bf726b..c888a26c2 100644 --- a/src/browser/base/content/zen-panels/popups.inc +++ b/src/browser/base/content/zen-panels/popups.inc @@ -3,23 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - diff --git a/src/zen/common/modules/ZenUIManager.mjs b/src/zen/common/modules/ZenUIManager.mjs index 5a3826d2f..e26abe4db 100644 --- a/src/zen/common/modules/ZenUIManager.mjs +++ b/src/zen/common/modules/ZenUIManager.mjs @@ -999,7 +999,7 @@ window.gZenVerticalTabsManager = { command="cmd_zenToggleTabsOnRight" /> `); - document.getElementById("viewToolbarsMenuSeparator").before(fragment); + document.getElementById("toolbar-context-customize").before(fragment); }, get _topButtonsSeparatorElement() { diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index 19b0abd68..ae6424fe3 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -247,7 +247,7 @@ window.gZenCompactModeManager = { } } - document.getElementById("viewToolbarsMenuSeparator").before(fragment); + document.getElementById("toolbar-context-customize").before(fragment); this.updateContextMenu(); }, diff --git a/src/zen/folders/ZenFolders.mjs b/src/zen/folders/ZenFolders.mjs index ffb57831e..f3183c76f 100644 --- a/src/zen/folders/ZenFolders.mjs +++ b/src/zen/folders/ZenFolders.mjs @@ -70,7 +70,24 @@ class nsZenFolders extends nsZenDOMOperatedFeature { ); document.getElementById("context_moveTabToGroup").before(contextMenuItems); const contextMenuItemsToolbar = window.MozXULElement.parseXULToFragment( - `` + ` + + + + + + + + ` ); document .getElementById("toolbar-context-openANewTab") From 2d6f2cbbde1516fa6991b0d94106ea9a2ad505c0 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:26:34 +0200 Subject: [PATCH 006/149] gh-12994: Fixed adress bar not being aligned with the container (gh-12997) --- src/browser/themes/shared/urlbar-searchbar-css.patch | 4 ++-- src/zen/common/styles/zen-omnibox.css | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/browser/themes/shared/urlbar-searchbar-css.patch b/src/browser/themes/shared/urlbar-searchbar-css.patch index 416f79f84..9af6e9d75 100644 --- a/src/browser/themes/shared/urlbar-searchbar-css.patch +++ b/src/browser/themes/shared/urlbar-searchbar-css.patch @@ -1,5 +1,5 @@ diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css -index cbbf55f31ae5e456401172f79ddbbe41256025a4..8cab0f2809a43c0aa4249453732eb0e006c2c676 100644 +index cbbf55f31ae5e456401172f79ddbbe41256025a4..dc471dfe30dedf7c4917322a5b2257a9ec9c4f90 100644 --- a/browser/themes/shared/urlbar-searchbar.css +++ b/browser/themes/shared/urlbar-searchbar.css @@ -10,7 +10,7 @@ @@ -25,7 +25,7 @@ index cbbf55f31ae5e456401172f79ddbbe41256025a4..8cab0f2809a43c0aa4249453732eb0e0 .urlbar[breakout][breakout-extend] { height: auto; + align-items: center; -+ :root:not([zen-single-toolbar='true']) { ++ :root:not([zen-single-toolbar='true']) & { margin-left: calc(-1 * var(--urlbar-margin-inline)); + } width: calc(var(--urlbar-width) + 2 * var(--urlbar-margin-inline)); diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index fa6171568..1619a6b38 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -682,7 +682,8 @@ } #identity-box { - margin-inline-end: 0; + margin-inline-end: 3px !important; + margin-inline-start: 2px !important; } } From a2796d7af002ce8a398b0845fa1e9145b20add87 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:14:23 +0200 Subject: [PATCH 007/149] gh-9600: Fixed text being unreadable with some themes (gh-12998) --- src/zen/common/styles/schemes/dark.inc.css | 1 - src/zen/common/styles/schemes/light.inc.css | 1 - src/zen/spaces/ZenGradientGenerator.mjs | 4 ++++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zen/common/styles/schemes/dark.inc.css b/src/zen/common/styles/schemes/dark.inc.css index 032dd757d..9b20f1a6a 100644 --- a/src/zen/common/styles/schemes/dark.inc.css +++ b/src/zen/common/styles/schemes/dark.inc.css @@ -3,5 +3,4 @@ % file, You can obtain one at http://mozilla.org/MPL/2.0/. color-scheme: dark; ---toolbar-color-scheme: dark; --zen-urlbar-outline-offset: -2px; diff --git a/src/zen/common/styles/schemes/light.inc.css b/src/zen/common/styles/schemes/light.inc.css index a3c18d0fd..d010f2f19 100644 --- a/src/zen/common/styles/schemes/light.inc.css +++ b/src/zen/common/styles/schemes/light.inc.css @@ -3,5 +3,4 @@ % file, You can obtain one at http://mozilla.org/MPL/2.0/. color-scheme: light; ---toolbar-color-scheme: light; --zen-urlbar-outline-offset: 0px; diff --git a/src/zen/spaces/ZenGradientGenerator.mjs b/src/zen/spaces/ZenGradientGenerator.mjs index e6d926bc7..c4ebebf78 100644 --- a/src/zen/spaces/ZenGradientGenerator.mjs +++ b/src/zen/spaces/ZenGradientGenerator.mjs @@ -1753,6 +1753,10 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature { "--toolbox-textcolor", `rgba(${textColor[0]}, ${textColor[1]}, ${textColor[2]}, ${textColor[3]})` ); + docElement.style.setProperty( + "--toolbar-color-scheme", + isDarkMode ? "dark" : "light" + ); } if (!skipUpdate) { From 742a1e688223ccc17e09b914dbf3a242c8ecc442 Mon Sep 17 00:00:00 2001 From: Davide Taffarello <78680412+TheSilvered@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:15:25 +0200 Subject: [PATCH 008/149] gh-12730: conflict keybord shortcut name always shows "Escape" (gh-12993) Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> --- src/browser/components/preferences/zen-settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/components/preferences/zen-settings.js b/src/browser/components/preferences/zen-settings.js index 4541bf90a..16ddcbc63 100644 --- a/src/browser/components/preferences/zen-settings.js +++ b/src/browser/components/preferences/zen-settings.js @@ -1067,7 +1067,7 @@ var gZenCKSSettings = { zenMissingKeyboardShortcutL10n[conflictShortcut.getID()] ?? conflictShortcut.getL10NID(); - const [group] = await document.l10n.formatValues([ + const [group, conflictName] = await document.l10n.formatValues([ { id: `${ZEN_CKS_GROUP_PREFIX}-${conflictShortcut.getGroup()}` }, { id: shortcutL10nKey }, ]); @@ -1082,7 +1082,7 @@ var gZenCKSSettings = { document.l10n.setAttributes(input.nextElementSibling, "zen-key-conflict", { group: group ?? "", - shortcut: shortcut ?? "", + shortcut: conflictName ?? shortcut ?? "", }); } } else { From be9928beda60ef424ede00aeed667cb7ea851b7c Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Mon, 30 Mar 2026 17:34:32 +0200 Subject: [PATCH 009/149] no-bug: Prevent focusing the urlbar on tab switch (gh-13002) --- .../components/tabbrowser/content/tabbrowser-js.patch | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index f3d858c99..f671b2632 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js -index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..d9491b680bf8839038dadc0c6ee52f81a655e998 100644 +index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..be4bedce98f404325e547dd8a4e73e895b6025b0 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -413,6 +413,7 @@ @@ -186,6 +186,15 @@ index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..d9491b680bf8839038dadc0c6ee52f81 // If focus is on the old tab, move it to the new tab. if (activeEl == oldTab) { newTab.focus(); +@@ -1822,7 +1902,7 @@ + // Focus the location bar if it was previously focused for that tab. + // In full screen mode, only bother making the location bar visible + // if the tab is a blank one. +- if (gURLBar.getBrowserState(newBrowser).urlbarFocused) { ++ if (gURLBar.getBrowserState(newBrowser).urlbarFocused && !gZenVerticalTabsManager._hasSetSingleToolbar) { + let selectURL = () => { + if (this._asyncTabSwitching) { + // Set _awaitingSetURI flag to suppress popup notification @@ -2110,7 +2190,12 @@ return this._setTabLabel(aTab, aLabel); } From 067b8244ecf823c77db23ad9bd6f42ba0c0b5d0c Mon Sep 17 00:00:00 2001 From: Tyson Cung <45380903+tysoncung@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:42:00 +0800 Subject: [PATCH 010/149] gh-12966: rename split view tab labels for clarity (gh-12983) Co-authored-by: Tyson Cung --- locales/bg/browser/browser/zen-split-view.ftl | 4 ++-- locales/bs/browser/browser/zen-split-view.ftl | 4 ++-- locales/en-GB/browser/browser/zen-split-view.ftl | 4 ++-- locales/en-US/browser/browser/zen-split-view.ftl | 6 +++--- locales/eu/browser/browser/zen-split-view.ftl | 6 +++--- locales/fa/browser/browser/zen-split-view.ftl | 4 ++-- locales/it/browser/browser/zen-split-view.ftl | 2 +- locales/nn-NO/browser/browser/zen-split-view.ftl | 4 ++-- locales/ro/browser/browser/zen-split-view.ftl | 4 ++-- locales/sk/browser/browser/zen-split-view.ftl | 4 ++-- locales/th/browser/browser/zen-split-view.ftl | 4 ++-- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/locales/bg/browser/browser/zen-split-view.ftl b/locales/bg/browser/browser/zen-split-view.ftl index e7cb9c67b..8fbcd79c2 100644 --- a/locales/bg/browser/browser/zen-split-view.ftl +++ b/locales/bg/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/bs/browser/browser/zen-split-view.ftl b/locales/bs/browser/browser/zen-split-view.ftl index 10593eed9..743688eed 100644 --- a/locales/bs/browser/browser/zen-split-view.ftl +++ b/locales/bs/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/en-GB/browser/browser/zen-split-view.ftl b/locales/en-GB/browser/browser/zen-split-view.ftl index 3593d390b..97d65b70a 100644 --- a/locales/en-GB/browser/browser/zen-split-view.ftl +++ b/locales/en-GB/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/en-US/browser/browser/zen-split-view.ftl b/locales/en-US/browser/browser/zen-split-view.ftl index 86090453a..8e9aaaed5 100644 --- a/locales/en-US/browser/browser/zen-split-view.ftl +++ b/locales/en-US/browser/browser/zen-split-view.ftl @@ -5,9 +5,9 @@ tab-zen-split-tabs = .label = { $tabCount -> - [-1] Unsplit Tabs - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [-1] Split out tab + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S diff --git a/locales/eu/browser/browser/zen-split-view.ftl b/locales/eu/browser/browser/zen-split-view.ftl index 0cf9037a1..a83fc33d2 100644 --- a/locales/eu/browser/browser/zen-split-view.ftl +++ b/locales/eu/browser/browser/zen-split-view.ftl @@ -5,9 +5,9 @@ tab-zen-split-tabs = .label = { $tabCount -> - [-1] Unsplit Tabs - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [-1] Split out tab + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/fa/browser/browser/zen-split-view.ftl b/locales/fa/browser/browser/zen-split-view.ftl index c9d226f89..bfcdba4dd 100644 --- a/locales/fa/browser/browser/zen-split-view.ftl +++ b/locales/fa/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/it/browser/browser/zen-split-view.ftl b/locales/it/browser/browser/zen-split-view.ftl index e0958b3ce..31a8ad7a5 100644 --- a/locales/it/browser/browser/zen-split-view.ftl +++ b/locales/it/browser/browser/zen-split-view.ftl @@ -6,7 +6,7 @@ tab-zen-split-tabs = .label = { $tabCount -> [1] Split Tab (sono necessarie più schede selezionate) - *[other] Split { $tabCount } Tabs + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/nn-NO/browser/browser/zen-split-view.ftl b/locales/nn-NO/browser/browser/zen-split-view.ftl index 10593eed9..743688eed 100644 --- a/locales/nn-NO/browser/browser/zen-split-view.ftl +++ b/locales/nn-NO/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/ro/browser/browser/zen-split-view.ftl b/locales/ro/browser/browser/zen-split-view.ftl index 10593eed9..743688eed 100644 --- a/locales/ro/browser/browser/zen-split-view.ftl +++ b/locales/ro/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/sk/browser/browser/zen-split-view.ftl b/locales/sk/browser/browser/zen-split-view.ftl index fb145b79e..3c7f07d8b 100644 --- a/locales/sk/browser/browser/zen-split-view.ftl +++ b/locales/sk/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = diff --git a/locales/th/browser/browser/zen-split-view.ftl b/locales/th/browser/browser/zen-split-view.ftl index 10593eed9..743688eed 100644 --- a/locales/th/browser/browser/zen-split-view.ftl +++ b/locales/th/browser/browser/zen-split-view.ftl @@ -5,8 +5,8 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Split Tab (multiple selected tabs needed) - *[other] Split { $tabCount } Tabs + [1] Join Tab (multiple selected tabs needed) + *[other] Join { $tabCount } Tabs } .accesskey = S zen-split-link = From 62286a27587c8d74ea75aea1ef1dd911249435dc Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:46:03 +0200 Subject: [PATCH 011/149] gh-13015: Fixed tablist scroll beibg occasionally stuck (gh-13017) --- .../content/widgets/arrowscrollbox-js.patch | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content/widgets/arrowscrollbox-js.patch b/src/toolkit/content/widgets/arrowscrollbox-js.patch index 4f15c2c29..082d496fe 100644 --- a/src/toolkit/content/widgets/arrowscrollbox-js.patch +++ b/src/toolkit/content/widgets/arrowscrollbox-js.patch @@ -1,5 +1,5 @@ diff --git a/toolkit/content/widgets/arrowscrollbox.js b/toolkit/content/widgets/arrowscrollbox.js -index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..be2cbdb20cb2064459b6f7bef56fd0470c3b7f40 100644 +index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..574149bffa49329e927c8db9db0c080eb6b87f5f 100644 --- a/toolkit/content/widgets/arrowscrollbox.js +++ b/toolkit/content/widgets/arrowscrollbox.js @@ -98,6 +98,7 @@ @@ -10,7 +10,19 @@ index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..be2cbdb20cb2064459b6f7bef56fd047 let contentSize = slot.getBoundingClientRect()[this.#verticalMode ? "height" : "width"]; // NOTE(emilio): This should be contentSize > scrollClientSize, but due -@@ -642,7 +643,7 @@ +@@ -125,6 +126,11 @@ + overflowObserver.observe(this.scrollbox); + } + ++ connectedMoveCallback() { ++ // See gh-13015, define connectedMoveCallback to prevent connectedCallback ++ // from being called when using moveBefore. ++ } ++ + connectedCallback() { + this.removeAttribute("overflowing"); + +@@ -642,7 +648,7 @@ on_wheel(event) { // Don't consume the event if we can't scroll. From f40a7aaee1cb0f409f1f142be1f3a4de897069f7 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:46:32 +0200 Subject: [PATCH 012/149] gh-13016: Fixed pinned tabs not being able to collapse (gh-13018) --- .../tabbrowser/content/tabgroup-js.patch | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/browser/components/tabbrowser/content/tabgroup-js.patch b/src/browser/components/tabbrowser/content/tabgroup-js.patch index 4517ac261..e1803b91f 100644 --- a/src/browser/components/tabbrowser/content/tabgroup-js.patch +++ b/src/browser/components/tabbrowser/content/tabgroup-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js -index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938d6923f3e 100644 +index 3ca119e8dc72fac652c98505211864483d98add2..b65307ee8df896488a4c51e3a25bf9ad9e1c8179 100644 --- a/browser/components/tabbrowser/content/tabgroup.js +++ b/browser/components/tabbrowser/content/tabgroup.js @@ -14,11 +14,11 @@ @@ -101,7 +101,13 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 resetDefaultGroupName = () => { this.#defaultGroupName = ""; -@@ -178,7 +201,9 @@ +@@ -175,10 +198,15 @@ + if (!this.#tabChangeObserver) { + this.#tabChangeObserver = new window.MutationObserver(mutations => { + if (!this.tabs.length) { ++ if (this.tagName === "zen-workspace-collapsible-pins") { ++ return; ++ } this.dispatchEvent( new CustomEvent("TabGroupRemoved", { bubbles: true }) ); @@ -111,7 +117,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 Services.obs.notifyObservers( this, "browser-tabgroup-removed-from-dom" -@@ -223,7 +248,10 @@ +@@ -223,7 +251,10 @@ } }); } @@ -123,7 +129,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 } get color() { -@@ -317,6 +345,9 @@ +@@ -317,6 +348,9 @@ } set collapsed(val) { @@ -133,7 +139,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 if (!!val == this.collapsed) { return; } -@@ -403,7 +434,6 @@ +@@ -403,7 +437,6 @@ tabGroupName, }) .then(result => { @@ -141,7 +147,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 }); } -@@ -478,13 +508,65 @@ +@@ -478,13 +511,65 @@ * @returns {MozTabbrowserTab[]} */ get tabs() { @@ -212,7 +218,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 } /** -@@ -592,7 +674,6 @@ +@@ -592,7 +677,6 @@ ); } else { if (tabOrSplitView.pinned) { @@ -220,7 +226,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 } let tabToMove = this.ownerGlobal === tabOrSplitView.ownerGlobal -@@ -661,7 +742,7 @@ +@@ -661,7 +745,7 @@ */ on_click(event) { let isToggleElement = @@ -229,7 +235,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938 event.target === this.#overflowCountLabel; if (isToggleElement && event.button === 0) { event.preventDefault(); -@@ -740,5 +821,6 @@ +@@ -740,5 +824,6 @@ } } From ba593a19dc0f2030de9ccbd48c81f8e8e4d833ed Mon Sep 17 00:00:00 2001 From: Zack Koppert Date: Tue, 31 Mar 2026 12:57:06 -0700 Subject: [PATCH 013/149] no-bug: update OSPO action references to canonical org path (gh-13028) --- .github/workflows/issue-metrics.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-metrics.yml b/.github/workflows/issue-metrics.yml index 56ac6763e..7a623410f 100644 --- a/.github/workflows/issue-metrics.yml +++ b/.github/workflows/issue-metrics.yml @@ -42,7 +42,7 @@ jobs: echo "last_month_year=$previous_year" >> "$GITHUB_ENV" - name: Run issue-metrics tool - uses: github/issue-metrics@v2 + uses: github-community-projects/issue-metrics@v2 env: GH_TOKEN: ${{ secrets.DEPLOY_KEY }} HIDE_AUTHOR: true From e32ff53d2d7ab6320981eeffc4a6da211effcfe6 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:20:25 +0200 Subject: [PATCH 014/149] gh-13030: Fixed unsplit tab item showing when it shouldn't (gh-13033) --- src/zen/split-view/ZenViewSplitter.mjs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/zen/split-view/ZenViewSplitter.mjs b/src/zen/split-view/ZenViewSplitter.mjs index 85afd37d6..dbc99e678 100644 --- a/src/zen/split-view/ZenViewSplitter.mjs +++ b/src/zen/split-view/ZenViewSplitter.mjs @@ -1164,12 +1164,16 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature { insetUpdateContextMenuItems() { const contentAreaContextMenu = document.getElementById("tabContextMenu"); contentAreaContextMenu.addEventListener("popupshowing", () => { - let isExistingSplitView = gBrowser.selectedTabs.some(tab => + let contextTab = TabContextMenu.contextTab; + let selectedTabs = contextTab.multiselected + ? gBrowser.selectedTabs + : [contextTab]; + let isExistingSplitView = selectedTabs.every(tab => tab.group?.hasAttribute("split-view-group") ); const splitTabCommand = document.getElementById("context_zenSplitTabs"); document.l10n.setAttributes(splitTabCommand, "tab-zen-split-tabs", { - tabCount: isExistingSplitView ? -1 : gBrowser.selectedTabs.length, + tabCount: isExistingSplitView ? -1 : selectedTabs.length, }); if (isExistingSplitView) { splitTabCommand.removeAttribute("hidden"); @@ -1243,8 +1247,8 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature { } else { tabs = [TabContextMenu.contextTab]; } - // If any is already in a split view, we unsplit them first - if (tabs.some(tab => tab.splitView)) { + // If all are already in a split view, we unsplit them first. + if (tabs.every(tab => tab.splitView)) { for (const tab of tabs) { if (tab.splitView) { this.removeTabFromGroup(tab); @@ -1268,7 +1272,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature { return false; } for (const tab of window.gBrowser.selectedTabs) { - if (tab.splitView || tab.hasAttribute("zen-empty-tab")) { + if (tab.hasAttribute("zen-empty-tab")) { return false; } } From 69e3a995aed03899daf8ea8f78217c4028c6161c Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:56:05 +0200 Subject: [PATCH 015/149] gh-13024: Fixed restoring tab state also taking into account scroll (gh-13034) --- src/zen/tabs/ZenPinnedTabManager.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index 7d26334ca..1e2d4fc3c 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -427,6 +427,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { state.image = tab.zenStaticIcon || initialState.image; state.index = 0; + // See gh-13024, we need to remove the scroll position from the state, + // otherwise when we reset the pinned tab, it will scroll to the previous position + // which can be confusing for the user, especially if they have a long page. + delete state.scroll; + SessionStore.setTabState(tab, state); this.resetPinChangedUrl(tab); } From 6b5f6c7b9d420fd76cf49953f7ebbe53fb2e0e7b Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:07:10 +0200 Subject: [PATCH 016/149] no-bug: Properly align identity box icon (gh-13035) --- src/zen/common/styles/zen-omnibox.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index 1619a6b38..a334a3d04 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -486,6 +486,11 @@ margin-block: -1px !important; } } + + & #identity-icon-box { + --urlbar-box-hover-bgcolor: transparent; + margin-inline: 2px 8px; + } } /* stylelint-disable-next-line media-query-no-invalid */ From 0619d3d8de970a1748eda8dbc8aa2d1c8f4e4cb8 Mon Sep 17 00:00:00 2001 From: Hythera <87016780+Hythera@users.noreply.github.com> Date: Thu, 2 Apr 2026 14:30:52 +0200 Subject: [PATCH 017/149] no-bug: remove obsolete patch from Firefox `149.0` (gh-13049) --- ..._macos_crash_on_shutdown_firefox_149.patch | 177 ------------------ 1 file changed, 177 deletions(-) delete mode 100644 src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch diff --git a/src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch b/src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch deleted file mode 100644 index c76f06760..000000000 --- a/src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch +++ /dev/null @@ -1,177 +0,0 @@ -diff --git a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs ---- a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs -+++ b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs -@@ -490,10 +490,27 @@ - if (accepted) { - return () => spinner.observe(); - } - return undefined; - }, -+ -+ /** -+ * Reset the phase after a call to _trigger(). -+ * For testing purposes only. -+ */ -+ get _reset() { -+ let accepted = Services.prefs.getBoolPref( -+ "toolkit.asyncshutdown.testing", -+ false -+ ); -+ if (accepted) { -+ return () => { -+ spinner = new Spinner(topic); -+ }; -+ } -+ return undefined; -+ }, - }); - gPhases.set(topic, phase); - return phase; - } - -diff --git a/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs b/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs ---- a/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs -+++ b/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs -@@ -104,18 +104,14 @@ - this._nimbusUpdateCallback = this.#onNimbusUpdate.bind(this); - // This will handle both Nimbus updates and pref changes. - lazy.NimbusFeatures.contentRelevancy.onUpdate(this._nimbusUpdateCallback); - this.#initialized = true; - -- if ( -- Services.startup.isInOrBeyondShutdownPhase( -- Ci.nsIAppStartup.SHUTDOWN_PHASE_APPSHUTDOWNCONFIRMED -- ) -- ) { -+ if (lazy.AsyncShutdown.profileChangeTeardown.isClosed) { - // Corner case, where we're already in the shutdown phase while being constructed. In this - // case, uninitialize immediately to deregister callback handlers -- // (#https://bugzilla.mozilla.org/show_bug.cgi?id=1990569#c11) -+ // (https://bugzilla.mozilla.org/show_bug.cgi?id=1990569#c11) - this.uninit(); - } else { - // If we're not in the above corner case, then register a shutdown blocker to uninitialize. - // Interrupt sooner prior to the `profile-before-change` phase to allow - // all the in-progress IOs to exit. -diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js ---- a/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js -+++ b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js -@@ -149,10 +149,39 @@ - await TestUtils.waitForCondition( - () => ContentRelevancyManager.interrupt.calledOnce, - "The interrupt shutdown blocker should be called" - ); - -+ AsyncShutdown.profileChangeTeardown._reset(); -+ Services.prefs.clearUserPref("toolkit.asyncshutdown.testing"); -+ Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); -+ gSandbox.restore(); -+}); -+ -+add_task(async function test_dont_register_blocker_if_in_shutdown() { -+ // Test a corner case: the ContentRelevancyManager is initialized during shutdown. -+ // -+ // In this case it shouldn't register a shutdown blocker, because it's too late to do that. -+ // Instead, it should just immediately uninitialize itself. -+ // -+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1990569 -+ ContentRelevancyManager.uninit(); -+ Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true); -+ await TestUtils.waitForTick(); -+ -+ gSandbox.spy(ContentRelevancyManager, "interrupt"); -+ -+ // Simulate shutdown. -+ Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true); -+ AsyncShutdown.profileChangeTeardown._trigger(); -+ ContentRelevancyManager.init(); -+ Assert.ok( -+ !ContentRelevancyManager.initialized, -+ "ContentRelevancyManager should have uninitialized itself" -+ ); -+ -+ AsyncShutdown.profileChangeTeardown._reset(); - Services.prefs.clearUserPref("toolkit.asyncshutdown.testing"); - Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); - gSandbox.restore(); - }); - -diff --git a/toolkit/modules/AppServicesTracing.sys.mjs b/toolkit/modules/AppServicesTracing.sys.mjs ---- a/toolkit/modules/AppServicesTracing.sys.mjs -+++ b/toolkit/modules/AppServicesTracing.sys.mjs -@@ -9,10 +9,11 @@ - */ - - const lazy = {}; - - ChromeUtils.defineESModuleGetters(lazy, { -+ AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", - // eslint-disable-next-line mozilla/use-console-createInstance - Log: "resource://gre/modules/Log.sys.mjs", - }); - - import { -@@ -118,20 +119,33 @@ - } - } - - /** A singleton uniffi callback interface. */ - class TracingEventHandler extends EventSink { -- static OBSERVER_NAME = "xpcom-will-shutdown"; -- - constructor() { - super(); - // Map targets to CallbackLists - this.targetCallbackLists = new Map(); - // CallbackList for callbacks registered with registerMinLevelEventSink - this.minLevelCallbackList = new CallbackList(); - -- Services.obs.addObserver(this, TracingEventHandler.OBSERVER_NAME); -+ // Choose `profileBeforeChange` to call `#close()` and deregister our callbacks. -+ // -+ // Most other components will shutdown during the `profileChangeTeardown` phase, since that's -+ // the last opportunity to write to the profile directory. By choosing the next one, we ensure -+ // we can forward any logging that happens when those components shutdown. -+ if (lazy.AsyncShutdown.profileBeforeChange.isClosed) { -+ // Corner case, where we're already in the shutdown phase while being constructed. In this -+ // case, uninitialize immediately. -+ this.#close(); -+ } else { -+ // If we're not in the above corner case, then register a shutdown blocker to uninitialize. -+ lazy.AsyncShutdown.profileBeforeChange.addBlocker( -+ "TracingEventHandler: deregister callbacks", -+ () => this.#close() -+ ); -+ } - } - - register(target, level, callback) { - if (this.targetCallbackLists === null) { - lazy.console.trace( -@@ -223,19 +237,17 @@ - targetList.processEvent(event); - } - this.minLevelCallbackList.processEvent(event); - } - -- observe(_aSubject, aTopic, _aData) { -- if (aTopic == TracingEventHandler.OBSERVER_NAME) { -- for (let target of this.targetCallbackLists.keys()) { -- unregisterEventSink(target); -- } -- unregisterMinLevelEventSink(); -- this.targetCallbackLists = null; -- this.minLevelCallbackList = null; -+ #close() { -+ for (let target of this.targetCallbackLists.keys()) { -+ unregisterEventSink(target); - } -+ unregisterMinLevelEventSink(); -+ this.targetCallbackLists = null; -+ this.minLevelCallbackList = null; - } - } - - // the singleton. - let tracingEventHandler = new TracingEventHandler(); - From 36aa7b0a209b192a832a83e01e35e837566093be Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:10:18 +0200 Subject: [PATCH 018/149] gh-13038: Fixed trying to swap browsers that dont exist (gh-13051) --- src/zen/sessionstore/ZenWindowSync.sys.mjs | 5 ++++- src/zen/tabs/ZenPinnedTabManager.mjs | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/zen/sessionstore/ZenWindowSync.sys.mjs b/src/zen/sessionstore/ZenWindowSync.sys.mjs index 95b6c8e70..564693dca 100644 --- a/src/zen/sessionstore/ZenWindowSync.sys.mjs +++ b/src/zen/sessionstore/ZenWindowSync.sys.mjs @@ -790,7 +790,10 @@ class nsZenWindowSync { // We *shouldn't* care about this scenario since the remoteness should be // the same anyways. if (!aOurTab.linkedBrowser || !aOtherTab.linkedBrowser) { - return true; + this.log( + `Cannot swap browsers between tabs ${aOurTab.id} and ${aOtherTab.id} because one of them doesn't have a linked browser` + ); + return false; } // Can't swap between chrome and content processes. if ( diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index 1e2d4fc3c..8a8e4e832 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -678,14 +678,15 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { return tab; } let workspaceId; + if ( + !tab.hasAttribute("zen-essential") && + tab.getAttribute("zen-workspace-id") != gZenWorkspaces.activeWorkspace + ) { + workspaceId = gZenWorkspaces.activeWorkspace; + } if (tab.ownerGlobal !== window) { fromDifferentWindow = true; - if ( - !tab.hasAttribute("zen-essential") && - tab.getAttribute("zen-workspace-id") != - gZenWorkspaces.activeWorkspace - ) { - workspaceId = gZenWorkspaces.activeWorkspace; + if (workspaceId) { tab.ownerGlobal.gBrowser.selectedTab = tab.ownerGlobal.gBrowser._findTabToBlurTo(tab, movingTabs); tab.ownerGlobal.gZenWorkspaces.moveTabToWorkspace(tab, workspaceId); @@ -700,9 +701,9 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { if (tab) { ++newIndex; } - if (workspaceId) { - tab.setAttribute("zen-workspace-id", workspaceId); - } + } + if (workspaceId) { + tab.setAttribute("zen-workspace-id", workspaceId); } return tab; }); From 92eb6b07c32b940f287f2f0e6ad017d847b13de7 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:12:24 +0200 Subject: [PATCH 019/149] gh-12985: Disable new firefox search widget (gh-13052) --- prefs/firefox/browser.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prefs/firefox/browser.yaml b/prefs/firefox/browser.yaml index 41575963d..23db6a4e4 100644 --- a/prefs/firefox/browser.yaml +++ b/prefs/firefox/browser.yaml @@ -86,3 +86,7 @@ - name: browser.tabs.splitView.enabled value: false locked: true + +# See gh-12985 for details on the following preferences +- name: browser.search.widget.new + value: true From dba5a0402c4fe7ac247eedfdcdd2bead4d6259c4 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:15:47 +0200 Subject: [PATCH 020/149] no-bug: Dont animate glance image preview opacity (gh-13055) --- src/zen/glance/ZenGlanceManager.mjs | 11 ----------- src/zen/glance/zen-glance.css | 5 +++++ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/zen/glance/ZenGlanceManager.mjs b/src/zen/glance/ZenGlanceManager.mjs index 47af5981b..a63ccb234 100644 --- a/src/zen/glance/ZenGlanceManager.mjs +++ b/src/zen/glance/ZenGlanceManager.mjs @@ -507,17 +507,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.#glances.get(this.#currentGlanceID).elementImageData = data.elementData; - gZenUIManager.motion.animate( - imageDataElement, - { - opacity: [1, 0], - }, - { - duration: this.#GLANCE_ANIMATION_DURATION / 2, - easing: "easeInOut", - } - ); - return imageDataElement; } diff --git a/src/zen/glance/zen-glance.css b/src/zen/glance/zen-glance.css index 02ffbd9bc..1257bcdc7 100644 --- a/src/zen/glance/zen-glance.css +++ b/src/zen/glance/zen-glance.css @@ -170,6 +170,7 @@ position: absolute; pointer-events: none; width: 100%; + height: 100%; max-width: 100%; max-height: 100%; z-index: 0; @@ -179,6 +180,10 @@ translate: -50% -50%; background: rgba(255, 255, 255, 0.1); + display: flex; + align-items: center; + justify-content: center; + & image { width: 100%; max-width: 100%; From b55358b9abc94813299f5302c373825cb1aaba36 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:17:08 +0200 Subject: [PATCH 021/149] gh-12979: Import compositor patches from upstream (gh-13054) --- ...calnote_to_dclayercompositionsurface.patch | 19 ++++++++ ...compositor_rendering_performance_fix.patch | 43 +++++++++++++++++++ ...979_3_clip_dirty_rect_to_device_size.patch | 21 +++++++++ src/external-patches/manifest.json | 20 ++++++--- 4 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch create mode 100644 src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch create mode 100644 src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch diff --git a/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch b/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch new file mode 100644 index 000000000..251b6eed1 --- /dev/null +++ b/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch @@ -0,0 +1,19 @@ +diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp +--- a/gfx/webrender_bindings/DCLayerTree.cpp ++++ b/gfx/webrender_bindings/DCLayerTree.cpp +@@ -2097,10 +2097,14 @@ + hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D), + (void**)getter_AddRefs(backBuffer), + &offset); + + if (FAILED(hr)) { ++ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); ++ ++ gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: " ++ << gfx::hexa(hr) << " " << rect; + RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW); + return; + } + + const auto gl = mDCLayerTree->GetGLContext(); + diff --git a/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch b/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch new file mode 100644 index 000000000..363bb391d --- /dev/null +++ b/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch @@ -0,0 +1,43 @@ +diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp +--- a/gfx/webrender_bindings/DCLayerTree.cpp ++++ b/gfx/webrender_bindings/DCLayerTree.cpp +@@ -2182,18 +2182,18 @@ + + updatePos = {0, 0}; + } + + mFirstDraw = false; ++ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); ++ MOZ_ASSERT(!rect.IsEmpty()); + + hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D), + (void**)getter_AddRefs(backBuffer), + &offset); + + if (FAILED(hr)) { +- LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); +- + gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: " + << gfx::hexa(hr) << " " << rect; + RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW); + return; + } +diff --git a/gfx/wr/webrender/src/renderer/composite.rs b/gfx/wr/webrender/src/renderer/composite.rs +--- a/gfx/wr/webrender/src/renderer/composite.rs ++++ b/gfx/wr/webrender/src/renderer/composite.rs +@@ -1120,11 +1120,13 @@ + // Only use supplied clear color for first content layer we encounter + let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT); + + if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() { + if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode { +- if dirty_rect.is_empty() { ++ let device_rect = DeviceRect::from_size(device_size.to_f32()); ++ let clipped_dirty_rect = dirty_rect.intersection_unchecked(&device_rect); ++ if clipped_dirty_rect.is_empty() { + continue; + } + } + } + + diff --git a/src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch b/src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch new file mode 100644 index 000000000..4cd381da1 --- /dev/null +++ b/src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch @@ -0,0 +1,21 @@ +diff --git a/gfx/wr/webrender/src/renderer/composite.rs b/gfx/wr/webrender/src/renderer/composite.rs +--- a/gfx/wr/webrender/src/renderer/composite.rs ++++ b/gfx/wr/webrender/src/renderer/composite.rs +@@ -974,12 +974,15 @@ + .iter() + .chain(self.layer_compositor_frame_state_in_prev_frame.as_ref().unwrap().rects_without_id.iter()) { + combined_dirty_rect = combined_dirty_rect.union(&rect); + } + ++ let device_rect = DeviceRect::from_size(device_size.to_f32()); ++ let clipped_dirty_rect = combined_dirty_rect.intersection_unchecked(&device_rect); ++ + partial_present_mode = Some(PartialPresentMode::Single { +- dirty_rect: combined_dirty_rect, ++ dirty_rect: clipped_dirty_rect, + }); + } else { + partial_present_mode = None; + } + + diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json index 157506bcb..6da075325 100644 --- a/src/external-patches/manifest.json +++ b/src/external-patches/manifest.json @@ -2,11 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. [ - { - "type": "phabricator", - "id": "D279007", - "name": "Fix MacOS Crash on Shutdown Firefox 149" - }, { "type": "phabricator", "id": "D284084", @@ -40,5 +35,20 @@ // the parameter's help description with the correct one. "application": "Application" } + }, + { + "type": "phabricator", + "id": "D291099", + "name": "gh-12979 1 Add gfxCriticalNote to DCLayerCompositionSurface" + }, + { + "type": "phabricator", + "id": "D291123", + "name": "gh-12979 2 Compositor rendering performance fix" + }, + { + "type": "phabricator", + "id": "D291714", + "name": "gh-12979 3 Clip dirty_rect to device_size" } ] From db3eea65b70826d16f044db58f058598d3745601 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Fri, 3 Apr 2026 00:00:22 +0200 Subject: [PATCH 022/149] gh-13060: Fixed collapsed pins not marked as active (gh-13061) --- .../tabbrowser/content/tab-js.patch | 28 ++++++++++--------- surfer.json | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/browser/components/tabbrowser/content/tab-js.patch b/src/browser/components/tabbrowser/content/tab-js.patch index 8bd69d35d..8f386d14f 100644 --- a/src/browser/components/tabbrowser/content/tab-js.patch +++ b/src/browser/components/tabbrowser/content/tab-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js -index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e0474669fc15c20 100644 +index e4266a159a0d5c42cc294602d00b8f66131f35d5..f3e362f062063ebe08bd26cc694f2d965ccffd84 100644 --- a/browser/components/tabbrowser/content/tab.js +++ b/browser/components/tabbrowser/content/tab.js @@ -21,6 +21,7 @@ @@ -52,7 +52,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 return; } -@@ -225,11 +228,23 @@ +@@ -225,11 +228,25 @@ } get visible() { @@ -74,14 +74,16 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 + } + currentParent = currentParent.group; + } -+ if (this.pinned && !this.hasAttribute("zen-essential") && gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs) { ++ if (this.pinned && !this.hasAttribute("zen-essential") && ++ gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs && ++ !gZenWorkspaces.activeWorkspaceElement.collapsiblePins.activeTabs?.includes(this)) { + return false; + } + return true; } get hidden() { -@@ -308,7 +323,7 @@ +@@ -308,7 +325,7 @@ return false; } @@ -90,7 +92,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 } get lastAccessed() { -@@ -393,7 +408,18 @@ +@@ -393,7 +410,18 @@ } get group() { @@ -110,7 +112,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 } get splitview() { -@@ -475,6 +501,10 @@ +@@ -475,6 +503,10 @@ } } @@ -121,7 +123,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 // If the previous target wasn't part of this tab then this is a mouseenter event. if (!this.contains(event.relatedTarget)) { this._mouseenter(); -@@ -504,6 +534,7 @@ +@@ -504,6 +536,7 @@ if (!this.contains(event.relatedTarget)) { this._mouseleave(); } @@ -129,7 +131,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 } on_dragstart(event) { -@@ -538,6 +569,8 @@ +@@ -538,6 +571,8 @@ this.style.MozUserFocus = "ignore"; } else if ( event.target.classList.contains("tab-close-button") || @@ -138,7 +140,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 event.target.classList.contains("tab-icon-overlay") || event.target.classList.contains("tab-audio-button") ) { -@@ -592,16 +625,21 @@ +@@ -592,16 +627,21 @@ this.style.MozUserFocus = ""; } @@ -161,7 +163,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 gBrowser.multiSelectedTabsCount > 0 && !event.target.classList.contains("tab-close-button") && !event.target.classList.contains("tab-icon-overlay") && -@@ -613,8 +651,9 @@ +@@ -613,8 +653,9 @@ } if ( @@ -173,7 +175,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 ) { if (this.activeMediaBlocked) { if (this.multiselected) { -@@ -632,7 +671,7 @@ +@@ -632,7 +673,7 @@ return; } @@ -182,7 +184,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 if (this.multiselected) { gBrowser.removeMultiSelectedTabs( lazy.TabMetrics.userTriggeredContext( -@@ -652,6 +691,14 @@ +@@ -652,6 +693,14 @@ // (see tabbrowser-tabs 'click' handler). gBrowser.tabContainer._blockDblClick = true; } @@ -197,7 +199,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466 } on_dblclick(event) { -@@ -675,6 +722,8 @@ +@@ -675,6 +724,8 @@ animate: true, triggeringEvent: event, }); diff --git a/surfer.json b/surfer.json index 00a8e1c6f..c06f1a6e0 100644 --- a/surfer.json +++ b/surfer.json @@ -20,7 +20,7 @@ "brandShortName": "Zen", "brandFullName": "Zen Browser", "release": { - "displayVersion": "1.19.5b", + "displayVersion": "1.19.6b", "github": { "repo": "zen-browser/desktop" }, From 6ffeecad3ac4a36dc090761ea26f073c0c35fc79 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sat, 4 Apr 2026 14:03:59 +0200 Subject: [PATCH 023/149] gh-10687: Space switching should ignore system prefs (gh-13079) --- prefs/zen/macos.yaml | 4 ++++ .../base/content/browser-gestureSupport-js.patch | 15 +++++++++++++-- src/widget/cocoa/nsCocoaUtils-mm.patch | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/widget/cocoa/nsCocoaUtils-mm.patch diff --git a/prefs/zen/macos.yaml b/prefs/zen/macos.yaml index bf28c7266..abca5c987 100644 --- a/prefs/zen/macos.yaml +++ b/prefs/zen/macos.yaml @@ -27,3 +27,7 @@ - name: widget.macos.native-popovers value: true condition: "defined(XP_MACOSX)" + +- name: zen.widget.macos.override-system-swipe-gestures + value: true + condition: "defined(XP_MACOSX)" diff --git a/src/browser/base/content/browser-gestureSupport-js.patch b/src/browser/base/content/browser-gestureSupport-js.patch index ef205d5df..7132d6fdd 100644 --- a/src/browser/base/content/browser-gestureSupport-js.patch +++ b/src/browser/base/content/browser-gestureSupport-js.patch @@ -1,8 +1,19 @@ diff --git a/browser/base/content/browser-gestureSupport.js b/browser/base/content/browser-gestureSupport.js -index a28d54bf72c0e6495b9586f220d1859aac794936..66154668b9f85ffbaacea1e8351370659260227b 100644 +index a28d54bf72c0e6495b9586f220d1859aac794936..411d7255a68c48643617d77cc279a0a831fdf5c9 100644 --- a/browser/base/content/browser-gestureSupport.js +++ b/browser/base/content/browser-gestureSupport.js -@@ -832,7 +832,7 @@ var gHistorySwipeAnimation = { +@@ -247,6 +247,10 @@ var gGestureSupport = { + : aEvent.DIRECTION_LEFT; + } + ++ if (!gHistorySwipeAnimation._isSupported()) { ++ return; ++ } ++ + return canGoBack || canGoForward; + }, + +@@ -832,7 +836,7 @@ var gHistorySwipeAnimation = { * @return true if there is a previous page in history, false otherwise. */ canGoBack: function HSA_canGoBack() { diff --git a/src/widget/cocoa/nsCocoaUtils-mm.patch b/src/widget/cocoa/nsCocoaUtils-mm.patch new file mode 100644 index 000000000..929b28238 --- /dev/null +++ b/src/widget/cocoa/nsCocoaUtils-mm.patch @@ -0,0 +1,14 @@ +diff --git a/widget/cocoa/nsCocoaUtils.mm b/widget/cocoa/nsCocoaUtils.mm +index 540130c449b859f50847cad8177bd1065f67078a..83f96be9dc5aefe178e788472f220e9d560f5e2d 100644 +--- a/widget/cocoa/nsCocoaUtils.mm ++++ b/widget/cocoa/nsCocoaUtils.mm +@@ -1632,7 +1632,8 @@ bool static ShouldConsiderStartingSwipeFromEvent(NSEvent* anEvent) { + return [anEvent type] == NSEventTypeScrollWheel && + eventPhase == NSEventPhaseBegan && + [anEvent hasPreciseScrollingDeltas] && +- [NSEvent isSwipeTrackingFromScrollEventsEnabled]; ++ ([NSEvent isSwipeTrackingFromScrollEventsEnabled] || ++ Preferences::GetBool("zen.widget.macos.override-system-swipe-gestures")); + } + + PanGestureInput nsCocoaUtils::CreatePanGestureEvent( From bbaf7279edf058dcfa519a7513e525834c4baa90 Mon Sep 17 00:00:00 2001 From: Chris McLaughlin Date: Sat, 4 Apr 2026 12:54:13 -0500 Subject: [PATCH 024/149] gh-12112: auto-focus URL bar when `replace-newtab` is disabled (gh-13080) Co-authored-by: mr. m --- src/zen/spaces/ZenSpaceManager.mjs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs index b58acc44f..d5c118b11 100644 --- a/src/zen/spaces/ZenSpaceManager.mjs +++ b/src/zen/spaces/ZenSpaceManager.mjs @@ -875,10 +875,12 @@ class nsZenWorkspaces { }; let removedEmptyTab = false; + let initialTabWasEmpty = false; if ( this._initialTab && !(this._initialTab._shouldRemove && this._initialTab._veryPossiblyEmpty) ) { + initialTabWasEmpty = !!this._initialTab._veryPossiblyEmpty; gBrowser.selectedTab = this._initialTab; this.moveTabToWorkspace(this._initialTab, this.activeWorkspace); gBrowser.moveTabTo(this._initialTab, { @@ -943,7 +945,12 @@ class nsZenWorkspaces { delete this._initialTab; } - showed &&= Services.prefs.getBoolPref("zen.urlbar.open-on-startup", true); + const openOnStartup = Services.prefs.getBoolPref( + "zen.urlbar.open-on-startup", + true + ); + showed &&= openOnStartup; + initialTabWasEmpty &&= openOnStartup; // Wait for the next event loop to ensure that the startup focus logic by // firefox has finished doing it's thing. @@ -951,7 +958,9 @@ class nsZenWorkspaces { setTimeout(() => { if (gZenVerticalTabsManager._canReplaceNewTab && showed) { BrowserCommands.openTab(); - } else if (!showed) { + } else if (showed || initialTabWasEmpty) { + openLocation(); + } else { gBrowser.selectedBrowser.focus(); } }); From d9e03e8b831db6e0d7cb9080717a4f4d70d6616c Mon Sep 17 00:00:00 2001 From: Chris McLaughlin Date: Sat, 4 Apr 2026 13:42:57 -0500 Subject: [PATCH 025/149] gh-13081: focus URL bar on new blank tab in single-toolbar mode (gh-13082) Co-authored-by: mr. m --- src/browser/components/tabbrowser/content/tabbrowser-js.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index f671b2632..a328ea9d9 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js -index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..be4bedce98f404325e547dd8a4e73e895b6025b0 100644 +index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..aed843d26eaf56d66883f95c373d40106d93dc08 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -413,6 +413,7 @@ @@ -191,7 +191,7 @@ index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..be4bedce98f404325e547dd8a4e73e89 // In full screen mode, only bother making the location bar visible // if the tab is a blank one. - if (gURLBar.getBrowserState(newBrowser).urlbarFocused) { -+ if (gURLBar.getBrowserState(newBrowser).urlbarFocused && !gZenVerticalTabsManager._hasSetSingleToolbar) { ++ if (gURLBar.getBrowserState(newBrowser).urlbarFocused && (!gZenVerticalTabsManager._hasSetSingleToolbar || isBlankPageURL(newBrowser.currentURI?.spec))) { let selectURL = () => { if (this._asyncTabSwitching) { // Set _awaitingSetURI flag to suppress popup notification From 8333c3412438cf4bd9d89389bf5a14cb0635d062 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:50:25 +0200 Subject: [PATCH 026/149] gh-13077: Fixed ctrl+W closing window when splitting tabs (gh-13083) --- src/browser/base/content/browser-commands-js.patch | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/browser/base/content/browser-commands-js.patch b/src/browser/base/content/browser-commands-js.patch index fa9a0af70..87a12716c 100644 --- a/src/browser/base/content/browser-commands-js.patch +++ b/src/browser/base/content/browser-commands-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/base/content/browser-commands.js b/browser/base/content/browser-commands.js -index 75ddd82c18979571f377dec94fe1883f1349cc16..58ae4d88f7f0b37187cb61fcaf4cf84a9af7991f 100644 +index 75ddd82c18979571f377dec94fe1883f1349cc16..129d78214db53fc8dbd17d23b4a5a042ec297a41 100644 --- a/browser/base/content/browser-commands.js +++ b/browser/base/content/browser-commands.js @@ -14,6 +14,10 @@ var BrowserCommands = { @@ -24,11 +24,14 @@ index 75ddd82c18979571f377dec94fe1883f1349cc16..58ae4d88f7f0b37187cb61fcaf4cf84a // A notification intended to be useful for modular peformance tracking // starting as close as is reasonably possible to the time when the user // expressed the intent to open a new tab. Since there are a lot of -@@ -399,6 +407,11 @@ var BrowserCommands = { +@@ -399,6 +407,14 @@ var BrowserCommands = { return; } + if (gBrowser.selectedTab.hasAttribute("zen-empty-tab")) { ++ if (gBrowser.selectedTab.hasAttribute("split-view")) { ++ return; ++ } + gZenWorkspaces.handleTabCloseWindow(); + return; + } @@ -36,7 +39,7 @@ index 75ddd82c18979571f377dec94fe1883f1349cc16..58ae4d88f7f0b37187cb61fcaf4cf84a // Keyboard shortcuts that would close a tab that is pinned select the first // unpinned tab instead. if ( -@@ -406,8 +419,8 @@ var BrowserCommands = { +@@ -406,8 +422,8 @@ var BrowserCommands = { (event.ctrlKey || event.metaKey || event.altKey) && gBrowser.selectedTab.pinned ) { From 16d7caa98f2ecc6481d10e6dea340af40676bcc8 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 5 Apr 2026 10:54:15 +0200 Subject: [PATCH 027/149] gh-13093: Fixed double seperator lines in context menu (gh-13094) --- .../customizableui/ToolbarContextMenu-sys-mjs.patch | 11 ++++++++++- src/zen/compact-mode/ZenCompactMode.mjs | 3 ++- src/zen/folders/ZenFolders.mjs | 1 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch b/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch index bf9fc9dbb..5cf0f5381 100644 --- a/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch +++ b/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch @@ -1,7 +1,16 @@ diff --git a/browser/components/customizableui/ToolbarContextMenu.sys.mjs b/browser/components/customizableui/ToolbarContextMenu.sys.mjs -index d5fd707b98e4b163a624c97ff4a8f2574e0b0180..32360b11270d9dad4b83229428932e598f69e774 100644 +index d5fd707b98e4b163a624c97ff4a8f2574e0b0180..a3ac939aa9133a678396c16bc6746444a3f3ac1f 100644 --- a/browser/components/customizableui/ToolbarContextMenu.sys.mjs +++ b/browser/components/customizableui/ToolbarContextMenu.sys.mjs +@@ -183,7 +183,7 @@ export var ToolbarContextMenu = { + + let showTabStripItems = toolbarItem?.id == "tabbrowser-tabs"; + let isVerticalTabStripMenu = +- showTabStripItems && toolbarItem.parentElement.id == "vertical-tabs"; ++ showTabStripItems && toolbarItem.parentElement.id == "TabsToolbar-customization-target"; + + if (aInsertPoint) { + aInsertPoint.hidden = isVerticalTabStripMenu; @@ -243,10 +243,7 @@ export var ToolbarContextMenu = { // Show/hide sidebar and vertical tabs menu items let sidebarRevampEnabled = Services.prefs.getBoolPref("sidebar.revamp"); diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index ae6424fe3..4d92efe89 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -233,6 +233,7 @@ window.gZenCompactModeManager = { + `); const idToAction = { @@ -247,7 +248,7 @@ window.gZenCompactModeManager = { } } - document.getElementById("toolbar-context-customize").before(fragment); + document.getElementById("toolbar-context-menu").prepend(fragment); this.updateContextMenu(); }, diff --git a/src/zen/folders/ZenFolders.mjs b/src/zen/folders/ZenFolders.mjs index f3183c76f..d5a579c4a 100644 --- a/src/zen/folders/ZenFolders.mjs +++ b/src/zen/folders/ZenFolders.mjs @@ -71,7 +71,6 @@ class nsZenFolders extends nsZenDOMOperatedFeature { document.getElementById("context_moveTabToGroup").before(contextMenuItems); const contextMenuItemsToolbar = window.MozXULElement.parseXULToFragment( ` - Date: Sun, 5 Apr 2026 20:38:04 +0200 Subject: [PATCH 028/149] gh-11667: Fixed unable to install addons in compact mode (gh-13097) --- .../modules/PopupNotifications-sys-mjs.patch | 20 +++++++++++++++++++ src/zen/compact-mode/ZenCompactMode.mjs | 7 +++++-- src/zen/compact-mode/sidebar.inc.css | 2 +- src/zen/compact-mode/toolbar.inc.css | 2 +- 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/toolkit/modules/PopupNotifications-sys-mjs.patch diff --git a/src/toolkit/modules/PopupNotifications-sys-mjs.patch b/src/toolkit/modules/PopupNotifications-sys-mjs.patch new file mode 100644 index 000000000..20ffbc3ac --- /dev/null +++ b/src/toolkit/modules/PopupNotifications-sys-mjs.patch @@ -0,0 +1,20 @@ +diff --git a/toolkit/modules/PopupNotifications.sys.mjs b/toolkit/modules/PopupNotifications.sys.mjs +index 393f98c71a3b82d0af8ae0e6a863c2ed2963a5db..4a064887e297102353870db9d82f867575dccbef 100644 +--- a/toolkit/modules/PopupNotifications.sys.mjs ++++ b/toolkit/modules/PopupNotifications.sys.mjs +@@ -1540,6 +1540,15 @@ PopupNotifications.prototype = { + ) { + for (let anchorElement of anchorElements) { + anchorElement.setAttribute(ICON_ATTRIBUTE_SHOWING, "true"); ++ let toolbox = anchorElement.closest("#navigator-toolbox"); ++ if (toolbox) { ++ // Disable transitions for now, see gh-11667 ++ toolbox.style.transition = "none"; ++ toolbox.setAttribute("zen-compact-mode-active", "true"); ++ anchorElement.ownerGlobal.setTimeout(() => { ++ toolbox.style.transition = ""; ++ }, 0); ++ } + } + }, + diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index 4d92efe89..0914fb89b 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -177,6 +177,7 @@ window.gZenCompactModeManager = { const attributes = [ "panelopen", "open", + "opening", "breakout-extend", "zen-floating-urlbar", ]; @@ -185,7 +186,8 @@ window.gZenCompactModeManager = { [ { selector: - ":is([panelopen='true'], [open='true'], [breakout-extend='true']):not(#urlbar[zen-floating-urlbar='true']):not(tab):not(.zen-compact-mode-ignore)", + ":where([panelopen='true'], [open='true'], [showing='true'], [breakout-extend='true'])" + + ":not(#urlbar[zen-floating-urlbar='true']):not(tab):not(.zen-compact-mode-ignore)", }, ], "zen-compact-mode-active", @@ -196,7 +198,8 @@ window.gZenCompactModeManager = { [ { selector: - ":is([panelopen='true'], [open='true'], #urlbar:focus-within, [breakout-extend='true']):not(.zen-compact-mode-ignore)", + ":where([panelopen='true'], [open='true'], [showing='true'], #urlbar:focus-within, [breakout-extend='true'])" + + ":not(.zen-compact-mode-ignore)", }, ], "zen-compact-mode-active", diff --git a/src/zen/compact-mode/sidebar.inc.css b/src/zen/compact-mode/sidebar.inc.css index 9d665df58..0422d3018 100644 --- a/src/zen/compact-mode/sidebar.inc.css +++ b/src/zen/compact-mode/sidebar.inc.css @@ -144,7 +144,7 @@ } } - #navigator-toolbox:is( + #navigator-toolbox:where( [zen-has-hover], [zen-user-show], [zen-has-empty-tab], [flash-popup], [has-popup-menu], [movingtab], diff --git a/src/zen/compact-mode/toolbar.inc.css b/src/zen/compact-mode/toolbar.inc.css index 484f98c25..e6bcf7b1a 100644 --- a/src/zen/compact-mode/toolbar.inc.css +++ b/src/zen/compact-mode/toolbar.inc.css @@ -49,7 +49,7 @@ } } - & #zen-appcontent-navbar-wrapper:is( + & #zen-appcontent-navbar-wrapper:where( [zen-has-hover], [has-popup-menu], [zen-compact-mode-active] From 640561ab1928a7084f8240de1c4b1c8e4dae0e7e Mon Sep 17 00:00:00 2001 From: Tito Oliveira <71538081+Panemiko@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:03:12 -0300 Subject: [PATCH 029/149] gh-13114: Remove 'slots filled' message in tab context (gh-13102) --- locales/en-US/browser/browser/zen-general.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en-US/browser/browser/zen-general.ftl b/locales/en-US/browser/browser/zen-general.ftl index ef3bbe3c5..f88f215fd 100644 --- a/locales/en-US/browser/browser/zen-general.ftl +++ b/locales/en-US/browser/browser/zen-general.ftl @@ -15,7 +15,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Add to Essentials .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } slots filled +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Remove from Essentials .accesskey = R From 631fb9fc3bbe702b648fd5f0aed00375cbc0aa73 Mon Sep 17 00:00:00 2001 From: reizumi Date: Tue, 7 Apr 2026 01:05:34 +0800 Subject: [PATCH 030/149] no-bug: optimize icons and replace existing icons (gh-13113) --- .../themes/shared/zen-icons/nucleo/algorithm.svg | 2 +- .../themes/shared/zen-icons/nucleo/arrow-down.svg | 2 +- .../themes/shared/zen-icons/nucleo/arrow-left.svg | 2 +- .../themes/shared/zen-icons/nucleo/arrow-right.svg | 2 +- .../themes/shared/zen-icons/nucleo/arrow-up.svg | 2 +- .../shared/zen-icons/nucleo/autoplay-media-blocked.svg | 2 +- .../shared/zen-icons/nucleo/autoplay-media-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/autoplay-media.svg | 2 +- .../themes/shared/zen-icons/nucleo/bookmark-hollow.svg | 2 +- .../shared/zen-icons/nucleo/bookmark-star-on-tray.svg | 2 +- .../themes/shared/zen-icons/nucleo/bookmark.svg | 2 +- .../themes/shared/zen-icons/nucleo/camera-blocked.svg | 2 +- .../themes/shared/zen-icons/nucleo/camera-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/camera.svg | 2 +- .../themes/shared/zen-icons/nucleo/canvas-blocked.svg | 6 +----- src/browser/themes/shared/zen-icons/nucleo/canvas.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/chevron.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/close.svg | 2 +- .../themes/shared/zen-icons/nucleo/container-tab.svg | 2 +- .../themes/shared/zen-icons/nucleo/cookies-fill.svg | 10 +++++----- .../themes/shared/zen-icons/nucleo/customize.svg | 2 +- .../themes/shared/zen-icons/nucleo/dart-down.svg | 10 +++++----- .../zen-icons/nucleo/desktop-notification-blocked.svg | 2 +- .../zen-icons/nucleo/desktop-notification-fill.svg | 2 +- .../shared/zen-icons/nucleo/desktop-notification.svg | 2 +- .../themes/shared/zen-icons/nucleo/developer.svg | 2 +- .../themes/shared/zen-icons/nucleo/downloads.svg | 2 +- .../themes/shared/zen-icons/nucleo/drag-indicator.svg | 2 +- .../themes/shared/zen-icons/nucleo/duplicate-tab.svg | 2 +- .../themes/shared/zen-icons/nucleo/edit-copy.svg | 2 +- .../themes/shared/zen-icons/nucleo/edit-cut.svg | 2 +- .../themes/shared/zen-icons/nucleo/edit-delete.svg | 2 +- .../themes/shared/zen-icons/nucleo/edit-paste.svg | 2 +- .../themes/shared/zen-icons/nucleo/edit-theme.svg | 2 +- .../themes/shared/zen-icons/nucleo/essential-add.svg | 2 +- .../shared/zen-icons/nucleo/essential-remove.svg | 2 +- .../themes/shared/zen-icons/nucleo/expand-sidebar.svg | 2 +- .../shared/zen-icons/nucleo/extension-blocked.svg | 2 +- .../themes/shared/zen-icons/nucleo/extension-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/extension.svg | 2 +- .../themes/shared/zen-icons/nucleo/face-sun.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/folder.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/forget.svg | 2 +- .../themes/shared/zen-icons/nucleo/fullscreen-exit.svg | 2 +- .../themes/shared/zen-icons/nucleo/fullscreen.svg | 2 +- .../themes/shared/zen-icons/nucleo/geo-blocked.svg | 2 +- .../themes/shared/zen-icons/nucleo/geo-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/geo.svg | 2 +- .../shared/zen-icons/nucleo/heart-circle-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/help.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/history.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/home.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/info.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/link.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/mail.svg | 4 +--- src/browser/themes/shared/zen-icons/nucleo/manage.svg | 2 +- .../themes/shared/zen-icons/nucleo/media-mute.svg | 2 +- .../themes/shared/zen-icons/nucleo/media-next.svg | 2 +- .../themes/shared/zen-icons/nucleo/media-pause.svg | 5 +---- .../themes/shared/zen-icons/nucleo/media-play.svg | 4 +--- .../themes/shared/zen-icons/nucleo/media-previous.svg | 2 +- .../themes/shared/zen-icons/nucleo/media-unmute.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/menu.svg | 2 +- .../zen-icons/nucleo/microphone-blocked-fill.svg | 2 +- .../shared/zen-icons/nucleo/microphone-blocked.svg | 2 +- .../themes/shared/zen-icons/nucleo/microphone-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/microphone.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/midi.svg | 4 +--- .../themes/shared/zen-icons/nucleo/moon-stars.svg | 2 +- .../themes/shared/zen-icons/nucleo/new-tab-image.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/open.svg | 2 +- .../themes/shared/zen-icons/nucleo/page-portrait.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/palette.svg | 2 +- .../themes/shared/zen-icons/nucleo/passwords.svg | 2 +- .../shared/zen-icons/nucleo/permissions-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/permissions.svg | 2 +- .../zen-icons/nucleo/persistent-storage-blocked.svg | 2 +- .../zen-icons/nucleo/persistent-storage-fill.svg | 2 +- .../shared/zen-icons/nucleo/persistent-storage.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/pin.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/plus.svg | 2 +- .../themes/shared/zen-icons/nucleo/popup-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/popup.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/print.svg | 2 +- .../themes/shared/zen-icons/nucleo/private-window.svg | 2 +- .../themes/shared/zen-icons/nucleo/privateBrowsing.svg | 2 +- .../themes/shared/zen-icons/nucleo/reader-mode.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/reload.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/save.svg | 2 +- .../themes/shared/zen-icons/nucleo/screen-blocked.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/screen.svg | 2 +- .../themes/shared/zen-icons/nucleo/screenshot.svg | 2 +- .../themes/shared/zen-icons/nucleo/search-glass.svg | 2 +- .../themes/shared/zen-icons/nucleo/search-page.svg | 2 +- .../themes/shared/zen-icons/nucleo/security-broken.svg | 2 +- .../shared/zen-icons/nucleo/security-warning.svg | 2 +- .../themes/shared/zen-icons/nucleo/security.svg | 2 +- .../themes/shared/zen-icons/nucleo/send-to-device.svg | 2 +- .../themes/shared/zen-icons/nucleo/settings-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/settings.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/share.svg | 2 +- .../themes/shared/zen-icons/nucleo/sidebar-right.svg | 2 +- .../themes/shared/zen-icons/nucleo/sidebars-right.svg | 2 +- .../themes/shared/zen-icons/nucleo/sparkles.svg | 2 +- .../themes/shared/zen-icons/nucleo/spell-check.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/split.svg | 2 +- .../zen-icons/nucleo/tab-audio-blocked-small.svg | 2 +- .../shared/zen-icons/nucleo/tab-audio-muted-small.svg | 2 +- .../zen-icons/nucleo/tab-audio-playing-small.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/tab.svg | 2 +- .../themes/shared/zen-icons/nucleo/tool-profiler.svg | 2 +- .../zen-icons/nucleo/tracking-protection-fill.svg | 2 +- .../shared/zen-icons/nucleo/tracking-protection.svg | 2 +- .../themes/shared/zen-icons/nucleo/translations.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/trash.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/unpin.svg | 2 +- .../shared/zen-icons/nucleo/video-blocked-fill.svg | 2 +- .../themes/shared/zen-icons/nucleo/video-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/window.svg | 2 +- .../themes/shared/zen-icons/nucleo/xr-blocked.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/xr-fill.svg | 2 +- src/browser/themes/shared/zen-icons/nucleo/xr.svg | 2 +- .../themes/shared/zen-icons/nucleo/zoom-out.svg | 2 +- 123 files changed, 131 insertions(+), 144 deletions(-) diff --git a/src/browser/themes/shared/zen-icons/nucleo/algorithm.svg b/src/browser/themes/shared/zen-icons/nucleo/algorithm.svg index f35991ccc..4594ea39f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/algorithm.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/algorithm.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/arrow-down.svg b/src/browser/themes/shared/zen-icons/nucleo/arrow-down.svg index 19b526e0b..af570ec31 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/arrow-down.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/arrow-down.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/arrow-left.svg b/src/browser/themes/shared/zen-icons/nucleo/arrow-left.svg index 885934f29..09a5dc028 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/arrow-left.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/arrow-left.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/arrow-right.svg b/src/browser/themes/shared/zen-icons/nucleo/arrow-right.svg index 88847cd96..9cefe9a0a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/arrow-right.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/arrow-right.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/arrow-up.svg b/src/browser/themes/shared/zen-icons/nucleo/arrow-up.svg index b72ea070d..100fcab9d 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/arrow-up.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/arrow-up.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-blocked.svg index fda0785c6..65ba9fc5d 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-fill.svg index d16ce98cf..8de8fafd8 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media.svg b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media.svg index a7dc91f2c..2d970131d 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/autoplay-media.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/autoplay-media.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/bookmark-hollow.svg b/src/browser/themes/shared/zen-icons/nucleo/bookmark-hollow.svg index ab5f27a89..4c25b7b84 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/bookmark-hollow.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/bookmark-hollow.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/bookmark-star-on-tray.svg b/src/browser/themes/shared/zen-icons/nucleo/bookmark-star-on-tray.svg index a8fd00b0a..166796c0f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/bookmark-star-on-tray.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/bookmark-star-on-tray.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/bookmark.svg b/src/browser/themes/shared/zen-icons/nucleo/bookmark.svg index 278b3fa90..2fad2d376 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/bookmark.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/bookmark.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/camera-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/camera-blocked.svg index acb82e38f..d0a58ee48 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/camera-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/camera-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/camera-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/camera-fill.svg index 60b32e501..ac6efa506 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/camera-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/camera-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/camera.svg b/src/browser/themes/shared/zen-icons/nucleo/camera.svg index 232a55ab9..5a49a2f80 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/camera.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/camera.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/canvas-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/canvas-blocked.svg index 05a21e86f..f012129e3 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/canvas-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/canvas-blocked.svg @@ -2,8 +2,4 @@ # 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/. - - - - - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/canvas.svg b/src/browser/themes/shared/zen-icons/nucleo/canvas.svg index 6d2221328..3f22037f0 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/canvas.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/canvas.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/chevron.svg b/src/browser/themes/shared/zen-icons/nucleo/chevron.svg index 8f6544c06..97611dfce 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/chevron.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/chevron.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/close.svg b/src/browser/themes/shared/zen-icons/nucleo/close.svg index c4d0be066..dc4791118 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/close.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/close.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/container-tab.svg b/src/browser/themes/shared/zen-icons/nucleo/container-tab.svg index c9b62fbd4..97ea3578e 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/container-tab.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/container-tab.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/cookies-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/cookies-fill.svg index 384076dc0..3fb917399 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/cookies-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/cookies-fill.svg @@ -1,5 +1,5 @@ -#filter dumbComments emptyLines substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - \ No newline at end of file +#filter dumbComments emptyLines substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + diff --git a/src/browser/themes/shared/zen-icons/nucleo/customize.svg b/src/browser/themes/shared/zen-icons/nucleo/customize.svg index 502159c61..1f8568882 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/customize.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/customize.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/dart-down.svg b/src/browser/themes/shared/zen-icons/nucleo/dart-down.svg index 5ab92a59b..b8b5f8536 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/dart-down.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/dart-down.svg @@ -1,5 +1,5 @@ -#filter dumbComments emptyLines substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - \ No newline at end of file +#filter dumbComments emptyLines substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + diff --git a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-blocked.svg index 2f34e73e5..e9c4bdd9d 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-fill.svg index c94bb578c..d18a8cb00 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification.svg b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification.svg index fe56121b8..4b47aa250 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/desktop-notification.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/desktop-notification.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/developer.svg b/src/browser/themes/shared/zen-icons/nucleo/developer.svg index 868c698b1..21cc6e2aa 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/developer.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/developer.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/downloads.svg b/src/browser/themes/shared/zen-icons/nucleo/downloads.svg index e2460d778..87aca2942 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/downloads.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/downloads.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/drag-indicator.svg b/src/browser/themes/shared/zen-icons/nucleo/drag-indicator.svg index fd2bb2afc..845c93494 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/drag-indicator.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/drag-indicator.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/duplicate-tab.svg b/src/browser/themes/shared/zen-icons/nucleo/duplicate-tab.svg index 5093208d1..806d411db 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/duplicate-tab.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/duplicate-tab.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/edit-copy.svg b/src/browser/themes/shared/zen-icons/nucleo/edit-copy.svg index 26ad8ee42..c88606b77 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/edit-copy.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/edit-copy.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/edit-cut.svg b/src/browser/themes/shared/zen-icons/nucleo/edit-cut.svg index e2c6dae14..1c30ad18e 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/edit-cut.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/edit-cut.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/edit-delete.svg b/src/browser/themes/shared/zen-icons/nucleo/edit-delete.svg index 187829213..c106d2db3 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/edit-delete.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/edit-delete.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/edit-paste.svg b/src/browser/themes/shared/zen-icons/nucleo/edit-paste.svg index ead4f5a3b..119b4f9b9 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/edit-paste.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/edit-paste.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/edit-theme.svg b/src/browser/themes/shared/zen-icons/nucleo/edit-theme.svg index a6c84ddf0..a949ad413 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/edit-theme.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/edit-theme.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/essential-add.svg b/src/browser/themes/shared/zen-icons/nucleo/essential-add.svg index 78ceabf53..815e8cc7d 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/essential-add.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/essential-add.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/essential-remove.svg b/src/browser/themes/shared/zen-icons/nucleo/essential-remove.svg index 5c8422cb3..d43e32d98 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/essential-remove.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/essential-remove.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/expand-sidebar.svg b/src/browser/themes/shared/zen-icons/nucleo/expand-sidebar.svg index 22d7bb3c0..fd2f53f0a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/expand-sidebar.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/expand-sidebar.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/extension-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/extension-blocked.svg index 42df02498..5a24a6931 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/extension-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/extension-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/extension-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/extension-fill.svg index bd54d8d8c..562d4f6b4 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/extension-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/extension-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/extension.svg b/src/browser/themes/shared/zen-icons/nucleo/extension.svg index 15f5e9b91..a706c639f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/extension.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/extension.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/face-sun.svg b/src/browser/themes/shared/zen-icons/nucleo/face-sun.svg index 543e131a0..9e989c0d9 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/face-sun.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/face-sun.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/folder.svg b/src/browser/themes/shared/zen-icons/nucleo/folder.svg index 0469c4dd3..4359e15ec 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/folder.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/folder.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/forget.svg b/src/browser/themes/shared/zen-icons/nucleo/forget.svg index db749e8a0..534c190fc 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/forget.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/forget.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/fullscreen-exit.svg b/src/browser/themes/shared/zen-icons/nucleo/fullscreen-exit.svg index 157cda0ca..6df790b96 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/fullscreen-exit.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/fullscreen-exit.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/fullscreen.svg b/src/browser/themes/shared/zen-icons/nucleo/fullscreen.svg index e426c3e8e..197955151 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/fullscreen.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/fullscreen.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/geo-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/geo-blocked.svg index d6238d47d..e3cbb283b 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/geo-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/geo-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/geo-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/geo-fill.svg index c97eaf78d..4ff0589f3 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/geo-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/geo-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/geo.svg b/src/browser/themes/shared/zen-icons/nucleo/geo.svg index 28fb9ea6e..40b42baab 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/geo.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/geo.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/heart-circle-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/heart-circle-fill.svg index e349c7d4c..10a98896a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/heart-circle-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/heart-circle-fill.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/help.svg b/src/browser/themes/shared/zen-icons/nucleo/help.svg index 81e870c99..e5fb256db 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/help.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/help.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/history.svg b/src/browser/themes/shared/zen-icons/nucleo/history.svg index a010a1c29..267f03bb1 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/history.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/history.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/home.svg b/src/browser/themes/shared/zen-icons/nucleo/home.svg index fc558b3c4..45e7017b2 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/home.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/home.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/info.svg b/src/browser/themes/shared/zen-icons/nucleo/info.svg index 86bac90dc..3a49e573b 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/info.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/info.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/link.svg b/src/browser/themes/shared/zen-icons/nucleo/link.svg index 278af3385..cb5530255 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/link.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/link.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/mail.svg b/src/browser/themes/shared/zen-icons/nucleo/mail.svg index ff8c736d7..5d35fbab6 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/mail.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/mail.svg @@ -2,6 +2,4 @@ # 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/. - - - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/manage.svg b/src/browser/themes/shared/zen-icons/nucleo/manage.svg index 6fe478571..b280bfb2c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/manage.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/manage.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-mute.svg b/src/browser/themes/shared/zen-icons/nucleo/media-mute.svg index d1a959d39..2919778f9 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-mute.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-mute.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-next.svg b/src/browser/themes/shared/zen-icons/nucleo/media-next.svg index 324696a19..fe3fecb6b 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-next.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-next.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-pause.svg b/src/browser/themes/shared/zen-icons/nucleo/media-pause.svg index f443c908a..6b0e84500 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-pause.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-pause.svg @@ -2,7 +2,4 @@ # 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/. - - - - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-play.svg b/src/browser/themes/shared/zen-icons/nucleo/media-play.svg index e64a4522b..ece7b0c35 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-play.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-play.svg @@ -2,6 +2,4 @@ # 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/. - - - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-previous.svg b/src/browser/themes/shared/zen-icons/nucleo/media-previous.svg index b742cf229..54ac78515 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-previous.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-previous.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/media-unmute.svg b/src/browser/themes/shared/zen-icons/nucleo/media-unmute.svg index c984a067d..828cc1e51 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/media-unmute.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/media-unmute.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/menu.svg b/src/browser/themes/shared/zen-icons/nucleo/menu.svg index f40520328..60a5fe231 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/menu.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/menu.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked-fill.svg index 113cb70e6..53b52dad0 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked-fill.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked.svg index ed26bd3d8..8a6d9a187 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/microphone-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/microphone-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/microphone-fill.svg index 78ad217ad..67c2e4f02 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/microphone-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/microphone-fill.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/microphone.svg b/src/browser/themes/shared/zen-icons/nucleo/microphone.svg index 5e4feacdd..69b35004f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/microphone.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/microphone.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/midi.svg b/src/browser/themes/shared/zen-icons/nucleo/midi.svg index 8d0ca17c5..ca5660a70 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/midi.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/midi.svg @@ -2,6 +2,4 @@ # 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/. - - - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/moon-stars.svg b/src/browser/themes/shared/zen-icons/nucleo/moon-stars.svg index f4739fbae..523323b51 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/moon-stars.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/moon-stars.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/new-tab-image.svg b/src/browser/themes/shared/zen-icons/nucleo/new-tab-image.svg index dda94088c..76ad06602 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/new-tab-image.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/new-tab-image.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/open.svg b/src/browser/themes/shared/zen-icons/nucleo/open.svg index 96bfa0966..ecb782117 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/open.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/open.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/page-portrait.svg b/src/browser/themes/shared/zen-icons/nucleo/page-portrait.svg index 8d7b773ec..4305f13f1 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/page-portrait.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/page-portrait.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/palette.svg b/src/browser/themes/shared/zen-icons/nucleo/palette.svg index 97219e0a1..86311017c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/palette.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/palette.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/passwords.svg b/src/browser/themes/shared/zen-icons/nucleo/passwords.svg index 21782beb0..c5134f8d8 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/passwords.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/passwords.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/permissions-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/permissions-fill.svg index 3d38645aa..8fea9f6dd 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/permissions-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/permissions-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/permissions.svg b/src/browser/themes/shared/zen-icons/nucleo/permissions.svg index b9d1adceb..670958d43 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/permissions.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/permissions.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-blocked.svg index 42df02498..5a24a6931 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-fill.svg index 1c5e3099d..46bf4c7b1 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage.svg b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage.svg index 66ad08c43..f67adadbc 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/persistent-storage.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/persistent-storage.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/pin.svg b/src/browser/themes/shared/zen-icons/nucleo/pin.svg index a00a00b17..c9b7956e2 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/pin.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/pin.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/plus.svg b/src/browser/themes/shared/zen-icons/nucleo/plus.svg index 0423e9ab9..73b9e148f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/plus.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/plus.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/popup-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/popup-fill.svg index 958aed3f2..613e790e1 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/popup-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/popup-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/popup.svg b/src/browser/themes/shared/zen-icons/nucleo/popup.svg index 66f513bfd..985630a5c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/popup.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/popup.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/print.svg b/src/browser/themes/shared/zen-icons/nucleo/print.svg index 8e16cfa3b..675345d5f 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/print.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/print.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/private-window.svg b/src/browser/themes/shared/zen-icons/nucleo/private-window.svg index 5e4a34322..9941ac6c8 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/private-window.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/private-window.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/privateBrowsing.svg b/src/browser/themes/shared/zen-icons/nucleo/privateBrowsing.svg index 5798464ba..9941ac6c8 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/privateBrowsing.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/privateBrowsing.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/reader-mode.svg b/src/browser/themes/shared/zen-icons/nucleo/reader-mode.svg index be854bc27..bbfbf0532 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/reader-mode.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/reader-mode.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/reload.svg b/src/browser/themes/shared/zen-icons/nucleo/reload.svg index 876728dc2..b48cd26d4 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/reload.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/reload.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/save.svg b/src/browser/themes/shared/zen-icons/nucleo/save.svg index aa51f6b3a..eeb0be9e3 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/save.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/save.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/screen-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/screen-blocked.svg index c1372dfb8..1a8f858ad 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/screen-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/screen-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/screen.svg b/src/browser/themes/shared/zen-icons/nucleo/screen.svg index 53453e919..3eaad0394 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/screen.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/screen.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/screenshot.svg b/src/browser/themes/shared/zen-icons/nucleo/screenshot.svg index 2d1224924..ab59fe5fb 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/screenshot.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/screenshot.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/search-glass.svg b/src/browser/themes/shared/zen-icons/nucleo/search-glass.svg index 947e7e4e5..05181f39a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/search-glass.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/search-glass.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/search-page.svg b/src/browser/themes/shared/zen-icons/nucleo/search-page.svg index 473dcaf09..b5afcb418 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/search-page.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/search-page.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/security-broken.svg b/src/browser/themes/shared/zen-icons/nucleo/security-broken.svg index 86396585e..704c7440a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/security-broken.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/security-broken.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/security-warning.svg b/src/browser/themes/shared/zen-icons/nucleo/security-warning.svg index 56671347e..fb1c7a4a6 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/security-warning.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/security-warning.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/security.svg b/src/browser/themes/shared/zen-icons/nucleo/security.svg index be0b9f9b2..d0d8a5831 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/security.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/security.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/send-to-device.svg b/src/browser/themes/shared/zen-icons/nucleo/send-to-device.svg index 47d89aa11..47f4831fc 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/send-to-device.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/send-to-device.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/settings-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/settings-fill.svg index 749d47eba..88595365e 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/settings-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/settings-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/settings.svg b/src/browser/themes/shared/zen-icons/nucleo/settings.svg index 00cc61192..9eac58174 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/settings.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/settings.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/share.svg b/src/browser/themes/shared/zen-icons/nucleo/share.svg index a4eb9e169..124307efb 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/share.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/share.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/sidebar-right.svg b/src/browser/themes/shared/zen-icons/nucleo/sidebar-right.svg index d25f84075..1256a3997 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/sidebar-right.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/sidebar-right.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/sidebars-right.svg b/src/browser/themes/shared/zen-icons/nucleo/sidebars-right.svg index c9531e507..77be9acda 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/sidebars-right.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/sidebars-right.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/sparkles.svg b/src/browser/themes/shared/zen-icons/nucleo/sparkles.svg index 63f0bf063..3fa7f008c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/sparkles.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/sparkles.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/spell-check.svg b/src/browser/themes/shared/zen-icons/nucleo/spell-check.svg index f800613a4..b2bc07dac 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/spell-check.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/spell-check.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/split.svg b/src/browser/themes/shared/zen-icons/nucleo/split.svg index 732e7f86f..6843842ae 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/split.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/split.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-blocked-small.svg b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-blocked-small.svg index 75e6d0a76..1a157f720 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-blocked-small.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-blocked-small.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-muted-small.svg b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-muted-small.svg index 9e67740ff..503b7cae5 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-muted-small.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-muted-small.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-playing-small.svg b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-playing-small.svg index 8aea8022d..371f0b12e 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tab-audio-playing-small.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tab-audio-playing-small.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tab.svg b/src/browser/themes/shared/zen-icons/nucleo/tab.svg index 482873893..154b67429 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tab.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tab.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tool-profiler.svg b/src/browser/themes/shared/zen-icons/nucleo/tool-profiler.svg index 721953849..741f98727 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tool-profiler.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tool-profiler.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tracking-protection-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/tracking-protection-fill.svg index 8a9ef1f1f..49f889a99 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tracking-protection-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tracking-protection-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/tracking-protection.svg b/src/browser/themes/shared/zen-icons/nucleo/tracking-protection.svg index 55aa2ee5d..7e9ee6b6a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/tracking-protection.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/tracking-protection.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/translations.svg b/src/browser/themes/shared/zen-icons/nucleo/translations.svg index 5aecf2311..f32d848ca 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/translations.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/translations.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/trash.svg b/src/browser/themes/shared/zen-icons/nucleo/trash.svg index 83346f596..97fa8c232 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/trash.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/trash.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/unpin.svg b/src/browser/themes/shared/zen-icons/nucleo/unpin.svg index 6ef1ef8d2..aec72314c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/unpin.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/unpin.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/video-blocked-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/video-blocked-fill.svg index b1e8fa101..741e8b98a 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/video-blocked-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/video-blocked-fill.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/video-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/video-fill.svg index f168e7a1d..8262338e7 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/video-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/video-fill.svg @@ -2,4 +2,4 @@ # 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/. - \ No newline at end of file + diff --git a/src/browser/themes/shared/zen-icons/nucleo/window.svg b/src/browser/themes/shared/zen-icons/nucleo/window.svg index dda94088c..7f00409e9 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/window.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/window.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/xr-blocked.svg b/src/browser/themes/shared/zen-icons/nucleo/xr-blocked.svg index bfd4c9f2e..2340b2eab 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/xr-blocked.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/xr-blocked.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/xr-fill.svg b/src/browser/themes/shared/zen-icons/nucleo/xr-fill.svg index bd387cd56..4719b3174 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/xr-fill.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/xr-fill.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/xr.svg b/src/browser/themes/shared/zen-icons/nucleo/xr.svg index e3e34c28c..5a38091ce 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/xr.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/xr.svg @@ -2,4 +2,4 @@ # 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/. - + diff --git a/src/browser/themes/shared/zen-icons/nucleo/zoom-out.svg b/src/browser/themes/shared/zen-icons/nucleo/zoom-out.svg index 6ef1ef8d2..aec72314c 100644 --- a/src/browser/themes/shared/zen-icons/nucleo/zoom-out.svg +++ b/src/browser/themes/shared/zen-icons/nucleo/zoom-out.svg @@ -2,4 +2,4 @@ # 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/. - + From 5ae688819e7d0da5f5183c9024ea21f0b61a84ae Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:35:55 +0200 Subject: [PATCH 031/149] gh-13119: Revert `:is -> :where` compact mode selectors (gh-13124) --- src/zen/compact-mode/sidebar.inc.css | 2 +- src/zen/compact-mode/toolbar.inc.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zen/compact-mode/sidebar.inc.css b/src/zen/compact-mode/sidebar.inc.css index 0422d3018..9d665df58 100644 --- a/src/zen/compact-mode/sidebar.inc.css +++ b/src/zen/compact-mode/sidebar.inc.css @@ -144,7 +144,7 @@ } } - #navigator-toolbox:where( + #navigator-toolbox:is( [zen-has-hover], [zen-user-show], [zen-has-empty-tab], [flash-popup], [has-popup-menu], [movingtab], diff --git a/src/zen/compact-mode/toolbar.inc.css b/src/zen/compact-mode/toolbar.inc.css index e6bcf7b1a..484f98c25 100644 --- a/src/zen/compact-mode/toolbar.inc.css +++ b/src/zen/compact-mode/toolbar.inc.css @@ -49,7 +49,7 @@ } } - & #zen-appcontent-navbar-wrapper:where( + & #zen-appcontent-navbar-wrapper:is( [zen-has-hover], [has-popup-menu], [zen-compact-mode-active] From f8efd2c22a82f047c6bc247d04c7d50bfa982814 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:43:06 +0200 Subject: [PATCH 032/149] no-bug: New Crowdin updates (gh-13132) --- locales/ar/browser/browser/zen-general.ftl | 13 ++--- locales/ar/browser/browser/zen-menubar.ftl | 2 +- .../ar/browser/browser/zen-vertical-tabs.ftl | 10 ++-- locales/ca/browser/browser/zen-general.ftl | 2 +- locales/ca/browser/browser/zen-split-view.ftl | 5 +- locales/cy/browser/browser/zen-general.ftl | 2 +- locales/cy/browser/browser/zen-workspaces.ftl | 6 +-- locales/el/browser/browser/zen-workspaces.ftl | 4 +- locales/fr/browser/browser/zen-general.ftl | 2 +- locales/ga-IE/browser/browser/zen-general.ftl | 8 +-- .../browser/browser/zen-vertical-tabs.ftl | 6 +-- .../browser/preferences/zen-preferences.ftl | 22 ++++---- locales/id/browser/browser/zen-general.ftl | 18 +++---- locales/id/browser/browser/zen-menubar.ftl | 2 +- .../id/browser/browser/zen-vertical-tabs.ftl | 4 +- locales/id/browser/browser/zen-welcome.ftl | 16 +++--- locales/id/browser/browser/zen-workspaces.ftl | 4 +- locales/is/browser/browser/zen-general.ftl | 2 +- .../browser/preferences/zen-preferences.ftl | 20 +++---- locales/ja/browser/browser/zen-general.ftl | 12 ++--- .../ja/browser/browser/zen-vertical-tabs.ftl | 8 +-- locales/ja/browser/browser/zen-workspaces.ftl | 6 +-- locales/nb/browser/browser/zen-general.ftl | 2 +- .../browser/preferences/zen-preferences.ftl | 54 +++++++++---------- locales/pl/browser/browser/zen-folders.ftl | 4 +- locales/pl/browser/browser/zen-general.ftl | 8 +-- locales/pl/browser/browser/zen-split-view.ftl | 11 ++-- .../pl/browser/browser/zen-vertical-tabs.ftl | 8 +-- locales/pl/browser/browser/zen-welcome.ftl | 2 +- .../pt-BR/browser/browser/zen-split-view.ftl | 5 +- locales/tr/browser/browser/zen-general.ftl | 2 +- locales/vi/browser/browser/zen-general.ftl | 4 +- locales/zh-CN/browser/browser/zen-general.ftl | 2 +- locales/zh-TW/browser/browser/zen-general.ftl | 2 +- 34 files changed, 142 insertions(+), 136 deletions(-) diff --git a/locales/ar/browser/browser/zen-general.ftl b/locales/ar/browser/browser/zen-general.ftl index 0ceabb83e..997a14a2b 100644 --- a/locales/ar/browser/browser/zen-general.ftl +++ b/locales/ar/browser/browser/zen-general.ftl @@ -6,9 +6,9 @@ zen-panel-ui-current-profile-text = الملف الشخصي الحالي unified-extensions-description = تستخدم الإضافات لجلب المزيد من الوظائف الإضافية إلى { -brand-short-name }. tab-context-zen-reset-pinned-tab = .label = - {$isEssential -> - [true] إعادة تعيين علامة التبويب الأساسية - *[false] إعادة تعيين التبويب المثبت + { $isEssential -> + [true] إعادة تعيين علامة التبويب الأساسية + *[false] إعادة تعيين التبويب المثبت } .accesskey = ر tab-context-zen-add-essential = @@ -20,10 +20,11 @@ tab-context-zen-remove-essential = .accesskey = R tab-context-zen-replace-pinned-url-with-current = .label = - {$isEssential -> + { $isEssential -> [true] استبدل الرابط الأساسي بـ - *[false] استبدل الرابط المثبت بـ - الحالي + *[false] + استبدل الرابط المثبت بـ + الحالي } .accesskey = C tab-context-zen-edit-title = diff --git a/locales/ar/browser/browser/zen-menubar.ftl b/locales/ar/browser/browser/zen-menubar.ftl index ccfb9f5ba..b1f8ed00d 100644 --- a/locales/ar/browser/browser/zen-menubar.ftl +++ b/locales/ar/browser/browser/zen-menubar.ftl @@ -4,7 +4,7 @@ zen-menubar-toggle-pinned-tabs = .label = - {$pinnedAreCollapsed -> + { $pinnedAreCollapsed -> [true] توسيع علامات التبويب المثبتة *[false] طي علامات التبويب المثبتة } diff --git a/locales/ar/browser/browser/zen-vertical-tabs.ftl b/locales/ar/browser/browser/zen-vertical-tabs.ftl index 151c53648..47898b5db 100644 --- a/locales/ar/browser/browser/zen-vertical-tabs.ftl +++ b/locales/ar/browser/browser/zen-vertical-tabs.ftl @@ -26,19 +26,19 @@ sidebar-zen-create-new = .label = إنشاء جديد... tabbrowser-unload-tab-button = .tooltiptext = - {$tabCount -> + { $tabCount -> [one] تفريغ والتبديل إلى علامة التبويب *[other] تفريغ { $tabCount } علامات التبويب والتبديل إلى الأولى } tabbrowser-reset-pin-button = .tooltiptext = - {$tabCount -> + { $tabCount -> [one] إعادة تعيين علامة التبويب وتثبيتها - *[other] إعادة تعيين وتثبيت { $tabCount} + *[other] إعادة تعيين وتثبيت { $tabCount } } zen-tab-sublabel = - {$tabSubtitle -> + { $tabSubtitle -> [zen-default-pinned] العودة إلى الرابط المثبت [zen-default-pinned-cmd] فصل عن علامة التبويب المثبتة - *[other] { $tabSubtitle} + *[other] { $tabSubtitle } } diff --git a/locales/ca/browser/browser/zen-general.ftl b/locales/ca/browser/browser/zen-general.ftl index ea3ccbf70..e9a05a52a 100644 --- a/locales/ca/browser/browser/zen-general.ftl +++ b/locales/ca/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Afegeix als essencials .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } espais ocupats +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Elimina dels essencials .accesskey = R diff --git a/locales/ca/browser/browser/zen-split-view.ftl b/locales/ca/browser/browser/zen-split-view.ftl index 3da537f6b..52ba7b3e1 100644 --- a/locales/ca/browser/browser/zen-split-view.ftl +++ b/locales/ca/browser/browser/zen-split-view.ftl @@ -5,8 +5,9 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Pestanya dividida (calen diverses pestanyes seleccionades) - *[other] Divideix { $tabCount } pestanyes + [-1] Pestanya dividida + [1] Uneix pestanyes (calen diverses pestanyes seleccionades) + *[other] Uneix { $tabCount } pestanyes } .accesskey = S zen-split-link = diff --git a/locales/cy/browser/browser/zen-general.ftl b/locales/cy/browser/browser/zen-general.ftl index a4f31b20b..9b8202002 100644 --- a/locales/cy/browser/browser/zen-general.ftl +++ b/locales/cy/browser/browser/zen-general.ftl @@ -22,7 +22,7 @@ tab-context-zen-replace-pinned-url-with-current = .label = { $isEssential -> [true] Amnewid URL Hanfodol gyda'r Cyfredol - *[false] Amnewid URL wedi'i binio gyda'r Cyfredol + *[false] Amnewid URL wedi'i binio gyda'r Cyfredol } .accesskey = P tab-context-zen-edit-title = diff --git a/locales/cy/browser/browser/zen-workspaces.ftl b/locales/cy/browser/browser/zen-workspaces.ftl index 30bc974eb..28f2adf99 100644 --- a/locales/cy/browser/browser/zen-workspaces.ftl +++ b/locales/cy/browser/browser/zen-workspaces.ftl @@ -2,7 +2,7 @@ # 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/. -zen-panel-ui-workspaces-text = Gofodau Gwaith +zen-panel-ui-workspaces-text = Gofodau zen-panel-ui-spaces-label = .label = Gofodau zen-panel-ui-workspaces-create = @@ -10,7 +10,7 @@ zen-panel-ui-workspaces-create = zen-panel-ui-folder-create = .label = Creu Ffolder zen-panel-ui-live-folder-create = - .label = Live Folder + .label = Ffolder Byw zen-panel-ui-new-empty-split = .label = Hollt Newydd zen-workspaces-panel-context-delete = @@ -25,7 +25,7 @@ zen-workspaces-panel-context-default-profile = zen-workspaces-panel-unload = .label = Dadlwytho Gofod zen-workspaces-panel-unload-others = - .label = Unload All Other Spaces + .label = Dadlwytho Pob Gofod Arall zen-workspaces-how-to-reorder-title = Sut i aildrefnu gofodau zen-workspaces-how-to-reorder-desc = Llusgwch yr eiconau gofod ar waelod y bar ochr i'w haildrefnu zen-workspaces-change-theme = diff --git a/locales/el/browser/browser/zen-workspaces.ftl b/locales/el/browser/browser/zen-workspaces.ftl index 7c0263a5c..320be140b 100644 --- a/locales/el/browser/browser/zen-workspaces.ftl +++ b/locales/el/browser/browser/zen-workspaces.ftl @@ -10,7 +10,7 @@ zen-panel-ui-workspaces-create = zen-panel-ui-folder-create = .label = Δημιουργία Φακέλου zen-panel-ui-live-folder-create = - .label = Live Folder + .label = Ζωντανός Φάκελος zen-panel-ui-new-empty-split = .label = Νέος Διαχωρισμός zen-workspaces-panel-context-delete = @@ -25,7 +25,7 @@ zen-workspaces-panel-context-default-profile = zen-workspaces-panel-unload = .label = Εκφόρτωση Χώρου Εργασίας zen-workspaces-panel-unload-others = - .label = Unload All Other Spaces + .label = Εκφόρτωση Όλων Των Άλλων Χώρων zen-workspaces-how-to-reorder-title = Πώς να αναδιατάξετε τους χώρους zen-workspaces-how-to-reorder-desc = Σύρετε τα εικονίδια χώρου στο κάτω μέρος της πλαϊνής μπάρας για να τα αναδιατάξετε zen-workspaces-change-theme = diff --git a/locales/fr/browser/browser/zen-general.ftl b/locales/fr/browser/browser/zen-general.ftl index ccb6cbd0b..51f0bc559 100644 --- a/locales/fr/browser/browser/zen-general.ftl +++ b/locales/fr/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Ajouter aux Essentials .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } emplacements occupés +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Retirer des Essentials .accesskey = R diff --git a/locales/ga-IE/browser/browser/zen-general.ftl b/locales/ga-IE/browser/browser/zen-general.ftl index 4bd0dd106..9b8963a6b 100644 --- a/locales/ga-IE/browser/browser/zen-general.ftl +++ b/locales/ga-IE/browser/browser/zen-general.ftl @@ -7,8 +7,8 @@ unified-extensions-description = Úsáidtear síntí chun níos mó feidhmiúlac tab-context-zen-reset-pinned-tab = .label = { $isEssential -> - [true] Athshocraigh an Cluaisín Riachtanach - *[false] Athshocraigh an Cluaisín Priontáilte + [true] Athshocraigh an Cluaisín Riachtanach + *[false] Athshocraigh an Cluaisín Priontáilte } .accesskey = R tab-context-zen-add-essential = @@ -21,8 +21,8 @@ tab-context-zen-remove-essential = tab-context-zen-replace-pinned-url-with-current = .label = { $isEssential -> - [true] Cuir an URL Riachtanach in ionad an URL Reatha - *[false] Cuir an URL Priontáilte in ionad an URL Reatha + [true] Cuir an URL Riachtanach in ionad an URL Reatha + *[false] Cuir an URL Priontáilte in ionad an URL Reatha } .accesskey = C tab-context-zen-edit-title = diff --git a/locales/ga-IE/browser/browser/zen-vertical-tabs.ftl b/locales/ga-IE/browser/browser/zen-vertical-tabs.ftl index 7d73f6055..9e7631a79 100644 --- a/locales/ga-IE/browser/browser/zen-vertical-tabs.ftl +++ b/locales/ga-IE/browser/browser/zen-vertical-tabs.ftl @@ -38,7 +38,7 @@ tabbrowser-reset-pin-button = } zen-tab-sublabel = { $tabSubtitle -> - [zen-default-pinned] Ar ais go dtí an url bioráilte - [zen-default-pinned-cmd] Ar leithligh ón gcluaisín bioráilte - *[other] { $tabSubtitle } + [zen-default-pinned] Ar ais go dtí an url bioráilte + [zen-default-pinned-cmd] Ar leithligh ón gcluaisín bioráilte + *[other] { $tabSubtitle } } diff --git a/locales/id/browser/browser/preferences/zen-preferences.ftl b/locales/id/browser/browser/preferences/zen-preferences.ftl index 4939f5492..dd9b7c3c8 100644 --- a/locales/id/browser/browser/preferences/zen-preferences.ftl +++ b/locales/id/browser/browser/preferences/zen-preferences.ftl @@ -43,13 +43,13 @@ category-zen-workspaces = .tooltiptext = { pane-zen-tabs-title } pane-settings-workspaces-title = Ruang Kerja zen-tabs-select-recently-used-on-close = - .label = When closing a tab, switch to the most recently used tab instead of the next tab + .label = Saat menutup tab, beralih ke tab yang terakhir digunakan alih-alih tab berikutnya zen-tabs-close-on-back-with-no-history = - .label = Tutup tab dan beralih ke tab pemiliknya (atau tab yang terakhir digunakan) saat kembali tanpa riwayat + .label = Tutup tab dan beralih ke tab asal (atau terakhir digunakan) saat kembali tanpa riwayat zen-settings-workspaces-sync-unpinned-tabs = - .label = Sync only pinned tabs in workspaces + .label = (Window Sync) Hanya sinkronkan tab tersemat dalam ruang kerja zen-tabs-cycle-by-attribute = - .label = Ctrl+Tab berputar hanya dalam tab Esensial atau Ruang Kerja + .label = Ctrl+Tab hanya beralih di antara tab Esensial atau Ruang Kerja zen-tabs-cycle-ignore-pending-tabs = .label = Lewati tab tak termuat saat beralih dengan Ctrl+Tab zen-tabs-cycle-by-attribute-warning = Ctrl+Tab akan beralih berdasarkan urutan terakhir digunakan @@ -63,18 +63,18 @@ zen-pinned-tab-manager-description = Kelola perilaku tambahan dari tab yang dise zen-pinned-tab-manager-restore-pinned-tabs-to-pinned-url = .label = Pulihkan tab yang disematkan ke URL awal saat mulai ulang zen-pinned-tab-manager-container-specific-essentials-enabled = - .label = Aktifkan kontainer-spesifik essentials + .label = Aktifkan pemisahan esensial per kontainer zen-pinned-tab-manager-close-shortcut-behavior-label = Perilaku Pintasan Tutup Tab zen-pinned-tab-manager-reset-unload-switch-close-shortcut-option = - .label = Setel Ulang URL, lepaskan, dan beralih ke tab berikutnya + .label = Setel ulang URL, lepaskan, dan beralih ke tab berikutnya zen-pinned-tab-manager-unload-switch-close-shortcut-option = .label = Lepaskan dan beralih ke tab berikutnya zen-pinned-tab-manager-reset-switch-close-shortcut-option = - .label = Setel Ulang URL dan beralih ke tab berikutnya + .label = Setel ulang URL dan beralih ke tab berikutnya zen-pinned-tab-manager-switch-close-shortcut-option = .label = Beralih ke tab berikutnya zen-pinned-tab-manager-reset-close-shortcut-option = - .label = Setel Ulang URL + .label = Setel ulang URL zen-pinned-tab-manager-close-close-shortcut-option = .label = Tutup tab pane-zen-workspaces-header = Ruang Kerja @@ -137,7 +137,7 @@ pane-zen-marketplace-title = Zen Mods zen-themes-auto-update = .label = Otomatis perbarui mod yang terinstal saat startup zen-settings-workspaces-force-container-tabs-to-workspace = - .label = Saat membuka tab kontainer, otomatis pindahkan ke ruang kerja default kontainer tab itu + .label = Otomatis pindahkan tab kontainer ke ruang kerja defaultnya saat dibuka zen-theme-marketplace-link = Kunjungi Toko zen-dark-theme-styles-header = Gaya Tema Gelap zen-dark-theme-styles-description = Mengkustomisasi mode gelap sesuai kemauanmu @@ -189,7 +189,7 @@ zen-tab-new-shortcut = Tab Baru zen-key-redo = Ulangi zen-restore-last-closed-tab-shortcut = Pulihkan Tab yang Terakhir Ditutup zen-location-open-shortcut = Buka Lokasi -zen-location-open-shortcut-alt = Buka Lokasi +zen-location-open-shortcut-alt = Buka Lokasi (Alt) zen-key-undo-close-window = Batalkan Tutup Jendela zen-text-action-undo-shortcut = Batalkan zen-text-action-redo-shortcut = Ulangi @@ -246,7 +246,7 @@ zen-search-find-again-shortcut = Temukan Lagi zen-search-find-again-shortcut-prev = Cari Sebelumnya zen-search-find-again-shortcut-2 = Cari Lagi (Alt) zen-bookmark-this-page-shortcut = Markahi Laman Ini -zen-bookmark-show-library-shortcut = Tampilkan Pustaka Bookmark +zen-bookmark-show-library-shortcut = Tampilkan Pustaka Markah zen-key-stop = Berhenti Memuat zen-full-zoom-reduce-shortcut = Perkecil zen-full-zoom-enlarge-shortcut = Perbesar diff --git a/locales/id/browser/browser/zen-general.ftl b/locales/id/browser/browser/zen-general.ftl index 0e5f6bfdc..e352fc1fd 100644 --- a/locales/id/browser/browser/zen-general.ftl +++ b/locales/id/browser/browser/zen-general.ftl @@ -3,26 +3,26 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. zen-panel-ui-current-profile-text = profil saat ini -unified-extensions-description = Ekstensi digunakan untuk menambahkan lebih banyak fungsi ekstra ke { -brand-short-name }. +unified-extensions-description = Ekstensi digunakan untuk menambahkan fungsi ekstra ke { -brand-short-name }. tab-context-zen-reset-pinned-tab = .label = { $isEssential -> - [true] Reset Essential Tab - *[false] Reset Pinned Tab + [true] Reset Tab Esensial ke URL awal + *[false] Reset Tab Sematan ke URL awal } .accesskey = R tab-context-zen-add-essential = - .label = Tambahkan ke Essentials + .label = Tambahkan ke Esensial .accesskey = E tab-context-zen-add-essential-badge = { $num } / { $max } slot terisi tab-context-zen-remove-essential = - .label = Hapus dari Essentials + .label = Hapus dari Esensial .accesskey = R tab-context-zen-replace-pinned-url-with-current = .label = { $isEssential -> - [true] Replace Essential URL with Current - *[false] Replace Pinned URL with Current + [true] Perbarui URL awal Tab Esensial + *[false] Perbarui URL awal Tab Sematan } .accesskey = C tab-context-zen-edit-title = @@ -41,7 +41,7 @@ pictureinpicture-minimize-btn = .tooltip = Minimalkan zen-panel-ui-gradient-generator-custom-color = Warna Kustom zen-copy-current-url-confirmation = URL Disalin! -zen-copy-current-url-as-markdown-confirmation = Copied current URL as Markdown! +zen-copy-current-url-as-markdown-confirmation = URL disalin sebagai Markdown! zen-general-cancel-label = .label = Batalkan zen-general-confirm = @@ -69,7 +69,7 @@ zen-site-data-settings = Pengaturan zen-generic-manage = Kelola zen-generic-more = Selengkapnya zen-generic-next = Lanjut -zen-essentials-promo-label = Tambahkan ke Essentials +zen-essentials-promo-label = Tambahkan ke Esensial zen-essentials-promo-sublabel = Akses tab favorit Anda hanya dengan sekali klik # These labels will be used for the site data panel settings zen-site-data-setting-allow = Diizinkan diff --git a/locales/id/browser/browser/zen-menubar.ftl b/locales/id/browser/browser/zen-menubar.ftl index 1b91dd1ab..3045694cf 100644 --- a/locales/id/browser/browser/zen-menubar.ftl +++ b/locales/id/browser/browser/zen-menubar.ftl @@ -19,4 +19,4 @@ zen-menubar-appearance-light = zen-menubar-appearance-dark = .label = Gelap zen-menubar-new-blank-window = - .label = New Blank Window + .label = Jendela Kosong Baru diff --git a/locales/id/browser/browser/zen-vertical-tabs.ftl b/locales/id/browser/browser/zen-vertical-tabs.ftl index edb8c6381..369fdb910 100644 --- a/locales/id/browser/browser/zen-vertical-tabs.ftl +++ b/locales/id/browser/browser/zen-vertical-tabs.ftl @@ -38,7 +38,7 @@ tabbrowser-reset-pin-button = } zen-tab-sublabel = { $tabSubtitle -> - [zen-default-pinned] Back to pinned url - [zen-default-pinned-cmd] Separate from pinned tab + [zen-default-pinned] Kembali ke URL Awal + [zen-default-pinned-cmd] Pisahkan dari tab tersemat *[other] { $tabSubtitle } } diff --git a/locales/id/browser/browser/zen-welcome.ftl b/locales/id/browser/browser/zen-welcome.ftl index 8cebcb240..4bfb2798e 100644 --- a/locales/id/browser/browser/zen-welcome.ftl +++ b/locales/id/browser/browser/zen-welcome.ftl @@ -3,23 +3,23 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. zen-welcome-title-line1 = Selamat datang di -zen-welcome-title-line2 = internet yang tenang +zen-welcome-title-line2 = internet yang lebih tenang zen-welcome-import-title = Permulaan baru, Bookmark tetap sama zen-welcome-import-description-1 = Bookmark, histori dan password anda adalah Jejak remah roti yang anda tinggalkan di internet--jangan tinggalkan begitu saja! zen-welcome-import-description-2 = Semudah mengambil dari peramban lain dan melanjutkan dari yang anda tinggalkan. zen-welcome-import-button = Impor sekarang -zen-welcome-set-default-browser = Atur { -brand-short-name } sebagai peramban bawaan -zen-welcome-dont-set-default-browser = Jangan membuat { -brand-short-name } sebagai peramban bawaan -zen-welcome-initial-essentials-title = Tab penting anda, akan selalu dalam genggaman -zen-welcome-initial-essentials-description-1 = Simpan tab penting anda mudah diakses dan berada dalam jangkauan anda, seberapapun anda membukanya. -zen-welcome-initial-essentials-description-2 = Tab penting selalu terlihat, dimanapun tempat kerja anda. -zen-welcome-workspace-colors-title = Ruang Kerja anda, Warna anda +zen-welcome-set-default-browser = Jadikan { -brand-short-name } sebagai peramban baku +zen-welcome-dont-set-default-browser = Jangan jadikan { -brand-short-name } sebagai peramban baku +zen-welcome-initial-essentials-title = Tab Penting Anda, Selalu dalam Jangkauan +zen-welcome-initial-essentials-description-1 = Pastikan tab terpenting Anda mudah diakses dan selalu tersedia, berapa pun jumlah tab yang Anda buka. +zen-welcome-initial-essentials-description-2 = Tab esensial selalu terlihat, di ruang kerja mana pun Anda berada. +zen-welcome-workspace-colors-title = Ruang Kerja Anda, Warna Anda zen-welcome-workspace-colors-description = Atur peramban anda dengan memberikan warna tersendiri tiap ruang kerja. zen-welcome-start-browsing-title = Semua Pengaturan selesai?
Mari mulai menjelajah! zen-welcome-start-browsing-description-1 = Anda selesai melakukan pengaturan dan siap untuk mulai. Klik tombol di bawah ini untuk mulai menjelajah dengan { -brand-short-name }. -zen-welcome-start-browsing = Penyelaman dimulai! +zen-welcome-start-browsing = Ayo, mulai! zen-welcome-default-search-title = Mesin Pencari Default Anda zen-welcome-default-search-description = Pilih mesin pencari default Anda. Anda selalu dapat mengubahnya nanti! zen-welcome-skip-button = Lewati diff --git a/locales/id/browser/browser/zen-workspaces.ftl b/locales/id/browser/browser/zen-workspaces.ftl index 138955863..abc634e71 100644 --- a/locales/id/browser/browser/zen-workspaces.ftl +++ b/locales/id/browser/browser/zen-workspaces.ftl @@ -25,7 +25,7 @@ zen-workspaces-panel-context-default-profile = zen-workspaces-panel-unload = .label = Lepaskan Ruang zen-workspaces-panel-unload-others = - .label = Unload All Other Spaces + .label = Lepaskan Ruang Lainnya zen-workspaces-how-to-reorder-title = Cara Mengurutkan Ulang Ruang zen-workspaces-how-to-reorder-desc = Seret ikon ruang di bagian bawah bilah sisi untuk menyusun ulang urutannya zen-workspaces-change-theme = @@ -61,7 +61,7 @@ zen-workspace-creation-profile = Profil .tooltiptext = Profil (Kontainer) digunakan untuk memisahkan cookie dan data situs antar Ruang. zen-workspace-creation-header = Buat sebuah Ruang zen-workspace-creation-label = Ruang digunakan untuk mengorganisasikan tab dan sesi Anda. -zen-workspaces-delete-workspace-title = Delete Workspace? +zen-workspaces-delete-workspace-title = Hapus Ruang? zen-workspaces-delete-workspace-body = Apakah Anda yakin ingin menghapus { $name }? Tindakan ini tidak bisa dibatalkan. # Note that the html tag MUST not be changed or removed, as it is used to better # display the shortcut in the toast notification. diff --git a/locales/is/browser/browser/zen-general.ftl b/locales/is/browser/browser/zen-general.ftl index 5b5bc95f4..fa7468dbc 100644 --- a/locales/is/browser/browser/zen-general.ftl +++ b/locales/is/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Bæta við þarfaflipa .accesskey = F -tab-context-zen-add-essential-badge = { $num } / { $max } hólf fyllt +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Fjarlægja úr þarfaflipum .accesskey = R diff --git a/locales/ja/browser/browser/preferences/zen-preferences.ftl b/locales/ja/browser/browser/preferences/zen-preferences.ftl index a3cba696b..33aa65fc3 100644 --- a/locales/ja/browser/browser/preferences/zen-preferences.ftl +++ b/locales/ja/browser/browser/preferences/zen-preferences.ftl @@ -5,7 +5,7 @@ pane-zen-looks-title = 外観 category-zen-looks = .tooltiptext = { pane-zen-looks-title }{ pane-zen-looks-title } -zen-warning-language = デフォルト言語を変更すると、ウェブサイトがあなたにトラッキングしやすいです。 +zen-warning-language = デフォルト言語を変更すると、ウェブサイトにトラッキングされやすくなります。 zen-vertical-tabs-layout-header = ブラウザーのレイアウト zen-vertical-tabs-layout-description = 自分に合ったレイアウトを選んでください zen-layout-single-toolbar = サイドバーのみ @@ -43,11 +43,11 @@ category-zen-workspaces = .tooltiptext = { pane-zen-tabs-title } pane-settings-workspaces-title = ワークスペース zen-tabs-select-recently-used-on-close = - .label = When closing a tab, switch to the most recently used tab instead of the next tab + .label = タブを閉じるときに、次のタブではなく最後に使用したタブに切り替える zen-tabs-close-on-back-with-no-history = .label = タブを閉じ、履歴がない状態で戻るときに所有者のタブ(または最近使用したタブ)に切り替えます zen-settings-workspaces-sync-unpinned-tabs = - .label = Sync only pinned tabs in workspaces + .label = ワークスペースのタブのうちピン留めされているタブのみを同期する zen-tabs-cycle-by-attribute = .label = Ctrl+Tabキーを押してワークスペースタブ内または重要なタブ内のサイクルを切り替えます zen-tabs-cycle-ignore-pending-tabs = @@ -57,11 +57,11 @@ zen-look-and-feel-compact-toolbar-themed = .label = コンパクトツールバーにテーマの背景を使用する zen-workspace-continue-where-left-off = .label = 中断したところから再開する -pane-zen-pinned-tab-manager-title = 固定したタブ -zen-pinned-tab-manager-header = 固定したタブの一般的な設定 -zen-pinned-tab-manager-description = 固定したタブの追加的な動作を管理する +pane-zen-pinned-tab-manager-title = ピン留めされたタブ +zen-pinned-tab-manager-header = ピン留めされたタブの設定 +zen-pinned-tab-manager-description = ピン留めされたタブの追加的な動作を管理する zen-pinned-tab-manager-restore-pinned-tabs-to-pinned-url = - .label = 固定したタブを起動時に元の固定したURLに復元します + .label = ピン留めされたタブを起動時に元のピン留めされた URL に復元します zen-pinned-tab-manager-container-specific-essentials-enabled = .label = コンテナ固有のEssentialsを有効にする zen-pinned-tab-manager-close-shortcut-behavior-label = タブを閉じるショートカットの動作 @@ -79,7 +79,7 @@ zen-pinned-tab-manager-close-close-shortcut-option = .label = タブを閉じる pane-zen-workspaces-header = ワークスペース zen-settings-workspaces-header = ワークスペースの一般的な設定 -zen-settings-workspaces-description = ワークスペースを使用すると、一度に複数のブラウジングセッションがあるといいです! +zen-settings-workspaces-description = ワークスペースを使用すると、同時に複数のブラウジングセッションを行うことができます! zen-settings-workspaces-enabled = .label = ワークスペースを有効にする zen-settings-workspaces-hide-default-container-indicator = @@ -279,8 +279,8 @@ zen-workspace-shortcut-switch-7 = ワークスペース7に切り替える zen-workspace-shortcut-switch-8 = ワークスペース8に切り替える zen-workspace-shortcut-switch-9 = ワークスペース9に切り替える zen-workspace-shortcut-switch-10 = ワークスペース10に切り替える -zen-workspace-shortcut-forward = ワークスペースを転送 -zen-workspace-shortcut-backward = 後方ワークスペース +zen-workspace-shortcut-forward = 次のワークスペースに移動 +zen-workspace-shortcut-backward = 前のワークスペースへ移動 zen-sidebar-shortcut-toggle = サイドバーの幅を切り替える zen-pinned-tab-shortcut-reset = ピン留めされたタブをピン留めしたURLにリセット zen-split-view-shortcut-grid = 分割表示グリッドの切り替え diff --git a/locales/ja/browser/browser/zen-general.ftl b/locales/ja/browser/browser/zen-general.ftl index 85b35e249..7f272d724 100644 --- a/locales/ja/browser/browser/zen-general.ftl +++ b/locales/ja/browser/browser/zen-general.ftl @@ -7,8 +7,8 @@ unified-extensions-description = 拡張機能は{ -brand-short-name }に多く tab-context-zen-reset-pinned-tab = .label = { $isEssential -> - [true] Reset Essential Tab - *[false] Reset Pinned Tab + [true] Essentialタブの遷移をリセット + *[false] ピン留めされたタブの遷移をリセット } .accesskey = R tab-context-zen-add-essential = @@ -21,8 +21,8 @@ tab-context-zen-remove-essential = tab-context-zen-replace-pinned-url-with-current = .label = { $isEssential -> - [true] Replace Essential URL with Current - *[false] Replace Pinned URL with Current + [true] EssentialタブのURLを今開いているURLで置き換える + *[false] ピン留めされたタブのURLを今開いているURLで置き換える } .accesskey = C tab-context-zen-edit-title = @@ -41,13 +41,13 @@ pictureinpicture-minimize-btn = .tooltip = 最小化 zen-panel-ui-gradient-generator-custom-color = カスタムカラー zen-copy-current-url-confirmation = URLをクリップボードにコピーしました! -zen-copy-current-url-as-markdown-confirmation = Copied current URL as Markdown! +zen-copy-current-url-as-markdown-confirmation = URLをMarkdownとしてコピーしました! zen-general-cancel-label = .label = キャンセル zen-general-confirm = .label = 確定 zen-pinned-tab-replaced = 固定したタブのURLが現在のURLに置き換えられました! -zen-tabs-renamed = タグの名前は無事に変更されました! +zen-tabs-renamed = タブの名前は無事に変更されました! zen-background-tab-opened-toast = 新しい背景タブが開きました! zen-workspace-renamed-toast = ワークスペースの名前が変更されました! zen-toggle-compact-mode-button = diff --git a/locales/ja/browser/browser/zen-vertical-tabs.ftl b/locales/ja/browser/browser/zen-vertical-tabs.ftl index d6fcad712..c759ab05d 100644 --- a/locales/ja/browser/browser/zen-vertical-tabs.ftl +++ b/locales/ja/browser/browser/zen-vertical-tabs.ftl @@ -33,12 +33,12 @@ tabbrowser-unload-tab-button = tabbrowser-reset-pin-button = .tooltiptext = { $tabCount -> - [one] タブをリセットして固定する - *[other] タブをリセットして{ $tabCount }つタブを固定する + [one] タブをリセットしてピン留め + *[other] タブをリセットして{ $tabCount }つのタブをピン留め } zen-tab-sublabel = { $tabSubtitle -> - [zen-default-pinned] Back to pinned url - [zen-default-pinned-cmd] Separate from pinned tab + [zen-default-pinned] ピン止めされた URL に戻る + [zen-default-pinned-cmd] ピン止めされたタブから切り離す *[other] { $tabSubtitle } } diff --git a/locales/ja/browser/browser/zen-workspaces.ftl b/locales/ja/browser/browser/zen-workspaces.ftl index 3310fe1e0..5af1417c3 100644 --- a/locales/ja/browser/browser/zen-workspaces.ftl +++ b/locales/ja/browser/browser/zen-workspaces.ftl @@ -2,7 +2,7 @@ # 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/. -zen-panel-ui-workspaces-text = スペース +zen-panel-ui-workspaces-text = ワークスペース zen-panel-ui-spaces-label = .label = スペース zen-panel-ui-workspaces-create = @@ -25,7 +25,7 @@ zen-workspaces-panel-context-default-profile = zen-workspaces-panel-unload = .label = スペースをアンロードする zen-workspaces-panel-unload-others = - .label = Unload All Other Spaces + .label = 他のスペースをアンロードする zen-workspaces-how-to-reorder-title = 並べ替える方法 zen-workspaces-how-to-reorder-desc = サイドバーの下部にあるスペースアイコンをドラッグして並べ替えます zen-workspaces-change-theme = @@ -68,7 +68,7 @@ zen-workspaces-delete-workspace-body = { $name }を削除してもよろしい zen-workspaces-close-all-unpinned-tabs-toast = タブを閉じました!元に戻すには、 { $shortcut }を使用してください。 zen-workspaces-close-all-unpinned-tabs-title = .label = 削除する - .tooltiptext = すべての固定しなかったタブを閉じる + .tooltiptext = すべてのピン留めされていないタブを閉じる zen-panel-ui-workspaces-change-forward = .label = 次のスペースに移動 zen-panel-ui-workspaces-change-back = diff --git a/locales/nb/browser/browser/zen-general.ftl b/locales/nb/browser/browser/zen-general.ftl index 16e27e1d2..6255689e7 100644 --- a/locales/nb/browser/browser/zen-general.ftl +++ b/locales/nb/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Legg til i essensielle .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } felt utfylt +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Fjern fra essensielle .accesskey = R diff --git a/locales/pl/browser/browser/preferences/zen-preferences.ftl b/locales/pl/browser/browser/preferences/zen-preferences.ftl index 1fd35037c..cb32bb957 100644 --- a/locales/pl/browser/browser/preferences/zen-preferences.ftl +++ b/locales/pl/browser/browser/preferences/zen-preferences.ftl @@ -5,9 +5,9 @@ pane-zen-looks-title = Wygląd i działanie category-zen-looks = .tooltiptext = { pane-zen-looks-title } -zen-warning-language = Zmiana domyślnego języka może ułatwić śledzenie stron internetowych. -zen-vertical-tabs-layout-header = Wygląd przeglądarki -zen-vertical-tabs-layout-description = Wybierz wygląd, który pasuje Ci najbardziej +zen-warning-language = Zmiana domyślnego języka może ułatwić stronom internetowym śledzenie Twojej aktywności. +zen-vertical-tabs-layout-header = Układ przeglądarki +zen-vertical-tabs-layout-description = Wybierz układ, który najbardziej Ci odpowiada zen-layout-single-toolbar = Tylko pasek boczny zen-layout-multiple-toolbar = Pasek boczny i górny pasek narzędzi zen-layout-collapsed-toolbar = Zwinięty pasek boczny @@ -43,15 +43,15 @@ category-zen-workspaces = .tooltiptext = { pane-zen-tabs-title } pane-settings-workspaces-title = Obszary robocze zen-tabs-select-recently-used-on-close = - .label = Podczas zamykania karty, przejdź do ostatnio używanej karty zamiast do następnej karty + .label = Podczas zamykania karty, przełącz na ostatnio używaną kartę zamiast na następną kartę zen-tabs-close-on-back-with-no-history = - .label = Zamknij kartę i przejdź do karty głównej (lub ostatnio używanej karty) podczas powrotu bez historii + .label = Zamknij kartę i przełącz na kartę nadrzędną (lub ostatnio używaną kartę) podczas cofania bez historii zen-settings-workspaces-sync-unpinned-tabs = .label = Zsynchronizuj tylko przypięte karty w obszarach roboczych zen-tabs-cycle-by-attribute = .label = Ctrl+Tab przełącza tylko między kartami niezbędnymi lub kartami obszaru roboczego zen-tabs-cycle-ignore-pending-tabs = - .label = Ignoruj oczekujące karty podczas przełączania między kartami z Ctrl+Tab + .label = Ignoruj oczekujące karty podczas przełączania się za pomocą skrótu Ctrl+Tab zen-tabs-cycle-by-attribute-warning = Ctrl+Tab będzie przełączał karty według ostatnio używanej kolejności, ponieważ jest włączona zen-look-and-feel-compact-toolbar-themed = .label = Użyj tła motywu dla kompaktowego paska narzędzi @@ -61,18 +61,18 @@ pane-zen-pinned-tab-manager-title = Przypięte karty zen-pinned-tab-manager-header = Ogólne ustawienia przypiętych kart zen-pinned-tab-manager-description = Zarządzaj dodatkowym zachowaniem przypiętych kart zen-pinned-tab-manager-restore-pinned-tabs-to-pinned-url = - .label = Przywróć przypięte karty do pierwotnie przypiętego adresu URL przy starcie + .label = Przywróć przypięte karty do ich pierwotnych adresów URL podczas uruchamiania zen-pinned-tab-manager-container-specific-essentials-enabled = - .label = Włącz podstawowe funkcje specyficzne dla kontenera + .label = Włącz niezbędne karty specyficzne dla kontenerów zen-pinned-tab-manager-close-shortcut-behavior-label = Zachowanie skrótu zamykania karty zen-pinned-tab-manager-reset-unload-switch-close-shortcut-option = - .label = Zresetuj adres URL, wyładuj i przejdź do następnej karty + .label = Zresetuj adres URL, wyładuj i przełącz na następną kartę zen-pinned-tab-manager-unload-switch-close-shortcut-option = - .label = Wyładuj i przejdź do następnej karty + .label = Wyładuj i przełącz na następną kartę zen-pinned-tab-manager-reset-switch-close-shortcut-option = - .label = Zresetuj adres URL i przejdź do następnej karty + .label = Zresetuj adres URL i przełącz na następną kartę zen-pinned-tab-manager-switch-close-shortcut-option = - .label = Przejdź do następnej karty + .label = Przełącz na następną kartę zen-pinned-tab-manager-reset-close-shortcut-option = .label = Zresetuj adres URL zen-pinned-tab-manager-close-close-shortcut-option = @@ -100,7 +100,7 @@ zen-vertical-tabs-expand-tabs-by-default = Rozwiń karty domyślnie zen-vertical-tabs-dont-expand-tabs-by-default = Nie rozwijaj domyślnie kart zen-vertical-tabs-expand-tabs-on-hover = Rozwiń zakładki po najechaniu kursorem (nie działa w trybie kompaktowym) zen-vertical-tabs-expand-tabs-header = Jak rozwinąć karty -zen-vertical-tabs-expand-tabs-description = Wybierz jak rozwinąć karty na pasku bocznym +zen-vertical-tabs-expand-tabs-description = Wybierz sposób rozwijania kart na pasku bocznym zen-theme-marketplace-header = Modyfikacje Zen zen-theme-disable-all-enabled = .title = Wyłącz wszystkie modyfikacje @@ -137,7 +137,7 @@ pane-zen-marketplace-title = Modyfikacje Zen zen-themes-auto-update = .label = Automatycznie aktualizuj zainstalowane modyfikacje podczas startu przeglądarki zen-settings-workspaces-force-container-tabs-to-workspace = - .label = Przełącz się do obszaru roboczego, w którym kontener jest ustawiony jako domyślny podczas otwierania kart kontenera + .label = Przełącz na obszar roboczy, w którym kontener jest ustawiony jako domyślny podczas otwierania kart kontenera zen-theme-marketplace-link = Odwiedź sklep zen-dark-theme-styles-header = Style ciemnego motywu zen-dark-theme-styles-description = Dostosuj ciemny motyw do swoich upodobań @@ -154,9 +154,9 @@ zen-urlbar-behavior-label = Zachowanie zen-urlbar-behavior-normal = .label = Normalne zen-urlbar-behavior-floating-on-type = - .label = Widoczny podczas pisania + .label = Pływający tylko podczas pisania zen-urlbar-behavior-float = - .label = Zawsze widoczny + .label = Zawsze pływający pane-zen-CKS-title = Skróty klawiaturowe category-zen-CKS = .tooltiptext = { pane-zen-CKS-title } @@ -166,7 +166,7 @@ category-zen-marketplace = zen-settings-CKS-header = Dostosuj skróty klawiaturowe zen-settings-CKS-description = Zmień domyślne skróty klawiaturowe zgodnie z własnymi preferencjami i popraw komfort przeglądania stron internetowych zen-settings-CKS-disable-firefox = - .label = Wyłącz domyślne skróty klawiszowe { -brand-short-name } + .label = Wyłącz domyślne skróty klawiaturowe { -brand-short-name } zen-settings-CKS-duplicate-shortcut = .label = Duplikuj skrót zen-settings-CKS-reset-shortcuts = @@ -182,7 +182,7 @@ zenCKSOption-group-zen-compact-mode = Tryb kompaktowy zenCKSOption-group-zen-workspace = Obszary robocze zenCKSOption-group-zen-other = Inne funkcje Zen zenCKSOption-group-zen-split-view = Podziel widok -zenCKSOption-group-devTools = Narzędzia developerskie +zenCKSOption-group-devTools = Narzędzia deweloperskie zen-key-quick-restart = Szybkie ponowne uruchomienie zen-window-new-shortcut = Nowe okno zen-tab-new-shortcut = Nowa karta @@ -214,7 +214,7 @@ zen-help-shortcut = Otwórz pomoc zen-preferences-shortcut = Otwórz ustawienia zen-hide-app-shortcut = Ukryj aplikację zen-hide-other-apps-shortcut = Ukryj inne aplikacje -zen-search-focus-shortcut = Szukaj w centrum uwagi +zen-search-focus-shortcut = Przejdź do wyszukiwania zen-search-focus-shortcut-alt = Przejdź do wyszukiwania (Alt) zen-downloads-shortcut = Otwórz pobieranie zen-addons-shortcut = Otwórz dodatki @@ -223,7 +223,7 @@ zen-save-page-shortcut = Zapisz stronę zen-print-shortcut = Wydrukuj stronę zen-close-shortcut-2 = Zamknij kartę zen-mute-toggle-shortcut = Przełącz wyciszenie -zen-key-delete = Usuń klucz +zen-key-delete = Klawisz Delete zen-key-go-back = Powrót zen-key-go-forward = Przejdź do przodu zen-nav-back-shortcut-alt = Nawiguj wstecz (Alt) @@ -281,13 +281,13 @@ zen-workspace-shortcut-switch-9 = Przełącz na obszar roboczy 9 zen-workspace-shortcut-switch-10 = Przełącz na obszar roboczy 10 zen-workspace-shortcut-forward = Następny obszar roboczy zen-workspace-shortcut-backward = Poprzedni obszar roboczy -zen-sidebar-shortcut-toggle = Przełącz szerokość paska bocznego -zen-pinned-tab-shortcut-reset = Zresetuj przypiętą kartę do przypiętego adresu URL -zen-split-view-shortcut-grid = Przełącz siatkę widoku dzielonego +zen-sidebar-shortcut-toggle = Przełącz szerokość panelu bocznego +zen-pinned-tab-shortcut-reset = Przywróć przypiętą kartę do przypiętego adresu URL +zen-split-view-shortcut-grid = Przełącz widok podziału na siatkę zen-split-view-shortcut-vertical = Przełącz podział ekranu w pionie zen-split-view-shortcut-horizontal = Przełącz podział ekranu w poziomie zen-split-view-shortcut-unsplit = Zamknij podział widoku -zen-new-empty-split-view-shortcut = Nowy pusty widok podziału +zen-new-empty-split-view-shortcut = Nowy pusty widok podzielony zen-key-select-tab-1 = Wybierz kartę #1 zen-key-select-tab-2 = Wybierz kartę #2 zen-key-select-tab-3 = Wybierz kartę #3 @@ -302,17 +302,17 @@ zen-key-goto-history = Przejdź do historii zen-key-go-home = Przejdź do strony głównej zen-bookmark-show-sidebar-shortcut = Pokaż pasek boczny zakładek zen-bookmark-show-toolbar-shortcut = Pokaż pasek zakładek -zen-devtools-toggle-shortcut = Włącz narzędzia developerskie +zen-devtools-toggle-shortcut = Przełącz narzędzia deweloperskie zen-devtools-toggle-browser-toolbox-shortcut = Włącz narzędzia przeglądarki zen-devtools-toggle-browser-console-shortcut = Włącz konsolę przeglądarki zen-devtools-toggle-responsive-design-mode-shortcut = Włącz tryb responsywny zen-devtools-toggle-inspector-shortcut = Włącz Inspektor -zen-devtools-toggle-web-console-shortcut = Włącz konsolę sieciową +zen-devtools-toggle-web-console-shortcut = Włącz konsolę zen-devtools-toggle-js-debugger-shortcut = Włącz debugger JavaScript zen-devtools-toggle-net-monitor-shortcut = Włącz monitor sieci zen-devtools-toggle-style-editor-shortcut = Włącz edytor stylów zen-devtools-toggle-performance-shortcut = Włącz Wydajność -zen-devtools-toggle-storage-shortcut = Włącz Pamięć +zen-devtools-toggle-storage-shortcut = Włącz Dane zen-devtools-toggle-dom-shortcut = Włącz DOM zen-devtools-toggle-accessibility-shortcut = Włącz Dostępność zen-close-all-unpinned-tabs-shortcut = Zamknij wszystkie nieprzypięte karty diff --git a/locales/pl/browser/browser/zen-folders.ftl b/locales/pl/browser/browser/zen-folders.ftl index d684d1c58..214a529c3 100644 --- a/locales/pl/browser/browser/zen-folders.ftl +++ b/locales/pl/browser/browser/zen-folders.ftl @@ -9,13 +9,13 @@ zen-folders-panel-rename-folder = zen-folders-panel-unpack-folder = .label = Rozpakuj folder zen-folders-new-subfolder = - .label = Nowy folder + .label = Nowy podfolder zen-folders-panel-delete-folder = .label = Usuń folder zen-folders-panel-convert-folder-to-space = .label = Konwertuj folder na przestrzeń zen-folders-panel-change-folder-space = - .label = Zmień nazwę przestrzeni... + .label = Zmień przestrzeń... zen-folders-unload-all-tooltip = .tooltiptext = Wyładuj aktywne w tym folderze zen-folders-unload-folder = diff --git a/locales/pl/browser/browser/zen-general.ftl b/locales/pl/browser/browser/zen-general.ftl index 9dec64db3..43b723f1e 100644 --- a/locales/pl/browser/browser/zen-general.ftl +++ b/locales/pl/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Dodaj do niezbędnych .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } zajętych miejsc +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Usuń z niezbędnych .accesskey = R @@ -47,7 +47,7 @@ zen-general-cancel-label = zen-general-confirm = .label = Potwierdź zen-pinned-tab-replaced = URL przypiętej karty został zastąpiony bieżącym adresem! -zen-tabs-renamed = Nazwa karty została z powodzeniem zmieniona! +zen-tabs-renamed = Nazwa karty została pomyślnie zmieniona! zen-background-tab-opened-toast = Nowa karta została otworzona w tle! zen-workspace-renamed-toast = Zmieniono nazwę przestrzeni roboczej! zen-toggle-compact-mode-button = @@ -92,7 +92,7 @@ zen-site-data-site-settings = zen-site-data-header-share = .tooltiptext = Udostępnij tę stronę zen-site-data-header-reader-mode = - .tooltiptext = Wejdź do trybu czytnika + .tooltiptext = Przejdź do trybu czytania zen-site-data-header-screenshot = .tooltiptext = Zrzut ekranu zen-site-data-header-bookmark = @@ -119,7 +119,7 @@ zen-sidebar-notification-restart-safe-mode-label = Coś się zepsuło? zen-sidebar-notification-restart-safe-mode-tooltip = .title = Zrestartuj w trybie bezpiecznym zen-window-sync-migration-dialog-title = Utrzymuj synchronizację okien -zen-window-sync-migration-dialog-message = Zen synchronizuje okna na jednym urządzeniu, żeby zmiany w jednym oknie były natychmiast odzwierciedlone w pozostałych. +zen-window-sync-migration-dialog-message = Zen synchronizuje teraz okna na tym samym urządzeniu, dzięki czemu zmiany wprowadzone w jednym oknie są natychmiast odzwierciedlane w pozostałych. zen-window-sync-migration-dialog-learn-more = Dowiedz się więcej zen-window-sync-migration-dialog-accept = Rozumiem zen-appmenu-new-blank-window = diff --git a/locales/pl/browser/browser/zen-split-view.ftl b/locales/pl/browser/browser/zen-split-view.ftl index 2b1fbc60d..54b7f4722 100644 --- a/locales/pl/browser/browser/zen-split-view.ftl +++ b/locales/pl/browser/browser/zen-split-view.ftl @@ -5,14 +5,15 @@ tab-zen-split-tabs = .label = { $tabCount -> - [-1] Rozdziel karty - [1] Podziel kartę (wymagane zaznaczenie wielu kart) - *[other] Podziel karty w liczbie: { $tabCount } + [-1] Oddziel kartę + [1] Złącz kartę (wymagane jest zaznaczenie wielu kart) + [few] Złącz { $tabCount } karty + *[other] Złącz { $tabCount } kart } .accesskey = S zen-split-link = - .label = Podziel link na nową kartę + .label = Otwórz link w widoku podzielonym .accesskey = S -zen-split-view-modifier-header = Podziel widok +zen-split-view-modifier-header = Widok podzielony zen-split-view-modifier-activate-reallocation = .label = Aktywuj realokację diff --git a/locales/pl/browser/browser/zen-vertical-tabs.ftl b/locales/pl/browser/browser/zen-vertical-tabs.ftl index b4eb2a704..23c158b23 100644 --- a/locales/pl/browser/browser/zen-vertical-tabs.ftl +++ b/locales/pl/browser/browser/zen-vertical-tabs.ftl @@ -27,14 +27,16 @@ sidebar-zen-create-new = tabbrowser-unload-tab-button = .tooltiptext = { $tabCount -> - [one] Dezaktywuj i przełącz na kartę - *[other] Dezaktywuj { $tabCount } karty i przełącz na pierwszą + [one] Wyładuj i przełącz na kartę + [few] Wyładuj { $tabCount } karty i przełącz na pierwszą + *[other] Wyładuj { $tabCount } kart i przełącz na pierwszą } tabbrowser-reset-pin-button = .tooltiptext = { $tabCount -> [one] Zresetuj i przypnij kartę - *[other] Zresetuj i przypnij karty w liczbie: { $tabCount } + [few] Zresetuj i przypnij { $tabCount } karty + *[other] Zresetuj i przypnij { $tabCount } kart } zen-tab-sublabel = { $tabSubtitle -> diff --git a/locales/pl/browser/browser/zen-welcome.ftl b/locales/pl/browser/browser/zen-welcome.ftl index 41665e0c9..b3ec9ae53 100644 --- a/locales/pl/browser/browser/zen-welcome.ftl +++ b/locales/pl/browser/browser/zen-welcome.ftl @@ -10,7 +10,7 @@ zen-welcome-import-description-2 = Łatwo przenieś je z innej przeglądarki i k zen-welcome-import-button = Zaimportuj teraz zen-welcome-set-default-browser = Ustaw { -brand-short-name } jako swoją domyślną przeglądarkę zen-welcome-dont-set-default-browser = NIE ustawiaj { -brand-short-name } jako swoja domyślna przeglądarka -zen-welcome-initial-essentials-title = Twoje kluczowe karty, zawsze w zasięgu +zen-welcome-initial-essentials-title = Twoje kluczowe karty, zawsze pod ręką zen-welcome-initial-essentials-description-1 = Utrzymuj swoje najważniejsze karty zawsze pod ręką, niezależnie od tego, jak wiele masz ich otwartych. zen-welcome-initial-essentials-description-2 = Niezbędne karty są zawsze widoczne, niezależnie od bieżącego obszaru roboczego. zen-welcome-workspace-colors-title = Twój obszar roboczy, Twoje kolory diff --git a/locales/pt-BR/browser/browser/zen-split-view.ftl b/locales/pt-BR/browser/browser/zen-split-view.ftl index 4d80e0a41..83351cef1 100644 --- a/locales/pt-BR/browser/browser/zen-split-view.ftl +++ b/locales/pt-BR/browser/browser/zen-split-view.ftl @@ -5,8 +5,9 @@ tab-zen-split-tabs = .label = { $tabCount -> - [1] Dividir aba (é necessário várias abas selecionadas) - *[other] Dividir { $tabCount } Abas + [-1] Dividir aba + [1] Juntar Aba (necessário várias abas selecionadas) + *[other] Juntar { $tabCount } Abas } .accesskey = S.O. zen-split-link = diff --git a/locales/tr/browser/browser/zen-general.ftl b/locales/tr/browser/browser/zen-general.ftl index 31df52d33..ffe49dd44 100644 --- a/locales/tr/browser/browser/zen-general.ftl +++ b/locales/tr/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = Temel sekmelere ekle .accesskey = E -tab-context-zen-add-essential-badge = { $num } / { $max } yuva dolu +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = Temel sekmelerden kaldır .accesskey = R diff --git a/locales/vi/browser/browser/zen-general.ftl b/locales/vi/browser/browser/zen-general.ftl index e3c36371c..22b6e477f 100644 --- a/locales/vi/browser/browser/zen-general.ftl +++ b/locales/vi/browser/browser/zen-general.ftl @@ -7,8 +7,8 @@ unified-extensions-description = Các tiện ích mở rộng được sử dụ tab-context-zen-reset-pinned-tab = .label = { $isEssential -> - [true] Đặt lại thẻ chính - *[false] Đặt lại thẻ đã ghim + [true] Đặt lại thẻ chính + *[false] Đặt lại thẻ đã ghim } .accesskey = R tab-context-zen-add-essential = diff --git a/locales/zh-CN/browser/browser/zen-general.ftl b/locales/zh-CN/browser/browser/zen-general.ftl index 06202624d..cdc66cb76 100644 --- a/locales/zh-CN/browser/browser/zen-general.ftl +++ b/locales/zh-CN/browser/browser/zen-general.ftl @@ -121,4 +121,4 @@ zen-window-sync-migration-dialog-message = Zen 现已支持同一设备上的窗 zen-window-sync-migration-dialog-learn-more = 了解更多 zen-window-sync-migration-dialog-accept = 知道了 zen-appmenu-new-blank-window = - .label = 新空白窗口 + .label = 新建空白窗口 diff --git a/locales/zh-TW/browser/browser/zen-general.ftl b/locales/zh-TW/browser/browser/zen-general.ftl index a4ad834c4..d73909f24 100644 --- a/locales/zh-TW/browser/browser/zen-general.ftl +++ b/locales/zh-TW/browser/browser/zen-general.ftl @@ -14,7 +14,7 @@ tab-context-zen-reset-pinned-tab = tab-context-zen-add-essential = .label = 新增至 Essentials .accesskey = E -tab-context-zen-add-essential-badge = 已使用 { $num } / { $max } 個位置 +tab-context-zen-add-essential-badge = { $num } / { $max } tab-context-zen-remove-essential = .label = 從 Essentials 中移除 .accesskey = R From 8d646b3e419ba71d56c69c311cea3b5dbc27dfae Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:43:49 +0200 Subject: [PATCH 033/149] gh-13131: Sync upstream Firefox to version `149.0.2` (gh-13129) --- .github/workflows/sync-upstream.yml | 8 ++-- README.md | 2 +- build/firefox-cache/l10n-last-commit-hash | 2 +- .../components/preferences/main-js.patch | 2 +- src/dom/base/Document-cpp.patch | 2 +- .../MediaController-webidl.patch | 6 +-- .../mediaelement/HTMLMediaElement-cpp.patch | 2 +- ...calnote_to_dclayercompositionsurface.patch | 19 -------- ...compositor_rendering_performance_fix.patch | 43 ------------------- ...2979_clip_dirty_rect_to_device_size.patch} | 0 src/external-patches/manifest.json | 12 +----- surfer.json | 8 ++-- 12 files changed, 17 insertions(+), 89 deletions(-) delete mode 100644 src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch delete mode 100644 src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch rename src/external-patches/firefox/{gh-12979_3_clip_dirty_rect_to_device_size.patch => gh-12979_clip_dirty_rect_to_device_size.patch} (100%) diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml index 3913e4099..a8f81b400 100644 --- a/.github/workflows/sync-upstream.yml +++ b/.github/workflows/sync-upstream.yml @@ -103,6 +103,10 @@ jobs: fi echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Import external patches + if: steps.git-check.outputs.files_changed == 'true' + run: python3 scripts/update_external_patches.py || true + - name: Check if patches got applied if: steps.git-check.outputs.files_changed == 'true' id: check-patches @@ -115,10 +119,6 @@ jobs: if: steps.git-check.outputs.files_changed == 'true' run: python3 scripts/import_external_tests.py || true - - name: Import external patches - if: steps.git-check.outputs.files_changed == 'true' - run: python3 scripts/update_external_patches.py || true - - name: Create pull request uses: peter-evans/create-pull-request@v7 if: steps.git-check.outputs.files_changed == 'true' diff --git a/README.md b/README.md index b6a817c47..ae40457ed 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne ### Firefox Versions -- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `149.0`! 🚀 +- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `149.0.2`! 🚀 - [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 149.0`! ### Contributing diff --git a/build/firefox-cache/l10n-last-commit-hash b/build/firefox-cache/l10n-last-commit-hash index 4024374c4..adafe3fc8 100644 --- a/build/firefox-cache/l10n-last-commit-hash +++ b/build/firefox-cache/l10n-last-commit-hash @@ -1 +1 @@ -0b65b47ceee455b324e13114b5bc3a7033a8b2a5 \ No newline at end of file +fc45ac45a16dd9312a3e678fdaef33aaa7e0e641 \ No newline at end of file diff --git a/src/browser/components/preferences/main-js.patch b/src/browser/components/preferences/main-js.patch index 2a03cb2c3..d13a304c5 100644 --- a/src/browser/components/preferences/main-js.patch +++ b/src/browser/components/preferences/main-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js -index e77dfebdf3a15033182eeae6eccd44a63aae3740..4e25b3e1abaeeaec3e83e0e1b53bf578eba5587b 100644 +index a5f2e4258942010ee61ed7a86497f51793366fcd..f01524a09512ec6cd1972a9fdb173ff427a0d753 100644 --- a/browser/components/preferences/main.js +++ b/browser/components/preferences/main.js @@ -2652,6 +2652,11 @@ SettingGroupManager.registerGroups({ diff --git a/src/dom/base/Document-cpp.patch b/src/dom/base/Document-cpp.patch index 665d7a948..79ca8e065 100644 --- a/src/dom/base/Document-cpp.patch +++ b/src/dom/base/Document-cpp.patch @@ -1,5 +1,5 @@ diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index b837e66d4fd5b6a96ad3d9c35f8e50e911cd168b..c35a395da59fc30d70b1e05b94db41b7136db0de 100644 +index 2876a539b21c038340d318d8f0d29da88c518686..1f6bbf828b86dc509f63c7c3d0032f1d4d551d9c 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -464,6 +464,7 @@ diff --git a/src/dom/chrome-webidl/MediaController-webidl.patch b/src/dom/chrome-webidl/MediaController-webidl.patch index d7c868534..3548fa9b6 100644 --- a/src/dom/chrome-webidl/MediaController-webidl.patch +++ b/src/dom/chrome-webidl/MediaController-webidl.patch @@ -1,5 +1,5 @@ diff --git a/dom/chrome-webidl/MediaController.webidl b/dom/chrome-webidl/MediaController.webidl -index 20f416d1c3b41798e0f90bbac5db40ed2a4ab000..1c5d893f9166a3aa7bc7802bb0d1207d169033ee 100644 +index 2df28da9620f8564edb3e77184c674a95941e022..4e2a126766999543422d3a90c66c629f46b58bda 100644 --- a/dom/chrome-webidl/MediaController.webidl +++ b/dom/chrome-webidl/MediaController.webidl @@ -20,6 +20,12 @@ enum MediaControlKey { @@ -15,9 +15,9 @@ index 20f416d1c3b41798e0f90bbac5db40ed2a4ab000..1c5d893f9166a3aa7bc7802bb0d1207d /** * MediaController is used to control media playback for a tab, and each tab * would only have one media controller, which can be accessed from the -@@ -32,10 +38,14 @@ interface MediaController : EventTarget { - readonly attribute boolean isAudible; +@@ -33,10 +39,14 @@ interface MediaController : EventTarget { readonly attribute boolean isPlaying; + readonly attribute boolean isAnyMediaBeingControlled; readonly attribute MediaSessionPlaybackState playbackState; + readonly attribute boolean isBeingUsedInPIPModeOrFullscreen; diff --git a/src/dom/media/mediaelement/HTMLMediaElement-cpp.patch b/src/dom/media/mediaelement/HTMLMediaElement-cpp.patch index 0df960077..e65990ad5 100644 --- a/src/dom/media/mediaelement/HTMLMediaElement-cpp.patch +++ b/src/dom/media/mediaelement/HTMLMediaElement-cpp.patch @@ -1,5 +1,5 @@ diff --git a/dom/media/mediaelement/HTMLMediaElement.cpp b/dom/media/mediaelement/HTMLMediaElement.cpp -index 624375b514cb0b101ae24bb5906d0097d4b335db..27c91b01db611a0cd75b20907310d2fa4c8a1b47 100644 +index b5b932e421894f33e1397149dcc580f891329cbc..ffc3fb68e01a0c11a3ebbbd7793e682d8dc6be47 100644 --- a/dom/media/mediaelement/HTMLMediaElement.cpp +++ b/dom/media/mediaelement/HTMLMediaElement.cpp @@ -451,6 +451,7 @@ class HTMLMediaElement::MediaControlKeyListener final diff --git a/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch b/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch deleted file mode 100644 index 251b6eed1..000000000 --- a/src/external-patches/firefox/gh-12979_1_add_gfxcriticalnote_to_dclayercompositionsurface.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp ---- a/gfx/webrender_bindings/DCLayerTree.cpp -+++ b/gfx/webrender_bindings/DCLayerTree.cpp -@@ -2097,10 +2097,14 @@ - hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D), - (void**)getter_AddRefs(backBuffer), - &offset); - - if (FAILED(hr)) { -+ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); -+ -+ gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: " -+ << gfx::hexa(hr) << " " << rect; - RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW); - return; - } - - const auto gl = mDCLayerTree->GetGLContext(); - diff --git a/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch b/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch deleted file mode 100644 index 363bb391d..000000000 --- a/src/external-patches/firefox/gh-12979_2_compositor_rendering_performance_fix.patch +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp ---- a/gfx/webrender_bindings/DCLayerTree.cpp -+++ b/gfx/webrender_bindings/DCLayerTree.cpp -@@ -2182,18 +2182,18 @@ - - updatePos = {0, 0}; - } - - mFirstDraw = false; -+ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); -+ MOZ_ASSERT(!rect.IsEmpty()); - - hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D), - (void**)getter_AddRefs(backBuffer), - &offset); - - if (FAILED(hr)) { -- LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect); -- - gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: " - << gfx::hexa(hr) << " " << rect; - RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW); - return; - } -diff --git a/gfx/wr/webrender/src/renderer/composite.rs b/gfx/wr/webrender/src/renderer/composite.rs ---- a/gfx/wr/webrender/src/renderer/composite.rs -+++ b/gfx/wr/webrender/src/renderer/composite.rs -@@ -1120,11 +1120,13 @@ - // Only use supplied clear color for first content layer we encounter - let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT); - - if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() { - if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode { -- if dirty_rect.is_empty() { -+ let device_rect = DeviceRect::from_size(device_size.to_f32()); -+ let clipped_dirty_rect = dirty_rect.intersection_unchecked(&device_rect); -+ if clipped_dirty_rect.is_empty() { - continue; - } - } - } - - diff --git a/src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch b/src/external-patches/firefox/gh-12979_clip_dirty_rect_to_device_size.patch similarity index 100% rename from src/external-patches/firefox/gh-12979_3_clip_dirty_rect_to_device_size.patch rename to src/external-patches/firefox/gh-12979_clip_dirty_rect_to_device_size.patch diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json index 6da075325..91c2934ab 100644 --- a/src/external-patches/manifest.json +++ b/src/external-patches/manifest.json @@ -36,19 +36,9 @@ "application": "Application" } }, - { - "type": "phabricator", - "id": "D291099", - "name": "gh-12979 1 Add gfxCriticalNote to DCLayerCompositionSurface" - }, - { - "type": "phabricator", - "id": "D291123", - "name": "gh-12979 2 Compositor rendering performance fix" - }, { "type": "phabricator", "id": "D291714", - "name": "gh-12979 3 Clip dirty_rect to device_size" + "name": "gh-12979 Clip dirty_rect to device_size" } ] diff --git a/surfer.json b/surfer.json index c06f1a6e0..a1ae58cdd 100644 --- a/surfer.json +++ b/surfer.json @@ -5,8 +5,8 @@ "binaryName": "zen", "version": { "product": "firefox", - "version": "149.0", - "candidate": "149.0", + "version": "149.0.2", + "candidate": "149.0.2", "candidateBuild": 1 }, "buildOptions": { @@ -20,7 +20,7 @@ "brandShortName": "Zen", "brandFullName": "Zen Browser", "release": { - "displayVersion": "1.19.6b", + "displayVersion": "1.19.7b", "github": { "repo": "zen-browser/desktop" }, @@ -54,4 +54,4 @@ "licenseType": "MPL-2.0" }, "updateHostname": "updates.zen-browser.app" -} +} \ No newline at end of file From 28fcaf94a350aad2433408642a3c23f0bdb216ed Mon Sep 17 00:00:00 2001 From: Afeefur <152735100+AfeefurR@users.noreply.github.com> Date: Tue, 7 Apr 2026 21:48:36 +0400 Subject: [PATCH 034/149] gh-13133: Add Duplicate tab keyboard shortcut (gh-13123) Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> --- .../browser/preferences/zen-preferences.ftl | 1 + .../base/content/zen-commands.inc.xhtml | 2 ++ src/zen/common/zen-sets.js | 8 ++++++++ src/zen/kbs/ZenKeyboardShortcuts.mjs | 18 +++++++++++++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/locales/en-US/browser/browser/preferences/zen-preferences.ftl b/locales/en-US/browser/browser/preferences/zen-preferences.ftl index 7b304613c..c803f7304 100644 --- a/locales/en-US/browser/browser/preferences/zen-preferences.ftl +++ b/locales/en-US/browser/browser/preferences/zen-preferences.ftl @@ -357,3 +357,4 @@ zen-devtools-toggle-dom-shortcut = Toggle DOM zen-devtools-toggle-accessibility-shortcut = Toggle Accessibility zen-close-all-unpinned-tabs-shortcut = Close All Unpinned Tabs zen-new-unsynced-window-shortcut = New Blank Window +zen-duplicate-tab-shortcut = Duplicate Tab \ No newline at end of file diff --git a/src/browser/base/content/zen-commands.inc.xhtml b/src/browser/base/content/zen-commands.inc.xhtml index de2cec15d..4f9e0fca9 100644 --- a/src/browser/base/content/zen-commands.inc.xhtml +++ b/src/browser/base/content/zen-commands.inc.xhtml @@ -66,4 +66,6 @@ + + diff --git a/src/zen/common/zen-sets.js b/src/zen/common/zen-sets.js index 6d539836c..1a1acb728 100644 --- a/src/zen/common/zen-sets.js +++ b/src/zen/common/zen-sets.js @@ -143,6 +143,14 @@ document.addEventListener( ZenLiveFoldersManager.handleEvent(event); break; } + case "cmd_zenDuplicateTab": { + const selectedTabs = gBrowser.selectedTabs; + let insertAt = selectedTabs.at(-1)._tPos + 1; + for (const tab of selectedTabs) { + gBrowser.duplicateTab(tab, true, { tabIndex: insertAt++ }); + } + break; + } default: gZenGlanceManager.handleMainCommandSet(event); if (event.target.id.startsWith("cmd_zenWorkspaceSwitch")) { diff --git a/src/zen/kbs/ZenKeyboardShortcuts.mjs b/src/zen/kbs/ZenKeyboardShortcuts.mjs index bceb9e66b..351bfd0a5 100644 --- a/src/zen/kbs/ZenKeyboardShortcuts.mjs +++ b/src/zen/kbs/ZenKeyboardShortcuts.mjs @@ -832,7 +832,7 @@ class nsZenKeyboardShortcutsLoader { } class nsZenKeyboardShortcutsVersioner { - static LATEST_KBS_VERSION = 16; + static LATEST_KBS_VERSION = 17; constructor() {} @@ -1196,6 +1196,22 @@ class nsZenKeyboardShortcutsVersioner { } } + if (version < 17) { + // Migrate from version 16 to 17. + // Add shortcut to Duplicate Tab + data.push( + new KeyShortcut( + "zen-duplicate-tab", + "", + "", + "windowAndTabManagement", + nsKeyShortcutModifiers.fromObject({}), + "cmd_zenDuplicateTab", + "zen-duplicate-tab-shortcut" + ) + ); + } + return data; } } From 73ae2fa258a5eaa10da25942e1955bcf694837ab Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:08:47 +0200 Subject: [PATCH 035/149] gh-13140: Fixed some items not respecting reduce motion (gh-13141) --- README.md | 2 +- src/zen/common/modules/ZenUIManager.mjs | 3 +++ src/zen/common/styles/zen-theme.css | 1 + src/zen/spaces/zen-workspaces.css | 5 ++++- src/zen/tabs/zen-tabs/vertical-tabs.css | 12 ++++++++---- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ae40457ed..fe46e784a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne ### Firefox Versions - [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `149.0.2`! 🚀 -- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 149.0`! +- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 149.0.2`! ### Contributing diff --git a/src/zen/common/modules/ZenUIManager.mjs b/src/zen/common/modules/ZenUIManager.mjs index e26abe4db..ff0af0495 100644 --- a/src/zen/common/modules/ZenUIManager.mjs +++ b/src/zen/common/modules/ZenUIManager.mjs @@ -432,6 +432,9 @@ window.gZenUIManager = { }, onUrlbarSearchModeChanged(event) { + if (gReduceMotion) { + return; + } const { searchMode } = event.detail; const input = gURLBar; if (gURLBar.hasAttribute("breakout-extend") && !this._animatingSearchMode) { diff --git a/src/zen/common/styles/zen-theme.css b/src/zen/common/styles/zen-theme.css index 223763421..7b333d1db 100644 --- a/src/zen/common/styles/zen-theme.css +++ b/src/zen/common/styles/zen-theme.css @@ -233,6 +233,7 @@ --zen-primary-color: rgb(11, 10, 11) !important; /* Make sure its in sync with getToolbarColor */ --toolbox-textcolor: rgba(255, 255, 255, 0.8) !important; + --toolbar-color-scheme: dark !important; } &[zen-unsynced-window='true'] { diff --git a/src/zen/spaces/zen-workspaces.css b/src/zen/spaces/zen-workspaces.css index e9ebba75e..97a2c11a3 100644 --- a/src/zen/spaces/zen-workspaces.css +++ b/src/zen/spaces/zen-workspaces.css @@ -309,13 +309,16 @@ /* mark: workspace element */ zen-workspace { flex-direction: column; - transition: padding-top 0.1s; width: calc(100% + var(--zen-toolbox-padding) * 2); position: absolute; height: 100%; overflow: hidden; color: var(--toolbox-textcolor); + @media not (prefers-reduced-motion: reduce) { + transition: padding-top 0.1s; + } + :root:not([zen-sidebar-expanded='true']) & { width: 100%; } diff --git a/src/zen/tabs/zen-tabs/vertical-tabs.css b/src/zen/tabs/zen-tabs/vertical-tabs.css index 6fd06719a..b324a7116 100644 --- a/src/zen/tabs/zen-tabs/vertical-tabs.css +++ b/src/zen/tabs/zen-tabs/vertical-tabs.css @@ -130,10 +130,14 @@ height: 22px; border: none; width: 100%; - transition: - height 0.08s ease-in-out, - padding 0.08s ease-in-out, - opacity 0.06s ease-in-out; + + @media not (prefers-reduced-motion: reduce) { + transition: + height 0.08s ease-in-out, + padding 0.08s ease-in-out, + opacity 0.06s ease-in-out; + } + overflow: hidden; position: relative; opacity: 1; From 561a03421fb4123572875a0a1e0b6e63122f4597 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:04:48 +0200 Subject: [PATCH 036/149] gh-13121: Fixed compact mode not hiding with translations (gh-13143) --- .../customizableui/ToolbarContextMenu-sys-mjs.patch | 10 +++++++++- src/zen/common/modules/ZenHasPolyfill.mjs | 6 ++++++ src/zen/compact-mode/ZenCompactMode.mjs | 5 ++--- src/zen/images/brand-header.svg | 6 ------ src/zen/images/jar.inc.mn | 1 - surfer.json | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) delete mode 100644 src/zen/images/brand-header.svg diff --git a/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch b/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch index 5cf0f5381..3a849bafb 100644 --- a/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch +++ b/src/browser/components/customizableui/ToolbarContextMenu-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/customizableui/ToolbarContextMenu.sys.mjs b/browser/components/customizableui/ToolbarContextMenu.sys.mjs -index d5fd707b98e4b163a624c97ff4a8f2574e0b0180..a3ac939aa9133a678396c16bc6746444a3f3ac1f 100644 +index d5fd707b98e4b163a624c97ff4a8f2574e0b0180..b5d7e84c3567e83b95a6493e8333d3036dc88f36 100644 --- a/browser/components/customizableui/ToolbarContextMenu.sys.mjs +++ b/browser/components/customizableui/ToolbarContextMenu.sys.mjs @@ -183,7 +183,7 @@ export var ToolbarContextMenu = { @@ -23,3 +23,11 @@ index d5fd707b98e4b163a624c97ff4a8f2574e0b0180..a3ac939aa9133a678396c16bc6746444 let toggleVerticalTabsItem = document.getElementById( "toolbar-context-toggle-vertical-tabs" +@@ -267,6 +264,7 @@ export var ToolbarContextMenu = { + document.getElementById("sidebarRevampSeparator").hidden = + !showSidebarActions || isVerticalTabStripMenu; + document.getElementById("customizationMenuSeparator").hidden = ++ true || + toolbarItem?.id == "tabbrowser-tabs" || + (toolbarItem?.localName == "toolbarspring" && + !CustomizationHandler.isCustomizing()) || diff --git a/src/zen/common/modules/ZenHasPolyfill.mjs b/src/zen/common/modules/ZenHasPolyfill.mjs index 986559d7f..44a7c685a 100644 --- a/src/zen/common/modules/ZenHasPolyfill.mjs +++ b/src/zen/common/modules/ZenHasPolyfill.mjs @@ -26,6 +26,12 @@ class nsHasPolyfill { if (selected?.tagName?.toLowerCase() === "menu") { return null; } + if (selected) { + gZenCompactModeManager.log( + `Selector "${selector}" exists for: `, + element + ); + } return selected; }); const { exists: shouldExist = true } = descendantSelectors; diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index 0914fb89b..112014547 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -177,7 +177,6 @@ window.gZenCompactModeManager = { const attributes = [ "panelopen", "open", - "opening", "breakout-extend", "zen-floating-urlbar", ]; @@ -186,7 +185,7 @@ window.gZenCompactModeManager = { [ { selector: - ":where([panelopen='true'], [open='true'], [showing='true'], [breakout-extend='true'])" + + ":where([panelopen='true'], [open='true'], [breakout-extend='true'])" + ":not(#urlbar[zen-floating-urlbar='true']):not(tab):not(.zen-compact-mode-ignore)", }, ], @@ -198,7 +197,7 @@ window.gZenCompactModeManager = { [ { selector: - ":where([panelopen='true'], [open='true'], [showing='true'], #urlbar:focus-within, [breakout-extend='true'])" + + ":where([panelopen='true'], [open='true'], [breakout-extend='true'])" + ":not(.zen-compact-mode-ignore)", }, ], diff --git a/src/zen/images/brand-header.svg b/src/zen/images/brand-header.svg deleted file mode 100644 index 21b542840..000000000 --- a/src/zen/images/brand-header.svg +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/src/zen/images/jar.inc.mn b/src/zen/images/jar.inc.mn index 39b41d70c..d5ac5ccd7 100644 --- a/src/zen/images/jar.inc.mn +++ b/src/zen/images/jar.inc.mn @@ -2,7 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. - content/browser/zen-images/brand-header.svg (../../zen/images/brand-header.svg) content/browser/zen-images/layouts/collapsed.png (../../zen/images/layouts/collapsed.png) content/browser/zen-images/layouts/multiple-toolbar.png (../../zen/images/layouts/multiple-toolbar.png) content/browser/zen-images/layouts/single-toolbar.png (../../zen/images/layouts/single-toolbar.png) diff --git a/surfer.json b/surfer.json index a1ae58cdd..0d514c975 100644 --- a/surfer.json +++ b/surfer.json @@ -20,7 +20,7 @@ "brandShortName": "Zen", "brandFullName": "Zen Browser", "release": { - "displayVersion": "1.19.7b", + "displayVersion": "1.19.8b", "github": { "repo": "zen-browser/desktop" }, From 9433b8a8f04253ebf2de0b3e6901f5940178cac8 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 8 Apr 2026 20:51:30 +0200 Subject: [PATCH 037/149] gh-13121: Fixed top bar not showing when urlbar is focused (gh-13150) --- src/zen/compact-mode/ZenCompactMode.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs index 112014547..01f2a4416 100644 --- a/src/zen/compact-mode/ZenCompactMode.mjs +++ b/src/zen/compact-mode/ZenCompactMode.mjs @@ -197,7 +197,7 @@ window.gZenCompactModeManager = { [ { selector: - ":where([panelopen='true'], [open='true'], [breakout-extend='true'])" + + ":where([panelopen='true'], [open='true'], #urlbar:focus-within, [breakout-extend='true'])" + ":not(.zen-compact-mode-ignore)", }, ], From 8b9f449f95c8dc24f00122182bc1d470e19d78cf Mon Sep 17 00:00:00 2001 From: Afeefur <152735100+AfeefurR@users.noreply.github.com> Date: Thu, 9 Apr 2026 03:36:37 +0400 Subject: [PATCH 038/149] no-bug: added tests for unloading all other workspaces (gh-13100) --- src/zen/spaces/ZenSpaceManager.mjs | 2 +- src/zen/tests/spaces/browser.toml | 2 + .../spaces/browser_unload_all_other_spaces.js | 162 ++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/zen/tests/spaces/browser_unload_all_other_spaces.js diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs index d5c118b11..d1f6a609d 100644 --- a/src/zen/spaces/ZenSpaceManager.mjs +++ b/src/zen/spaces/ZenSpaceManager.mjs @@ -1551,7 +1551,7 @@ class nsZenWorkspaces { !tab.hasAttribute("pending") ); - await gBrowser.explicitUnloadTabs(tabsToUnload); // TODO: unit test this + await gBrowser.explicitUnloadTabs(tabsToUnload); } moveTabToWorkspace(tab, workspaceID) { diff --git a/src/zen/tests/spaces/browser.toml b/src/zen/tests/spaces/browser.toml index ac77baa44..deacec1f7 100644 --- a/src/zen/tests/spaces/browser.toml +++ b/src/zen/tests/spaces/browser.toml @@ -24,4 +24,6 @@ support-files = [ ["browser_private_mode_startup.js"] +["browser_unload_all_other_spaces.js"] + ["browser_workspace_bookmarks.js"] diff --git a/src/zen/tests/spaces/browser_unload_all_other_spaces.js b/src/zen/tests/spaces/browser_unload_all_other_spaces.js new file mode 100644 index 000000000..0280519c1 --- /dev/null +++ b/src/zen/tests/spaces/browser_unload_all_other_spaces.js @@ -0,0 +1,162 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(async function () {}); + +// verify that with only one workspace, regular tabs should remain loaded +add_task(async function test_UnloadAllOtherWorkspace_oneWorkspace() { + const workspace = + await gZenWorkspaces.createAndSaveWorkspace("Test Workspace"); + const workspaceId = workspace.uuid; + await gZenWorkspaces.changeWorkspace(workspace); + + const tabs = []; + for (let i = 0; i < 3; i++) { + const tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + `data:text/html,Hi! I am regular tab ${i}`, + true, + { skipAnimation: true } + ); + tabs.push(tab); + } + + for (const tab of tabs) { + ok(!tab.hasAttribute("pending"), "Tab should not be pending before unload"); + ok(tab.linkedPanel, "Tab should have linked panel before unload"); + } + + await gZenWorkspaces.unloadAllOtherWorkspaces(); + + for (const tab of tabs) { + ok(!tab.hasAttribute("pending"), "Tab should not be pending after unload"); + ok(tab.linkedPanel, "Tab should have linked panel after unload"); + } + + await gZenWorkspaces.removeWorkspace(workspaceId); +}); + +// with multiple workspaces, only regular tabs in other workspaces should be unloaded +add_task(async function test_UnloadAllOtherWorkspace_multipleWorkspaces() { + const inactiveWorkspace = + await gZenWorkspaces.createAndSaveWorkspace("Inactive Workspace"); + const activeWorkspace = + await gZenWorkspaces.createAndSaveWorkspace("Active Workspace"); + + const inactiveWorkspaceId = inactiveWorkspace.uuid; + const activeWorkspaceId = activeWorkspace.uuid; + + const inactiveWorkspaceTabs = []; + for (let i = 0; i < 2; i++) { + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + `data:text/html,Regular Tab ${i} in Inactive`, + true, + { skipAnimation: true } + ); + tab.setAttribute("zen-workspace-id", inactiveWorkspaceId); + inactiveWorkspaceTabs.push(tab); + } + + const activeWorkspaceTabs = []; + for (let i = 0; i < 2; i++) { + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + `data:text/html,Regular Tab ${i} in Active`, + true, + { skipAnimation: true } + ); + tab.setAttribute("zen-workspace-id", activeWorkspaceId); + activeWorkspaceTabs.push(tab); + } + + await gZenWorkspaces.unloadAllOtherWorkspaces(); + + for (const tab of activeWorkspaceTabs) { + ok( + !tab.hasAttribute("pending"), + "Tab in active workspace should not be unloaded" + ); + ok(tab.linkedPanel, "Tab in active workspace should have linked panel"); + } + + for (const tab of inactiveWorkspaceTabs) { + ok( + tab.hasAttribute("pending"), + "Tab in inactive workspace should be unloaded" + ); + ok( + !tab.linkedPanel, + "Tab in inactive workspace should not have linked panel" + ); + } + await gZenWorkspaces.removeWorkspace(inactiveWorkspaceId); + await gZenWorkspaces.removeWorkspace(activeWorkspaceId); +}); + +// essentials in any workspace are not unloaded +add_task(async function test_UnloadAllOtherWorkspace_essentials() { + const activeWorkspace = + await gZenWorkspaces.createAndSaveWorkspace("Active Workspace"); + const inactiveWorkspace = + await gZenWorkspaces.createAndSaveWorkspace("Inactive Workspace"); + + const activeWorkspaceId = activeWorkspace.uuid; + const inactiveWorkspaceId = inactiveWorkspace.uuid; + + const activeWorkspaceTabs = []; + for (let i = 0; i < 2; i++) { + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + `data:text/html,Essential Tab ${i} in Active`, + true, + { skipAnimation: true } + ); + tab.setAttribute("zen-workspace-id", activeWorkspaceId); + tab.setAttribute("zen-essential", "true"); + activeWorkspaceTabs.push(tab); + } + + const inactiveWorkspaceTabs = []; + for (let i = 0; i < 2; i++) { + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + `data:text/html,Essential Tab ${i} in Inactive`, + true, + { skipAnimation: true } + ); + gZenPinnedTabManager.addToEssentials(tab); + inactiveWorkspaceTabs.push(tab); + } + + await gZenWorkspaces.unloadAllOtherWorkspaces(); + + for (const tab of activeWorkspaceTabs) { + ok( + !tab.hasAttribute("pending"), + "Essential Tab in active workspace should not be unloaded" + ); + ok( + tab.linkedPanel, + "Essential Tab in active workspace should have linked panel" + ); + } + + for (const tab of inactiveWorkspaceTabs) { + ok( + !tab.hasAttribute("pending"), + "Essential Tab in inactive workspace should not be unloaded" + ); + ok( + tab.linkedPanel, + "Essential Tab in inactive workspace should have linked panel" + ); + } + for (const tab of inactiveWorkspaceTabs) { + gBrowser.removeTab(tab); + } + await gZenWorkspaces.removeWorkspace(inactiveWorkspaceId); + await gZenWorkspaces.removeWorkspace(activeWorkspaceId); +}); From 270db6d6713d2c6c14d9df0b4bc7662843d3d54e Mon Sep 17 00:00:00 2001 From: JDX50S <71799746+smoke-wolf@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:28:31 -0300 Subject: [PATCH 039/149] Merge commit from fork * security: enable MAR signature verification for updates Remove `--enable-unverified-updates` from the common mozconfig. This flag was disabling all MAR (Mozilla ARchive) signature verification in the updater binary, meaning update packages were applied without any cryptographic authenticity check. With this flag removed, the Mozilla build system will: - Link NSS and signmar into the updater binary - Enable SecVerifyTransformCreate-based signature verification on macOS - Require MAR files to contain valid signatures before applying REQUIRED FOLLOW-UP (maintainer action): 1. Generate a Zen-specific MAR signing keypair (RSA-PKCS1-SHA384) See: https://firefox-source-docs.mozilla.org/build/buildsystem/mar.html 2. Place the public key DER file(s) in the source tree at toolkit/mozapps/update/updater/release_primary.der 3. Sign MAR files during the release build with the private key 4. Set ACCEPTED_MAR_CHANNEL_IDS in update-settings.ini to restrict which update channels the updater will accept Ref: GHSA-qpj9-m8jc-mw6q * no-bug: Added signature steps * no-bug: Export browser/installer/package-manifest.in --------- Co-authored-by: Maliq Barnard Co-authored-by: Mr. M --- .github/workflows/build.yml | 14 ++ .github/workflows/linux-release-build.yml | 8 + .github/workflows/src/release-build.sh | 2 + .gitignore | 7 + build/signing/public_key.der | Bin 0 -> 550 bytes configs/common/mozconfig | 4 +- scripts/mar_sign.sh | 165 ++++++++++++++++++ .../installer/package-manifest-in.patch | 14 +- .../update/updater/updater-common-build.patch | 2 +- 9 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 build/signing/public_key.der create mode 100644 scripts/mar_sign.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 607470d6f..07203a4a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -505,6 +505,20 @@ jobs: run: | git clone https://github.com/zen-browser/windows-binaries.git .github/workflows/object --depth 1 + - name: Download signmar-linux-x86_64 from artifacts + uses: actions/download-artifact@v4 + with: + name: signmar-linux-x86_64 + + - name: Sign MAR files + env: + SIGNMAR: ${{ github.workspace }}/signmar-linux-x86_64 + ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} + ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} + ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} + run: | + bash scripts/mar_sign.sh -s + - name: Copy update manifests env: RELEASE_BRANCH: ${{ inputs.update_branch }} diff --git a/.github/workflows/linux-release-build.yml b/.github/workflows/linux-release-build.yml index 93c6a70da..2ce7906cc 100644 --- a/.github/workflows/linux-release-build.yml +++ b/.github/workflows/linux-release-build.yml @@ -173,3 +173,11 @@ jobs: retention-days: 5 name: linux_update_manifest_${{ matrix.arch }} path: ./dist/update + + - name: Upload signmar + if: ${{ matrix.arch == 'x86_64' }} + uses: actions/upload-artifact@v4 + with: + retention-days: 2 + name: signmar-linux-x86_64 + path: engine/obj-x86_64-pc-linux-gnu/dist/bin/signmar diff --git a/.github/workflows/src/release-build.sh b/.github/workflows/src/release-build.sh index e553f3942..4a522473d 100644 --- a/.github/workflows/src/release-build.sh +++ b/.github/workflows/src/release-build.sh @@ -10,6 +10,8 @@ fi . $HOME/.cargo/env +sh ./scripts/mar_sign.sh -i + ulimit -n 4096 if command -v Xvfb &> /dev/null; then diff --git a/.gitignore b/.gitignore index 716fd810f..67b3b7ef6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,10 @@ locales/firefox-l10n/ .DS_Store mozconfig + +build/signing/env/ +build/signing/nss_config/ +build/signing/cert.pem +build/signing/private_key.pem +build/signing/private_key.p12 + diff --git a/build/signing/public_key.der b/build/signing/public_key.der new file mode 100644 index 0000000000000000000000000000000000000000..68994169095e588fc3ab481756409d8c543063fd GIT binary patch literal 550 zcmXqLVp1~TW#iOp^Jx3d%gD&c%D~*j#Lr;R#Kgta#Kg$3q4`(*--S09#J*>)^_B^l zw}fjYlistF=hxZY$n9g{y5=_Z*gNl2=bdy`r!?s6d!MYEV70b&XKYK>`nl;#Pg>7e zzR~SxIkSexGVh;j-tLyv^l*44ael>z*)J+>lkS}QtsPd_j4dAaWLzeDPoD-S7sS~<@^vU&27oiCWrCAl8s%D??# zzWUrZ9&sj5B_Gebs=9b)*UR4>n;iG=*lJn*=S!ac<3|inZoB zYyZ?wPvXG6Qhv*)zGH@dP*_4f65cA-~u)<*8kNtd?z_u{~6?&xD%S#E94 z+EsJn)Q$Or%2 zJd>`my!d-hGSGni>12D|3(~Un@y#zC_h=k{c|Ea2)hB}IhlW9CYT#1Yw>L|_J>3@Z z>wdMlU**XK>z*kc*rIraPfdHmP2HFmRqmU8pW7s-_ieEMP`WI+Kq*L6f9f24zb`JQ OgkK+UWMXDyU<3f&oC#|H literal 0 HcmV?d00001 diff --git a/configs/common/mozconfig b/configs/common/mozconfig index 3d41bc83a..16a51385a 100644 --- a/configs/common/mozconfig +++ b/configs/common/mozconfig @@ -48,6 +48,8 @@ if test "$ZEN_RELEASE"; then ac_add_options --enable-optimize + ac_add_options --enable-verify-mar + ac_add_options --enable-release ac_add_options --disable-debug ac_add_options --disable-debug-symbols @@ -89,8 +91,6 @@ if test "$ZEN_RELEASE"; then ac_add_options --enable-replace-malloc fi -ac_add_options --enable-unverified-updates - ac_add_options --enable-jxl ac_add_options --with-unsigned-addon-scopes=app,system diff --git a/scripts/mar_sign.sh b/scripts/mar_sign.sh new file mode 100644 index 000000000..2dfbfbc6c --- /dev/null +++ b/scripts/mar_sign.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# 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/. + +set -e + +CERT_PATH_DIR=build/signing +UPDATER_CERT_DIR="engine/toolkit/mozapps/update/updater" +NSS_CONFIG_DIR="$CERT_PATH_DIR/nss_config" + +generate_certs() { + mkdir temp + cd temp + + # 1. Generate private key + openssl genrsa -out private_key.pem 4096 + + # 2. Generate self-signed certificate (required for PKCS#12 bundling) + openssl req -new -x509 \ + -key private_key.pem \ + -out cert.pem \ + -subj "/CN=MAR Signing" + + # 3. Export public key as SPKI DER (for embedding in updater) + openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der + + cd .. + mkdir -p "$CERT_PATH_DIR" + mv temp/private_key.pem "$CERT_PATH_DIR"/private_key.pem + mv temp/cert.pem "$CERT_PATH_DIR"/cert.pem + mv temp/public_key.der "$CERT_PATH_DIR"/public_key.der + + mkdir -p "$CERT_PATH_DIR/env" + base64 -w 0 "$CERT_PATH_DIR"/cert.pem > "$CERT_PATH_DIR"/env/ZEN_SIGNING_CERT_PEM_BASE64 + base64 -w 0 "$CERT_PATH_DIR"/private_key.pem > "$CERT_PATH_DIR"/env/ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 + + # Verify public key + openssl rsa -in "$CERT_PATH_DIR"/public_key.der \ + -pubin -inform DER -text -noout + + rm -rf temp +} + +import_cert() { + if [ ! -f "$CERT_PATH_DIR/public_key.der" ]; then + echo "Error: public_key.der not found. Run with -g first." >&2 + exit 1 + fi + echo "Importing certificate into $UPDATER_CERT_DIR/release_primary.der" + cp "$CERT_PATH_DIR/public_key.der" "$UPDATER_CERT_DIR/release_primary.der" + echo "Importing certificate into $UPDATER_CERT_DIR/release_secondary.der" + cp "$CERT_PATH_DIR/public_key.der" "$UPDATER_CERT_DIR/release_secondary.der" + echo "Done. Rebuild the updater to embed the new certificate." +} + +create_nss_config_dir() { + rm -rf "$NSS_CONFIG_DIR" + mkdir "$NSS_CONFIG_DIR" + + if [ -z "$ZEN_MAR_SIGNING_PASSWORD" ]; then + echo "Warning: ZEN_MAR_SIGNING_PASSWORD environment variable not set. Using empty password." >&2 + ZEN_MAR_SIGNING_PASSWORD="" + fi + + password_file="$NSS_CONFIG_DIR/password.txt" + echo "$ZEN_MAR_SIGNING_PASSWORD" > "$password_file" + + if [ "$ZEN_SIGNING_CERT_PEM_BASE64" ]; then + echo "Decoding signing certificate from ZEN_SIGNING_CERT_PEM_BASE64 environment variable..." + echo "$ZEN_SIGNING_CERT_PEM_BASE64" | base64 -d > "$CERT_PATH_DIR/cert.pem" + fi + + if [ "$ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64" ]; then + echo "Decoding signing private key from ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 environment variable..." + echo "$ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64" | base64 -d > "$CERT_PATH_DIR/private_key.pem" + fi + + echo "Generating NSS config directory at $NSS_CONFIG_DIR" + certutil -N -d "$NSS_CONFIG_DIR" -f "$password_file" + + echo "Wrapping private key into PKCS#12..." + echo "Wrapping key + cert into PKCS#12..." + openssl pkcs12 -export \ + -inkey "$CERT_PATH_DIR/private_key.pem" \ + -in "$CERT_PATH_DIR/cert.pem" \ + -name "private_key" \ + -passout pass:"$ZEN_MAR_SIGNING_PASSWORD" \ + -out "$CERT_PATH_DIR/private_key.p12" + + echo "Importing PKCS#12 into NSS database..." + pk12util \ + -i "$CERT_PATH_DIR/private_key.p12" \ + -d "$NSS_CONFIG_DIR" \ + -W "$ZEN_MAR_SIGNING_PASSWORD" \ + -K "$ZEN_MAR_SIGNING_PASSWORD" +} + +cleanup_certs() { + rm -rf "$NSS_CONFIG_DIR" + rm -rf "$CERT_PATH_DIR/env" + + rm -f "$CERT_PATH_DIR/private_key.p12" + rm -f "$CERT_PATH_DIR/private_key.pem" + rm -f "$CERT_PATH_DIR/cert.pem" +} + +sign_mars() { + if [ ! -f "$SIGNMAR" ]; then + echo "Error: signmar not found at $SIGNMAR. Build the engine first." >&2 + exit 1 + fi + + create_nss_config_dir + + folders=( + linux.mar + linux-aarch64.mar + windows.mar + windows-arm64 + macos.mar + ) + # each folder will contain the .mar files for that platform, and the signature will be written in-place + for folder in "${folders[@]}"; do + if [ -d "$folder" ]; then + for mar_file in "$folder"/*.mar; do + if [ -f "$mar_file" ]; then + echo "" + echo "Signing $mar_file..." + # mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -s "$mar_file" "$mar_file".signed + echo "Signed $mar_file. Verifying signature..." + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -v "$mar_file".signed + mv "$mar_file".signed "$mar_file" + echo "Successfully signed $mar_file" + else + echo "No .mar files found in $folder, skipping." + fi + done + else + echo "Directory $folder not found, skipping." + fi + done + + cleanup_certs +} + +case "$1" in + -g) + generate_certs + ;; + -i) + import_cert + ;; + -s) + sign_mars + ;; + *) + echo "Usage: $0 [-g] [-i] [-s]" >&2 + echo " -g Generate MAR signing certificates" >&2 + echo " -i Import the certificate into the updater (release_primary.der)" >&2 + echo " -s Sign *.mar files in the current directory in-place" >&2 + exit 1 + ;; +esac diff --git a/src/browser/installer/package-manifest-in.patch b/src/browser/installer/package-manifest-in.patch index 3aec7d9df..f07fcc3ac 100644 --- a/src/browser/installer/package-manifest-in.patch +++ b/src/browser/installer/package-manifest-in.patch @@ -1,18 +1,8 @@ diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 36eafe35063f02fe3d4acaab24a08dc1b7b0ae24..951889b156498f66118d67d4245aca649e27a3a2 100644 +index 36eafe35063f02fe3d4acaab24a08dc1b7b0ae24..b6bf327bf286de5246e5c50d89519d16d5771caf 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -378,17 +378,17 @@ bin/libfreebl_64int_3.so - ; [MaintenanceService] - ; - #ifdef MOZ_MAINTENANCE_SERVICE --@BINPATH@/maintenanceservice.exe --@BINPATH@/maintenanceservice_installer.exe -+;@BINPATH@/maintenanceservice.exe -+;@BINPATH@/maintenanceservice_installer.exe - #endif - - ; [Crash Reporter] +@@ -386,9 +386,9 @@ bin/libfreebl_64int_3.so ; #ifdef MOZ_CRASHREPORTER #ifdef XP_MACOSX diff --git a/src/toolkit/mozapps/update/updater/updater-common-build.patch b/src/toolkit/mozapps/update/updater/updater-common-build.patch index 03390b4c7..ee8ed45d6 100644 --- a/src/toolkit/mozapps/update/updater/updater-common-build.patch +++ b/src/toolkit/mozapps/update/updater/updater-common-build.patch @@ -7,7 +7,7 @@ index 57ea0415653678bb300e277e66c97e332e756cc7..5f757e68a685948c83fee8f963c49bee "signmar", ] + if CONFIG["OS_ARCH"] == "Linux": -+ # Zen: --enable-unverified-updates is enabled, the RPATH is not added ++ # Zen: ensure RPATH is set so NSS/signmar libs are found at runtime + OS_LIBS += [ + "-Wl,-rpath=\\$$ORIGIN", + ] From 5163cf68d685c6813652bb84edd7358b04ba92c2 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 9 Apr 2026 19:57:59 +0200 Subject: [PATCH 040/149] no-bug: update script execution to use bash for mar_sign.sh (gh-13181) --- .github/workflows/src/release-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/src/release-build.sh b/.github/workflows/src/release-build.sh index 4a522473d..7b2a5b034 100644 --- a/.github/workflows/src/release-build.sh +++ b/.github/workflows/src/release-build.sh @@ -10,7 +10,7 @@ fi . $HOME/.cargo/env -sh ./scripts/mar_sign.sh -i +bash ./scripts/mar_sign.sh -i ulimit -n 4096 From 4ca83bfe338d0a21914b03b54522622609408e3d Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:06:27 +0200 Subject: [PATCH 041/149] no-bug: remove unnecessary verification option from build configuration (gh-13182) --- configs/common/mozconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/configs/common/mozconfig b/configs/common/mozconfig index 16a51385a..a93df9072 100644 --- a/configs/common/mozconfig +++ b/configs/common/mozconfig @@ -48,8 +48,6 @@ if test "$ZEN_RELEASE"; then ac_add_options --enable-optimize - ac_add_options --enable-verify-mar - ac_add_options --enable-release ac_add_options --disable-debug ac_add_options --disable-debug-symbols From a2a64cec6a04bbed67615643f2f9e00b5ad78208 Mon Sep 17 00:00:00 2001 From: Slowlife Date: Fri, 10 Apr 2026 01:22:06 +0700 Subject: [PATCH 042/149] gh-13085: add support for new gh pull request dashboard (gh-13090) --- src/zen/live-folders/ZenLiveFolder.sys.mjs | 6 +- .../providers/GithubLiveFolder.sys.mjs | 248 +++++++++++------- 2 files changed, 159 insertions(+), 95 deletions(-) diff --git a/src/zen/live-folders/ZenLiveFolder.sys.mjs b/src/zen/live-folders/ZenLiveFolder.sys.mjs index 821a1fb29..54ed5d2c1 100644 --- a/src/zen/live-folders/ZenLiveFolder.sys.mjs +++ b/src/zen/live-folders/ZenLiveFolder.sys.mjs @@ -122,7 +122,7 @@ export class nsZenLiveFolderProvider { this.manager.saveState(); } - fetch(url, { maxContentLength = 5 * 1024 * 1024 } = {}) { + fetch(url, { maxContentLength = 5 * 1024 * 1024, headers = {} } = {}) { const uri = lazy.NetUtil.newURI(url); // TODO: Support userContextId when fetching, it should be inherited from the folder's // current space context ID. @@ -155,6 +155,10 @@ export class nsZenLiveFolderProvider { triggeringPrincipal: principal, }).QueryInterface(Ci.nsIHttpChannel); + for (const [name, value] of Object.entries(headers)) { + channel.setRequestHeader(name, value, false); + } + let httpStatus = null; let contentType = ""; let headerCharset = null; diff --git a/src/zen/live-folders/providers/GithubLiveFolder.sys.mjs b/src/zen/live-folders/providers/GithubLiveFolder.sys.mjs index 1deeb6f43..398ebaa77 100644 --- a/src/zen/live-folders/providers/GithubLiveFolder.sys.mjs +++ b/src/zen/live-folders/providers/GithubLiveFolder.sys.mjs @@ -32,6 +32,26 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { return "zen-live-folder-github-no-filter"; } + if ( + this.state.type === "pull-requests" && + typeof this.state.isJsonApi !== "boolean" + ) { + const { text, status } = await this.fetch(this.state.url, { + headers: { + Accept: "application/json,text/html", + }, + }); + if (status === 404) { + return "zen-live-folder-github-no-auth"; + } + try { + JSON.parse(text); + this.state.isJsonApi = true; + } catch { + this.state.isJsonApi = false; + } + } + const queries = this.#buildSearchOptions(); const requests = await Promise.all( queries.map(query => { @@ -56,11 +76,15 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { } if (items) { - items.forEach(item => combinedItems.set(item.id, item)); + for (const item of items) { + combinedItems.set(item.id, item); + } } if (activeRepos) { - activeRepos.forEach(repo => combinedActiveRepos.add(repo)); + for (const repo of activeRepos) { + combinedActiveRepos.add(repo); + } } } @@ -73,39 +97,44 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { } async parsePullRequests(url) { - const { text, status } = await this.fetch(url); + const { text, status } = await this.fetch(url, { + headers: { + Accept: "application/json,text/html", + }, + }); + if (status !== 200) { + return { status }; + } + + let parsedJson = null; try { - const document = new DOMParser().parseFromString(text, "text/html"); - const issues = document.querySelectorAll("div[id^=issue_]"); + parsedJson = JSON.parse(text); + this.state.isJsonApi = true; + } catch { + if (this.state.isJsonApi) { + this.state.isJsonApi = false; + // throw to indicate user to re-try (Url may contain invalid params for non-json /pulls) + throw new Error("Unexpected content type"); + } + } + + if (parsedJson) { + const results = + parsedJson.payload.pullsDashboardSurfaceContentRoute.results; + const items = []; - const activeRepos = []; + const activeRepos = new Set(); - if (issues.length) { - const authors = document.querySelectorAll(".opened-by a"); - const titles = document.querySelectorAll("a[id^=issue_]"); - - for (let i = 0; i < issues.length; i++) { - const author = authors[i].textContent; - const title = titles[i].textContent; - - const repo = titles[i].previousElementSibling.textContent.trim(); - if (repo) { - activeRepos.push(repo); - } - - const idMatch = authors[i].parentElement.textContent - .match(/#[0-9]+/) - .shift(); - - items.push({ - title, - subtitle: author, - icon: "chrome://browser/content/zen-images/favicons/github.svg", - url: new URL(titles[i].href, this.state.url), - id: `${repo}${idMatch}`, - }); - } + for (const pr of results) { + activeRepos.add(pr.repoNameWithOwner); + items.push({ + id: `${pr.repoNameWithOwner}#${pr.number}`, + title: pr.title, + subtitle: pr.author.displayLogin, + icon: "chrome://browser/content/zen-images/favicons/github.svg", + url: pr.permalink, + }); } return { @@ -114,78 +143,109 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { items, activeRepos, }; - } catch (err) { - console.error("Failed to parse Github pull requests", err); - return { - status, - }; } + const document = new DOMParser().parseFromString(text, "text/html"); + const issues = document.querySelectorAll("div[id^=issue_]"); + + const items = []; + const activeRepos = new Set(); + + if (issues.length) { + const authors = document.querySelectorAll(".opened-by a"); + const titles = document.querySelectorAll("a[id^=issue_]"); + + for (let i = 0; i < issues.length; i++) { + const author = authors[i].textContent; + const title = titles[i].textContent; + + const repo = titles[i].previousElementSibling.textContent.trim(); + if (repo) { + activeRepos.add(repo); + } + + const idMatch = authors[i].parentElement.textContent + .match(/#[0-9]+/) + .shift(); + + items.push({ + title, + subtitle: author, + icon: "chrome://browser/content/zen-images/favicons/github.svg", + url: new URL(titles[i].href, this.state.url), + id: `${repo}${idMatch}`, + }); + } + } + + return { + status, + + items, + activeRepos, + }; } async parseIssues(url) { const { text, status } = await this.fetch(url); - try { - const document = new DOMParser().parseFromString(text, "text/html"); - const issues = document.querySelectorAll( - "div[class^=IssueItem-module__defaultRepoContainer]" - ); - const items = []; - const activeRepos = []; - - if (issues.length) { - const authors = document.querySelectorAll( - "a[class^=IssueItem-module__authorCreatedLink]" - ); - const titles = document.querySelectorAll( - "div[class^=Title-module__container]" - ); - const links = document.querySelectorAll( - '[data-testid="issue-pr-title-link"]' - ); - - for (let i = 0; i < issues.length; i++) { - const [rawRepo, rawNumber] = issues[i].childNodes; - const author = authors[i]?.textContent; - const title = titles[i]?.textContent; - const issueUrl = links[i]?.href; - - const repo = rawRepo.textContent?.trim(); - if (repo) { - activeRepos.push(repo); - } - - const numberMatch = rawNumber?.textContent?.match(/[0-9]+/); - const number = numberMatch?.[0] ?? ""; - - items.push({ - title, - subtitle: author, - icon: "chrome://browser/content/zen-images/favicons/github.svg", - url: "https://github.com" + issueUrl, - id: `${repo}#${number}`, - }); - } - } - - return { - status, - - items, - activeRepos, - }; - } catch (err) { - console.error("Failed to parse Github Issues", err); - return { - status, - }; + if (status !== 200) { + return { status }; } + + const document = new DOMParser().parseFromString(text, "text/html"); + const issues = document.querySelectorAll( + "div[class^=IssueItem-module__defaultRepoContainer]" + ); + const items = []; + const activeRepos = new Set(); + + if (issues.length) { + const authors = document.querySelectorAll( + "a[class^=IssueItem-module__authorCreatedLink]" + ); + const titles = document.querySelectorAll( + "div[class^=Title-module__container]" + ); + const links = document.querySelectorAll( + '[data-testid="issue-pr-title-link"]' + ); + + for (let i = 0; i < issues.length; i++) { + const [rawRepo, rawNumber] = issues[i].childNodes; + const author = authors[i]?.textContent; + const title = titles[i]?.textContent; + const issueUrl = links[i]?.href; + + const repo = rawRepo.textContent?.trim(); + if (repo) { + activeRepos.add(repo); + } + + const numberMatch = rawNumber?.textContent?.match(/[0-9]+/); + const number = numberMatch?.[0] ?? ""; + + items.push({ + title, + subtitle: author, + icon: "chrome://browser/content/zen-images/favicons/github.svg", + url: "https://github.com" + issueUrl, + id: `${repo}#${number}`, + }); + } + } + + return { + status, + + items, + activeRepos, + }; } #buildSearchOptions() { const baseQuery = [ this.state.type === "pull-requests" ? "is:pr" : "is:issue", - "state:open", + "is:open", "sort:updated-desc", ]; @@ -219,7 +279,7 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { } const searchParams = []; - if (this.state.type === "pull-requests") { + if (this.state.type === "pull-requests" && !this.state.isJsonApi) { for (const query of queries) { searchParams.push(`${baseQuery.join(" ")} ${query}`); } @@ -227,8 +287,8 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider { return searchParams; } - // type: issues - return [`${baseQuery.join(" ")} ${queries.join(" OR ")}`]; + // type: issues or pull requests json api + return [`${baseQuery.join(" ")} (${queries.join(" OR ")})`]; } get options() { From fc2eb5a20b50914db97deec1cc4b9d754d2c5399 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 9 Apr 2026 22:40:38 +0200 Subject: [PATCH 043/149] no-bug: Re-enable maintenance service (gh-13186) --- configs/windows/mozconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/configs/windows/mozconfig b/configs/windows/mozconfig index ffe7892bf..9290c08bc 100644 --- a/configs/windows/mozconfig +++ b/configs/windows/mozconfig @@ -26,9 +26,6 @@ fi # This line should be removed once the detection is fixed. ac_add_options --without-ccache -ac_add_options --disable-maintenance-service -ac_add_options --disable-bits-download - if test "$SURFER_COMPAT" = "x86_64"; then ac_add_options --target=x86_64-pc-windows-msvc ac_add_options --enable-eme=widevine,wmfcdm From 0a7e81f53255a24e829c2939e8beeee9b76752e0 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Thu, 9 Apr 2026 22:41:27 +0200 Subject: [PATCH 044/149] gh-8932: Add more PGO instrumentation (gh-13158) --- scripts/update_external_patches.py | 2 +- .../ff150_1_pgo_patch_for_bug-1962418.patch | 441 +++++++++ .../ff150_2_pgo_patch_for_bug-2011620.patch | 409 +++++++++ .../ff150_3_pgo_patch_for_bug-2014422.patch | 868 ++++++++++++++++++ src/external-patches/manifest.json | 15 + src/zen/common/sys/ZenActorsManager.sys.mjs | 2 +- 6 files changed, 1735 insertions(+), 2 deletions(-) create mode 100644 src/external-patches/firefox/ff150_1_pgo_patch_for_bug-1962418.patch create mode 100644 src/external-patches/firefox/ff150_2_pgo_patch_for_bug-2011620.patch create mode 100644 src/external-patches/firefox/ff150_3_pgo_patch_for_bug-2014422.patch diff --git a/scripts/update_external_patches.py b/scripts/update_external_patches.py index 1ad279ab6..3e4c1057b 100644 --- a/scripts/update_external_patches.py +++ b/scripts/update_external_patches.py @@ -55,7 +55,7 @@ def main(): name = patch.get("name") if not phab_id or not name: die(f"Patch entry missing 'id' or 'name': {patch}") - name = name.replace(" ", "_").lower() + name = name.replace(" ", "_").replace(".", "_").lower() output_file = os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch") print(f"Processing Phabricator patch: {phab_id} -> {output_file}") download_phab_patch(phab_id, output_file) diff --git a/src/external-patches/firefox/ff150_1_pgo_patch_for_bug-1962418.patch b/src/external-patches/firefox/ff150_1_pgo_patch_for_bug-1962418.patch new file mode 100644 index 000000000..efe430372 --- /dev/null +++ b/src/external-patches/firefox/ff150_1_pgo_patch_for_bug-1962418.patch @@ -0,0 +1,441 @@ +diff --git a/build/pgo/index.html b/build/pgo/index.html +--- a/build/pgo/index.html ++++ b/build/pgo/index.html +@@ -3,11 +3,50 @@ + * 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/. */ + + /* global Quitter */ + +- var list = [ ++ var defaultTimeout = 2 * 1000; ++ var extendedTimeout = 2 * 60 * 1000; ++ var superExtendedTimeout = 5 * 60 * 1000; ++ var hasExtendedCorpus = ++ new URLSearchParams(location.search).get("extendedCorpus") == "true"; ++ ++ function waitTimeout(time) { ++ return new Promise(resolve => { ++ window.setTimeout(() => { ++ resolve(); ++ }, time); ++ }); ++ } ++ ++ /** ++ * An item in the PGO training corpus ++ */ ++ class Item { ++ url; ++ timeout; ++ ++ constructor(url, timeout = defaultTimeout) { ++ this.url = url; ++ this.timeout = timeout; ++ } ++ ++ async run() { ++ var subWindow = window.open(this.url); ++ ++ // Prevent the perf-reftest-singletons from calling alert() ++ subWindow.tpRecordTime = function () {}; ++ ++ // Wait until the timeout is finished ++ await waitTimeout(this.timeout); ++ ++ subWindow.close(); ++ } ++ } ++ ++ var defaultItemUrls = [ + "blueprint/elements.html", + "blueprint/forms.html", + "blueprint/grid.html", + "blueprint/sample.html", + "js-input/3d-thingy.html", +@@ -72,42 +111,46 @@ + "talos/tests/perf-reftest-singletons/style-sharing.html", + "talos/tests/perf-reftest-singletons/svg-text-textLength-1.html", + "talos/tests/perf-reftest-singletons/svg-text-getExtentOfChar-1.html", + "talos/tests/perf-reftest-singletons/tiny-traversal-singleton.html", + "talos/tests/perf-reftest-singletons/window-named-property-get.html", +- "webkit/PerformanceTests/Speedometer/index.html", +- "http://localhost:8000/index.html?startAutomatically=true", +- "webkit/PerformanceTests/webaudio/index.html?raptor&rendering-buffer-length=30", + ]; +- var defaultInterval = 2000; +- var idx = 0; +- var w; + +- window.onload = function () { +- w = window.open("about:blank"); +- window.setTimeout(loadURL, defaultInterval); +- }; +- function loadURL() { +- var interval = defaultInterval; +- var testURL = list[idx++]; +- if (testURL.includes("webkit") || testURL.includes("localhost")) { +- interval = 120000; +- } +- w.close(); +- w = window.open(testURL); +- // Prevent the perf-reftest-singletons from calling alert() +- w.tpRecordTime = function () {}; ++ // Start with items with the default timeout ++ var items = defaultItemUrls.map(x => new Item(x)); + +- if (idx < list.length) { +- window.setTimeout(loadURL, interval); +- } else { +- window.setTimeout(Quitter.quit, interval); +- } ++ // Add items that needs longer timeouts ++ items.push( ++ new Item("webkit/PerformanceTests/Speedometer/index.html", extendedTimeout), ++ new Item( ++ "http://localhost:8000/index.html?startAutomatically=true", ++ extendedTimeout ++ ), ++ new Item( ++ "webkit/PerformanceTests/webaudio/index.html?raptor&rendering-buffer-length=30", ++ extendedTimeout ++ ) ++ ); ++ ++ // Add optional items if there is a 'pgo-extended-corpus' provided ++ if (hasExtendedCorpus) { ++ items.push( ++ new Item( ++ "http://localhost:8001/index.html?startAutomatically=true&testIterationCount=3&worstCaseCount=1", ++ superExtendedTimeout ++ ) ++ ); + } +- var i; + +- for (i = 0; i < list.length; i++) { ++ window.onload = async function () { ++ for (let item of items) { ++ await item.run(); ++ } ++ Quitter.quit(); ++ }; ++ ++ for (let item of items) { + // eslint-disable-next-line no-unsanitized/method +- document.write(list[i]); ++ document.write(item.url); + document.write("
"); + } + +diff --git a/build/pgo/profileserver.py b/build/pgo/profileserver.py +--- a/build/pgo/profileserver.py ++++ b/build/pgo/profileserver.py +@@ -56,12 +56,33 @@ + test_name=name, + ) + return rc + + ++class ProfileServerCLI(CLI): ++ def __init__(self, args=sys.argv[1:]): ++ CLI.__init__(self, args=args) ++ ++ def add_options(self, parser): ++ CLI.add_options(self, parser) ++ ++ # add profileserver options ++ parser.add_option( ++ "-e", ++ "--extended-corpus", ++ dest="extended_corpus_dir", ++ help="Directory of the optional extended corpus.", ++ metavar=None, ++ default=None, ++ ) ++ ++ def extended_corpus_dir(self): ++ return self.options.extended_corpus_dir ++ ++ + if __name__ == "__main__": +- cli = CLI() ++ cli = ProfileServerCLI() + debug_args, interactive = cli.debugger_arguments() + runner_args = cli.runner_args() + + build = MozbuildObject.from_environment() + +@@ -72,29 +93,51 @@ + except BinaryNotFoundException as e: + print(f"{e}\n\n{e.help()}\n") + sys.exit(1) + binary = os.path.normpath(os.path.abspath(binary)) + ++ extended_corpus_dir = cli.extended_corpus_dir() ++ has_extended_corpus = extended_corpus_dir is not None ++ + path_mappings = { + k: os.path.join(build.topsrcdir, v) for k, v in PATH_MAPPINGS.items() + } + httpd = MozHttpd( + port=PORT, + docroot=os.path.join(build.topsrcdir, "build", "pgo"), + path_mappings=path_mappings, + ) + httpd.start(block=False) + ++ # Speedometer3 must run in its own server. The benchmark assumes that it ++ # is in a root path, and will fail if it's not. + sp3_httpd = MozHttpd( + port=8000, + docroot=os.path.join( + build.topsrcdir, "third_party", "webkit", "PerformanceTests", "Speedometer3" + ), + path_mappings=path_mappings, + ) + sp3_httpd.start(block=False) + print("started SP3 server on port 8000") ++ ++ if has_extended_corpus: ++ js3_dir = os.path.join(extended_corpus_dir, "JetStream") ++ ++ if not os.path.exists(js3_dir): ++ print(f"Error: JetStream directory does not exist at {js3_dir}") ++ sys.exit(1) ++ ++ # JetStream3 must run in its own server. The benchmark assumes that it ++ # is in a root path, and will fail if it's not. ++ js3_httpd = MozHttpd( ++ port=8001, ++ docroot=js3_dir, ++ ) ++ js3_httpd.start(block=False) ++ print("started JS3 server on port 8001") ++ + locations = ServerLocations() + locations.add_host(host="127.0.0.1", port=PORT, options="primary,privileged") + + old_profraw_files = glob.glob("*.profraw") + for f in old_profraw_files: +@@ -167,10 +210,12 @@ + if logfile: + print("Firefox output (%s):" % logfile) + with open(logfile) as f: + print(f.read()) + sp3_httpd.stop() ++ if has_extended_corpus: ++ js3_httpd.stop() + httpd.stop() + get_crashreports(profilePath, name="Profile initialization") + sys.exit(ret) + + jarlog = os.getenv("JARLOG_FILE") +@@ -182,21 +227,26 @@ + + if "UPLOAD_PATH" in env: + process_args["logfile"] = os.path.join( + env["UPLOAD_PATH"], "profile-run-2.log" + ) +- cmdargs = ["http://localhost:%d/index.html" % PORT] ++ cmdargs = [ ++ "http://localhost:%d/index.html?extendedCorpus=%s" ++ % (PORT, str(has_extended_corpus).lower()) ++ ] + runner = FirefoxRunner( + profile=profile, + binary=binary, + cmdargs=cmdargs, + env=env, + process_args=process_args, + ) + runner.start(debug_args=debug_args, interactive=interactive) + ret = runner.wait() + sp3_httpd.stop() ++ if has_extended_corpus: ++ js3_httpd.stop() + httpd.stop() + if ret: + print("Firefox exited with code %d during profiling" % ret) + logfile = process_args.get("logfile") + if logfile: +diff --git a/python/mozbuild/mozbuild/build_commands.py b/python/mozbuild/mozbuild/build_commands.py +--- a/python/mozbuild/mozbuild/build_commands.py ++++ b/python/mozbuild/mozbuild/build_commands.py +@@ -10,10 +10,11 @@ + + import mozpack.path as mozpath + from mach.decorators import Command, CommandArgument + + from mozbuild.backend import backends ++from mozbuild.bootstrap import bootstrap_toolchain + from mozbuild.mozconfig import MozconfigLoader + from mozbuild.util import ( + MOZBUILD_METRICS_PATH, + ensure_l10n_central, + get_latest_file, +@@ -275,10 +276,21 @@ + raise Exception("Cannot specify targets (%s) in MOZ_PGO=1 builds" % what) + instr = command_context._spawn(BuildDriver) + orig_topobjdir = instr._topobjdir + instr._topobjdir = mozpath.join(instr._topobjdir, "instrumented") + ++ # Allow opt-in of using the pgo-extended-corpus ++ use_extended_corpus = ( ++ configure_args and "MOZ_PGO_EXTENDED_CORPUS=1" in configure_args ++ ) ++ ++ # Get the location of the pgo-extended-corpus, if we are using it ++ if use_extended_corpus: ++ pgo_extended_corpus = bootstrap_toolchain("pgo-extended-corpus") ++ if not pgo_extended_corpus: ++ raise Exception("Cannot find pgo-extended-corpus.") ++ + append_env = {"MOZ_PROFILE_GENERATE": "1"} + status = instr.build( + command_context.metrics, + what=what, + jobs=jobs, +@@ -312,10 +324,13 @@ + pgo_env["JARLOG_FILE"] = mozpath.join(orig_topobjdir, "jarlog/en-US.log") + pgo_cmd = [ + command_context.virtualenv_manager.python_path, + mozpath.join(command_context.topsrcdir, "build/pgo/profileserver.py"), + ] ++ if use_extended_corpus: ++ pgo_cmd.extend(["--extended-corpus", str(pgo_extended_corpus)]) ++ + subprocess.check_call(pgo_cmd, cwd=instr.topobjdir, env=pgo_env) + + # Set the default build to MOZ_PROFILE_USE + append_env = {"MOZ_PROFILE_USE": "1"} + +diff --git a/taskcluster/kinds/fetch/benchmarks.yml b/taskcluster/kinds/fetch/benchmarks.yml +--- a/taskcluster/kinds/fetch/benchmarks.yml ++++ b/taskcluster/kinds/fetch/benchmarks.yml +@@ -15,5 +15,22 @@ + fetch: + type: static-url + url: https://github.com/mozilla/perf-automation/releases/download/V1/web-tooling-benchmark-b2ac25c897c9.zip + sha256: 93b0b51df0cec3ca9bfa0bdf81d782306dcf18532e39b3ff3180409125daaff1 + size: 5444135 ++ ++# A collection of benchmarks for use in PGO profiling runs. Currently it is ++# just JetStream3. ++# ++# Keep this in sync with the version used in performance testing by updating: ++# 1. `testing/raptor/raptor/tests/benchmarks/jetstream3-desktop.toml` ++# 2. `testing/raptor/raptor/tests/benchmarks/jetstream3-mobile.toml` ++pgo-extended-corpus: ++ description: JetStream3 benchmark suite ++ fetch: ++ type: static-url ++ url: https://github.com/WebKit/JetStream/archive/a3f5c45465f5271bed385321a0587bd4202682d6.tar.gz ++ sha256: 0af66b94bfbc2eb67cbe6c30bbafd13d7789f8f8623d308783194934601b5fdd ++ size: 194426956 ++ artifact-name: pgo-extended-corpus.tar.zst ++ strip-components: 1 ++ add-prefix: pgo-extended-corpus/JetStream/ +diff --git a/taskcluster/kinds/generate-profile/kind.yml b/taskcluster/kinds/generate-profile/kind.yml +--- a/taskcluster/kinds/generate-profile/kind.yml ++++ b/taskcluster/kinds/generate-profile/kind.yml +@@ -3,10 +3,11 @@ + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + --- + loader: taskgraph.loader.transform:loader + + kind-dependencies: ++ - fetch + - toolchain + - instrumented-build + + transforms: + - gecko_taskgraph.transforms.build_attrs:transforms +@@ -22,10 +23,13 @@ + treeherder: + symbol: Bpgo(run) + kind: build + tier: 1 + use-python: default ++ fetches: ++ fetch: ++ - pgo-extended-corpus + + tasks: + linux64-shippable/opt: + description: "Linux64 Profile Generation" + shipping-phase: build +diff --git a/taskcluster/scripts/misc/run-profileserver-macos.sh b/taskcluster/scripts/misc/run-profileserver-macos.sh +--- a/taskcluster/scripts/misc/run-profileserver-macos.sh ++++ b/taskcluster/scripts/misc/run-profileserver-macos.sh +@@ -13,8 +13,8 @@ + export LLVM_PROFDATA=$MOZ_FETCHES_DIR/clang/bin/llvm-profdata + + set -v + + ./mach python python/mozbuild/mozbuild/action/install.py $MOZ_FETCHES_DIR/target.dmg $MOZ_FETCHES_DIR +-./mach python build/pgo/profileserver.py --binary $MOZ_FETCHES_DIR/*.app/Contents/MacOS/firefox ++./mach python build/pgo/profileserver.py --binary $MOZ_FETCHES_DIR/*.app/Contents/MacOS/firefox --extended-corpus $MOZ_FETCHES_DIR/pgo-extended-corpus/ + + tar -Jcvf $UPLOAD_PATH/profdata.tar.xz merged.profdata en-US.log +diff --git a/taskcluster/scripts/misc/run-profileserver.sh b/taskcluster/scripts/misc/run-profileserver.sh +--- a/taskcluster/scripts/misc/run-profileserver.sh ++++ b/taskcluster/scripts/misc/run-profileserver.sh +@@ -35,8 +35,8 @@ + # Move our fetched firefox into objdir/dist so the jarlog entries will match + # the paths when the final PGO stage packages the build. + mkdir -p $PGO_RUNDIR + mkdir -p $UPLOAD_PATH + mv $MOZ_FETCHES_DIR/firefox $PGO_RUNDIR +-./mach python build/pgo/profileserver.py --binary $PGO_RUNDIR/firefox/firefox ++./mach python build/pgo/profileserver.py --binary $PGO_RUNDIR/firefox/firefox --extended-corpus $MOZ_FETCHES_DIR/pgo-extended-corpus/ + + tar -acvf $UPLOAD_PATH/profdata.tar.xz merged.profdata en-US.log +diff --git a/testing/mozharness/scripts/android_emulator_pgo.py b/testing/mozharness/scripts/android_emulator_pgo.py +--- a/testing/mozharness/scripts/android_emulator_pgo.py ++++ b/testing/mozharness/scripts/android_emulator_pgo.py +@@ -22,10 +22,11 @@ + from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options + + PAGES = [ + "js-input/webkit/PerformanceTests/Speedometer/index.html", + "js-input/webkit/PerformanceTests/Speedometer3/index.html?startAutomatically=true", ++ # TODO: Add support for the pgo-extended-corpus to get JetStream3 running here. + "blueprint/sample.html", + "blueprint/forms.html", + "blueprint/grid.html", + "blueprint/elements.html", + "js-input/3d-thingy.html", +diff --git a/testing/raptor/raptor/tests/benchmarks/jetstream3-desktop.toml b/testing/raptor/raptor/tests/benchmarks/jetstream3-desktop.toml +--- a/testing/raptor/raptor/tests/benchmarks/jetstream3-desktop.toml ++++ b/testing/raptor/raptor/tests/benchmarks/jetstream3-desktop.toml +@@ -14,10 +14,12 @@ + test_url = "http://:/" + type = "benchmark" + unit = "score" + support_class = "jetstream3.py" + repository = "https://github.com/webkit/jetstream" ++# Keep this in sync with the version used in PGO instrumentation by updating ++# `taskcluster/kinds/fetch/benchmarks.yml`. + repository_revision = "a3f5c45465f5271bed385321a0587bd4202682d6" + test_script = "jetstream3.js" + + ["jetstream3"] + suite_name = "JetStream3.0" +diff --git a/testing/raptor/raptor/tests/benchmarks/jetstream3-mobile.toml b/testing/raptor/raptor/tests/benchmarks/jetstream3-mobile.toml +--- a/testing/raptor/raptor/tests/benchmarks/jetstream3-mobile.toml ++++ b/testing/raptor/raptor/tests/benchmarks/jetstream3-mobile.toml +@@ -19,10 +19,12 @@ + test_url = "http://:/" + type = "benchmark" + unit = "score" + support_class = "jetstream3.py" + repository = "https://github.com/webkit/jetstream" ++# Keep this in sync with the version used in PGO instrumentation by updating ++# `taskcluster/kinds/fetch/benchmarks.yml`. + repository_revision = "a3f5c45465f5271bed385321a0587bd4202682d6" + test_script = "jetstream3.js" + + ["jetstream3"] + suite_name = "JetStream3.0" + diff --git a/src/external-patches/firefox/ff150_2_pgo_patch_for_bug-2011620.patch b/src/external-patches/firefox/ff150_2_pgo_patch_for_bug-2011620.patch new file mode 100644 index 000000000..da9579a02 --- /dev/null +++ b/src/external-patches/firefox/ff150_2_pgo_patch_for_bug-2011620.patch @@ -0,0 +1,409 @@ +diff --git a/build/pgo/index.html b/build/pgo/index.html +--- a/build/pgo/index.html ++++ b/build/pgo/index.html +@@ -10,10 +10,11 @@ + "blueprint/forms.html", + "blueprint/grid.html", + "blueprint/sample.html", + "js-input/3d-thingy.html", + "js-input/crypto-otp.html", ++ "js-input/normalizer_bench.html", + "js-input/sunspider/3d-cube.html", + "js-input/sunspider/3d-morph.html", + "js-input/sunspider/3d-raytrace.html", + "js-input/sunspider/access-binary-trees.html", + "js-input/sunspider/access-fannkuch.html", +diff --git a/build/pgo/js-input/normalizer_bench.html b/build/pgo/js-input/normalizer_bench.html +new file mode 100644 +--- /dev/null ++++ b/build/pgo/js-input/normalizer_bench.html +@@ -0,0 +1,358 @@ ++ ++ ++ ++ ++Normalizer bench ++ ++

Normalizer Bench

++
++
S
++
Short: NFD fits in 32 UTF-16 code units. French and German are adjusted to take a substring that contains a non-ASCII character. (Long input contains the same information in each language instead of having a fixed UTF-16 length.)
++
L
++
Latin1.
++
U
++
Forced UTF-16 form for Latin1 languages. (One non-Latin1 character added to the string.)
++
W
++
Forced write: In the UTF-16 case, a singleton is prepended to force the normalizer to start writing from the start. In the Latin1 case, a character with a compatibility decomposition is prepended, since there are no singletons in Latin1. This means the effect is seen only in the K forms.
++
C
++
Forced copy: In the UTF-16 case, a singleton is appended to force the normalizer to make a copy even when normalizing from NFC to a C form or from NFD to a D form. In the Latin1 case, a character with a compatibility decomposition is appended, since there are no singletons in Latin1. This means the effect is seen only in the K form corresponding to the input C or D form.
++
++ ++

Bench not started.

++ ++ ++ ++ ++
InputNFCNFKCNFDNFKD
Bench not run.
++ ++ ++ +diff --git a/testing/mozharness/scripts/android_emulator_pgo.py b/testing/mozharness/scripts/android_emulator_pgo.py +--- a/testing/mozharness/scripts/android_emulator_pgo.py ++++ b/testing/mozharness/scripts/android_emulator_pgo.py +@@ -28,10 +28,11 @@ + "blueprint/forms.html", + "blueprint/grid.html", + "blueprint/elements.html", + "js-input/3d-thingy.html", + "js-input/crypto-otp.html", ++ "js-input/normalizer_bench.html", + "js-input/sunspider/3d-cube.html", + "js-input/sunspider/3d-morph.html", + "js-input/sunspider/3d-raytrace.html", + "js-input/sunspider/access-binary-trees.html", + "js-input/sunspider/access-fannkuch.html", +diff --git a/toolkit/content/license.html b/toolkit/content/license.html +--- a/toolkit/content/license.html ++++ b/toolkit/content/license.html +@@ -5786,10 +5786,11 @@ +
  • third_party/rust/yoke-derive
  • +
  • third_party/rust/zerofrom
  • +
  • third_party/rust/zerofrom-derive
  • +
  • third_party/rust/zerovec
  • +
  • third_party/rust/zerovec-derive
  • ++
  • build/pgo/js-input/normalizer_bench.html
  • + + + +
    +             UNICODE LICENSE V3
    +
    diff --git a/src/external-patches/firefox/ff150_3_pgo_patch_for_bug-2014422.patch b/src/external-patches/firefox/ff150_3_pgo_patch_for_bug-2014422.patch
    new file mode 100644
    index 000000000..99add604c
    --- /dev/null
    +++ b/src/external-patches/firefox/ff150_3_pgo_patch_for_bug-2014422.patch
    @@ -0,0 +1,868 @@
    +diff --git a/build/pgo/index.html b/build/pgo/index.html
    +--- a/build/pgo/index.html
    ++++ b/build/pgo/index.html
    +@@ -49,10 +49,11 @@
    +     "blueprint/forms.html",
    +     "blueprint/grid.html",
    +     "blueprint/sample.html",
    +     "js-input/3d-thingy.html",
    +     "js-input/crypto-otp.html",
    ++    "js-input/collator_bench.html",
    +     "js-input/normalizer_bench.html",
    +     "js-input/sunspider/3d-cube.html",
    +     "js-input/sunspider/3d-morph.html",
    +     "js-input/sunspider/3d-raytrace.html",
    +     "js-input/sunspider/access-binary-trees.html",
    +diff --git a/build/pgo/js-input/collator_bench.html b/build/pgo/js-input/collator_bench.html
    +new file mode 100644
    +--- /dev/null
    ++++ b/build/pgo/js-input/collator_bench.html
    +@@ -0,0 +1,817 @@
    ++
    ++
    ++
    ++
    ++Collator bench
    ++
    ++

    Collator Bench

    ++ ++

    Bench not started.

    ++ ++ ++ ++ ++
    WorkloadTime
    Bench not run.
    ++ ++ ++ ++ +diff --git a/testing/mozharness/scripts/android_emulator_pgo.py b/testing/mozharness/scripts/android_emulator_pgo.py +--- a/testing/mozharness/scripts/android_emulator_pgo.py ++++ b/testing/mozharness/scripts/android_emulator_pgo.py +@@ -29,10 +29,11 @@ + "blueprint/forms.html", + "blueprint/grid.html", + "blueprint/elements.html", + "js-input/3d-thingy.html", + "js-input/crypto-otp.html", ++ "js-input/collator_bench.html", + "js-input/normalizer_bench.html", + "js-input/sunspider/3d-cube.html", + "js-input/sunspider/3d-morph.html", + "js-input/sunspider/3d-raytrace.html", + "js-input/sunspider/access-binary-trees.html", +diff --git a/toolkit/content/license.html b/toolkit/content/license.html +--- a/toolkit/content/license.html ++++ b/toolkit/content/license.html +@@ -5788,10 +5788,11 @@ +
  • third_party/rust/zerofrom
  • +
  • third_party/rust/zerofrom-derive
  • +
  • third_party/rust/zerovec
  • +
  • third_party/rust/zerovec-derive
  • +
  • build/pgo/js-input/normalizer_bench.html
  • ++
  • build/pgo/js-input/collator_bench.html
  • + + + +
    +             UNICODE LICENSE V3
    +
    diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json
    index 91c2934ab..ff81da911 100644
    --- a/src/external-patches/manifest.json
    +++ b/src/external-patches/manifest.json
    @@ -40,5 +40,20 @@
         "type": "phabricator",
         "id": "D291714",
         "name": "gh-12979 Clip dirty_rect to device_size"
    +  },
    +  {
    +    "type": "phabricator",
    +    "id": "D256645",
    +    "name": "FF150 1 PGO patch for bug-1962418"
    +  },
    +  {
    +    "type": "phabricator",
    +    "id": "D279829",
    +    "name": "FF150 2 PGO patch for bug-2011620"
    +  },
    +  {
    +    "type": "phabricator",
    +    "id": "D281762",
    +    "name": "FF150 3 PGO patch for bug-2014422"
       }
     ]
    diff --git a/src/zen/common/sys/ZenActorsManager.sys.mjs b/src/zen/common/sys/ZenActorsManager.sys.mjs
    index 6595d55ee..3f1404557 100644
    --- a/src/zen/common/sys/ZenActorsManager.sys.mjs
    +++ b/src/zen/common/sys/ZenActorsManager.sys.mjs
    @@ -54,7 +54,7 @@ let JSWINDOWACTORS = {
           },
         },
         allFrames: true,
    -    matches: ["*://*/*"],
    +    remoteTypes: ["web", "file"],
         enablePreference: "zen.glance.enabled",
       },
     };
    
    From 4add28d3c026d1f2d30dfe8bed1d22f660491f44 Mon Sep 17 00:00:00 2001
    From: CosmoCreeper <179134799+CosmoCreeper@users.noreply.github.com>
    Date: Thu, 9 Apr 2026 16:46:47 -0400
    Subject: [PATCH 045/149] no-bug: Remove non-existent hooks property (gh-13160)
    
    Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
    ---
     package.json | 4 ----
     1 file changed, 4 deletions(-)
    
    diff --git a/package.json b/package.json
    index a9d156ad1..f5dff7d7a 100644
    --- a/package.json
    +++ b/package.json
    @@ -23,7 +23,6 @@
         "sync:l10n": "python3 scripts/update_ff.py --just-l10n",
         "lint": "cd engine && ./mach lint zen",
         "lint:fix": "npm run lint -- --fix",
    -    "prepare": "husky",
         "reset-ff": "surfer reset",
         "surfer": "surfer",
         "test": "python3 scripts/run_tests.py",
    @@ -38,9 +37,6 @@
         "type": "git",
         "url": "git+https://github.com/zen-browser/desktop.git"
       },
    -  "hooks": {
    -    "pre-commit": "npm run prepare"
    -  },
       "keywords": [],
       "author": "",
       "license": "MPL-2.0",
    
    From dfc47ee5d746e9f0e77544ccc65edcf5ff5382df Mon Sep 17 00:00:00 2001
    From: DQSS 
    Date: Thu, 9 Apr 2026 22:51:24 +0200
    Subject: [PATCH 046/149] gh-12241: fix skip startup bookmark invalidation when
     no workspace bookmarks exist (gh-13168)
    
    ---
     src/zen/spaces/ZenSpaceManager.mjs | 10 ++++++++--
     1 file changed, 8 insertions(+), 2 deletions(-)
    
    diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs
    index d1f6a609d..53dcf5bed 100644
    --- a/src/zen/spaces/ZenSpaceManager.mjs
    +++ b/src/zen/spaces/ZenSpaceManager.mjs
    @@ -2469,8 +2469,14 @@ class nsZenWorkspaces {
           }
         }
     
    -    // Reset bookmarks
    -    this.#invalidateBookmarkContainers();
    +    // Avoid forcing a startup toolbar rebuild when there are no
    +    // workspace-specific bookmark assignments to apply.
    +    const hasWorkspaceBookmarks = !!Object.keys(
    +      this._workspaceBookmarksCache?.bookmarks || {}
    +    ).length;
    +    if (!onInit || hasWorkspaceBookmarks) {
    +      this.#invalidateBookmarkContainers();
    +    }
     
         // Update workspace indicator
         await this.updateWorkspaceIndicator(workspace, this.workspaceIndicator);
    
    From 000098adb1a8af279c274e3f00cbc71a7ecc4b04 Mon Sep 17 00:00:00 2001
    From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
    Date: Thu, 9 Apr 2026 23:40:53 +0200
    Subject: [PATCH 047/149] no-bug: bump axios from 1.13.6 to 1.15.0 in the
     npm_and_yarn group across 1 directory (gh-13187)
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    Bumps the npm_and_yarn group with 1 update in the / directory:
    [axios](https://github.com/axios/axios).
    
    Updates `axios` from 1.13.6 to 1.15.0
    
    Release notes

    Sourced from axios's releases.

    v1.15.0

    This release delivers two critical security patches, adds runtime support for Deno and Bun, and includes significant CI hardening, documentation improvements, and routine dependency updates.

    ⚠️ Important Changes

    • Deprecation: url.parse() usage has been replaced to address Node.js deprecation warnings. If you are on a recent version of Node.js, this resolves console warnings you may have been seeing. (#10625)

    🔒 Security Fixes

    • Proxy Handling: Fixed a no_proxy hostname normalisation bypass that could lead to Server-Side Request Forgery (SSRF). (#10661)
    • Header Injection: Fixed an unrestricted cloud metadata exfiltration vulnerability via a header injection chain. (#10660)

    🚀 New Features

    • Runtime Support: Added compatibility checks and documentation for Deno and Bun environments. (#10652, #10653)

    🔧 Maintenance & Chores

    • CI Security: Hardened workflow permissions to least privilege, added the zizmor security scanner, pinned action versions, and gated npm publishing with OIDC and environment protection. (#10618, #10619, #10627, #10637, #10666)
    • Dependencies: Bumped serialize-javascript, handlebars, picomatch, vite, and denoland/setup-deno to latest versions. Added a 7-day Dependabot cooldown period. (#10574, #10572, #10568, #10663, #10664, #10665, #10669, #10670, #10616)
    • Documentation: Unified docs, improved beforeRedirect credential leakage example, clarified withCredentials/withXSRFToken behaviour, HTTP/2 support notes, async/await timeout error handling, header case preservation, and various typo fixes. (#10649, #10624, #7452, #7471, #10654, #10644, #10589)
    • Housekeeping: Removed stale files, regenerated lockfile, and updated sponsor scripts and blocks. (#10584, #10650, #10582, #10640, #10659, #10668)
    • Tests: Added regression coverage for urlencoded Content-Type casing. (#10573)

    🌟 New Contributors

    We are thrilled to welcome our new contributors. Thank you for helping improve Axios:

    v1.14.0

    This release focuses on compatibility fixes, adapter stability improvements, and test/tooling modernisation.

    ⚠️ Important Changes

    • Breaking Changes: None identified in this release.
    • Action Required: If you rely on env-based proxy behaviour or CJS resolution edge-cases, validate your integration after upgrade (notably proxy-from-env v2 alignment and main entry compatibility fix).

    🚀 New Features

    • Runtime Features: No new end-user features were introduced in this release.
    • Test Coverage Expansion: Added broader smoke/module test coverage for CJS and ESM package usage. (#7510)

    🐛 Bug Fixes

    • Headers: Trim trailing CRLF in normalised header values. (#7456)
    • HTTP/2: Close detached HTTP/2 sessions on timeout to avoid lingering sessions. (#7457)
    • Fetch Adapter: Cancel ReadableStream created during request-stream capability probing to prevent async resource leaks. (#7515)
    • Proxy Handling: Fixed env proxy behavior with proxy-from-env v2 usage. (#7499)

    ... (truncated)

    Changelog

    Sourced from axios's changelog.

    Changelog

    1.13.3 (2026-01-20)

    Bug Fixes

    • http2: Use port 443 for HTTPS connections by default. (#7256) (d7e6065)
    • interceptor: handle the error in the same interceptor (#6269) (5945e40)
    • main field in package.json should correspond to cjs artifacts (#5756) (7373fbf)
    • package.json: add 'bun' package.json 'exports' condition. Load the Node.js build in Bun instead of the browser build (#5754) (b89217e)
    • silentJSONParsing=false should throw on invalid JSON (#7253) (#7257) (7d19335)
    • turn AxiosError into a native error (#5394) (#5558) (1c6a86d)
    • types: add handlers to AxiosInterceptorManager interface (#5551) (8d1271b)
    • types: restore AxiosError.cause type from unknown to Error (#7327) (d8233d9)
    • unclear error message is thrown when specifying an empty proxy authorization (#6314) (6ef867e)

    Features

    Reverts

    • Revert "fix: silentJSONParsing=false should throw on invalid JSON (#7253) (#7…" (#7298) (a4230f5), closes #7253 #7 #7298
    • deps: bump peter-evans/create-pull-request from 7 to 8 in the github-actions group (#7334) (2d6ad5e)

    Contributors to this release

    ... (truncated)

    Commits
    • 772a4e5 chore(release): prepare release 1.15.0 (#10671)
    • 4b07137 chore(deps-dev): bump vite from 8.0.0 to 8.0.5 in /tests/smoke/esm (#10663)
    • 51e57b3 chore(deps-dev): bump vite from 8.0.2 to 8.0.5 (#10664)
    • fba1a77 chore(deps-dev): bump vite from 8.0.2 to 8.0.5 in /tests/module/esm (#10665)
    • 0bf6e28 chore(deps): bump denoland/setup-deno in the github-actions group (#10669)
    • 8107157 chore(deps-dev): bump the development_dependencies group with 4 updates (#10670)
    • e66530e ci: require npm-publish environment for releases (#10666)
    • 49f23cb chore(sponsor): update sponsor block (#10668)
    • 3631854 fix: unrestricted cloud metadata exfiltration via header injection chain (#10...
    • fb3befb fix: no_proxy hostname normalization bypass leads to ssrf (#10661)
    • Additional commits viewable in compare view
    Install script changes

    This version modifies prepare script that runs during installation. Review the package contents before updating.


    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=axios&package-manager=npm_and_yarn&previous-version=1.13.6&new-version=1.15.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/zen-browser/desktop/network/alerts).
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65a139677..c773998a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1005,15 +1005,15 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/b4a": { @@ -3254,11 +3254,14 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pump": { "version": "3.0.2", From 11cf410f873c22e9680f21c8a7437b565d6ef427 Mon Sep 17 00:00:00 2001 From: JDX50S <71799746+smoke-wolf@users.noreply.github.com> Date: Fri, 10 Apr 2026 07:25:16 -0300 Subject: [PATCH 048/149] no-bug: fix SIGNMAR path in Sign MAR step to point at binary not directory (gh-13193) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 07203a4a6..92ca489cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -512,7 +512,7 @@ jobs: - name: Sign MAR files env: - SIGNMAR: ${{ github.workspace }}/signmar-linux-x86_64 + SIGNMAR: ${{ github.workspace }}/signmar-linux-x86_64/signmar ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} From 97451e23c82eee85e614a1eaa274799e3cdababd Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:17:52 +0200 Subject: [PATCH 049/149] no-bug: Individually download each artifact on release (gh-13199) --- .github/workflows/build.yml | 33 ++++++++++++++++++++++++++++----- package-lock.json | 11 +++++++---- scripts/mar_sign.sh | 2 ++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92ca489cd..e9218085c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -490,8 +490,35 @@ jobs: submodules: recursive token: ${{ secrets.DEPLOY_KEY }} - - name: Download artifact + - name: Download artifact (source) uses: actions/download-artifact@v4 + with: + name: zen.source.tar.zst + + - name: Download artifact (MAR files) + uses: actions/download-artifact@v4 + with: + pattern: "*.mar" + + - name: Download artifact (Linux tars) + uses: actions/download-artifact@v4 + with: + pattern: "zen.linux-*.tar.xz" + + - name: Download artifact (Linux AppImage) + uses: actions/download-artifact@v4 + with: + pattern: "zen-*.AppImage*" + + - name: Download artifact (macOS universal DMG) + uses: actions/download-artifact@v4 + with: + name: zen.macos-universal.dmg + + - name: Download artifact (Windows installers) + uses: actions/download-artifact@v4 + with: + pattern: "zen.installer*.exe" - name: Checkout updates repository uses: actions/checkout@v4 @@ -565,8 +592,6 @@ jobs: ./zen-x86_64.AppImage.zsync/* ./zen-aarch64.AppImage/* ./zen-aarch64.AppImage.zsync/* - ./zen.win-x86_64.zip/* - ./zen.win-arm64.zip/* ./linux.mar/* ./linux-aarch64.mar/* ./windows.mar/* @@ -604,8 +629,6 @@ jobs: ./zen-x86_64.AppImage.zsync/* ./zen-aarch64.AppImage/* ./zen-aarch64.AppImage.zsync/* - ./.github/workflows/object/windows-x64-signed-x86_64/zen.win-x86_64.zip - ./.github/workflows/object/windows-x64-signed-arm64/zen.win-arm64.zip ./linux.mar/* ./linux-aarch64.mar/* ./.github/workflows/object/windows-x64-signed-x86_64/windows.mar diff --git a/package-lock.json b/package-lock.json index c773998a9..fa57400cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4177,16 +4177,19 @@ "peer": true }, "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/zip": { diff --git a/scripts/mar_sign.sh b/scripts/mar_sign.sh index 2dfbfbc6c..8b12a5d68 100644 --- a/scripts/mar_sign.sh +++ b/scripts/mar_sign.sh @@ -111,6 +111,8 @@ sign_mars() { exit 1 fi + chmod +x "$SIGNMAR" + create_nss_config_dir folders=( From fd8308fcb12631f1c498d7cb9e0351263acd799b Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:03:04 +0200 Subject: [PATCH 050/149] Revert "no-bug: Individually download each artifact on release" (gh-13211) Reverts zen-browser/desktop#13199 --------- Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> --- .github/workflows/build.yml | 29 +---------------------------- package-lock.json | 11 ++++------- 2 files changed, 5 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e9218085c..00e8d76f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -490,35 +490,8 @@ jobs: submodules: recursive token: ${{ secrets.DEPLOY_KEY }} - - name: Download artifact (source) + - name: Download artifact uses: actions/download-artifact@v4 - with: - name: zen.source.tar.zst - - - name: Download artifact (MAR files) - uses: actions/download-artifact@v4 - with: - pattern: "*.mar" - - - name: Download artifact (Linux tars) - uses: actions/download-artifact@v4 - with: - pattern: "zen.linux-*.tar.xz" - - - name: Download artifact (Linux AppImage) - uses: actions/download-artifact@v4 - with: - pattern: "zen-*.AppImage*" - - - name: Download artifact (macOS universal DMG) - uses: actions/download-artifact@v4 - with: - name: zen.macos-universal.dmg - - - name: Download artifact (Windows installers) - uses: actions/download-artifact@v4 - with: - pattern: "zen.installer*.exe" - name: Checkout updates repository uses: actions/checkout@v4 diff --git a/package-lock.json b/package-lock.json index fa57400cb..c773998a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4177,19 +4177,16 @@ "peer": true }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" + "node": ">= 14" } }, "node_modules/zip": { From 76b7bc96ef1e2d690ee86b62b926276a9af2a6a3 Mon Sep 17 00:00:00 2001 From: JDX50S <71799746+smoke-wolf@users.noreply.github.com> Date: Sat, 11 Apr 2026 07:39:44 -0300 Subject: [PATCH 051/149] gh-10746: Fix SMAuthorizedClients wrong Team ID (gh-13191) --- .../moz-configure/update-programs-configure.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/build/moz-configure/update-programs-configure.patch diff --git a/src/build/moz-configure/update-programs-configure.patch b/src/build/moz-configure/update-programs-configure.patch new file mode 100644 index 000000000..a3b7d8feb --- /dev/null +++ b/src/build/moz-configure/update-programs-configure.patch @@ -0,0 +1,13 @@ +diff --git a/build/moz.configure/update-programs.configure b/build/moz.configure/update-programs.configure +index d87fd6dd35b1211a7ef8f64c2e2af18b91dc1f43..e6691d50e6b2ee05828a25b2dc3cb71895ff6bd7 100644 +--- a/build/moz.configure/update-programs.configure ++++ b/build/moz.configure/update-programs.configure +@@ -73,7 +73,7 @@ def mac_prod_requirements_string(identifier): + f'identifier "{identifier}" and anchor apple generic and ' + "certificate 1[field.1.2.840.113635.100.6.2.6] and " + "certificate leaf[field.1.2.840.113635.100.6.1.13] and " +- 'certificate leaf[subject.OU] = "43AQ936H96"' ++ 'certificate leaf[subject.OU] = "9V5K9TP787"' + ) + + From a4f0d01a88d10447682cfa29dde8b6aa16441c2a Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sat, 11 Apr 2026 16:45:24 +0200 Subject: [PATCH 052/149] no-bug: Sign mars after building them (gh-13213) --- .github/workflows/build.yml | 14 ----- .github/workflows/linux-release-build.yml | 17 ++--- .../macos-universal-release-build.yml | 9 +++ .github/workflows/windows-release-build.yml | 10 +++ prefs/zen/split-view.yaml | 4 +- prefs/zen/workspaces.yaml | 2 +- prefs/zen/zen.yaml | 2 +- scripts/mar_sign.sh | 62 ++++++++----------- 8 files changed, 59 insertions(+), 61 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00e8d76f1..3d0fe531c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -505,20 +505,6 @@ jobs: run: | git clone https://github.com/zen-browser/windows-binaries.git .github/workflows/object --depth 1 - - name: Download signmar-linux-x86_64 from artifacts - uses: actions/download-artifact@v4 - with: - name: signmar-linux-x86_64 - - - name: Sign MAR files - env: - SIGNMAR: ${{ github.workspace }}/signmar-linux-x86_64/signmar - ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} - ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} - ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} - run: | - bash scripts/mar_sign.sh -s - - name: Copy update manifests env: RELEASE_BRANCH: ${{ inputs.update_branch }} diff --git a/.github/workflows/linux-release-build.yml b/.github/workflows/linux-release-build.yml index 2ce7906cc..50a7b954c 100644 --- a/.github/workflows/linux-release-build.yml +++ b/.github/workflows/linux-release-build.yml @@ -153,6 +153,15 @@ jobs: mv dist/zen-*.tar.xz "zen.linux-${{ matrix.arch }}.tar.xz" mv dist/output.mar linux${{ matrix.arch == 'aarch64' && '-aarch64' || '' }}.mar + - name: Sign MAR + env: + SIGNMAR: engine/obj-${{ matrix.arch == 'aarch64' && 'aarch64-unknown' || 'x86_64-pc' }}-linux-gnu/dist/bin/signmar + ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} + ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} + ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} + run: | + bash scripts/mar_sign.sh -s ./linux${{ matrix.arch == 'aarch64' && '-aarch64' || '' }}.mar + - name: Upload build artifact (binary) uses: actions/upload-artifact@v4 with: @@ -173,11 +182,3 @@ jobs: retention-days: 5 name: linux_update_manifest_${{ matrix.arch }} path: ./dist/update - - - name: Upload signmar - if: ${{ matrix.arch == 'x86_64' }} - uses: actions/upload-artifact@v4 - with: - retention-days: 2 - name: signmar-linux-x86_64 - path: engine/obj-x86_64-pc-linux-gnu/dist/bin/signmar diff --git a/.github/workflows/macos-universal-release-build.yml b/.github/workflows/macos-universal-release-build.yml index dbc2130f0..ea62c9667 100644 --- a/.github/workflows/macos-universal-release-build.yml +++ b/.github/workflows/macos-universal-release-build.yml @@ -247,6 +247,15 @@ jobs: npm run package -- --verbose mv ./dist/output.mar ./macos.mar + - name: Sign MAR + env: + SIGNMAR: engine/obj-x86_64-apple-darwin/dist/bin/signmar + ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} + ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} + ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} + run: | + bash scripts/mar_sign.sh -s ./macos.mar + - name: Upload build artifact (.mar) uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/windows-release-build.yml b/.github/workflows/windows-release-build.yml index a7260a733..353732b61 100644 --- a/.github/workflows/windows-release-build.yml +++ b/.github/workflows/windows-release-build.yml @@ -281,6 +281,16 @@ jobs: mv ./dist/output.mar windows${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.mar mv ./dist/zen.installer.exe ./zen.installer${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.exe + - name: Sign MAR + if: ${{ !inputs.generate-gpo }} + env: + SIGNMAR: engine/obj-${{ matrix.arch }}-pc-windows-msvc/dist/bin/signmar + ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} + ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} + ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} + run: | + bash scripts/mar_sign.sh -s ./windows${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.mar + - name: Upload artifact (PGO) uses: actions/upload-artifact@v4 if: ${{ inputs.generate-gpo && matrix.arch == 'x86_64' }} diff --git a/prefs/zen/split-view.yaml b/prefs/zen/split-view.yaml index 869b4c459..aa02b6def 100644 --- a/prefs/zen/split-view.yaml +++ b/prefs/zen/split-view.yaml @@ -15,7 +15,7 @@ value: true - name: zen.splitView.drag-over-split-delayMC - value: 1000 + value: 350 - name: zen.splitView.drag-over-split-threshold - value: 40 + value: 25 diff --git a/prefs/zen/workspaces.yaml b/prefs/zen/workspaces.yaml index 400a4bc9e..58a0499ac 100644 --- a/prefs/zen/workspaces.yaml +++ b/prefs/zen/workspaces.yaml @@ -33,7 +33,7 @@ value: true - name: zen.workspaces.dnd-switch-padding - value: 5 + value: 20 - name: zen.workspaces.debug value: "@cond" diff --git a/prefs/zen/zen.yaml b/prefs/zen/zen.yaml index fd0dbd67f..685bb3866 100644 --- a/prefs/zen/zen.yaml +++ b/prefs/zen/zen.yaml @@ -27,7 +27,7 @@ value: 20 # Percentage of folder height to trigger dragover - name: zen.tabs.dnd-switch-space-delay - value: 800 # milliseconds + value: 500 # milliseconds - name: zen.ctrlTab.show-pending-tabs value: false diff --git a/scripts/mar_sign.sh b/scripts/mar_sign.sh index 8b12a5d68..43b9eb7e7 100644 --- a/scripts/mar_sign.sh +++ b/scripts/mar_sign.sh @@ -84,7 +84,7 @@ create_nss_config_dir() { openssl pkcs12 -export \ -inkey "$CERT_PATH_DIR/private_key.pem" \ -in "$CERT_PATH_DIR/cert.pem" \ - -name "private_key" \ + -name "mar_cert" \ -passout pass:"$ZEN_MAR_SIGNING_PASSWORD" \ -out "$CERT_PATH_DIR/private_key.p12" @@ -105,7 +105,19 @@ cleanup_certs() { rm -f "$CERT_PATH_DIR/cert.pem" } -sign_mars() { +sign_mar() { + local mar_file="$1" + + if [ -z "$mar_file" ]; then + echo "Error: .mar file path is required. Usage: $0 -s " >&2 + exit 1 + fi + + if [ ! -f "$mar_file" ]; then + echo "Error: .mar file not found at $mar_file" >&2 + exit 1 + fi + if [ ! -f "$SIGNMAR" ]; then echo "Error: signmar not found at $SIGNMAR. Build the engine first." >&2 exit 1 @@ -115,34 +127,14 @@ sign_mars() { create_nss_config_dir - folders=( - linux.mar - linux-aarch64.mar - windows.mar - windows-arm64 - macos.mar - ) - # each folder will contain the .mar files for that platform, and the signature will be written in-place - for folder in "${folders[@]}"; do - if [ -d "$folder" ]; then - for mar_file in "$folder"/*.mar; do - if [ -f "$mar_file" ]; then - echo "" - echo "Signing $mar_file..." - # mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar - "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -s "$mar_file" "$mar_file".signed - echo "Signed $mar_file. Verifying signature..." - "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -v "$mar_file".signed - mv "$mar_file".signed "$mar_file" - echo "Successfully signed $mar_file" - else - echo "No .mar files found in $folder, skipping." - fi - done - else - echo "Directory $folder not found, skipping." - fi - done + echo "" + echo "Signing $mar_file..." + # mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_cert" -s "$mar_file" "$mar_file".signed + echo "Signed $mar_file. Verifying signature..." + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_cert" -v "$mar_file".signed + mv "$mar_file".signed "$mar_file" + echo "Successfully signed $mar_file" cleanup_certs } @@ -155,13 +147,13 @@ case "$1" in import_cert ;; -s) - sign_mars + sign_mar "$2" ;; *) - echo "Usage: $0 [-g] [-i] [-s]" >&2 - echo " -g Generate MAR signing certificates" >&2 - echo " -i Import the certificate into the updater (release_primary.der)" >&2 - echo " -s Sign *.mar files in the current directory in-place" >&2 + echo "Usage: $0 [-g] [-i] [-s ]" >&2 + echo " -g Generate MAR signing certificates" >&2 + echo " -i Import the certificate into the updater (release_primary.der)" >&2 + echo " -s Sign the given .mar file in-place" >&2 exit 1 ;; esac From cc46a1ee551900a19b920cc755e0100037687be1 Mon Sep 17 00:00:00 2001 From: Phannawich Jadpotwanich <40864901+phannawich@users.noreply.github.com> Date: Sat, 11 Apr 2026 08:32:23 -0700 Subject: [PATCH 053/149] gh-11835: resolve copy URL return about:blank during pending navigations (gh-12521) Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> --- .../urlbar/content/UrlbarInput-mjs.patch | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/browser/components/urlbar/content/UrlbarInput-mjs.patch b/src/browser/components/urlbar/content/UrlbarInput-mjs.patch index 4bc827b9e..0e2a7888a 100644 --- a/src/browser/components/urlbar/content/UrlbarInput-mjs.patch +++ b/src/browser/components/urlbar/content/UrlbarInput-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs -index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc6b01181b 100644 +index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..c17b4553829854340ef512dcb90bfd387069c8da 100644 --- a/browser/components/urlbar/content/UrlbarInput.mjs +++ b/browser/components/urlbar/content/UrlbarInput.mjs @@ -68,6 +68,13 @@ const lazy = XPCOMUtils.declareLazy({ @@ -75,7 +75,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc } if (isCanonized) { -@@ -2598,6 +2630,32 @@ export class UrlbarInput extends HTMLElement { +@@ -2598,6 +2630,42 @@ export class UrlbarInput extends HTMLElement { await this.#updateLayoutBreakoutDimensions(); } @@ -92,9 +92,19 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc + + get zenStrippedURI() { + let strippedURI = null; ++ let activeBrowser = this.window.gBrowser?.selectedBrowser; ++ let uriString = activeBrowser.userTypedValue || ++ (activeBrowser.currentURI ? activeBrowser.currentURI.spec : ""); ++ ++ let uri; ++ try { ++ uri = Services.io.newURI(uriString); ++ } catch (e) { ++ // Fallback if the provisional string isn't a valid URI yet ++ uri = activeBrowser.currentURI; ++ } + + // Error check occurs during isClipboardURIValid -+ let uri = this.window.gBrowser.currentURI; + try { + strippedURI = lazy.QueryStringStripper.stripForCopyOrShare(uri); + } catch (e) { @@ -108,7 +118,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc startLayoutExtend() { if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) { // Do not expand if the Urlbar does not support being expanded or it is -@@ -2612,6 +2670,13 @@ export class UrlbarInput extends HTMLElement { +@@ -2612,6 +2680,13 @@ export class UrlbarInput extends HTMLElement { this.setAttribute("breakout-extend", "true"); @@ -122,7 +132,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc // 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")) { -@@ -2631,6 +2696,27 @@ export class UrlbarInput extends HTMLElement { +@@ -2631,6 +2706,27 @@ export class UrlbarInput extends HTMLElement { return; } @@ -150,7 +160,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc this.removeAttribute("breakout-extend"); this.#updateTextboxPosition(); } -@@ -2661,7 +2747,7 @@ export class UrlbarInput extends HTMLElement { +@@ -2661,7 +2757,7 @@ export class UrlbarInput extends HTMLElement { forceUnifiedSearchButtonAvailable = false ) { let prevState = this.getAttribute("pageproxystate"); @@ -159,7 +169,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc this.setAttribute("pageproxystate", state); this._inputContainer.setAttribute("pageproxystate", state); this._identityBox?.setAttribute("pageproxystate", state); -@@ -2915,10 +3001,12 @@ export class UrlbarInput extends HTMLElement { +@@ -2915,10 +3011,12 @@ export class UrlbarInput extends HTMLElement { return; } this.style.top = px( @@ -172,7 +182,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc ); } -@@ -2977,9 +3065,10 @@ export class UrlbarInput extends HTMLElement { +@@ -2977,9 +3075,10 @@ export class UrlbarInput extends HTMLElement { return; } @@ -184,7 +194,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc ); this.style.setProperty( "--urlbar-height", -@@ -3413,6 +3502,7 @@ export class UrlbarInput extends HTMLElement { +@@ -3413,6 +3512,7 @@ export class UrlbarInput extends HTMLElement { } _toggleActionOverride(event) { @@ -192,7 +202,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc if ( event.keyCode == KeyEvent.DOM_VK_SHIFT || event.keyCode == KeyEvent.DOM_VK_ALT || -@@ -3516,8 +3606,8 @@ export class UrlbarInput extends HTMLElement { +@@ -3516,8 +3616,8 @@ export class UrlbarInput extends HTMLElement { if (!this.#isAddressbar) { return val; } @@ -203,7 +213,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc : val; // Only trim value if the directionality doesn't change to RTL and we're not // showing a strikeout https protocol. -@@ -3824,6 +3914,7 @@ export class UrlbarInput extends HTMLElement { +@@ -3824,6 +3924,7 @@ export class UrlbarInput extends HTMLElement { resultDetails = null, browser = this.window.gBrowser.selectedBrowser ) { @@ -211,7 +221,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc if (this.#isAddressbar) { this.#prepareAddressbarLoad( url, -@@ -3935,6 +4026,10 @@ export class UrlbarInput extends HTMLElement { +@@ -3935,6 +4036,10 @@ export class UrlbarInput extends HTMLElement { } reuseEmpty = true; } @@ -222,7 +232,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc if ( where == "tab" && reuseEmpty && -@@ -3942,6 +4037,9 @@ export class UrlbarInput extends HTMLElement { +@@ -3942,6 +4047,9 @@ export class UrlbarInput extends HTMLElement { ) { where = "current"; } @@ -232,7 +242,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc return where; } -@@ -4196,6 +4294,7 @@ export class UrlbarInput extends HTMLElement { +@@ -4196,6 +4304,7 @@ export class UrlbarInput extends HTMLElement { this.setResultForCurrentValue(null); this.handleCommand(); this.controller.clearLastQueryContextCache(); @@ -240,7 +250,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc this._suppressStartQuery = false; }); -@@ -4203,7 +4302,6 @@ export class UrlbarInput extends HTMLElement { +@@ -4203,7 +4312,6 @@ export class UrlbarInput extends HTMLElement { 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. @@ -248,7 +258,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc let controller = this.document.commandDispatcher.getControllerForCommand("cmd_paste"); -@@ -4319,7 +4417,11 @@ export class UrlbarInput extends HTMLElement { +@@ -4319,7 +4427,11 @@ export class UrlbarInput extends HTMLElement { if (!engineName && !source && !this.hasAttribute("searchmode")) { return; } @@ -261,7 +271,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc if (this._searchModeIndicatorTitle) { this._searchModeIndicatorTitle.textContent = ""; this._searchModeIndicatorTitle.removeAttribute("data-l10n-id"); -@@ -4629,6 +4731,7 @@ export class UrlbarInput extends HTMLElement { +@@ -4629,6 +4741,7 @@ export class UrlbarInput extends HTMLElement { this.document.l10n.setAttributes( this.inputField, @@ -269,7 +279,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc l10nId, l10nId == "urlbar-placeholder-with-name" ? { name: engineName } -@@ -4742,6 +4845,11 @@ export class UrlbarInput extends HTMLElement { +@@ -4742,6 +4855,11 @@ export class UrlbarInput extends HTMLElement { } _on_click(event) { @@ -281,7 +291,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc switch (event.target) { case this.inputField: case this._inputContainer: -@@ -4820,7 +4928,7 @@ export class UrlbarInput extends HTMLElement { +@@ -4820,7 +4938,7 @@ export class UrlbarInput extends HTMLElement { } } @@ -290,7 +300,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc this.view.autoOpen({ event }); } else { if (this._untrimOnFocusAfterKeydown) { -@@ -4860,9 +4968,16 @@ export class UrlbarInput extends HTMLElement { +@@ -4860,9 +4978,16 @@ export class UrlbarInput extends HTMLElement { } _on_mousedown(event) { @@ -308,7 +318,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc if ( event.composedTarget != this.inputField && event.composedTarget != this._inputContainer -@@ -4872,6 +4987,10 @@ export class UrlbarInput extends HTMLElement { +@@ -4872,6 +4997,10 @@ export class UrlbarInput extends HTMLElement { this.focusedViaMousedown = !this.focused; this._preventClickSelectsAll = this.focused; @@ -319,7 +329,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc // Keep the focus status, since the attribute may be changed // upon calling this.focus(). -@@ -4907,7 +5026,7 @@ export class UrlbarInput extends HTMLElement { +@@ -4907,7 +5036,7 @@ export class UrlbarInput extends HTMLElement { } // 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. @@ -328,7 +338,7 @@ index 2e6e2be9d7e28c3f189131ec19a26d552d13af99..101b5a3a70c24f28a755f2ca6630a6bc break; } -@@ -5235,7 +5354,7 @@ export class UrlbarInput extends HTMLElement { +@@ -5235,7 +5364,7 @@ export class UrlbarInput extends HTMLElement { // When we are in actions search mode we can show more results so // increase the limit. let maxResults = From 7bbbdd3c4b8ea787b00220b074d46b9311571848 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sun, 12 Apr 2026 22:55:36 +0200 Subject: [PATCH 054/149] gh-9540: Fixed duplicate bookmarks appearing on startup (gh-13232) --- src/zen/common/modules/ZenStartup.mjs | 4 ++++ src/zen/spaces/ZenSpaceBookmarksStorage.js | 2 +- src/zen/spaces/ZenSpaceManager.mjs | 9 +++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/zen/common/modules/ZenStartup.mjs b/src/zen/common/modules/ZenStartup.mjs index bfa20f596..664d4bc96 100644 --- a/src/zen/common/modules/ZenStartup.mjs +++ b/src/zen/common/modules/ZenStartup.mjs @@ -98,6 +98,10 @@ class ZenStartup { this.isReady = true; this.promiseInitializedResolve(); delete this.promiseInitializedResolve; + + setTimeout(() => { + gZenWorkspaces._invalidateBookmarkContainers(); + }); }); } diff --git a/src/zen/spaces/ZenSpaceBookmarksStorage.js b/src/zen/spaces/ZenSpaceBookmarksStorage.js index 59da45f61..acfd1ec2e 100644 --- a/src/zen/spaces/ZenSpaceBookmarksStorage.js +++ b/src/zen/spaces/ZenSpaceBookmarksStorage.js @@ -49,7 +49,7 @@ window.ZenWorkspaceBookmarksStorage = { timestamp INTEGER NOT NULL, UNIQUE(bookmark_guid), FOREIGN KEY(bookmark_guid) REFERENCES moz_bookmarks(guid) ON DELETE CASCADE - ) + ) `); // Create index for changes tracking diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs index 53dcf5bed..c0df1329b 100644 --- a/src/zen/spaces/ZenSpaceManager.mjs +++ b/src/zen/spaces/ZenSpaceManager.mjs @@ -2475,14 +2475,14 @@ class nsZenWorkspaces { this._workspaceBookmarksCache?.bookmarks || {} ).length; if (!onInit || hasWorkspaceBookmarks) { - this.#invalidateBookmarkContainers(); + this._invalidateBookmarkContainers(); } // Update workspace indicator await this.updateWorkspaceIndicator(workspace, this.workspaceIndicator); // Fix ctrl+tab behavior. Note, we dont call it with "await" because we dont want to wait for it - this._fixCtrlTabBehavior(); + this.#fixCtrlTabBehavior(); // Bug: When updating from previous versions, we used to hide the tabs not used in the new workspace // we now need to show them again. @@ -2512,12 +2512,13 @@ class nsZenWorkspaces { ); } - async _fixCtrlTabBehavior() { + // Intentionally keep it as async! + async #fixCtrlTabBehavior() { ctrlTab.uninit(); ctrlTab.readPref(); } - #invalidateBookmarkContainers() { + _invalidateBookmarkContainers() { for (let i = 0, len = this.bookmarkMenus.length; i < len; i++) { const element = document.getElementById(this.bookmarkMenus[i]); if (element && element._placesView) { From adc8c92816f7fbb0665ae5f360714ce15c4de422 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Mon, 13 Apr 2026 15:49:24 +0200 Subject: [PATCH 055/149] gh-9836: Finish the MAR signing workflow (gh-13216) --- .github/workflows/build.yml | 22 +++- .github/workflows/linux-release-build.yml | 17 ++- .../macos-universal-release-build.yml | 9 -- .github/workflows/windows-release-build.yml | 20 +--- scripts/mar_sign.sh | 110 ++++++++++++++---- .../shared/preferences/zen-preferences.css | 1 + 6 files changed, 113 insertions(+), 66 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d0fe531c..3bd0e581d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,7 +126,7 @@ jobs: permissions: contents: write name: Generate build data - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: ubuntu-latest needs: buildid outputs: build_date: ${{ steps.data.outputs.builddate }} @@ -359,7 +359,7 @@ jobs: name: AppImage build - Linux ${{ matrix.arch }} permissions: contents: write - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: ubuntu-latest strategy: matrix: arch: [x86_64, aarch64] @@ -439,7 +439,7 @@ jobs: path: ./dist/zen-${{ matrix.arch }}.AppImage.zsync stop-self-hosted: - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: ubuntu-latest needs: [windows-step-3, linux] if: always() steps: @@ -505,10 +505,22 @@ jobs: run: | git clone https://github.com/zen-browser/windows-binaries.git .github/workflows/object --depth 1 + - name: Sign MAR files + env: + SIGNMAR: ${{ github.workspace }}/linux-bin-x86_64/signmar + ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} + ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} + ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} + run: | + bash scripts/mar_sign.sh -s + - name: Copy update manifests env: RELEASE_BRANCH: ${{ inputs.update_branch }} run: | + # IMPORTANT: If changing any of these names, + # make sure to also update the paths in the mar_sign.sh script + cd updates-server mkdir -p updates cp -a ../linux_update_manifest_x86_64/. updates/ @@ -602,7 +614,7 @@ jobs: permissions: write-all name: Prepare Flatpak needs: [release, linux, build-data] - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: ubuntu-latest steps: - name: Checkout Flatpak repository @@ -661,7 +673,7 @@ jobs: permissions: write-all name: Release Flatpak needs: [prepare-flatpak, build-data] - runs-on: blacksmith-2vcpu-ubuntu-2404 + runs-on: ubuntu-latest steps: - name: Checkout Flatpak repository diff --git a/.github/workflows/linux-release-build.yml b/.github/workflows/linux-release-build.yml index 50a7b954c..2fba0e880 100644 --- a/.github/workflows/linux-release-build.yml +++ b/.github/workflows/linux-release-build.yml @@ -153,15 +153,6 @@ jobs: mv dist/zen-*.tar.xz "zen.linux-${{ matrix.arch }}.tar.xz" mv dist/output.mar linux${{ matrix.arch == 'aarch64' && '-aarch64' || '' }}.mar - - name: Sign MAR - env: - SIGNMAR: engine/obj-${{ matrix.arch == 'aarch64' && 'aarch64-unknown' || 'x86_64-pc' }}-linux-gnu/dist/bin/signmar - ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} - ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} - ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} - run: | - bash scripts/mar_sign.sh -s ./linux${{ matrix.arch == 'aarch64' && '-aarch64' || '' }}.mar - - name: Upload build artifact (binary) uses: actions/upload-artifact@v4 with: @@ -182,3 +173,11 @@ jobs: retention-days: 5 name: linux_update_manifest_${{ matrix.arch }} path: ./dist/update + + - name: Upload linux bin + if: ${{ matrix.arch == 'x86_64' }} + uses: actions/upload-artifact@v4 + with: + retention-days: 2 + name: linux-bin-x86_64 + path: engine/obj-x86_64-pc-linux-gnu/dist/bin/ diff --git a/.github/workflows/macos-universal-release-build.yml b/.github/workflows/macos-universal-release-build.yml index ea62c9667..dbc2130f0 100644 --- a/.github/workflows/macos-universal-release-build.yml +++ b/.github/workflows/macos-universal-release-build.yml @@ -247,15 +247,6 @@ jobs: npm run package -- --verbose mv ./dist/output.mar ./macos.mar - - name: Sign MAR - env: - SIGNMAR: engine/obj-x86_64-apple-darwin/dist/bin/signmar - ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} - ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} - ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} - run: | - bash scripts/mar_sign.sh -s ./macos.mar - - name: Upload build artifact (.mar) uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/windows-release-build.yml b/.github/workflows/windows-release-build.yml index 353732b61..10c1da6d3 100644 --- a/.github/workflows/windows-release-build.yml +++ b/.github/workflows/windows-release-build.yml @@ -281,21 +281,11 @@ jobs: mv ./dist/output.mar windows${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.mar mv ./dist/zen.installer.exe ./zen.installer${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.exe - - name: Sign MAR - if: ${{ !inputs.generate-gpo }} - env: - SIGNMAR: engine/obj-${{ matrix.arch }}-pc-windows-msvc/dist/bin/signmar - ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }} - ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }} - ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }} - run: | - bash scripts/mar_sign.sh -s ./windows${{ matrix.arch == 'aarch64' && '-arm64' || '' }}.mar - - name: Upload artifact (PGO) uses: actions/upload-artifact@v4 if: ${{ inputs.generate-gpo && matrix.arch == 'x86_64' }} with: - retention-days: 5 + retention-days: 2 name: ${{ matrix.arch == 'aarch64' && 'arm64' || matrix.arch }}-${{ inputs.profile-data-path-archive }} path: ./zen.win64-pgo-stage-1.zip @@ -322,14 +312,6 @@ jobs: name: windows-x64-obj-${{ matrix.arch == 'aarch64' && 'arm64' || matrix.arch }} path: obj-${{ matrix.arch }}-pc-windows-msvc - - name: Upload artifact (if Twilight branch, binary) - if: ${{ inputs.release-branch == 'twilight' && !inputs.generate-gpo }} - uses: actions/upload-artifact@v4 - with: - retention-days: 5 - name: zen.win-${{ matrix.arch == 'aarch64' && 'arm64' || matrix.arch }}.zip - path: ./zen.win-${{ matrix.arch == 'aarch64' && 'arm64' || matrix.arch }}.zip - - name: Upload artifact (if Twilight branch, installer) if: ${{ inputs.release-branch == 'twilight' && !inputs.generate-gpo }} uses: actions/upload-artifact@v4 diff --git a/scripts/mar_sign.sh b/scripts/mar_sign.sh index 43b9eb7e7..fb47c6a80 100644 --- a/scripts/mar_sign.sh +++ b/scripts/mar_sign.sh @@ -84,7 +84,7 @@ create_nss_config_dir() { openssl pkcs12 -export \ -inkey "$CERT_PATH_DIR/private_key.pem" \ -in "$CERT_PATH_DIR/cert.pem" \ - -name "mar_cert" \ + -name "mar_sig" \ -passout pass:"$ZEN_MAR_SIGNING_PASSWORD" \ -out "$CERT_PATH_DIR/private_key.p12" @@ -105,19 +105,58 @@ cleanup_certs() { rm -f "$CERT_PATH_DIR/cert.pem" } -sign_mar() { - local mar_file="$1" - - if [ -z "$mar_file" ]; then - echo "Error: .mar file path is required. Usage: $0 -s " >&2 - exit 1 - fi - - if [ ! -f "$mar_file" ]; then - echo "Error: .mar file not found at $mar_file" >&2 +update_manifests() { + mar_file=$(basename "$1") + if [[ "$mar_file" == "linux.mar" ]]; then + manifest="linux_update_manifest_x86_64" + elif [[ "$mar_file" == "linux-aarch64.mar" ]]; then + manifest="linux_update_manifest_aarch64" + elif [[ "$mar_file" == "windows.mar" ]]; then + manifest=".github/workflows/object/windows-x64-signed-x86_64/update_manifest" + if [ ! -f "$manifest" ]; then + manifest="windows_update_manifest_x86_64" + fi + elif [[ "$mar_file" == "windows-arm64.mar" ]]; then + manifest=".github/workflows/object/windows-x64-signed-arm64/update_manifest" + if [ ! -f "$manifest" ]; then + manifest="windows_update_manifest_arm64" + fi + elif [[ "$mar_file" == "macos.mar" ]]; then + manifest="macos_update_manifest" + else + echo "Unknown MAR file name format: $mar_file. Skipping manifest update." >&2 exit 1 fi + # There can be any update.xml file, lets just recursively search for the one + manifest_files=$(find "$manifest" -type f -name "update.xml") + for manifest_file in $manifest_files; do + # Example manifest: + # + # + # + # + # When signing the mar, hashValue and size will change, so we need to update the manifest with + # the new values. We can get the new values by running "mar -i signed_mar_file.mar" + echo "Updating manifest $manifest_file with new hash and size for $mar_file" + size=$(wc -c < "$1" | tr -d ' ') + hashValue=$(sha512sum "$1" | awk '{print $1}') + # Update the manifest with the new values. We can use sed to do this. + # We need to find the line that contains the URL of the mar file, and update the hashValue and size attributes in the same element. + old_hashValue=$(grep -oP 'hashValue="\K[^"]+' "$manifest_file") + old_size=$(grep -oP 'size="\K[^"]+' "$manifest_file") + if [ -z "$old_hashValue" ] || [ -z "$old_size" ]; then + echo "Could not find old hashValue or size in manifest. Skipping manifest update." >&2 + exit 1 + fi + echo "Old hashValue: $old_hashValue, Old size: $old_size" + echo "New hashValue: $hashValue, New size: $size" + sed -i.bak "s/hashValue=\"$old_hashValue\"/hashValue=\"$hashValue\"/g; s/size=\"$old_size\"/size=\"$size\"/g" "$manifest_file" + rm "$manifest_file.bak" + echo "Manifest updated with new hashValue and size for $mar_file" + done +} +sign_mars() { if [ ! -f "$SIGNMAR" ]; then echo "Error: signmar not found at $SIGNMAR. Build the engine first." >&2 exit 1 @@ -127,14 +166,37 @@ sign_mar() { create_nss_config_dir - echo "" - echo "Signing $mar_file..." - # mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar - "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_cert" -s "$mar_file" "$mar_file".signed - echo "Signed $mar_file. Verifying signature..." - "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_cert" -v "$mar_file".signed - mv "$mar_file".signed "$mar_file" - echo "Successfully signed $mar_file" + folders=( + linux.mar + linux-aarch64.mar + windows.mar + windows-arm64.mar + macos.mar + ) + # each folder will contain the .mar files for that platform, and the signature will be written in-place + for folder in "${folders[@]}"; do + if [ -d "$folder" ]; then + for mar_file in "$folder"/*.mar; do + if [ -f "$mar_file" ]; then + echo "" + echo "Signing $mar_file..." + # mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_sig" -s "$mar_file" "$mar_file".signed + echo "Signed $mar_file. Verifying signature..." + "$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "mar_sig" -v "$mar_file".signed + mv "$mar_file".signed "$mar_file" + echo "Successfully signed $mar_file" + update_manifests "$mar_file" + else + echo "No .mar files found in $folder, skipping." + exit 1 + fi + done + else + echo "Directory $folder not found, skipping." + exit 1 + fi + done cleanup_certs } @@ -147,13 +209,13 @@ case "$1" in import_cert ;; -s) - sign_mar "$2" + sign_mars ;; *) - echo "Usage: $0 [-g] [-i] [-s ]" >&2 - echo " -g Generate MAR signing certificates" >&2 - echo " -i Import the certificate into the updater (release_primary.der)" >&2 - echo " -s Sign the given .mar file in-place" >&2 + echo "Usage: $0 [-g] [-i] [-s]" >&2 + echo " -g Generate MAR signing certificates" >&2 + echo " -i Import the certificate into the updater (release_primary.der)" >&2 + echo " -s Sign *.mar files in the current directory in-place" >&2 exit 1 ;; esac diff --git a/src/browser/themes/shared/preferences/zen-preferences.css b/src/browser/themes/shared/preferences/zen-preferences.css index bae330acc..788ad5c76 100644 --- a/src/browser/themes/shared/preferences/zen-preferences.css +++ b/src/browser/themes/shared/preferences/zen-preferences.css @@ -504,6 +504,7 @@ groupbox h2 { #setting-control-sidebarChatbotFieldset, #aiControlsDescription, #category-ai-features, +#setting-control-supportFirefox, .mission-message, html|setting-group[data-subcategory="layout"] { display: none !important; From d540c6cddfd46f2739f88afc7246adc72d85dd15 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:33:01 +0200 Subject: [PATCH 056/149] no-bug: Block loading glance from unmatching principals (gh-13237) --- src/zen/glance/ZenGlanceManager.mjs | 181 +++++++++++-------- src/zen/glance/actors/ZenGlanceChild.sys.mjs | 85 ++++++--- src/zen/glance/zen-glance.css | 5 +- 3 files changed, 165 insertions(+), 106 deletions(-) diff --git a/src/zen/glance/ZenGlanceManager.mjs b/src/zen/glance/ZenGlanceManager.mjs index a63ccb234..0f3112570 100644 --- a/src/zen/glance/ZenGlanceManager.mjs +++ b/src/zen/glance/ZenGlanceManager.mjs @@ -34,7 +34,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { // Arc animation configuration #ARC_CONFIG = Object.freeze({ - ARC_STEPS: 400, // Increased for smoother bounce + ARC_STEPS: 80, // Browser interpolates between keyframes natively MAX_ARC_HEIGHT: 25, ARC_HEIGHT_RATIO: 0.2, // Arc height = distance * ratio (capped at MAX_ARC_HEIGHT) }); @@ -78,7 +78,11 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { menuitem.setAttribute("data-l10n-id", "zen-open-link-in-glance"); menuitem.addEventListener("command", () => - this.openGlance({ url: gContextMenu.linkURL }) + this.openGlance({ + url: gContextMenu.linkURL, + triggeringPrincipal: + Services.scriptSecurityManager.getSystemPrincipal(), + }) ); document @@ -171,19 +175,20 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { /** * Create a new browser element for a glance * - * @param {string} url - The URL to load + * @param {object} data - Glance data including URL and dimensions * @param {Tab} currentTab - The current tab - * @param {Tab} existingTab - Optional existing tab to reuse + * @param {Tab|null} existingTab - Optional existing tab to reuse * @returns {Browser} The created browser element */ - #createBrowserElement(url, currentTab, existingTab = null) { - const newTabOptions = this.#createTabOptions(currentTab); + #createBrowserElement(data, currentTab, existingTab = null) { + const url = data.url; + const newTabOptions = this.#createTabOptions(currentTab, data); const newUUID = gZenUIManager.generateUuidv4(); currentTab._selected = true; const newTab = existingTab ?? - gBrowser.addTrustedTab(Services.io.newURI(url).spec, newTabOptions); + gBrowser.addTab(Services.io.newURI(url).spec, newTabOptions); this.#configureNewTab(newTab, currentTab, newUUID); this.#registerGlance(newTab, currentTab, newUUID); @@ -196,14 +201,18 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { * Create tab options for a new glance tab * * @param {Tab} currentTab - The current tab + * @param {object} data - Glance data for the new tab * @returns {object} Tab options */ - #createTabOptions(currentTab) { + #createTabOptions(currentTab, data) { return { userContextId: currentTab.getAttribute("usercontextid") || "", skipBackgroundNotify: true, insertTab: true, skipLoad: false, + skipAnimation: true, + ownerTab: currentTab, + triggeringPrincipal: data.triggeringPrincipal, }; } @@ -364,7 +373,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.#setAnimationState(true); const currentTab = ownerTab ?? gBrowser.selectedTab; const browserElement = this.#createBrowserElement( - data.url, + data, currentTab, existingTab ); @@ -393,7 +402,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { * @returns {Promise} Promise that resolves to the glance tab */ #animateGlanceOpening(data, browserElement) { - this.#prepareGlanceAnimation(data, browserElement); + this.#prepareGlanceAnimation(data); // FIXME(cheffy): We *must* have the call back async (at least, // until a better solution is found). If we do it inside the requestAnimationFrame, // we see flashing and if we do it directly, the animation does not play at all. @@ -417,15 +426,13 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { * Prepare the glance for animation * * @param {object} data - Glance data - * @param {Browser} browserElement - The browser element */ - #prepareGlanceAnimation(data, browserElement) { + #prepareGlanceAnimation(data) { this.quickOpenGlance(); const newButtons = this.#createNewOverlayButtons(); this.browserWrapper.appendChild(newButtons); this.#setupGlancePositioning(data); - this.#configureBrowserElement(browserElement); } /** @@ -463,9 +470,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.overlay.removeAttribute("fade-out"); this.browserWrapper.setAttribute("animate", true); - this.browserWrapper.style.transform = `translate(${left - width / 2}px, ${top - height / 2}px)`; - this.browserWrapper.style.width = `${width}px`; - this.browserWrapper.style.height = `${height}px`; this.#storeOriginalPosition({ top, left, width, height }); this.overlay.style.overflow = "visible"; @@ -510,33 +514,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { return imageDataElement; } - /** - * Configure browser element for animation - * - * @param {Browser} browserElement - The browser element - */ - #configureBrowserElement(browserElement) { - const rect = window.windowUtils.getBoundsWithoutFlushing( - this.browserWrapper.parentElement - ); - const minWidth = rect.width * 0.8; - const minHeight = rect.height * 0.8; - - browserElement.style.minWidth = `${minWidth}px`; - browserElement.style.minHeight = `${minHeight}px`; - } - - /** - * Get the transform origin for the animation - * - * @param {object} data - Glance data with position and dimensions - * @returns {string} The transform origin CSS value - */ - #getTransformOrigin(data) { - const { clientX, clientY } = data; - return `${clientX}px ${clientY}px`; - } - /** * Execute the main glance animation * @@ -547,11 +524,13 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { #executeGlanceAnimation(data, browserElement, resolve) { const imageDataElement = this.#handleElementPreview(data); - // Create curved animation sequence - const arcSequence = this.#createGlanceArcSequence(data, "opening"); - const transformOrigin = this.#getTransformOrigin(data); - - this.browserWrapper.style.transformOrigin = transformOrigin; + // Create the curved animation sequence. The transform origin is handled + // separately (for example via CSS on the wrapper). + const arcSequence = this.#createGlanceArcSequence( + data, + "opening", + imageDataElement + ); // Only animate if there is element data, so we can apply a // nice fade-in effect to the content. But if it doesn't exist, @@ -601,10 +580,41 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { * * @param {object} data - Glance data with position and dimensions * @param {string} direction - 'opening' or 'closing' + * @param {Element|null} imageDataElement - The image data element for preview (optional) * @returns {object} Animation sequence object */ - #createGlanceArcSequence(data, direction) { - const { clientX, clientY, width, height } = data; + #createGlanceArcSequence(data, direction, imageDataElement = null) { + let { clientX, clientY, width, height } = data; + if (imageDataElement?.parentElement) { + // Since we are animating scale transforms on the wrapper, we need to + // adjust the width/height to match the scaled size of the element preview, + // so the image preview properly matches the size of the animating browser + // during the animation. + // For example: + // +-- wrapper --------------------------+ + // | | + // | +--- element preview -------------+ | + // | | | | + // | +---------------------------------+ | + // | | + // +-------------------------------------+ + // We are scaling the wrapper while having only the element preview size + // in mind, so we need to adjust the width/height to match the size of the element preview + const rect = imageDataElement.getBoundingClientRect(); + const imageRect = + imageDataElement.firstElementChild.getBoundingClientRect(); + const widthRatio = rect.width / imageRect.width; + // Since the image hasn't loaded at this point, so the image's height is 0 + // we need to calculate the height ratio based on the original aspect ratio of the image + const aspectRatio = width / height; + const heightRatio = rect.height / (rect.width / aspectRatio); + const originalWidth = width; + const originalHeight = height; + width *= widthRatio; + height *= heightRatio; + clientX -= (width - originalWidth) / 2; + clientY -= (height - originalHeight) / 2; + } // Calculate start and end positions based on direction let startPosition, endPosition; @@ -643,6 +653,12 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { }; } + // Reference size used as the scale(1, 1) baseline — this matches the + // wrapper's natural CSS size (80% x 100% of the tab panels) so the + // animation can run entirely on the compositor via transform. + const refWidth = tabPanelsRect.width * widthPercent; + const refHeight = tabPanelsRect.height; + // Calculate distance and arc parameters const distance = this.#calculateDistance(startPosition, endPosition); const { arcHeight, shouldArcDownward } = this.#calculateOptimalArc( @@ -652,9 +668,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { ); const sequence = { - transform: [], - width: [], - height: [], + x: [], + y: [], + scaleY: [], + scaleX: [], }; const steps = this.#ARC_CONFIG.ARC_STEPS; @@ -684,6 +701,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { const currentHeight = startPosition.height + (endPosition.height - startPosition.height) * eased; + const scaleX = currentWidth / refWidth; + const scaleY = currentHeight / refHeight; // Calculate position on arc const distanceX = endPosition.x - startPosition.x; @@ -695,11 +714,12 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { distanceY * eased + arcDirection * arcHeight * (1 - (2 * eased - 1) ** 2); - sequence.transform.push( - `translate(${x - currentWidth / 2}px, ${y - currentHeight / 2}px)` - ); - sequence.width.push(`${currentWidth}px`); - sequence.height.push(`${currentHeight}px`); + let translateX = x - currentWidth / 2; + let translateY = y - currentHeight / 2; + sequence.x.push(translateX); + sequence.y.push(translateY); + sequence.scaleX.push(scaleX); + sequence.scaleY.push(scaleY); } return sequence; @@ -763,19 +783,16 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { imageDataElement.remove(); } + // Batch all style/attribute writes together to avoid interleaved + // read/write layout thrashing. this.browserWrapper.style.transformOrigin = ""; - - browserElement.style.minWidth = ""; - browserElement.style.minHeight = ""; - this.browserWrapper.style.height = "100%"; this.browserWrapper.style.width = "80%"; - - gBrowser.tabContainer._invalidateCachedTabs(); - this.overlay.style.removeProperty("overflow"); this.browserWrapper.removeAttribute("animate"); this.browserWrapper.setAttribute("has-finished-animation", true); + this.overlay.style.removeProperty("overflow"); + gBrowser.tabContainer._invalidateCachedTabs(); this.#setAnimationState(false); this.#currentTab.dispatchEvent(new Event("GlanceOpen", { bubbles: true })); resolve(this.#currentTab); @@ -970,19 +987,14 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { } } - #imageBitmapToBase64(imageBitmap) { - // 1. Create a canvas with the same size as the ImageBitmap - const canvas = document.createElement("canvas"); - canvas.width = imageBitmap.width; - canvas.height = imageBitmap.height; - - // 2. Draw the ImageBitmap onto the canvas + async #imageBitmapToBase64(imageBitmap) { + // Use OffscreenCanvas + blob URL to avoid blocking the main thread + // with synchronous base64 encoding from toDataURL(). + const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height); const ctx = canvas.getContext("2d"); ctx.drawImage(imageBitmap, 0, 0); - - // 3. Convert the canvas content to a Base64 string (PNG by default) - const base64String = canvas.toDataURL("image/png"); - return base64String; + const blob = await canvas.convertToBlob({ type: "image/png" }); + return URL.createObjectURL(blob); } /** @@ -1027,12 +1039,20 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.#currentGlanceID ).elementImageData; - this.#addElementPreview(elementImageData); + const imageDataElement = this.#addElementPreview(elementImageData); // Create curved closing animation sequence const closingData = this.#createClosingDataFromOriginalPosition(originalPosition); - const arcSequence = this.#createGlanceArcSequence(closingData, "closing"); + const arcSequence = this.#createGlanceArcSequence( + closingData, + "closing", + imageDataElement + ); + + // Batch style writes before starting animation to avoid layout thrashing + this.browserWrapper.style.width = ""; + this.browserWrapper.style.height = ""; gZenUIManager.motion .animate(this.browserWrapper, arcSequence, { @@ -1084,6 +1104,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { const imageDataElement = this.#createGlancePreviewElement(elementImageData); this.browserWrapper.prepend(imageDataElement); + return imageDataElement; } } @@ -1506,6 +1527,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.openGlance( { url: undefined, + // No need for triggeringPrincipal here }, tab, tab.owner @@ -1692,6 +1714,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { clientY: top, width: rect.width, height: rect.height, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }; } @@ -1871,6 +1894,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { ...clickPosition, width: 0, height: 0, + triggeringPrincipal: + Services.scriptSecurityManager.getSystemPrincipal(), }, currentTab, parentTab diff --git a/src/zen/glance/actors/ZenGlanceChild.sys.mjs b/src/zen/glance/actors/ZenGlanceChild.sys.mjs index 6583c9ef2..45a3b520a 100644 --- a/src/zen/glance/actors/ZenGlanceChild.sys.mjs +++ b/src/zen/glance/actors/ZenGlanceChild.sys.mjs @@ -2,6 +2,21 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs", +}); + +XPCOMUtils.defineLazyPreferenceGetter( + lazy, + "blockJavascript", + "browser.link.alternative_click.block_javascript", + true +); + export class ZenGlanceChild extends JSWindowActorChild { #activationMethod; @@ -26,31 +41,27 @@ export class ZenGlanceChild extends JSWindowActorChild { return !(event.ctrlKey ^ event.altKey ^ event.shiftKey ^ event.metaKey); } - #openGlance(target) { - let url = target.href; - // Add domain to relative URLs - if (!url.match(/^(?:[a-z]+:)?\/\//i)) { - url = this.contentWindow.location.origin + url; - } + #openGlance(href, principal) { this.sendAsyncMessage("ZenGlance:OpenGlance", { - url, + url: href, + triggeringPrincipal: principal, }); } - #sendClickDataToParent(target, element) { - if (!element && !target) { + #sendClickDataToParent(node, originalTarget) { + if (!node) { return; } - if (!target) { - target = element; - } // Get the largest element we can get. If the `A` element // is a parent of the original target, use the anchor element, // otherwise use the original target. - let rect = element.getBoundingClientRect(); - const anchorRect = target.getBoundingClientRect(); - if (anchorRect.width * anchorRect.height > rect.width * rect.height) { - rect = anchorRect; + let rect = node.getBoundingClientRect(); + const originalTargetRect = originalTarget.getBoundingClientRect(); + if ( + originalTargetRect.width * originalTargetRect.height > + rect.width * rect.height + ) { + rect = originalTargetRect; } this.sendAsyncMessage("ZenGlance:RecordLinkClickData", { clientX: rect.left, @@ -68,29 +79,50 @@ export class ZenGlanceChild extends JSWindowActorChild { */ #getTargetFromEvent(event) { // get closest A element - const target = event.target.closest("A"); - const elementToRecord = event.originalTarget || event.target; + let [href, node, principal] = + lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event); return { - target, - elementToRecord, + href, + node, + principal, }; } + #checkSecurity(href, principal) { + if ( + lazy.blockJavascript && + Services.io.extractScheme(href) == "javascript" + ) { + // We don't want to open new tabs or windows for javascript: links. + return true; + } + + try { + Services.scriptSecurityManager.checkLoadURIStrWithPrincipal( + principal, + href + ); + } catch (e) { + return true; + } + return false; + } + on_mousedown(event) { - const { target, elementToRecord } = this.#getTargetFromEvent(event); + const { node } = this.#getTargetFromEvent(event); // We record the link data anyway, even if the glance may be invoked // or not. We have some cases where glance would open, for example, // when clicking on a link with a different domain where glance would open. // The problem is that at that stage we don't know the rect or even what // element has been clicked, so we send the data here. - this.#sendClickDataToParent(target, elementToRecord); + this.#sendClickDataToParent(node, event.target); } on_click(event) { - const { target } = this.#getTargetFromEvent(event); + const { node, href, principal } = this.#getTargetFromEvent(event); if ( event.button !== 0 || - !target || + !node || event.defaultPrevented || this.#ensureOnlyKeyModifiers(event) ) { @@ -106,9 +138,12 @@ export class ZenGlanceChild extends JSWindowActorChild { } else if (activationMethod === "meta" && !event.metaKey) { return; } + if (this.#checkSecurity(href, principal)) { + return; + } event.preventDefault(); event.stopPropagation(); - this.#openGlance(target); + this.#openGlance(href, principal); } on_keydown(event) { diff --git a/src/zen/glance/zen-glance.css b/src/zen/glance/zen-glance.css index 1257bcdc7..807aea8c2 100644 --- a/src/zen/glance/zen-glance.css +++ b/src/zen/glance/zen-glance.css @@ -120,14 +120,14 @@ } & .browserContainer { - transform: translate(-50%, -50%); position: fixed; flex: unset !important; width: 80%; height: 100%; &:not([has-finished-animation="true"]) { - will-change: width, height, transform; + will-change: transform; + transform-origin: 0 0; #statuspanel { display: none; @@ -178,7 +178,6 @@ top: 50%; left: 50%; translate: -50% -50%; - background: rgba(255, 255, 255, 0.1); display: flex; align-items: center; From 7ed7b63b084b453d2b90230da09002f3bc642292 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 14 Apr 2026 01:03:47 +0200 Subject: [PATCH 057/149] no-bug: Adress possible memory leaks (gh-13242) --- prefs/zen/glance.yaml | 2 +- src/zen/glance/ZenGlanceManager.mjs | 28 +++++-- src/zen/glance/actors/ZenGlanceParent.sys.mjs | 14 ++-- src/zen/mods/ZenMods.mjs | 82 ++++++++++++------- 4 files changed, 82 insertions(+), 44 deletions(-) diff --git a/prefs/zen/glance.yaml b/prefs/zen/glance.yaml index ef01648c1..299e616c7 100644 --- a/prefs/zen/glance.yaml +++ b/prefs/zen/glance.yaml @@ -15,7 +15,7 @@ value: "alt" # ctrl, alt, shift - name: zen.glance.animation-duration - value: 350 # in milliseconds + value: 300 # in milliseconds - name: zen.glance.deactivate-docshell-during-animation value: true diff --git a/src/zen/glance/ZenGlanceManager.mjs b/src/zen/glance/ZenGlanceManager.mjs index 0f3112570..877b35fbb 100644 --- a/src/zen/glance/ZenGlanceManager.mjs +++ b/src/zen/glance/ZenGlanceManager.mjs @@ -318,7 +318,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { data.width, data.height ); - return await this.#imageBitmapToBase64( + return await this.#imageBitmapToObjectURL( await window.browsingContext.currentWindowGlobal.drawSnapshot( rect, 1, @@ -785,7 +785,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { // Batch all style/attribute writes together to avoid interleaved // read/write layout thrashing. - this.browserWrapper.style.transformOrigin = ""; this.browserWrapper.style.height = "100%"; this.browserWrapper.style.width = "80%"; this.browserWrapper.removeAttribute("animate"); @@ -987,16 +986,31 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { } } - async #imageBitmapToBase64(imageBitmap) { - // Use OffscreenCanvas + blob URL to avoid blocking the main thread - // with synchronous base64 encoding from toDataURL(). + async #imageBitmapToObjectURL(imageBitmap) { + // OffscreenCanvas + convertToBlob avoids the synchronous PNG re-encode + // and base64 string copy that toDataURL performs on the main thread. + // Callers must release the URL via #deleteGlance when the glance entry + // is removed so the blob can be freed. const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height); const ctx = canvas.getContext("2d"); ctx.drawImage(imageBitmap, 0, 0); const blob = await canvas.convertToBlob({ type: "image/png" }); + imageBitmap.close(); return URL.createObjectURL(blob); } + #deleteGlance(glanceID) { + const entry = this.#glances.get(glanceID); + if (!entry) { + return; + } + this.#glances.delete(glanceID); + const url = entry.elementData ?? entry.elementImageData; + if (typeof url === "string") { + URL.revokeObjectURL(url); + } + } + /** * Animate parent background restoration * @@ -1196,7 +1210,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { */ #resetGlanceState(setNewID) { this.#currentParentTab.removeAttribute("glance-id"); - this.#glances.delete(this.#currentGlanceID); + this.#deleteGlance(this.#currentGlanceID); this.#currentGlanceID = setNewID; this.#duringOpening = false; } @@ -1545,7 +1559,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature { this.animatingFullOpen = false; const glanceID = this.#currentGlanceID; this.closeGlance({ noAnimation: true, skipPermitUnload: true }); - this.#glances.delete(glanceID); + this.#deleteGlance(glanceID); } /** diff --git a/src/zen/glance/actors/ZenGlanceParent.sys.mjs b/src/zen/glance/actors/ZenGlanceParent.sys.mjs index e5a366867..748c18912 100644 --- a/src/zen/glance/actors/ZenGlanceParent.sys.mjs +++ b/src/zen/glance/actors/ZenGlanceParent.sys.mjs @@ -22,13 +22,15 @@ export class ZenGlanceParent extends JSWindowActorParent { break; } case "ZenGlance:CloseGlance": { - const params = { + // Explicitly allowlist fields from content; never forward + // skipPermitUnload or other privileged flags. + const { noAnimation, setNewID, hasFocused } = message.data ?? {}; + this.browsingContext.topChromeWindow.gZenGlanceManager.closeGlance({ onTabClose: true, - ...message.data, - }; - this.browsingContext.topChromeWindow.gZenGlanceManager.closeGlance( - params - ); + noAnimation: !!noAnimation, + setNewID: typeof setNewID === "string" ? setNewID : null, + hasFocused: !!hasFocused, + }); break; } case "ZenGlance:RecordLinkClickData": { diff --git a/src/zen/mods/ZenMods.mjs b/src/zen/mods/ZenMods.mjs index a050c92d3..0fa521b1d 100644 --- a/src/zen/mods/ZenMods.mjs +++ b/src/zen/mods/ZenMods.mjs @@ -7,6 +7,10 @@ import { nsZenMultiWindowFeature, } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs"; +const DOT_RE = /\./g; +const WHITESPACE_RE = /\s/g; +const NON_NAME_RE = /[^A-Za-z_-]+/g; + /** * Zen Mods Manager, handles downloading, updating and applying Zen Mods. * @@ -171,47 +175,57 @@ class nsZenMods extends nsZenPreloadedFeature { } #writeToDom(modsWithPreferences) { - for (const browser of nsZenMultiWindowFeature.browsers) { + // Precompute per-mod data once; values are global prefs and sanitized + // names don't vary per browser window, so this hoists O(windows) work. + const prepared = modsWithPreferences.map( // eslint-disable-next-line no-shadow - for (const { enabled, preferences, name } of modsWithPreferences) { - const sanitizedName = this.sanitizeModName(name); + ({ enabled, preferences, name }) => ({ + enabled, + sanitizedName: this.sanitizeModName(name), + prefs: preferences.map(({ property, type }) => ({ + property, + type, + sanitizedProperty: property?.replaceAll(DOT_RE, "-"), + value: + enabled === undefined || enabled + ? Services.prefs.getStringPref(property, "") + : "", + })), + }) + ); + for (const browser of nsZenMultiWindowFeature.browsers) { + const doc = browser.document; + const root = doc.documentElement; + + for (const { enabled, sanitizedName, prefs } of prepared) { if (enabled !== undefined && !enabled) { - const element = browser.document.getElementById(sanitizedName); - + const element = doc.getElementById(sanitizedName); if (element) { element.remove(); } - for (const { property } of preferences.filter( - ({ type }) => type !== "checkbox" - )) { - const sanitizedProperty = property?.replaceAll(/\./g, "-"); - - browser.document - .querySelector(":root") - .style.removeProperty(`--${sanitizedProperty}`); + for (const { type, sanitizedProperty } of prefs) { + if (type === "checkbox") { + continue; + } + root.style.removeProperty(`--${sanitizedProperty}`); } continue; } - for (const { property, type } of preferences) { - const value = Services.prefs.getStringPref(property, ""); - const sanitizedProperty = property?.replaceAll(/\./g, "-"); - + for (const { type, sanitizedProperty, value } of prefs) { switch (type) { case "dropdown": { if (value !== "") { - let element = browser.document.getElementById(sanitizedName); + let element = doc.getElementById(sanitizedName); if (!element) { - element = browser.document.createElement("div"); - + element = doc.createElement("div"); element.style.display = "none"; element.setAttribute("id", sanitizedName); - - browser.document.body.appendChild(element); + doc.body.appendChild(element); } element.setAttribute(sanitizedProperty, value); @@ -221,13 +235,9 @@ class nsZenMods extends nsZenPreloadedFeature { case "string": { if (value === "") { - browser.document - .querySelector(":root") - .style.removeProperty(`--${sanitizedProperty}`); + root.style.removeProperty(`--${sanitizedProperty}`); } else { - browser.document - .querySelector(":root") - .style.setProperty(`--${sanitizedProperty}`, value); + root.style.setProperty(`--${sanitizedProperty}`, value); } break; } @@ -308,6 +318,19 @@ class nsZenMods extends nsZenPreloadedFeature { } async #downloadUrlToFile(url, path, maxRetries = 3, retryDelayMs = 500) { + // Mod assets must come over HTTPS. Without a signing/hash scheme this + // is the minimum guard against MITM or a store-hosted HTTP redirect + // serving attacker-controlled CSS/JSON into the chrome profile. + let parsed; + try { + parsed = new URL(url); + } catch { + throw new Error(`[ZenMods]: Invalid mod asset URL: ${url}`); + } + if (parsed.protocol !== "https:") { + throw new Error(`[ZenMods]: Refusing non-HTTPS mod asset URL: ${url}`); + } + let attempt = 0; while (attempt < maxRetries) { @@ -377,8 +400,7 @@ class nsZenMods extends nsZenPreloadedFeature { sanitizeModName(aName) { // Do not change to "mod-" for backwards compatibility - // eslint-disable-next-line no-shadow - return `theme-${aName?.replaceAll(/\s/g, "-")?.replaceAll(/[^A-Za-z_-]+/g, "")}`; + return `theme-${aName?.replaceAll(WHITESPACE_RE, "-")?.replaceAll(NON_NAME_RE, "")}`; } get updatePref() { From 826f1f355f97a2ad5b1d21fac4e128354407383b Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Tue, 14 Apr 2026 11:17:41 +0200 Subject: [PATCH 058/149] no-bug: New popup layout and stylings (gh-13245) --- .../prompts/content/commonDialog-css.patch | 7 ++-- src/zen/common/styles/zen-animations.css | 4 +-- src/zen/common/styles/zen-buttons.css | 32 +++++++++++-------- src/zen/common/styles/zen-panels/dialog.css | 6 ++-- src/zen/common/styles/zen-theme.css | 4 +-- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/toolkit/components/prompts/content/commonDialog-css.patch b/src/toolkit/components/prompts/content/commonDialog-css.patch index ad3ab9c8c..3a55f9f89 100644 --- a/src/toolkit/components/prompts/content/commonDialog-css.patch +++ b/src/toolkit/components/prompts/content/commonDialog-css.patch @@ -1,5 +1,5 @@ diff --git a/toolkit/components/prompts/content/commonDialog.css b/toolkit/components/prompts/content/commonDialog.css -index d811fb62d502cf6fc0bf8163f11e1d264dee9e82..9aa4dc90c73e2f1e2fdcb6bdc26a505402a5c28f 100644 +index d811fb62d502cf6fc0bf8163f11e1d264dee9e82..88e9a4f508f3d640bdbb3a31928e777629afcd80 100644 --- a/toolkit/components/prompts/content/commonDialog.css +++ b/toolkit/components/prompts/content/commonDialog.css @@ -3,7 +3,8 @@ @@ -12,12 +12,13 @@ index d811fb62d502cf6fc0bf8163f11e1d264dee9e82..9aa4dc90c73e2f1e2fdcb6bdc26a5054 } dialog[insecureauth] { -@@ -91,7 +92,7 @@ dialog[insecureauth] { +@@ -91,7 +92,8 @@ dialog[insecureauth] { --grid-padding: 16px; /* All the inner items should have 4px inline margin, leading to 1.16em spacing * between the dialog and its contents, and 8px horizontal spacing between items. */ - padding: var(--grid-padding) calc(var(--grid-padding) - 4px); -+ padding: 26px 22px; ++ padding: 30px 26px; ++ gap: 4px; &::part(dialog-button) { /* Adjust vertical margins for buttons in subdialogs. */ diff --git a/src/zen/common/styles/zen-animations.css b/src/zen/common/styles/zen-animations.css index 7f08377be..9756f8894 100644 --- a/src/zen/common/styles/zen-animations.css +++ b/src/zen/common/styles/zen-animations.css @@ -39,12 +39,12 @@ @keyframes zen-dialog-fade-in { from { opacity: 0; - transform: translateY(-10px); + transform: translateY(calc(-10% - 10px)); } to { opacity: 1; - transform: translateY(0); + transform: translateY(-10%); } } diff --git a/src/zen/common/styles/zen-buttons.css b/src/zen/common/styles/zen-buttons.css index 0c1f6afde..d94c2c367 100644 --- a/src/zen/common/styles/zen-buttons.css +++ b/src/zen/common/styles/zen-buttons.css @@ -18,21 +18,22 @@ xul|button { } dialog::part(dialog-button) { - --button-background-color: light-dark(white, #302f63); + --button-background-color: light-dark(rgba(28, 28, 28, 0.1), rgba(255, 255, 255, .1)) !important; --button-background-color-hover: color-mix(in srgb, var(--button-background-color) 90%, transparent); --button-background-color-active: color-mix(in srgb, var(--button-background-color) 80%, transparent); - --button-background-color-primary: #3138fc; + --button-background-color-primary: light-dark(#1c1c1c, #dddddd); --button-background-color-primary-hover: color-mix(in srgb, var(--button-background-color-primary) 95%, transparent); - --button-text-color-primary: white; - --button-text-color-primary-hover: var(--button-text-color-primary); - border-color: light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)) !important; - border-bottom-width: 2px !important; + --button-background-color-primary-active: color-mix(in srgb, var(--button-background-color-primary) 90%, transparent); + position: relative; + border: none; + border-radius: 10px; } dialog[defaultButton="accept"]::part(dialog-button) { &:is([dlgtype="accept"], [dlgtype="cancel"]) { padding-inline-end: 3.7em; + @media (-moz-platform: windows) { padding-inline-end: 4em; } @@ -41,25 +42,27 @@ dialog[defaultButton="accept"]::part(dialog-button) { border-radius: 4px; font-weight: 600; position: absolute; - right: 0.6em; padding: 3px 0; top: 50%; transform: translateY(-50%); - font-size: 12px; - width: 34px; text-align: center; } &[dlgtype="accept"]::after { content: "⏎"; - background: rgba(255, 255, 255, 0.1); - outline: 2px solid color-mix(in srgb, currentColor 20%, transparent); - outline-offset: -2px; + right: 0.6em; + font-size: 12px; + width: 36px; + color: light-dark(rgba(255, 255, 255, 0.80), rgba(0, 0, 0, 0.60)); } &[dlgtype="cancel"]::after { content: "ESC"; - background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + right: 1em; + font-size: 8px; + width: 30px; + color: light-dark(rgba(28, 28, 28, 0.7), rgba(255, 255, 255, 0.6)) !important; + outline: 1px solid light-dark(rgba(28, 28, 28, 0.1), rgba(255, 255, 255, 0.1)) !important; } } } @@ -68,7 +71,8 @@ xul|button:not(#zen-workspaces-button):active { transform: scale(0.98); } -.footer-button { +.footer-button, +dialog::part(dialog-button) { font-weight: 500 !important; transition: scale 0.2s; diff --git a/src/zen/common/styles/zen-panels/dialog.css b/src/zen/common/styles/zen-panels/dialog.css index 4b41dd0dc..d149f6648 100644 --- a/src/zen/common/styles/zen-panels/dialog.css +++ b/src/zen/common/styles/zen-panels/dialog.css @@ -4,9 +4,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ .dialogBox { - outline: 1px solid light-dark(transparent, #646464); animation: zen-dialog-fade-in 0.3s ease-out; border-radius: 12px !important; - border: 1px solid light-dark(#a8a8a9, black); + border: 1px solid light-dark(rgba(168, 168, 169, 0.50), var(--zen-dialog-background)) !important; + outline: 1px solid light-dark(transparent, rgba(168, 168, 169, 0.50)) !important; + box-shadow: 0 10px 8px rgba(0, 0 , 0, 0.15) !important; outline-offset: -1.5px; + transform: translateY(-10%); } diff --git a/src/zen/common/styles/zen-theme.css b/src/zen/common/styles/zen-theme.css index 7b333d1db..85abf3bc3 100644 --- a/src/zen/common/styles/zen-theme.css +++ b/src/zen/common/styles/zen-theme.css @@ -59,7 +59,7 @@ color-mix(in srgb, var(--zen-primary-color) 1%, var(--zen-branding-bg) 99%) ); - --zen-dialog-background: light-dark(#FAFBFF, #161C31); + --zen-dialog-background: light-dark(#fafbff, #1c1c1c); --zen-urlbar-background: light-dark( color-mix(in srgb, var(--zen-primary-color) 3%, #f4f4f4 97%), color-mix(in srgb, var(--zen-primary-color) 4%, rgb(24, 24, 24) 96%) @@ -113,7 +113,7 @@ --button-border-color: var(--in-content-primary-button-border-color) !important; --button-font-weight: 500 !important; - --button-border-radius: 6px; + --button-border-radius: 8px; --button-text-color-primary: var(--in-content-primary-button-text-color) !important; --button-background-color: var(--in-content-button-background) !important; From 767dfce556f27fc7d2d98fcccc86fc642d24904e Mon Sep 17 00:00:00 2001 From: rain capsule <29630035+busybox11@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:11:18 +0200 Subject: [PATCH 059/149] gh-7099: slight CSS and SVG optimizations on notes anim loop (gh-13246) --- src/zen/images/note-indicator.svg | 106 +++++++++++++-------------- src/zen/media/zen-media-controls.css | 8 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/zen/images/note-indicator.svg b/src/zen/images/note-indicator.svg index 02ff00771..1c69eae03 100644 --- a/src/zen/images/note-indicator.svg +++ b/src/zen/images/note-indicator.svg @@ -6,13 +6,44 @@ - - - - + + - - - + + - - - + + - - - + + - - - + + - - - + + diff --git a/src/zen/media/zen-media-controls.css b/src/zen/media/zen-media-controls.css index 8b23e50ee..9cabf107e 100644 --- a/src/zen/media/zen-media-controls.css +++ b/src/zen/media/zen-media-controls.css @@ -117,16 +117,16 @@ & #zen-media-focus-button::after { content: ""; position: absolute; - width: 110%; - height: 110%; background: url("chrome://browser/content/zen-images/note-indicator.svg") no-repeat; top: -70%; - left: 50%; - transform: translateX(-50%); + left: 0; + right: 0; + bottom: 0; z-index: 0; pointer-events: none; transition: opacity 0.8s ease; opacity: 1; + will-change: opacity; } &:is(:not(.playing:not([muted])), :hover) #zen-media-focus-button::after { From c128b79723dfa4509c016baaf14652e97708e7ce Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:49:52 +0200 Subject: [PATCH 060/149] gh-13258: Implement new loading indicator (gh-13259) --- prefs/zen/view.yaml | 3 + src/browser/base/content/browser-js.patch | 19 +-- src/zen/common/modules/ZenStartup.mjs | 11 ++ src/zen/common/moz.build | 5 + src/zen/common/styles/zen-animations.css | 35 +++++ src/zen/common/styles/zen-omnibox.css | 9 +- .../common/styles/zen-single-components.css | 44 ++++++ src/zen/common/sys/ui/ZenProgressBar.sys.mjs | 127 ++++++++++++++++++ src/zen/common/sys/ui/ZenUIComponent.sys.mjs | 61 +++++++++ src/zen/glance/zen-glance.css | 6 - src/zen/tabs/ZenPinnedTabManager.mjs | 19 +-- 11 files changed, 307 insertions(+), 32 deletions(-) create mode 100644 src/zen/common/sys/ui/ZenProgressBar.sys.mjs create mode 100644 src/zen/common/sys/ui/ZenUIComponent.sys.mjs diff --git a/prefs/zen/view.yaml b/prefs/zen/view.yaml index d990c13fa..1f36da3f0 100644 --- a/prefs/zen/view.yaml +++ b/prefs/zen/view.yaml @@ -57,3 +57,6 @@ - name: zen.view.overflow-webext-toolbar value: "@IS_TWILIGHT@" + +- name: zen.view.enable-loading-indicator + value: true diff --git a/src/browser/base/content/browser-js.patch b/src/browser/base/content/browser-js.patch index 15dfe2198..a36248923 100644 --- a/src/browser/base/content/browser-js.patch +++ b/src/browser/base/content/browser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js -index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..37db181d7e71fb6250df5bae363e9cf984b44f79 100644 +index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..3ed2fc4d08b20883e0587e4435daacd86ad603de 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -33,6 +33,7 @@ ChromeUtils.defineESModuleGetters(this, { @@ -24,16 +24,7 @@ index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..37db181d7e71fb6250df5bae363e9cf9 if (backDisabled) { backCommand.removeAttribute("disabled"); } else { -@@ -2305,6 +2311,8 @@ var XULBrowserWindow = { - AboutReaderParent.updateReaderButton(gBrowser.selectedBrowser); - TranslationsParent.onLocationChange(gBrowser.selectedBrowser); - -+ gZenPinnedTabManager.onLocationChange(gBrowser.selectedBrowser, location); -+ - PictureInPicture.updateUrlbarToggle(gBrowser.selectedBrowser); - - if (!gMultiProcessBrowser) { -@@ -3820,7 +3828,7 @@ function warnAboutClosingWindow() { +@@ -3820,7 +3826,7 @@ function warnAboutClosingWindow() { if (!isPBWindow && !toolbar.visible) { return gBrowser.warnAboutClosingTabs( @@ -42,7 +33,7 @@ index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..37db181d7e71fb6250df5bae363e9cf9 gBrowser.closingTabsEnum.ALL ); } -@@ -3860,7 +3868,7 @@ function warnAboutClosingWindow() { +@@ -3860,7 +3866,7 @@ function warnAboutClosingWindow() { return ( isPBWindow || gBrowser.warnAboutClosingTabs( @@ -51,7 +42,7 @@ index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..37db181d7e71fb6250df5bae363e9cf9 gBrowser.closingTabsEnum.ALL ) ); -@@ -3885,7 +3893,7 @@ function warnAboutClosingWindow() { +@@ -3885,7 +3891,7 @@ function warnAboutClosingWindow() { AppConstants.platform != "macosx" || isPBWindow || gBrowser.warnAboutClosingTabs( @@ -60,7 +51,7 @@ index 0ea3d82b88819c41ffd866ae9533ebb5a7bff957..37db181d7e71fb6250df5bae363e9cf9 gBrowser.closingTabsEnum.ALL ) ); -@@ -4825,6 +4833,9 @@ var ConfirmationHint = { +@@ -4825,6 +4831,9 @@ var ConfirmationHint = { } document.l10n.setAttributes(this._message, messageId, options.l10nArgs); diff --git a/src/zen/common/modules/ZenStartup.mjs b/src/zen/common/modules/ZenStartup.mjs index 664d4bc96..a0611a8df 100644 --- a/src/zen/common/modules/ZenStartup.mjs +++ b/src/zen/common/modules/ZenStartup.mjs @@ -57,6 +57,7 @@ class ZenStartup { gZenWorkspaces.init(); setTimeout(() => { gZenUIManager.init(); + this.#initUIComponents(); this.#checkForWelcomePage(); }, 0); } catch (e) { @@ -161,6 +162,16 @@ class ZenStartup { } } + #initUIComponents() { + const kUIComponents = ["ZenProgressBar"]; + for (let component of kUIComponents) { + const module = ChromeUtils.importESModule( + "resource:///modules/zen/ui/" + component + ".sys.mjs" + ); + new module[component](window); + } + } + #checkForWelcomePage() { const kWelcomeScreenSeenPref = "zen.welcome-screen.seen"; if (Services.env.get("MOZ_HEADLESS")) { diff --git a/src/zen/common/moz.build b/src/zen/common/moz.build index 8dc973b44..115234dad 100644 --- a/src/zen/common/moz.build +++ b/src/zen/common/moz.build @@ -7,3 +7,8 @@ EXTRA_JS_MODULES += [ "sys/ZenCustomizableUI.sys.mjs", "sys/ZenUIMigration.sys.mjs", ] + +EXTRA_JS_MODULES.zen.ui += [ + "sys/ui/ZenProgressBar.sys.mjs", + "sys/ui/ZenUIComponent.sys.mjs", +] diff --git a/src/zen/common/styles/zen-animations.css b/src/zen/common/styles/zen-animations.css index 9756f8894..9b0185ada 100644 --- a/src/zen/common/styles/zen-animations.css +++ b/src/zen/common/styles/zen-animations.css @@ -56,3 +56,38 @@ background-position: -400% 50%; } } + +@keyframes zen-progress-bar-pulse { + 0% { + transform: scale(0.8) translate(-50%, -50%); + opacity: 0.6; + } + 50% { + transform: scale(0.95) translate(-50%, -50%); + opacity: 1; + } + 100% { + transform: scale(0.8) translate(-50%, -50%); + opacity: 0.6; + } +} + +@keyframes zen-progress-bar-long-load { + 0% { + left: -100%; + opacity: 1; + } + + 100% { + left: 100%; + opacity: 1; + } +} + +@keyframes zen-progress-bar-settle { + to { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + width: 10rem; + } +} diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index a334a3d04..0a29c1936 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -486,11 +486,12 @@ margin-block: -1px !important; } } +} - & #identity-icon-box { - --urlbar-box-hover-bgcolor: transparent; - margin-inline: 2px 8px; - } +#urlbar[open][zen-floating-urlbar="true"] #identity-icon-box, +:root[zen-single-toolbar="true"] #urlbar[breakout-extend="true"] #identity-icon-box { + --urlbar-box-hover-bgcolor: transparent; + margin-inline: 2px 8px; } /* stylelint-disable-next-line media-query-no-invalid */ diff --git a/src/zen/common/styles/zen-single-components.css b/src/zen/common/styles/zen-single-components.css index f40e64210..f4a6d582a 100644 --- a/src/zen/common/styles/zen-single-components.css +++ b/src/zen/common/styles/zen-single-components.css @@ -683,3 +683,47 @@ } } } + +/* Loading progress bar */ +#zen-loading-progress-bar { + position: fixed; + top: max(calc(var(--zen-element-separation) / -2), -4px); + left: 50%; + transform: translate(-50%, -50%) scale(0); + background: light-dark(rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.7)); + height: .4rem; + width: 5rem; + z-index: 9; + border-radius: 100px; + transition: opacity .3s ease-in-out, + background-color .3s ease-in-out, + transform .3s ease-in-out; + overflow: clip; + pointer-events: none; + animation: zen-progress-bar-pulse 1.5s linear infinite forwards; + transform-origin: 0 0; + + &[long-load="true"] { + opacity: 1; + animation: zen-progress-bar-settle .3s ease-out forwards; + background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)); + + &::before { + content: ""; + position: absolute; + top: 0; + height: 100%; + width: 75%; + opacity: 0; + animation: zen-progress-bar-long-load 1s ease-in-out infinite; + animation-delay: 0.3s; + background: light-dark(rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.7)); + border-radius: inherit; + } + } + + /* stylelint-disable-next-line media-query-no-invalid */ + @media not -moz-pref("zen.view.enable-loading-indicator") { + display: none; + } +} diff --git a/src/zen/common/sys/ui/ZenProgressBar.sys.mjs b/src/zen/common/sys/ui/ZenProgressBar.sys.mjs new file mode 100644 index 000000000..e8fa8157e --- /dev/null +++ b/src/zen/common/sys/ui/ZenProgressBar.sys.mjs @@ -0,0 +1,127 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import { ZenUIComponent } from "resource:///modules/zen/ui/ZenUIComponent.sys.mjs"; + +const WAIT_BEFORE_SHOWING_LONG_LOAD = 3000; + +export class ZenProgressBar extends ZenUIComponent { + #element = null; + #loadingTab = null; + #longLoadTimer = null; + + init() { + this.listenBrowserTabsProgress(); + this.addEventListener("TabSelect"); + } + + onStateChange(aWebProgress) { + this.#checkBrowserProgress(aWebProgress); + } + + onLocationChange(webProgress) { + this.#checkBrowserProgress(webProgress); + } + + on_TabSelect() { + const gBrowser = this.window.gBrowser; + const selectedTab = gBrowser.selectedTab; + this.onLocationChange(gBrowser.getBrowserForTab(selectedTab)); + } + + get #progressBar() { + if (!this.#loadingTab) { + return null; + } + if (!this.#element) { + this.#element = this.window.document.createXULElement("hbox"); + this.#element.id = "zen-loading-progress-bar"; + } + if ( + this.#element._loadingTab?.deref() !== this.#loadingTab && + this.#loadingTab + ) { + this.#element._loadingTab = new WeakRef(this.#loadingTab); + const container = this.window.document.getElementById( + this.#loadingTab.linkedPanel + ); + container.firstChild.before(this.#element); + this.window.gZenUIManager.elementAnimate( + this.#element, + { + opacity: [0, 0.6], + }, + { + duration: 400, + } + ); + } + return this.#element; + } + + #checkBrowserProgress(webProgress) { + const window = this.window; + const gBrowser = window.gBrowser; + const tab = gBrowser.getTabForBrowser(webProgress); + const isLoading = + tab?.selected && + (tab.hasAttribute("busy") || tab.hasAttribute("progress")); + if (isLoading) { + this.#showProgressBar(tab); + } else { + this.#hideProgressBar(); + } + } + + #hideProgressBar() { + const progressBar = this.#element; + const window = this.window; + if (this.#longLoadTimer) { + window.clearTimeout(this.#longLoadTimer); + this.#longLoadTimer = null; + } + + this.#loadingTab = null; + if (!progressBar) { + return; + } + const callback = () => { + delete progressBar._loadingTab; + progressBar.remove(); + this.#element = null; + }; + if (this.window.gReduceMotion) { + callback(); + return; + } + this.window.gZenUIManager + .elementAnimate( + progressBar, + { + transform: ["scaleX(0.8) translate(-50%, -50%)"], + opacity: [0], + }, + { + duration: 300, + } + ) + .then(callback); + } + + #showProgressBar(aTab) { + if (this.#loadingTab === aTab) { + return; + } + this.#loadingTab = aTab; + const progressBar = this.#progressBar; + progressBar.removeAttribute("fade-out"); + progressBar.removeAttribute("long-load"); + this.#longLoadTimer = this.window.setTimeout(() => { + if (this.#loadingTab === aTab) { + progressBar.setAttribute("long-load", "true"); + } + this.#longLoadTimer = null; + }, WAIT_BEFORE_SHOWING_LONG_LOAD); + } +} diff --git a/src/zen/common/sys/ui/ZenUIComponent.sys.mjs b/src/zen/common/sys/ui/ZenUIComponent.sys.mjs new file mode 100644 index 000000000..7a26773ea --- /dev/null +++ b/src/zen/common/sys/ui/ZenUIComponent.sys.mjs @@ -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/. + +/** + * Base class for UI components in Zen. + * UI components are responsible for managing their own event listeners + * and providing a consistent interface for handling events. + */ +export class ZenUIComponent { + #window = null; + #eventListeners = new Set(); + + constructor(aWindow) { + this.#window = aWindow; + this.init(); + this.#window.addEventListener("unload", () => { + if (typeof this.uninit === "function") { + this.uninit(); + } + for (const { type, options } of this.#eventListeners) { + this.#window.removeEventListener(type, this, options); + } + this.#eventListeners.clear(); + }); + } + + get window() { + return this.#window; + } + + /** + * Adds an event listener to the component that will automatically be removed when the window unloads. + * + * @param {string} type - The event type to listen for. + * @param {object} options - The event listener function or an object containing options. + * @returns {void} + */ + addEventListener(type, options = {}) { + this.#window.addEventListener(type, this, options); + if (options?.once) { + return; + } + this.#eventListeners.add({ type, options }); + } + + listenBrowserTabsProgress() { + this.#window.gBrowser.addTabsProgressListener(this); + } + + listenBrowserProgress() { + this.#window.gBrowser.addProgressListener(this); + } + + handleEvent(event) { + const handlerName = "on_" + event.type; + if (typeof this[handlerName] === "function") { + this[handlerName](event); + } + } +} diff --git a/src/zen/glance/zen-glance.css b/src/zen/glance/zen-glance.css index 807aea8c2..bca099ab7 100644 --- a/src/zen/glance/zen-glance.css +++ b/src/zen/glance/zen-glance.css @@ -96,12 +96,6 @@ .browserSidebarContainer.zen-glance-background { box-shadow: var(--zen-big-shadow); - - & .browserContainer { - /* For rounding the corners of the content to work while - * applying a transformation to the container. */ - will-change: transform; - } } .browserSidebarContainer.zen-glance-background, diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index 8a8e4e832..2c048c8cc 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -79,8 +79,9 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { this._zenClickEventListener = this._onTabClick.bind(this); gZenWorkspaces._resolvePinnedInitialized(); - if (lazy.zenPinnedTabRestorePinnedTabsToPinnedUrl) { - gZenWorkspaces.promiseInitialized.then(() => { + gZenWorkspaces.promiseInitialized.then(() => { + gBrowser.addTabsProgressListener(this); + if (lazy.zenPinnedTabRestorePinnedTabsToPinnedUrl) { for (const tab of gZenWorkspaces.allStoredTabs) { try { this.resetPinnedTab(tab); @@ -88,8 +89,8 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { console.error("Error restoring pinned tab:", ex); } } - }); - } + } + }); } log(message) { @@ -833,11 +834,13 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { } } - onLocationChange(aBrowser, aLocation) { + onLocationChange(aBrowser, aWebProgress, aRequest, aLocationURI) { + // eslint-disable-next-line no-shadow + let location = aLocationURI ? aLocationURI.spec : ""; if ( - (aLocation == "about:blank" && + (location == "about:blank" && BrowserUIUtils.checkEmptyPageOrigin(aBrowser)) || - aLocation == "" + location == "" ) { return; } @@ -852,7 +855,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { } // Remove # and ? from the URL const pinUrl = tab._zenPinnedInitialState.entry.url.split("#")[0]; - const currentUrl = aLocation.split("#")[0]; + const currentUrl = location.split("#")[0]; // Add an indicator that the pin has been changed if (pinUrl === currentUrl) { this.resetPinChangedUrl(tab); From b988f23a14df2ca0b60d6fd61f6226524aeffdf9 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 15 Apr 2026 18:59:40 +0200 Subject: [PATCH 061/149] gh-10649: Implement JSON store length hints (gh-13260) --- scripts/update_external_patches.py | 36 ++- .../session_store_use_size_hint/D247145.patch | 61 ++++ .../session_store_use_size_hint/D247215.patch | 251 ++++++++++++++++ .../session_store_use_size_hint/D247217.patch | 279 ++++++++++++++++++ src/external-patches/manifest.json | 9 + src/toolkit/modules/JSONFile-sys-mjs.patch | 29 ++ .../sessionstore/ZenSessionManager.sys.mjs | 22 +- 7 files changed, 667 insertions(+), 20 deletions(-) create mode 100644 src/external-patches/firefox/session_store_use_size_hint/D247145.patch create mode 100644 src/external-patches/firefox/session_store_use_size_hint/D247215.patch create mode 100644 src/external-patches/firefox/session_store_use_size_hint/D247217.patch create mode 100644 src/toolkit/modules/JSONFile-sys-mjs.patch diff --git a/scripts/update_external_patches.py b/scripts/update_external_patches.py index 3e4c1057b..341cb77f7 100644 --- a/scripts/update_external_patches.py +++ b/scripts/update_external_patches.py @@ -24,6 +24,9 @@ def download_phab_patch(phab_id, output_file): print(f"Downloading patch from {patch_url}") response = requests.get(patch_url) response.raise_for_status() # Raise an error for bad responses + folder = os.path.dirname(output_file) + if not os.path.exists(folder): + os.makedirs(folder) with open(output_file, 'wb') as f: f.write(response.content) print(f"Patch saved to {output_file}") @@ -51,24 +54,27 @@ def main(): expected_files = set() for patch in manifest: if patch.get("type") == "phabricator": - phab_id = patch.get("id") + phab_ids = [patch.get("id")] if patch.get("id") else patch.get("ids", []) name = patch.get("name") - if not phab_id or not name: + if not phab_ids or not name: die(f"Patch entry missing 'id' or 'name': {patch}") name = name.replace(" ", "_").replace(".", "_").lower() - output_file = os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch") - print(f"Processing Phabricator patch: {phab_id} -> {output_file}") - download_phab_patch(phab_id, output_file) - replaces = patch.get("replaces", {}) - for replace in replaces.keys(): - value = replaces[replace] - with open(output_file, 'r') as f: - content = f.read() - if replace not in content: - die(f"Replace string '{replace}' not found in {output_file}") - with open(output_file, 'w') as f: - f.write(content.replace(replace, value)) - expected_files.add(output_file) + for phab_id in phab_ids: + output_file = ( + os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch") + if len(phab_ids) == 1 else + os.path.join(OUTPUT_DIR, "firefox", name, f"{phab_id}.patch") + ) + print(f"Processing Phabricator patch: {phab_id} -> {output_file}") + download_phab_patch(phab_id, output_file) + replaces = patch.get("replaces", {}) + for replace in replaces.keys(): + value = replaces[replace] + with open(output_file, 'r') as f: + content = f.read() + with open(output_file, 'w') as f: + f.write(content.replace(replace, value)) + expected_files.add(output_file) elif patch.get("type") == "local": print(f"Local patch: {patch.get('path')}") expected_files.add(os.path.join(OUTPUT_DIR, patch.get("path"))) diff --git a/src/external-patches/firefox/session_store_use_size_hint/D247145.patch b/src/external-patches/firefox/session_store_use_size_hint/D247145.patch new file mode 100644 index 000000000..c52eb4b92 --- /dev/null +++ b/src/external-patches/firefox/session_store_use_size_hint/D247145.patch @@ -0,0 +1,61 @@ +diff --git a/js/public/JSON.h b/js/public/JSON.h +--- a/js/public/JSON.h ++++ b/js/public/JSON.h +@@ -24,16 +24,23 @@ + * writing stringified data by exactly one call of |callback|, passing |data| as + * argument. + * + * In cases where JSON.stringify would return undefined, this function calls + * |callback| with the string "null". ++ * ++ * If a length hint is passed, space will be reserved for at least that many ++ * characters. + */ + extern JS_PUBLIC_API bool JS_Stringify(JSContext* cx, + JS::MutableHandle value, + JS::Handle replacer, + JS::Handle space, + JSONWriteCallback callback, void* data); ++extern JS_PUBLIC_API bool JS_StringifyWithLengthHint( ++ JSContext* cx, JS::MutableHandle value, ++ JS::Handle replacer, JS::Handle space, ++ JSONWriteCallback callback, void* data, size_t lengthHint); + + namespace JS { + + /** + * An API akin to JS_Stringify but with the goal of not having observable +diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp +--- a/js/src/jsapi.cpp ++++ b/js/src/jsapi.cpp +@@ -3663,17 +3663,29 @@ + } + + JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp, + HandleObject replacer, HandleValue space, + JSONWriteCallback callback, void* data) { ++ return JS_StringifyWithLengthHint(cx, vp, replacer, space, callback, data, 0); ++} ++ ++JS_PUBLIC_API bool JS_StringifyWithLengthHint(JSContext* cx, ++ MutableHandleValue vp, ++ HandleObject replacer, ++ HandleValue space, ++ JSONWriteCallback callback, ++ void* data, size_t lengthHint) { + AssertHeapIsIdle(); + CHECK_THREAD(cx); + cx->check(replacer, space); + StringBuilder sb(cx); + if (!sb.ensureTwoByteChars()) { + return false; + } ++ if (lengthHint && !sb.reserve(lengthHint)) { ++ return false; ++ } + if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal)) { + return false; + } + if (sb.empty() && !sb.append(cx->names().null)) { + return false; + diff --git a/src/external-patches/firefox/session_store_use_size_hint/D247215.patch b/src/external-patches/firefox/session_store_use_size_hint/D247215.patch new file mode 100644 index 000000000..53e619863 --- /dev/null +++ b/src/external-patches/firefox/session_store_use_size_hint/D247215.patch @@ -0,0 +1,251 @@ +diff --git a/dom/chrome-webidl/IOUtils.webidl b/dom/chrome-webidl/IOUtils.webidl +--- a/dom/chrome-webidl/IOUtils.webidl ++++ b/dom/chrome-webidl/IOUtils.webidl +@@ -94,23 +94,23 @@ + * otherwise rejects with a DOMException. + */ + [NewObject] + Promise writeUTF8(DOMString path, UTF8String string, optional WriteOptions options = {}); + /** +- * Attempts to serialize |value| into a JSON string and encode it as into a +- * UTF-8 string, then safely write the result to a file at |path|. Works +- * exactly like |write|. ++ * Attempts to serialize |value| into a JSON string and encode it as a UTF-8 ++ * string, then safely write the result to a file at |path|. Works exactly ++ * like |write|. + * + * @param path An absolute file path + * @param value The value to be serialized. + * @param options Options for writing the file. The "append" mode is not supported. + * + * @return Resolves with the number of bytes successfully written to the file, + * otherwise rejects with a DOMException. + */ + [NewObject] +- Promise writeJSON(DOMString path, any value, optional WriteOptions options = {}); ++ Promise writeJSON(DOMString path, any value, optional WriteJSONOptions options = {}); + /** + * Moves the file from |sourcePath| to |destPath|, creating necessary parents. + * If |destPath| is a directory, then the source file will be moved into the + * destination directory. + * +@@ -567,10 +567,39 @@ + * If true, compress the data with LZ4-encoding before writing to the file. + */ + boolean compress = false; + }; + ++/** ++ * Options to be passed to the |IOUtils.writeJSON| method. ++ */ ++dictionary WriteJSONOptions: WriteOptions { ++ /** ++ * An optional length hint that will be used to pre-allocate the buffer that ++ * will hold the stringified JSON. ++ * ++ * This is the *length* and not the size (i.e., it is the number of UTF-16 ++ * codepoints and not the number of bytes). ++ */ ++ unsigned long long lengthHint = 0; ++}; ++ ++/** ++ * Information about a WriteJSON operation. ++ */ ++dictionary WriteJSONResult { ++ /** ++ * The number of bytes written. ++ */ ++ required unsigned long long size; ++ ++ /** ++ * The length of the stringified JSON (in UTF-16 codepoints). ++ */ ++ required unsigned long long jsonLength; ++}; ++ + /** + * Options to be passed to the |IOUtils.move| method. + */ + dictionary MoveOptions { + /** +diff --git a/xpcom/ioutils/IOUtils.h b/xpcom/ioutils/IOUtils.h +--- a/xpcom/ioutils/IOUtils.h ++++ b/xpcom/ioutils/IOUtils.h +@@ -94,11 +94,11 @@ + const nsACString& aString, const dom::WriteOptions& aOptions, + ErrorResult& aError); + + static already_AddRefed WriteJSON( + dom::GlobalObject& aGlobal, const nsAString& aPath, +- JS::Handle aValue, const dom::WriteOptions& aOptions, ++ JS::Handle aValue, const dom::WriteJSONOptions& aOptions, + ErrorResult& aError); + + static already_AddRefed Move(dom::GlobalObject& aGlobal, + const nsAString& aSourcePath, + const nsAString& aDestPath, +@@ -736,13 +736,16 @@ + RefPtr mBackupFile; + RefPtr mTmpFile; + dom::WriteMode mMode; + bool mFlush = false; + bool mCompress = false; ++ size_t mLengthHint = 0; + + static Result FromBinding( + const dom::WriteOptions& aOptions); ++ static Result FromBinding( ++ const dom::WriteJSONOptions& aOptions); + }; + + /** + * Re-implements the file compression and decompression utilities found + * in toolkit/components/lz4/lz4.js +diff --git a/xpcom/ioutils/IOUtils.cpp b/xpcom/ioutils/IOUtils.cpp +--- a/xpcom/ioutils/IOUtils.cpp ++++ b/xpcom/ioutils/IOUtils.cpp +@@ -589,15 +589,21 @@ + return WriteSync(file, AsBytes(Span(str)), opts); + }); + }); + } + ++static bool AppendJSON(const char16_t* aBuf, uint32_t aLen, void* aStr) { ++ nsAString* str = static_cast(aStr); ++ ++ return str->Append(aBuf, aLen, fallible); ++} ++ + /* static */ + already_AddRefed IOUtils::WriteJSON(GlobalObject& aGlobal, + const nsAString& aPath, + JS::Handle aValue, +- const WriteOptions& aOptions, ++ const WriteJSONOptions& aOptions, + ErrorResult& aError) { + return WithPromiseAndState( + aGlobal, aError, [&](Promise* promise, auto& state) { + nsCOMPtr file = new nsLocalFile(); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, +@@ -623,14 +629,15 @@ + file->HumanReadablePath().get())); + return; + } + + JSContext* cx = aGlobal.Context(); +- JS::Rooted rootedValue(cx, aValue); ++ JS::Rooted value(cx, aValue); + nsString string; +- if (!nsContentUtils::StringifyJSON(cx, aValue, string, +- UndefinedIsNullStringLiteral)) { ++ if (!JS_StringifyWithLengthHint(cx, &value, nullptr, ++ JS::NullHandleValue, AppendJSON, ++ &string, opts.mLengthHint)) { + JS::Rooted exn(cx, JS::UndefinedValue()); + if (JS_GetPendingException(cx, &exn)) { + JS_ClearPendingException(cx); + promise->MaybeReject(exn); + } else { +@@ -639,22 +646,29 @@ + "Could not serialize object to JSON"_ns)); + } + return; + } + +- DispatchAndResolve( ++ DispatchAndResolve( + state->mEventQueue, promise, + [file = std::move(file), string = std::move(string), +- opts = std::move(opts)]() -> Result { ++ opts = std::move(opts)]() -> Result { + nsAutoCString utf8Str; + if (!CopyUTF16toUTF8(string, utf8Str, fallible)) { + return Err(IOError( + NS_ERROR_OUT_OF_MEMORY, + "Failed to write to `%s': could not allocate buffer", + file->HumanReadablePath().get())); + } +- return WriteSync(file, AsBytes(Span(utf8Str)), opts); ++ ++ uint32_t size = ++ MOZ_TRY(WriteSync(file, AsBytes(Span(utf8Str)), opts)); ++ ++ dom::WriteJSONResult result; ++ result.mSize = size; ++ result.mJsonLength = static_cast(string.Length()); ++ return result; + }); + }); + } + + /* static */ +@@ -2840,10 +2854,20 @@ + + opts.mCompress = aOptions.mCompress; + return opts; + } + ++Result ++IOUtils::InternalWriteOpts::FromBinding(const WriteJSONOptions& aOptions) { ++ InternalWriteOpts opts = ++ MOZ_TRY(FromBinding(static_cast(aOptions))); ++ ++ opts.mLengthHint = aOptions.mLengthHint; ++ ++ return opts; ++} ++ + /* static */ + Result IOUtils::JsBuffer::Create( + IOUtils::BufferKind aBufferKind, size_t aCapacity) { + JsBuffer buffer(aBufferKind, aCapacity); + if (aCapacity != 0 && !buffer.mBuffer) { +diff --git a/xpcom/ioutils/tests/test_ioutils_read_write_json.html b/xpcom/ioutils/tests/test_ioutils_read_write_json.html +--- a/xpcom/ioutils/tests/test_ioutils_read_write_json.html ++++ b/xpcom/ioutils/tests/test_ioutils_read_write_json.html +@@ -140,10 +140,43 @@ + ); + + await cleanup(filename); + }); + ++ add_task(async function test_writeJSON_return() { ++ const filename = PathUtils.join(PathUtils.tempDir, "test_ioutils_writeJSON_return.tmp"); ++ ++ const obj = { emoji: "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️‍🌈 🥠 🏴‍☠️ 🪐" }; ++ ++ const expectedJson = JSON.stringify(obj); ++ const size = new TextEncoder().encode(expectedJson).byteLength; ++ ++ { ++ const result = await IOUtils.writeJSON(filename, obj, { lengthHint: 0 }); ++ ++ is(await IOUtils.readUTF8(filename), expectedJson, "should have written expected JSON"); ++ ++ is(typeof result, "object", "writeJSON returns an object"); ++ ok(result !== null, "writeJSON returns non-null"); ++ ++ ok(Object.hasOwn(result, "size"), "result has size property"); ++ ok(Object.hasOwn(result, "jsonLength"), "result has jsonLength property"); ++ ++ is(result.size, size, "Should have written the expected number of bytes"); ++ is(result.jsonLength, expectedJson.length, "Should have written the expected number of UTF-16 codepoints"); ++ } ++ ++ { ++ const result = await IOUtils.writeJSON(filename, obj, { lengthHint: expectedJson.length, compress: true }); ++ ++ isnot(result.size, size, "Should have written a different number of bytes due to compression"); ++ is(result.jsonLength, expectedJson.length, "Should have written the same number of UTF-16 codepoints"); ++ } ++ ++ await cleanup(filename); ++ }); ++ + add_task(async function test_append_json() { + const filename = PathUtils.join(PathUtils.tempDir, "test_ioutils_append_json.tmp"); + + await IOUtils.writeJSON(filename, OBJECT); + + diff --git a/src/external-patches/firefox/session_store_use_size_hint/D247217.patch b/src/external-patches/firefox/session_store_use_size_hint/D247217.patch new file mode 100644 index 000000000..31ffe06f9 --- /dev/null +++ b/src/external-patches/firefox/session_store_use_size_hint/D247217.patch @@ -0,0 +1,279 @@ +diff --git a/browser/components/sessionstore/SessionFile.sys.mjs b/browser/components/sessionstore/SessionFile.sys.mjs +--- a/browser/components/sessionstore/SessionFile.sys.mjs ++++ b/browser/components/sessionstore/SessionFile.sys.mjs +@@ -503,10 +503,12 @@ + if (isFinalWrite) { + Services.obs.notifyObservers( + null, + "sessionstore-final-state-write-complete" + ); ++ ++ lazy.SessionWriter.deinit(); + } + }); + }, + + async wipe() { +diff --git a/browser/components/sessionstore/SessionWriter.sys.mjs b/browser/components/sessionstore/SessionWriter.sys.mjs +--- a/browser/components/sessionstore/SessionWriter.sys.mjs ++++ b/browser/components/sessionstore/SessionWriter.sys.mjs +@@ -6,10 +6,12 @@ + + ChromeUtils.defineESModuleGetters(lazy, { + sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs", + }); + ++const BROWSER_PURGE_SESSION_HISTORY = "browser:purge-session-history"; ++ + /** + * We just started (we haven't written anything to disk yet) from + * `Paths.clean`. The backup directory may not exist. + */ + const STATE_CLEAN = "clean"; +@@ -58,10 +60,14 @@ + export const SessionWriter = { + init(origin, useOldExtension, paths, prefs = {}) { + return SessionWriterInternal.init(origin, useOldExtension, paths, prefs); + }, + ++ deinit() { ++ return SessionWriterInternal.deinit(); ++ }, ++ + /** + * Write the contents of the session file. + * + * @param state - May get changed on shutdown. + */ +@@ -80,10 +86,17 @@ + return await SessionWriterInternal.wipe(); + } finally { + unlock(); + } + }, ++ ++ /** ++ * *Test Only* Return the SessionWriter's length hint for writing JSON. ++ */ ++ get _jsonLengthHint() { ++ return SessionWriterInternal.jsonLengthHint; ++ }, + }; + + const SessionWriterInternal = { + // Path to the files used by the SessionWriter + Paths: null, +@@ -104,10 +117,19 @@ + /** + * Number of old upgrade backups that are being kept + */ + maxUpgradeBackups: null, + ++ /** ++ * The size of the last write with IOUtils.writeJSON. ++ * ++ * Because SessionWriter writes such a large object graph we will otherwise ++ * spend a large portion of `write()` doing memory allocations and memcpy ++ * when serializing the session file to disk. ++ */ ++ jsonLengthHint: 0, ++ + /** + * Initialize (or reinitialize) the writer. + * + * @param {string} origin Which of sessionstore.js or its backups + * was used. One of the `STATE_*` constants defined above. +@@ -136,13 +158,20 @@ + this.Paths = paths; + this.maxUpgradeBackups = prefs.maxUpgradeBackups; + this.maxSerializeBack = prefs.maxSerializeBack; + this.maxSerializeForward = prefs.maxSerializeForward; + this.upgradeBackupNeeded = paths.nextUpgradeBackup != paths.upgradeBackup; ++ ++ Services.obs.addObserver(this, BROWSER_PURGE_SESSION_HISTORY); ++ + return { result: true }; + }, + ++ deinit() { ++ Services.obs.removeObserver(this, BROWSER_PURGE_SESSION_HISTORY); ++ }, ++ + /** + * Write the session to disk. + * Write the session to disk, performing any necessary backup + * along the way. + * +@@ -208,36 +237,42 @@ + // We are shutting down. At this stage, we know that + // $Paths.clean is either absent or corrupted. If it was + // originally present and valid, it has been moved to + // $Paths.cleanBackup a long time ago. We can therefore write + // with the guarantees that we erase no important data. +- await IOUtils.writeJSON(this.Paths.clean, state, { ++ const result = await IOUtils.writeJSON(this.Paths.clean, state, { + tmpPath: this.Paths.clean + ".tmp", + compress: true, ++ lengthHint: this.jsonLengthHint, + }); ++ this.jsonLengthHint = result.jsonLength; + fileStat = await IOUtils.stat(this.Paths.clean); + } else if (this.state == STATE_RECOVERY) { + // At this stage, either $Paths.recovery was written >= 15 + // seconds ago during this session or we have just started + // from $Paths.recovery left from the previous session. Either + // way, $Paths.recovery is good. We can move $Path.backup to + // $Path.recoveryBackup without erasing a good file with a bad + // file. +- await IOUtils.writeJSON(this.Paths.recovery, state, { ++ const result = await IOUtils.writeJSON(this.Paths.recovery, state, { + tmpPath: this.Paths.recovery + ".tmp", + backupFile: this.Paths.recoveryBackup, + compress: true, ++ lengthHint: this.jsonLengthHint, + }); ++ this.jsonLengthHint = result.jsonLength; + fileStat = await IOUtils.stat(this.Paths.recovery); + } else { + // In other cases, either $Path.recovery is not necessary, or + // it doesn't exist or it has been corrupted. Regardless, + // don't backup $Path.recovery. +- await IOUtils.writeJSON(this.Paths.recovery, state, { ++ const result = await IOUtils.writeJSON(this.Paths.recovery, state, { + tmpPath: this.Paths.recovery + ".tmp", + compress: true, ++ lengthHint: this.jsonLengthHint, + }); ++ this.jsonLengthHint = result.jsonLength; + fileStat = await IOUtils.stat(this.Paths.recovery); + } + + telemetry.writeFileMs = Date.now() - startWriteMs; + telemetry.fileSizeBytes = fileStat.size; +@@ -420,6 +455,18 @@ + + if (exn) { + throw exn; + } + }, ++ ++ observe(_subject, topic, _data) { ++ switch (topic) { ++ case BROWSER_PURGE_SESSION_HISTORY: ++ this._onPurgeSessionHistory(); ++ break; ++ } ++ }, ++ ++ _onPurgeSessionHistory() { ++ this.jsonLengthHint = 0; ++ }, + }; +diff --git a/browser/components/sessionstore/test/unit/test_write_json_length_hint.js b/browser/components/sessionstore/test/unit/test_write_json_length_hint.js +new file mode 100644 +--- /dev/null ++++ b/browser/components/sessionstore/test/unit/test_write_json_length_hint.js +@@ -0,0 +1,91 @@ ++/* Any copyright is dedicated to the Public Domain. ++ http://creativecommons.org/publicdomain/zero/1.0/ */ ++ ++"use strict"; ++ ++const { updateAppInfo } = ChromeUtils.importESModule( ++ "resource://testing-common/AppInfo.sys.mjs" ++); ++ ++const profile = do_get_profile(); ++ ++updateAppInfo({ ++ name: "SessionRestoreTest", ++ ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}", ++ version: "1", ++ platformVersion: "", ++}); ++ ++const { SessionFile } = ChromeUtils.importESModule( ++ "resource:///modules/sessionstore/SessionFile.sys.mjs" ++); ++const { SessionWriter } = ChromeUtils.importESModule( ++ "resource:///modules/sessionstore/SessionWriter.sys.mjs" ++); ++ ++add_setup(async function setup() { ++ const source = do_get_file("data/sessionstore_valid.js"); ++ source.copyTo(profile, "sessionstore.js"); ++ ++ await writeCompressedFile( ++ SessionFile.Paths.clean.replace("jsonlz4", "js"), ++ SessionFile.Paths.clean ++ ); ++ ++ await SessionFile.read(); ++}); ++ ++add_task(async function test_json_length_hint() { ++ await IOUtils.writeJSON(PathUtils.join(PathUtils.profileDir, "dingus"), { ++ gunk: true, ++ }); ++ ++ Assert.equal( ++ SessionWriter._jsonLengthHint, ++ 0, ++ "SessionWriter length hint starts at 0" ++ ); ++ ++ await SessionFile.write({}); ++ ++ const lengthHint = SessionWriter._jsonLengthHint; ++ ++ Assert.equal( ++ SessionWriter._jsonLengthHint, ++ JSON.stringify({}).length, ++ "SessionWriter should cache length hint" ++ ); ++ ++ const contents = await IOUtils.readJSON( ++ PathUtils.join(do_get_cwd().path, "data", "sessionstore_complete.json") ++ ); ++ await SessionFile.write(contents); ++ ++ Assert.notEqual( ++ SessionWriter._jsonLengthHint, ++ lengthHint, ++ "SessionWriter length hint updated" ++ ); ++ ++ Assert.greater( ++ SessionWriter._jsonLengthHint, ++ lengthHint, ++ "SessionWriteLength hint is now larger" ++ ); ++ ++ Services.obs.notifyObservers(null, "browser:purge-session-history"); ++ ++ Assert.equal( ++ SessionWriter._jsonLengthHint, ++ 0, ++ "browser:purge-session-history notification cleans length hint" ++ ); ++ ++ await SessionFile.write(contents); ++ ++ Assert.notEqual( ++ SessionWriter._jsonLengthHint, ++ lengthHint, ++ "SessionWriter length hint updated" ++ ); ++}); +diff --git a/browser/components/sessionstore/test/unit/xpcshell.toml b/browser/components/sessionstore/test/unit/xpcshell.toml +--- a/browser/components/sessionstore/test/unit/xpcshell.toml ++++ b/browser/components/sessionstore/test/unit/xpcshell.toml +@@ -39,5 +39,7 @@ + skip-if = [ + "condprof", # Bug 1769154 + ] + + ["test_startup_session_async.js"] ++ ++["test_write_json_length_hint.js"] + diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json index ff81da911..89232ce68 100644 --- a/src/external-patches/manifest.json +++ b/src/external-patches/manifest.json @@ -55,5 +55,14 @@ "type": "phabricator", "id": "D281762", "name": "FF150 3 PGO patch for bug-2014422" + }, + { + "type": "phabricator", + "ids": [ + "D247145", + "D247215", + "D247217" + ], + "name": "Session store use size hint" } ] diff --git a/src/toolkit/modules/JSONFile-sys-mjs.patch b/src/toolkit/modules/JSONFile-sys-mjs.patch new file mode 100644 index 000000000..ca854e039 --- /dev/null +++ b/src/toolkit/modules/JSONFile-sys-mjs.patch @@ -0,0 +1,29 @@ +diff --git a/toolkit/modules/JSONFile.sys.mjs b/toolkit/modules/JSONFile.sys.mjs +index 397991e4af8f49b6365d729fc11267b5c1113400..1955b7ff1d428e891f5ef066e7a4ac25aa5ec9b4 100644 +--- a/toolkit/modules/JSONFile.sys.mjs ++++ b/toolkit/modules/JSONFile.sys.mjs +@@ -132,6 +132,7 @@ export function JSONFile(config) { + this._finalizeInternalBound, + () => ({ sanitizedBasename: this.sanitizedBasename }) + ); ++ this._useSizeHints = config.useSizeHints ?? false; + } + + JSONFile.prototype = { +@@ -423,11 +424,15 @@ JSONFile.prototype = { + } + + try { +- await IOUtils.writeJSON( ++ if (this._useSizeHints && this._lastSavedSize) { ++ this._options.lengthHint = this._lastSavedSize; ++ } ++ const result = await IOUtils.writeJSON( + this.path, + this._data, + Object.assign({ tmpPath: this.path + ".tmp" }, this._options) + ); ++ this._lastSavedSize = this._useSizeHints ? result.jsonLength : null; + } catch (ex) { + if (typeof this._data.toJSONSafe == "function") { + // If serialization fails, try fallback safe JSON converter. diff --git a/src/zen/sessionstore/ZenSessionManager.sys.mjs b/src/zen/sessionstore/ZenSessionManager.sys.mjs index ac23ac37c..6ff9860c7 100644 --- a/src/zen/sessionstore/ZenSessionManager.sys.mjs +++ b/src/zen/sessionstore/ZenSessionManager.sys.mjs @@ -64,6 +64,10 @@ class nsZenSidebarObject { return Cu.cloneInto(this.#sidebar, {}); } + get dataWithoutCloning() { + return this.#sidebar; + } + set data(data) { if (typeof data !== "object") { throw new Error("Sidebar data must be an object"); @@ -100,6 +104,10 @@ export class nsZenSessionManager { path: this.#storeFilePath, compression: "lz4", backupTo, + useSizeHints: Services.prefs.getBoolPref( + "zen.session-store.use-size-hints", + true + ), }); this.log("Session file path:", this.#file.path); this.#deferredBackupTask = new lazy.DeferredTask(async () => { @@ -412,10 +420,10 @@ export class nsZenSessionManager { if ( this.#shouldRestoreOnlyPinned && !this.#shouldRestoreFromCrash && - this.#sidebar?.tabs + this.#sidebarWithoutCloning?.tabs ) { this.log("Restoring only pinned tabs into windows"); - const sidebar = this.#sidebar; + const sidebar = this.#sidebarWithoutCloning; sidebar.tabs = (sidebar.tabs || []).filter(tab => tab.pinned); this.#sidebar = sidebar; } @@ -449,6 +457,10 @@ export class nsZenSessionManager { return this.#sidebarObject.data; } + get #sidebarWithoutCloning() { + return this.#sidebarObject.dataWithoutCloning; + } + set #sidebar(data) { this.#sidebarObject.data = data; } @@ -590,7 +602,7 @@ export class nsZenSessionManager { ); this.#collectWindowData(windows); // This would save the data to disk asynchronously or when quitting the app. - let sidebar = this.#sidebar; + let sidebar = this.#sidebarWithoutCloning; this.#file.data = sidebar; if (soon) { this.#file.saveSoon(); @@ -897,7 +909,7 @@ export class nsZenSessionManager { onNewEmptySession(aWindow) { this.log("Restoring empty session with Zen session data"); aWindow.gZenWorkspaces.restoreWorkspacesFromSessionStore({ - spaces: this.#sidebar.spaces || [], + spaces: this.#sidebarWithoutCloning.spaces || [], }); } @@ -909,7 +921,7 @@ export class nsZenSessionManager { * @returns {Array} The cloned spaces data. */ getClonedSpaces() { - const sidebar = this.#sidebar; + const sidebar = this.#sidebarWithoutCloning; if (!sidebar || !sidebar.spaces) { return []; } From 29e7fe12a88021122bd85103b2115d68c28230a8 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 15 Apr 2026 20:25:10 +0200 Subject: [PATCH 062/149] gh-13264: Add tests for media player (gh-13262) --- src/zen/common/styles/zen-buttons.css | 4 + src/zen/tests/manifest.toml | 4 + src/zen/tests/media/browser.toml | 16 ++ src/zen/tests/media/browser_media_metadata.js | 63 +++++ src/zen/tests/media/browser_media_mute.js | 64 +++++ .../tests/media/browser_media_next_track.js | 74 +++++ .../browser_media_shows_on_tab_switch.js | 74 +++++ src/zen/tests/media/head.js | 96 +++++++ src/zen/tests/mochitests/moz.build | 1 + .../almostSilentAudioTrack.webm | Bin 0 -> 1699661 bytes .../mochitests/tabMediaIndicator/audio.ogg | Bin 0 -> 14293 bytes .../audioEndedDuringPlaying.webm | Bin 0 -> 109366 bytes .../mochitests/tabMediaIndicator/browser.toml | 44 +++ .../browser_destroy_iframe.js | 50 ++++ .../browser_mediaPlayback.js | 42 +++ .../browser_mediaPlayback_mute.js | 118 ++++++++ ...browser_mediaplayback_audibility_change.js | 258 ++++++++++++++++++ .../tabMediaIndicator/browser_mute.js | 19 ++ .../tabMediaIndicator/browser_mute2.js | 32 +++ .../browser_mute_webAudio.js | 72 +++++ .../browser_sound_indicator_silent_video.js | 95 +++++++ .../browser_webAudio_hideSoundPlayingIcon.js | 60 ++++ .../browser_webAudio_silentData.js | 57 ++++ .../browser_webaudio_audibility_change.js | 172 ++++++++++++ .../file_almostSilentAudioTrack.html | 18 ++ .../file_autoplay_media.html | 9 + .../tabMediaIndicator/file_empty.html | 8 + .../tabMediaIndicator/file_mediaPlayback.html | 9 + .../file_mediaPlayback2.html | 14 + .../file_mediaPlaybackFrame.html | 2 + .../file_mediaPlaybackFrame2.html | 2 + .../file_silentAudioTrack.html | 18 ++ .../tabMediaIndicator/file_webAudio.html | 29 ++ .../mochitests/tabMediaIndicator/gizmo.mp4 | Bin 0 -> 455255 bytes .../mochitests/tabMediaIndicator/head.js | 165 +++++++++++ .../mochitests/tabMediaIndicator/noaudio.webm | Bin 0 -> 105755 bytes .../tabMediaIndicator/silentAudioTrack.webm | Bin 0 -> 224800 bytes src/zen/tests/moz.build | 1 + 38 files changed, 1690 insertions(+) create mode 100644 src/zen/tests/media/browser.toml create mode 100644 src/zen/tests/media/browser_media_metadata.js create mode 100644 src/zen/tests/media/browser_media_mute.js create mode 100644 src/zen/tests/media/browser_media_next_track.js create mode 100644 src/zen/tests/media/browser_media_shows_on_tab_switch.js create mode 100644 src/zen/tests/media/head.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/almostSilentAudioTrack.webm create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/audio.ogg create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/audioEndedDuringPlaying.webm create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser.toml create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_destroy_iframe.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mediaPlayback.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mediaPlayback_mute.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mediaplayback_audibility_change.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mute.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mute2.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_mute_webAudio.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_sound_indicator_silent_video.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_webAudio_hideSoundPlayingIcon.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_webAudio_silentData.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/browser_webaudio_audibility_change.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_almostSilentAudioTrack.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_autoplay_media.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_empty.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_mediaPlayback.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_mediaPlayback2.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_mediaPlaybackFrame.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_mediaPlaybackFrame2.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_silentAudioTrack.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/file_webAudio.html create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/gizmo.mp4 create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/head.js create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/noaudio.webm create mode 100644 src/zen/tests/mochitests/tabMediaIndicator/silentAudioTrack.webm diff --git a/src/zen/common/styles/zen-buttons.css b/src/zen/common/styles/zen-buttons.css index d94c2c367..a3dfd404a 100644 --- a/src/zen/common/styles/zen-buttons.css +++ b/src/zen/common/styles/zen-buttons.css @@ -38,6 +38,10 @@ dialog[defaultButton="accept"]::part(dialog-button) { padding-inline-end: 4em; } + @media (-moz-platform: linux) { + padding-inline-end: 3.1em; + } + &::after { border-radius: 4px; font-weight: 600; diff --git a/src/zen/tests/manifest.toml b/src/zen/tests/manifest.toml index 60c0975dc..18334b2f8 100644 --- a/src/zen/tests/manifest.toml +++ b/src/zen/tests/manifest.toml @@ -25,5 +25,9 @@ disable = [ "browser_setDesktopBackgroundPreview.js", ] +[tabMediaIndicator] +source = "browser/components/tabbrowser/test/browser/tabMediaIndicator" +is_direct_path = true + [tooltiptext] source = "toolkit/components/tooltiptext" diff --git a/src/zen/tests/media/browser.toml b/src/zen/tests/media/browser.toml new file mode 100644 index 000000000..52752f239 --- /dev/null +++ b/src/zen/tests/media/browser.toml @@ -0,0 +1,16 @@ +# 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/. + +[DEFAULT] +support-files = [ + "head.js", +] + +["browser_media_metadata.js"] + +["browser_media_mute.js"] + +["browser_media_next_track.js"] + +["browser_media_shows_on_tab_switch.js"] diff --git a/src/zen/tests/media/browser_media_metadata.js b/src/zen/tests/media/browser_media_metadata.js new file mode 100644 index 000000000..a048b8cac --- /dev/null +++ b/src/zen/tests/media/browser_media_metadata.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// User flow: +// 1. A page (think Spotify, YouTube Music) plays media and publishes +// title/artist via navigator.mediaSession.metadata. +// 2. User switches off that tab, media bar appears. +// 3. The title and artist labels in the bar show what the page published. +// 4. The page then updates the metadata mid-playback (next song starts). +// 5. The bar updates live, without the user having to switch tabs again. +// +// This is what makes the bar feel connected to the playing page instead of +// a generic "something is playing" indicator. + +add_task(async function test_media_bar_shows_metadata_from_page() { + const originalTab = gBrowser.selectedTab; + const mediaTab = await addMediaTab(); + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + + try { + await setMediaSessionMetadata(mediaTab, { + title: "Sandstorm", + artist: "Darude", + }); + await playVideoIn(mediaTab); + await BrowserTestUtils.switchTab(gBrowser, originalTab); + await waitForMediaBarVisible(); + + const titleEl = document.getElementById("zen-media-title"); + const artistEl = document.getElementById("zen-media-artist"); + + await BrowserTestUtils.waitForCondition( + () => titleEl.textContent === "Sandstorm", + "title label reflects the page's mediaSession metadata" + ); + Assert.equal( + artistEl.textContent, + "Darude", + "artist label reflects the page's mediaSession metadata" + ); + + // Page updates metadata mid-playback. + await setMediaSessionMetadata(mediaTab, { + title: "Levels", + artist: "Avicii", + }); + await BrowserTestUtils.waitForCondition( + () => titleEl.textContent === "Levels", + "title updates live when the page changes its mediaSession metadata" + ); + Assert.equal( + artistEl.textContent, + "Avicii", + "artist updates live alongside the title" + ); + } finally { + await pauseVideoIn(mediaTab); + BrowserTestUtils.removeTab(mediaTab); + gBrowser.selectedTab = originalTab; + } +}); diff --git a/src/zen/tests/media/browser_media_mute.js b/src/zen/tests/media/browser_media_mute.js new file mode 100644 index 000000000..766059fd0 --- /dev/null +++ b/src/zen/tests/media/browser_media_mute.js @@ -0,0 +1,64 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// User flow: +// 1. User plays a video, switches tabs, media bar appears. +// 2. User clicks the mute button on the Zen media bar. +// 3. The underlying tab actually goes silent (browser.audioMuted flips). +// 4. The media bar reflects that with the `muted` attribute so the icon +// changes. +// 5. Clicking again unmutes. +// +// If this breaks, the user sees a mute button that looks toggled but the +// audio keeps playing — or worse, the tab is muted but the button still +// says "unmuted". + +add_task(async function test_mute_from_media_bar() { + const originalTab = gBrowser.selectedTab; + const mediaTab = await addMediaTab(); + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + + try { + await playVideoIn(mediaTab); + await BrowserTestUtils.switchTab(gBrowser, originalTab); + await waitForMediaBarVisible(); + + ok( + !mediaTab.linkedBrowser.audioMuted, + "precondition: playing tab starts unmuted" + ); + ok( + !mediaBar().hasAttribute("muted"), + "precondition: media bar has no muted attribute" + ); + + clickMediaButton("zen-media-mute-button"); + await BrowserTestUtils.waitForCondition( + () => mediaTab.linkedBrowser.audioMuted, + "tab becomes muted after clicking the media bar mute button" + ); + ok( + mediaBar().hasAttribute("muted"), + "media bar reflects the muted state in its attribute" + ); + + clickMediaButton("zen-media-mute-button"); + await BrowserTestUtils.waitForCondition( + () => !mediaTab.linkedBrowser.audioMuted, + "clicking again unmutes the tab" + ); + ok( + !mediaBar().hasAttribute("muted"), + "media bar drops the muted attribute" + ); + } finally { + if (mediaTab.linkedBrowser.audioMuted) { + mediaTab.toggleMuteAudio(); + } + await pauseVideoIn(mediaTab); + BrowserTestUtils.removeTab(mediaTab); + gBrowser.selectedTab = originalTab; + } +}); diff --git a/src/zen/tests/media/browser_media_next_track.js b/src/zen/tests/media/browser_media_next_track.js new file mode 100644 index 000000000..f4797e7e0 --- /dev/null +++ b/src/zen/tests/media/browser_media_next_track.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// User flow: +// 1. A music page registers a "nexttrack" action handler (like most +// streaming sites do). +// 2. User is on another tab, media bar is showing with the next-track +// button enabled. +// 3. User clicks next-track. +// 4. The action fires inside the page — the page is responsible for +// loading the next song. Zen's job here is to relay the click. +// +// Also guards the button-enablement logic: if the page does NOT register a +// handler, the next-track button must be disabled. Otherwise clicks go +// nowhere and users think the bar is broken. + +add_task(async function test_next_track_relays_to_page() { + const originalTab = gBrowser.selectedTab; + const mediaTab = await addMediaTab(); + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + + try { + await playVideoIn(mediaTab); + await setMediaSessionActionHandler(mediaTab, "nexttrack"); + + await BrowserTestUtils.switchTab(gBrowser, originalTab); + await waitForMediaBarVisible(); + + const nextButton = document.getElementById("zen-media-nexttrack-button"); + + // supportedkeyschange propagates asynchronously; wait for the bar's + // next-track button to become enabled before clicking. + await BrowserTestUtils.waitForCondition( + () => !nextButton.disabled, + "next-track button becomes enabled once the page registers a handler" + ); + + const actionFired = waitForMediaSessionAction(mediaTab); + clickMediaButton("zen-media-nexttrack-button"); + + const result = await actionFired; + ok(result, "page's nexttrack MediaSession handler was invoked"); + } finally { + await pauseVideoIn(mediaTab); + BrowserTestUtils.removeTab(mediaTab); + gBrowser.selectedTab = originalTab; + } +}); + +add_task(async function test_next_track_button_disabled_without_handler() { + const originalTab = gBrowser.selectedTab; + const mediaTab = await addMediaTab(); + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + + try { + // Deliberately do NOT install a nexttrack handler. + await playVideoIn(mediaTab); + await BrowserTestUtils.switchTab(gBrowser, originalTab); + await waitForMediaBarVisible(); + + const nextButton = document.getElementById("zen-media-nexttrack-button"); + Assert.equal( + nextButton.disabled, + true, + "next-track button stays disabled when the page registers no handler" + ); + } finally { + await pauseVideoIn(mediaTab); + BrowserTestUtils.removeTab(mediaTab); + gBrowser.selectedTab = originalTab; + } +}); diff --git a/src/zen/tests/media/browser_media_shows_on_tab_switch.js b/src/zen/tests/media/browser_media_shows_on_tab_switch.js new file mode 100644 index 000000000..783a88af1 --- /dev/null +++ b/src/zen/tests/media/browser_media_shows_on_tab_switch.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// User flow: +// 1. User opens a page with audio and hits play. +// 2. User switches to a different tab. +// 3. The Zen media control bar should appear (so the user can still +// pause/skip without going back to the noisy tab). +// 4. User switches back to the audio tab. +// 5. The media bar should hide again — it's redundant next to the real +// page controls. +// +// This covers the real contract users see: the DOMAudioPlaybackStarted → +// TabSelect → showMediaControls chain in nsZenMediaController, plus the +// inverse path on selecting the playing tab. A regression anywhere in that +// chain (event wiring, the 500ms tab-switch debounce, the hidden attribute +// flip) surfaces as a bar that either never shows or never hides. + +// note: We keep setting timeouts because media player takes a bit to +// get removed (after the animation, more specifically) + +add_task(async function test_media_bar_shows_when_switching_off_playing_tab() { + gZenMediaController.onControllerClose(); + await BrowserTestUtils.waitForCondition( + () => !isMediaBarVisible(), + "media bar hides again once the playing tab regains focus" + ); + + const originalTab = gBrowser.selectedTab; + const mediaTab = await addMediaTab(); + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + + ok( + !isMediaBarVisible(), + "media bar is hidden while the playing tab is the active tab" + ); + + try { + await playVideoIn(mediaTab); + + ok( + !isMediaBarVisible(), + "media bar remains hidden while focused on the playing tab" + ); + + // Switch away. The controller schedules showMediaControls() on a 500ms + // timer; wait for the visibility flip rather than racing it. + await BrowserTestUtils.switchTab(gBrowser, originalTab); + await new Promise(r => setTimeout(r, 1000)); + await BrowserTestUtils.waitForCondition( + isMediaBarVisible, + "media bar becomes visible after switching off the playing tab" + ); + + Assert.equal( + gZenMediaController._currentBrowser?.browserId, + mediaTab.linkedBrowser.browserId, + "media controller is bound to the media tab's browser, not the selected tab" + ); + + await BrowserTestUtils.switchTab(gBrowser, mediaTab); + await new Promise(r => setTimeout(r, 1000)); + await BrowserTestUtils.waitForCondition( + () => !isMediaBarVisible(), + "media bar hides again once the playing tab regains focus" + ); + } finally { + await pauseVideoIn(mediaTab); + BrowserTestUtils.removeTab(mediaTab); + gBrowser.selectedTab = originalTab; + } +}); diff --git a/src/zen/tests/media/head.js b/src/zen/tests/media/head.js new file mode 100644 index 000000000..82de52c6c --- /dev/null +++ b/src/zen/tests/media/head.js @@ -0,0 +1,96 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Shared mozilla-central fixture from the Picture-in-Picture tests: an HTML +// page with two looping