From 6475f8de0e5c5ed2922453039b4b5e522ed490b4 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Wed, 27 May 2026 13:39:22 +0200 Subject: [PATCH] gh-13844: Part 3 - Fixed text inputs not being filtered through boosts (gh-13893) --- src/image/AutoRestoreSVGState-h.patch | 14 ++++ src/layout/base/nsPresContext-h.patch | 39 +++++++++ src/layout/painting/nsImageRenderer-cpp.patch | 13 ++- src/layout/svg/SVGImageContext-cpp.patch | 41 +++++++++- src/layout/svg/SVGImageContext-h.patch | 80 +++++++++++++++++++ src/widget/Theme-cpp.patch | 56 +++++++++++++ src/widget/Theme-h.patch | 19 +++++ src/zen/boosts/nsZenBoostsBackend.cpp | 38 +++++---- 8 files changed, 280 insertions(+), 20 deletions(-) create mode 100644 src/image/AutoRestoreSVGState-h.patch create mode 100644 src/layout/base/nsPresContext-h.patch create mode 100644 src/layout/svg/SVGImageContext-h.patch create mode 100644 src/widget/Theme-cpp.patch create mode 100644 src/widget/Theme-h.patch diff --git a/src/image/AutoRestoreSVGState-h.patch b/src/image/AutoRestoreSVGState-h.patch new file mode 100644 index 000000000..bd6502135 --- /dev/null +++ b/src/image/AutoRestoreSVGState-h.patch @@ -0,0 +1,14 @@ +diff --git a/image/AutoRestoreSVGState.h b/image/AutoRestoreSVGState.h +index be639a7b78c13c2d56be49a9690bf711ccaf0a8f..28bea58034ead1206d77521934e92d3a69bfd84b 100644 +--- a/image/AutoRestoreSVGState.h ++++ b/image/AutoRestoreSVGState.h +@@ -47,6 +47,9 @@ class MOZ_STACK_CLASS AutoRestoreSVGState final { + } + return dom::PrefersColorSchemeOverride::None; + }()); ++ pc->SetZenBoostsOverride(aSVGContext.GetZenBoostsAccent(), ++ aSVGContext.GetZenBoostsComplementaryRotation(), ++ aSVGContext.GetZenBoostsInverted()); + } + + aSVGDocumentWrapper->mIsDrawing = true; diff --git a/src/layout/base/nsPresContext-h.patch b/src/layout/base/nsPresContext-h.patch new file mode 100644 index 000000000..f408114e4 --- /dev/null +++ b/src/layout/base/nsPresContext-h.patch @@ -0,0 +1,39 @@ +diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h +index 13aa7141c8e5297d0dd6aa9bd78fd32f050e8123..149a89e928d354f116c54f71605830f5ec6b7f8a 100644 +--- a/layout/base/nsPresContext.h ++++ b/layout/base/nsPresContext.h +@@ -594,6 +594,22 @@ class nsPresContext : public nsISupports, + */ + void SetColorSchemeOverride(mozilla::dom::PrefersColorSchemeOverride); + ++ // Zen boosts override. SVG images render in their own document, which has no ++ // BrowsingContext to carry the page's boost, so the host propagates it here. ++ void SetZenBoostsOverride(nscolor aAccent, float aComplementaryRotation, ++ bool aInverted) { ++ mZenBoostsOverrideAccent = aAccent; ++ mZenBoostsOverrideComplementaryRotation = aComplementaryRotation; ++ mZenBoostsOverrideInverted = aInverted; ++ mHasZenBoostsOverride = true; ++ } ++ bool HasZenBoostsOverride() const { return mHasZenBoostsOverride; } ++ nscolor ZenBoostsOverrideAccent() const { return mZenBoostsOverrideAccent; } ++ float ZenBoostsOverrideComplementaryRotation() const { ++ return mZenBoostsOverrideComplementaryRotation; ++ } ++ bool ZenBoostsOverrideInverted() const { return mZenBoostsOverrideInverted; } ++ + /** + * Return the device's screen size in inches, for font size + * inflation. +@@ -1441,6 +1457,11 @@ class nsPresContext : public nsISupports, + mozilla::dom::PrefersColorSchemeOverride mOverriddenOrEmbedderColorScheme; + mozilla::StyleForcedColors mForcedColors; + ++ nscolor mZenBoostsOverrideAccent = 0; ++ float mZenBoostsOverrideComplementaryRotation = 0.0f; ++ bool mZenBoostsOverrideInverted = false; ++ bool mHasZenBoostsOverride = false; ++ + protected: + virtual ~nsPresContext(); + diff --git a/src/layout/painting/nsImageRenderer-cpp.patch b/src/layout/painting/nsImageRenderer-cpp.patch index 574f1c0f6..6323f3471 100644 --- a/src/layout/painting/nsImageRenderer-cpp.patch +++ b/src/layout/painting/nsImageRenderer-cpp.patch @@ -1,5 +1,5 @@ diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp -index 4acb7670e971024f9c63e48ff711bbdd1dc02301..9ac1ae1b66eb6fb10195cd3709e0e29d8d53b574 100644 +index 4acb7670e971024f9c63e48ff711bbdd1dc02301..518543f29f396d819a71edb984879de22f8434a8 100644 --- a/layout/painting/nsImageRenderer.cpp +++ b/layout/painting/nsImageRenderer.cpp @@ -90,7 +90,7 @@ static already_AddRefed GetSymbolicIconImage(nsAtom* aName, @@ -29,7 +29,16 @@ index 4acb7670e971024f9c63e48ff711bbdd1dc02301..9ac1ae1b66eb6fb10195cd3709e0e29d renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aDest, aFill, aRepeatSize, aSrc, -@@ -1076,7 +1076,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext, +@@ -670,6 +670,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( + nsPresContext::AppUnitsToIntCSSPixels(aDest.height)}; + + SVGImageContext svgContext(Some(destCSSSize)); ++ SVGImageContext::MaybeStoreZenBoosts(svgContext, ++ *mForFrame->PresContext()); + Maybe region; + + const int32_t appUnitsPerDevPixel = +@@ -1076,7 +1078,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext, if (mImage->IsGradient()) { nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create( diff --git a/src/layout/svg/SVGImageContext-cpp.patch b/src/layout/svg/SVGImageContext-cpp.patch index e14b964cd..4e8258689 100644 --- a/src/layout/svg/SVGImageContext-cpp.patch +++ b/src/layout/svg/SVGImageContext-cpp.patch @@ -1,8 +1,45 @@ diff --git a/layout/svg/SVGImageContext.cpp b/layout/svg/SVGImageContext.cpp -index ecbda963b75fb70b62885a0c8f7a517011a8d5dc..1200a51aee7db4ee1a014308581ada1002c0d05f 100644 +index ecbda963b75fb70b62885a0c8f7a517011a8d5dc..5f55f0a4174db830656d434b5295835ab18e6619 100644 --- a/layout/svg/SVGImageContext.cpp +++ b/layout/svg/SVGImageContext.cpp -@@ -57,12 +57,14 @@ void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext, +@@ -10,6 +10,7 @@ + #include "mozilla/LookAndFeel.h" + #include "mozilla/ServoCSSParser.h" + #include "mozilla/StaticPrefs_svg.h" ++#include "mozilla/dom/BrowsingContext.h" + #include "mozilla/dom/Document.h" + #include "nsIFrame.h" + #include "nsISVGPaintContext.h" +@@ -18,6 +19,19 @@ + + namespace mozilla { + ++/* static */ ++void SVGImageContext::MaybeStoreZenBoosts(SVGImageContext& aContext, ++ const nsPresContext& aPresContext) { ++ if (dom::Document* doc = aPresContext.Document()) { ++ if (dom::BrowsingContext* bc = doc->GetBrowsingContext()) { ++ bc = bc->Top(); ++ aContext.SetZenBoosts(bc->ZenBoostsData(), ++ bc->ZenBoostsComplementaryRotation(), ++ bc->IsZenBoostsInverted()); ++ } ++ } ++} ++ + /* static */ + void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext, + nsIFrame* aFromFrame, +@@ -43,6 +57,8 @@ void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext, + aContext.SetColorScheme(Some(scheme)); + } + ++ MaybeStoreZenBoosts(aContext, aPresContext); ++ + const nsStyleSVG* style = aStyle.StyleSVG(); + if (!style->ExposesContextProperties()) { + // Content must have '-moz-context-properties' set to the names of the +@@ -57,12 +73,14 @@ void SVGImageContext::MaybeStoreContextPaint(SVGImageContext& aContext, if ((style->mMozContextProperties.bits & StyleContextPropertyBits::FILL) && style->mFill.kind.IsColor()) { haveContextPaint = true; diff --git a/src/layout/svg/SVGImageContext-h.patch b/src/layout/svg/SVGImageContext-h.patch new file mode 100644 index 000000000..c0cff0a5d --- /dev/null +++ b/src/layout/svg/SVGImageContext-h.patch @@ -0,0 +1,80 @@ +diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h +index 159d9cbbd0711076ee6c2a71a3da04bd92a0102c..daefc40590c4d7d7fac9db25c6ec4ba2424dded5 100644 +--- a/layout/svg/SVGImageContext.h ++++ b/layout/svg/SVGImageContext.h +@@ -6,6 +6,7 @@ + #define LAYOUT_SVG_SVGIMAGECONTEXT_H_ + + #include "Units.h" ++#include "nsColor.h" + #include "mozilla/Maybe.h" + #include "mozilla/SVGContextPaint.h" + #include "mozilla/SVGPreserveAspectRatio.h" +@@ -63,6 +64,11 @@ class SVGImageContext { + nsISVGPaintContext* aPaintContext, + imgIContainer* aImgContainer); + ++ // Carry the host document's Zen boost into the image context so the image ++ // renders with the same accent/inversion as the page. ++ static void MaybeStoreZenBoosts(SVGImageContext& aContext, ++ const nsPresContext& aPresContext); ++ + const Maybe& GetViewportSize() const { return mViewportSize; } + + void SetViewportSize(const Maybe& aSize) { +@@ -75,6 +81,21 @@ class SVGImageContext { + mColorScheme = aScheme; + } + ++ // Zen boosts state carried from the host document so the image renders with ++ // the same boost. Part of the cache key below so boosted and unboosted ++ // renderings don't collide. ++ void SetZenBoosts(nscolor aAccent, float aComplementaryRotation, ++ bool aInverted) { ++ mZenBoostsAccent = aAccent; ++ mZenBoostsComplementaryRotation = aComplementaryRotation; ++ mZenBoostsInverted = aInverted; ++ } ++ nscolor GetZenBoostsAccent() const { return mZenBoostsAccent; } ++ float GetZenBoostsComplementaryRotation() const { ++ return mZenBoostsComplementaryRotation; ++ } ++ bool GetZenBoostsInverted() const { return mZenBoostsInverted; } ++ + const Maybe& GetPreserveAspectRatio() const { + return mPreserveAspectRatio; + } +@@ -107,7 +128,11 @@ class SVGImageContext { + + return contextPaintIsEqual && mViewportSize == aOther.mViewportSize && + mPreserveAspectRatio == aOther.mPreserveAspectRatio && +- mColorScheme == aOther.mColorScheme; ++ mColorScheme == aOther.mColorScheme && ++ mZenBoostsAccent == aOther.mZenBoostsAccent && ++ mZenBoostsComplementaryRotation == ++ aOther.mZenBoostsComplementaryRotation && ++ mZenBoostsInverted == aOther.mZenBoostsInverted; + } + + bool operator!=(const SVGImageContext&) const = default; +@@ -119,7 +144,9 @@ class SVGImageContext { + } + return HashGeneric(hash, mViewportSize.map(HashSize).valueOr(0), + mPreserveAspectRatio.map(HashPAR).valueOr(0), +- mColorScheme.map(HashColorScheme).valueOr(0)); ++ mColorScheme.map(HashColorScheme).valueOr(0), ++ mZenBoostsAccent, mZenBoostsComplementaryRotation, ++ mZenBoostsInverted); + } + + private: +@@ -138,6 +165,9 @@ class SVGImageContext { + Maybe mViewportSize; + Maybe mPreserveAspectRatio; + Maybe mColorScheme; ++ nscolor mZenBoostsAccent = 0; ++ float mZenBoostsComplementaryRotation = 0.0f; ++ bool mZenBoostsInverted = false; + }; + + } // namespace mozilla diff --git a/src/widget/Theme-cpp.patch b/src/widget/Theme-cpp.patch new file mode 100644 index 000000000..1b88b2c75 --- /dev/null +++ b/src/widget/Theme-cpp.patch @@ -0,0 +1,56 @@ +diff --git a/widget/Theme.cpp b/widget/Theme.cpp +index 766a8ca4bc6fcc98f719ad4f472b20bc1d198ac9..be4419cfafb55e5cac8f5de741185ee3cabc4722 100644 +--- a/widget/Theme.cpp ++++ b/widget/Theme.cpp +@@ -18,6 +18,7 @@ + #include "mozilla/RelativeLuminanceUtils.h" + #include "mozilla/ScrollContainerFrame.h" + #include "mozilla/StaticPrefs_widget.h" ++#include "mozilla/nsZenBoostsBackend.h" + #include "mozilla/webrender/WebRenderAPI.h" + #include "nsCSSColorUtils.h" + #include "nsCSSRendering.h" +@@ -670,10 +671,15 @@ template + void Theme::PaintTextField(PaintBackendData& aPaintData, + const LayoutDeviceRect& aRect, + const ElementState& aState, const Colors& aColors, +- DPIRatio aDpiRatio) { ++ DPIRatio aDpiRatio, const nsIFrame* aFrame) { + auto [backgroundColor, borderColor] = + ComputeTextfieldColors(aState, aColors, OutlineCoversBorder::Yes); + ++ // The default field background comes from a theme/system color rather than a ++ // resolved style color, so apply Zen boosts here to match boosted content. ++ backgroundColor = sRGBColor::FromABGR(zen::nsZenBoostsBackend::ResolveStyleColor( ++ backgroundColor.ToABGR(), aFrame)); ++ + const CSSCoord radius = 2.0f; + + ThemeDrawing::PaintRoundedRectWithRadius(aPaintData, aRect, backgroundColor, +@@ -690,9 +696,9 @@ template + void Theme::PaintListbox(PaintBackendData& aPaintData, + const LayoutDeviceRect& aRect, + const ElementState& aState, const Colors& aColors, +- DPIRatio aDpiRatio) { ++ DPIRatio aDpiRatio, const nsIFrame* aFrame) { + // We happen to share style between text fields and list boxes. +- return PaintTextField(aPaintData, aRect, aState, aColors, aDpiRatio); ++ return PaintTextField(aPaintData, aRect, aState, aColors, aDpiRatio, aFrame); + } + + template +@@ -1158,10 +1164,12 @@ bool Theme::DoDrawWidgetBackground(PaintBackendData& aPaintData, + case StyleAppearance::Textfield: + case StyleAppearance::NumberInput: + case StyleAppearance::PasswordInput: +- PaintTextField(aPaintData, devPxRect, elementState, colors, dpiRatio); ++ PaintTextField(aPaintData, devPxRect, elementState, colors, dpiRatio, ++ aFrame); + break; + case StyleAppearance::Listbox: +- PaintListbox(aPaintData, devPxRect, elementState, colors, dpiRatio); ++ PaintListbox(aPaintData, devPxRect, elementState, colors, dpiRatio, ++ aFrame); + break; + case StyleAppearance::Menulist: + PaintMenulist(aPaintData, devPxRect, elementState, colors, dpiRatio); diff --git a/src/widget/Theme-h.patch b/src/widget/Theme-h.patch new file mode 100644 index 000000000..e7aad5d42 --- /dev/null +++ b/src/widget/Theme-h.patch @@ -0,0 +1,19 @@ +diff --git a/widget/Theme.h b/widget/Theme.h +index 4e0acbb25b9e39b712a2d96d8dee366dfdce4a01..9aa377ca9f0d7f96d938339d198b797ceebbc602 100644 +--- a/widget/Theme.h ++++ b/widget/Theme.h +@@ -161,10 +161,12 @@ class Theme : protected nsNativeTheme, public nsITheme { + const ElementState&, DPIRatio); + template + void PaintTextField(PaintBackendData&, const LayoutDeviceRect&, +- const ElementState&, const Colors&, DPIRatio); ++ const ElementState&, const Colors&, DPIRatio, ++ const nsIFrame*); + template + void PaintListbox(PaintBackendData&, const LayoutDeviceRect&, +- const ElementState&, const Colors&, DPIRatio); ++ const ElementState&, const Colors&, DPIRatio, ++ const nsIFrame*); + template + void PaintMenulist(PaintBackendData&, const LayoutDeviceRect&, + const ElementState&, const Colors&, DPIRatio); diff --git a/src/zen/boosts/nsZenBoostsBackend.cpp b/src/zen/boosts/nsZenBoostsBackend.cpp index f9eaf6461..6a64cd724 100644 --- a/src/zen/boosts/nsZenBoostsBackend.cpp +++ b/src/zen/boosts/nsZenBoostsBackend.cpp @@ -386,8 +386,9 @@ inline static nscolor zenInvertColorChannel(nscolor aColor) { * not touch (devtools highlighters, screenshots, the boosts overlays * themselves, and other native-anonymous UI such as scrollbars). A null frame * gives no document to anchor the boost on, so it is treated the same way. - * CSS generated content (::before/::after/::marker/::backdrop) is - * native-anonymous too but is author content, so it is not exempt. + * Author-facing content that happens to be native-anonymous is not exempt: + * UA-widget form-control internals (including the text the user types into an + * input), and pseudo-elements such as ::before/::after/::marker/::placeholder. */ ZEN_HOT_FUNCTION inline static bool IsBoostExemptFrame(const nsIFrame* aFrame) { @@ -398,21 +399,17 @@ inline static bool IsBoostExemptFrame(const nsIFrame* aFrame) { if (!content || !content->IsInNativeAnonymousSubtree()) { return false; } - if (const nsIContent* root = - content->GetClosestNativeAnonymousSubtreeRoot()) { - if (root->IsElement()) { - switch (root->AsElement()->GetPseudoElementType()) { - case mozilla::PseudoStyleType::Before: - case mozilla::PseudoStyleType::After: - case mozilla::PseudoStyleType::Marker: - case mozilla::PseudoStyleType::Backdrop: - return false; - default: - break; - } - } + // Form-control internals (and media controls) live in UA-widget shadow + // trees; the text typed into an input is author content and should be + // boosted. Classic native-anonymous UI (scrollbars, devtools) has no + // containing shadow and falls through to the pseudo-element check below. + if (content->GetContainingShadow()) { + return false; } - return true; + const nsIContent* root = content->GetClosestNativeAnonymousSubtreeRoot(); + return !root || !root->IsElement() || + !mozilla::PseudoStyle::IsPseudoElement( + root->AsElement()->GetPseudoElementType()); } /** @@ -429,6 +426,15 @@ inline static void GetZenBoostsDataForFrame(const nsIFrame* aFrame, if (!presContext) { return; } + // SVG images render in their own document with no BrowsingContext; the host + // propagates its boost onto the image document's PresContext instead. + if (presContext->HasZenBoostsOverride()) { + *aData = presContext->ZenBoostsOverrideAccent(); + *aComplementaryRotation = + presContext->ZenBoostsOverrideComplementaryRotation(); + *aIsInverted = presContext->ZenBoostsOverrideInverted(); + return; + } const mozilla::dom::BrowsingContext* browsingContext = nullptr; if (auto document = presContext->Document()) { browsingContext = document->GetBrowsingContext();