diff --git a/prefs/zen/theme.yaml b/prefs/zen/theme.yaml index a77cff584..fe0a8d485 100644 --- a/prefs/zen/theme.yaml +++ b/prefs/zen/theme.yaml @@ -18,7 +18,7 @@ value: true - name: zen.theme.acrylic-elements - value: false + value: "@IS_TWILIGHT@" - name: zen.theme.disable-lightweight value: true diff --git a/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch b/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch new file mode 100644 index 000000000..2b534d0bc --- /dev/null +++ b/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch @@ -0,0 +1,172 @@ +diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp +--- a/gfx/webrender_bindings/WebRenderAPI.cpp ++++ b/gfx/webrender_bindings/WebRenderAPI.cpp +@@ -298,11 +298,13 @@ + panic_on_gl_error, picTileWidth, picTileHeight, + gfx::gfxVars::WebRenderRequiresHardwareDriver(), + StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup(), + StaticPrefs::gfx_webrender_max_shared_surface_size_AtStartup(), + StaticPrefs::gfx_webrender_enable_subpixel_aa_AtStartup(), +- compositor->ShouldUseLayerCompositor())) { ++ compositor->ShouldUseLayerCompositor(), ++ StaticPrefs:: ++ gfx_webrender_opaque_backdrop_fallback_AtStartup())) { + // wr_window_new puts a message into gfxCriticalNote if it returns + // false + MOZ_ASSERT(errorMessage); + error.AssignASCII(errorMessage); + wr_api_free_error_msg(errorMessage); +diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs +--- a/gfx/webrender_bindings/src/bindings.rs ++++ b/gfx/webrender_bindings/src/bindings.rs +@@ -1998,10 +1998,11 @@ + reject_software_rasterizer: bool, + low_quality_pinch_zoom: bool, + max_shared_surface_size: i32, + enable_subpixel_aa: bool, + use_layer_compositor: bool, ++ opaque_backdrop_fallback: bool, + ) -> bool { + assert!(unsafe { is_in_render_thread() }); + + // Ensure the WR profiler callbacks are hooked up to the Gecko profiler. + set_profiler_hooks(Some(&PROFILER_HOOKS)); +@@ -2164,10 +2165,11 @@ + texture_cache_config, + reject_software_rasterizer, + low_quality_pinch_zoom, + max_shared_surface_size, + enable_dithering, ++ opaque_backdrop_fallback, + ..Default::default() + }; + + let window_size = DeviceIntSize::new(window_width, window_height); + let notifier = Box::new(CppNotifier { window_id }); +diff --git a/gfx/wr/webrender/src/device/gl.rs b/gfx/wr/webrender/src/device/gl.rs +--- a/gfx/wr/webrender/src/device/gl.rs ++++ b/gfx/wr/webrender/src/device/gl.rs +@@ -3982,10 +3982,14 @@ + + pub fn disable_color_write(&self) { + self.gl.color_mask(false, false, false, false); + } + ++ pub fn set_color_mask(&self, r: bool, g: bool, b: bool, a: bool) { ++ self.gl.color_mask(r, g, b, a); ++ } ++ + pub fn set_blend(&mut self, enable: bool) { + if enable { + self.gl.enable(gl::BLEND); + } else { + self.gl.disable(gl::BLEND); +diff --git a/gfx/wr/webrender/src/renderer/init.rs b/gfx/wr/webrender/src/renderer/init.rs +--- a/gfx/wr/webrender/src/renderer/init.rs ++++ b/gfx/wr/webrender/src/renderer/init.rs +@@ -204,10 +204,12 @@ + pub low_quality_pinch_zoom: bool, + pub max_shared_surface_size: i32, + /// If true, open a debug socket to listen for remote debugger. + /// Relies on `debugger` cargo feature being enabled. + pub enable_debugger: bool, ++ /// See explanation of `gfx.webrender.opaque-backdrop-fallback`. ++ pub opaque_backdrop_fallback: bool, + } + + impl WebRenderOptions { + /// Number of batches to look back in history for adding the current + /// transparent instance into. +@@ -277,10 +279,11 @@ + enable_instancing: true, + reject_software_rasterizer: false, + low_quality_pinch_zoom: false, + max_shared_surface_size: 2048, + enable_debugger: true, ++ opaque_backdrop_fallback: false, + } + } + } + + /// Initializes WebRender and creates a `Renderer` and `RenderApiSender`. +@@ -802,10 +805,11 @@ + allocated_native_surfaces: FastHashSet::default(), + debug_overlay_state: DebugOverlayState::new(), + buffer_damage_tracker: BufferDamageTracker::default(), + max_primitive_instance_count, + enable_instancing: options.enable_instancing, ++ opaque_backdrop_fallback: options.opaque_backdrop_fallback, + consecutive_oom_frames: 0, + target_frame_publish_id: None, + pending_result_msg: None, + layer_compositor_frame_state_in_prev_frame: None, + external_composite_debug_items: Vec::new(), +diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs +--- a/gfx/wr/webrender/src/renderer/mod.rs ++++ b/gfx/wr/webrender/src/renderer/mod.rs +@@ -867,10 +867,12 @@ + buffer_damage_tracker: BufferDamageTracker, + + max_primitive_instance_count: usize, + enable_instancing: bool, + ++ opaque_backdrop_fallback: bool, ++ + /// Count consecutive oom frames to detectif we are stuck unable to render + /// in a loop. + consecutive_oom_frames: u32, + + /// update() defers processing of ResultMsg, if frame_publish_id of +@@ -2787,18 +2789,29 @@ + let read_target = ReadTarget::from_texture(cache_texture); + + // Should always be drawing to picture cache tiles or off-screen surface! + debug_assert!(!draw_target.is_default()); + let device_to_framebuffer = Scale::new(1i32); ++ let dest_fb_rect = dest * device_to_framebuffer; + + self.device.blit_render_target( + read_target, + src * device_to_framebuffer, + draw_target, +- dest * device_to_framebuffer, ++ dest_fb_rect, + TextureFilter::Linear, + ); ++ ++ if self.opaque_backdrop_fallback { ++ self.device.set_color_mask(false, false, false, true); ++ self.device.clear_target( ++ Some([0.0, 0.0, 0.0, 1.0]), ++ None, ++ Some(dest_fb_rect), ++ ); ++ self.device.set_color_mask(true, true, true, true); ++ } + } + } + } + + fn draw_picture_cache_target( +diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml +--- a/modules/libpref/init/StaticPrefList.yaml ++++ b/modules/libpref/init/StaticPrefList.yaml +@@ -8439,10 +8439,17 @@ + #else + value: false + #endif + mirror: once + ++# Make backdrop-filter treat its captured backdrop as if it had been ++# composited over an opaque-black background. (See bug 2036640) ++- name: gfx.webrender.opaque-backdrop-fallback ++ type: bool ++ value: true ++ mirror: once ++ + # Disable wait of GPU execution completion + - name: gfx.webrender.wait-gpu-finished.disabled + type: bool + value: false + mirror: once + diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json index 671ab5007..8c67f7d7b 100644 --- a/src/external-patches/manifest.json +++ b/src/external-patches/manifest.json @@ -33,6 +33,12 @@ "\n\n": "\n // may want to figure out a more robust way to detect abandonment." } }, + { + "type": "file", + // TODO: Convert into https://phabricator.services.mozilla.com/D298079 + // once it gets accepted. + "path": "firefox/allow_backdrop_to_work_on_transparency.patch" + }, { "type": "local", "path": "firefox/no_liquid_glass_icon.patch" diff --git a/src/zen/boosts/actors/ZenBoostsChild.sys.mjs b/src/zen/boosts/actors/ZenBoostsChild.sys.mjs index 65c08834d..4217c3053 100644 --- a/src/zen/boosts/actors/ZenBoostsChild.sys.mjs +++ b/src/zen/boosts/actors/ZenBoostsChild.sys.mjs @@ -174,7 +174,7 @@ export class ZenBoostsChild extends JSWindowActorChild { } this.#removeEventListeners(); break; - case "DOMDocElementInserted": + case "DOMWindowCreated": this.#applyBoostForPageIfAvailable(); break; default: diff --git a/src/zen/boosts/nsZenBCOverrides.cpp b/src/zen/boosts/nsZenBCOverrides.cpp index 52536ddac..89c75b04e 100644 --- a/src/zen/boosts/nsZenBCOverrides.cpp +++ b/src/zen/boosts/nsZenBCOverrides.cpp @@ -38,6 +38,18 @@ void BrowsingContext::WalkPresContexts(Callback&& aCallback) { }); } +static void RefreshBoostCacheIfMatchesCurrent(BrowsingContext* aChanged) { + auto* backend = zen::nsZenBoostsBackend::GetInstance(); + if (!backend) { + return; + } + auto current = backend->GetCurrentBrowsingContext(); + if (!current || current->Top() != aChanged) { + return; + } + backend->RefreshCachedBoostState(); +} + /** * @brief Called when the ZenBoostsData field is set on a browsing context. * Triggers a restyle if the boost data has changed. @@ -49,6 +61,7 @@ void BrowsingContext::DidSet(FieldIndex, if (ZenBoostsData() == aOldValue) { return; } + RefreshBoostCacheIfMatchesCurrent(this); PresContextAffectingFieldChanged(); TRIGGER_PRES_CONTEXT_RESTYLE(); } @@ -64,6 +77,7 @@ void BrowsingContext::DidSet(FieldIndex, if (IsZenBoostsInverted() == aOldValue) { return; } + RefreshBoostCacheIfMatchesCurrent(this); PresContextAffectingFieldChanged(); TRIGGER_PRES_CONTEXT_RESTYLE(); } diff --git a/src/zen/boosts/nsZenBoostsBackend.cpp b/src/zen/boosts/nsZenBoostsBackend.cpp index 825cc971c..9c545ddf4 100644 --- a/src/zen/boosts/nsZenBoostsBackend.cpp +++ b/src/zen/boosts/nsZenBoostsBackend.cpp @@ -145,7 +145,7 @@ inline static auto zenPrecomputeAccent(nscolor aAccentColor) { return aOriginalColor; } - const float inv255 = 1.0f / 255.0f; + constexpr float inv255 = 1.0f / 255.0f; const float blendFactor = contrast * inv255; // sRGB -> linear @@ -261,7 +261,9 @@ inline static nscolor zenInvertColorChannel(nscolor aColor) { } /** - * @brief Retrieves the current boost data from the browsing context. + * @brief Retrieves the current boost data from the browsing context. When + * called without aPresContext, reads the precomputed cache populated on + * presshell entry; otherwise resolves from the supplied PresContext. */ ZEN_HOT_FUNCTION inline static void GetZenBoostsDataFromBrowsingContext( @@ -272,11 +274,14 @@ inline static void GetZenBoostsDataFromBrowsingContext( !SHOULD_APPLY_BOOSTS_TO_ANONYMOUS_CONTENT())) { return; } - auto browsingContext = zenBoosts->GetCurrentBrowsingContext(); - if (aPresContext) { - if (auto document = aPresContext->Document()) { - browsingContext = document->GetBrowsingContext(); - } + if (!aPresContext) { + *aData = zenBoosts->mCachedCurrentAccent; + *aIsInverted = zenBoosts->mCachedCurrentInverted; + return; + } + mozilla::dom::BrowsingContext* browsingContext = nullptr; + if (auto document = aPresContext->Document()) { + browsingContext = document->GetBrowsingContext(); } if (!browsingContext) { return; @@ -318,6 +323,18 @@ auto nsZenBoostsBackend::onPresShellEntered(mozilla::dom::Document* aDocument) return; } mCurrentBrowsingContext = browsingContext; + RefreshCachedBoostState(); +} + +auto nsZenBoostsBackend::RefreshCachedBoostState() -> void { + if (!mCurrentBrowsingContext) { + mCachedCurrentAccent = 0; + mCachedCurrentInverted = false; + return; + } + auto top = mCurrentBrowsingContext->Top(); + mCachedCurrentAccent = top->ZenBoostsData(); + mCachedCurrentInverted = top->IsZenBoostsInverted(); } [[nodiscard]] ZEN_HOT_FUNCTION auto diff --git a/src/zen/boosts/nsZenBoostsBackend.h b/src/zen/boosts/nsZenBoostsBackend.h index 943a5ac8a..b79d7ef4e 100644 --- a/src/zen/boosts/nsZenBoostsBackend.h +++ b/src/zen/boosts/nsZenBoostsBackend.h @@ -64,11 +64,27 @@ class nsZenBoostsBackend final { */ auto onPresShellEntered(mozilla::dom::Document* aDocument) -> void; + /** + * @brief Refresh the cached boost state from the current top BrowsingContext. + * Called from onPresShellEntered and from BrowsingContext::DidSet hooks when + * the underlying boost fields change. + */ + auto RefreshCachedBoostState() -> void; + [[nodiscard]] inline auto GetCurrentBrowsingContext() const { return mCurrentBrowsingContext; } + /** + * Cached boost data for the current top BrowsingContext, refreshed on + * presshell entry and on DidSet hooks. Read by the per-color hot path so + * that boost-off pages don't pay for a BrowsingContext walk on every color + * resolve. + */ + ZenBoostData mCachedCurrentAccent = 0; + bool mCachedCurrentInverted = false; + private: /** * The presshell of the current document being rendered. diff --git a/src/zen/common/styles/zen-overflowing-addons.css b/src/zen/common/styles/zen-overflowing-addons.css index ab172f5e4..34391ce96 100644 --- a/src/zen/common/styles/zen-overflowing-addons.css +++ b/src/zen/common/styles/zen-overflowing-addons.css @@ -10,7 +10,8 @@ gap: 8px; padding: 8px 2px; padding-bottom: 0; - grid-template-columns: calc(var(--border-radius-medium) - 4px); + border-radius: calc(var(--border-radius-medium) - 4px); + grid-template-columns: repeat(auto-fit, minmax(32px, 1fr)); & .unified-extensions-item { flex: 1; diff --git a/src/zen/common/sys/ZenActorsManager.sys.mjs b/src/zen/common/sys/ZenActorsManager.sys.mjs index 8123ad26b..766193ad3 100644 --- a/src/zen/common/sys/ZenActorsManager.sys.mjs +++ b/src/zen/common/sys/ZenActorsManager.sys.mjs @@ -67,7 +67,7 @@ if (!Services.appinfo.inSafeMode) { child: { esModuleURI: "resource:///actors/ZenBoostsChild.sys.mjs", events: { - DOMDocElementInserted: { capture: true }, + DOMWindowCreated: {}, unload: {}, }, },