gh-13844: Part 3 - Fixed text inputs not being filtered through boosts (gh-13893)

This commit is contained in:
mr. m
2026-05-27 13:39:22 +02:00
committed by GitHub
parent 2fb59e2c82
commit 8a0a6cbede
8 changed files with 280 additions and 20 deletions

View File

@@ -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;

View File

@@ -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();

View File

@@ -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<imgIContainer> 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<ImageIntRegion> region;
const int32_t appUnitsPerDevPixel =
@@ -1076,7 +1078,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
if (mImage->IsGradient()) {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(

View File

@@ -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;

View File

@@ -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<CSSIntSize>& GetViewportSize() const { return mViewportSize; }
void SetViewportSize(const Maybe<CSSIntSize>& 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<SVGPreserveAspectRatio>& 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<CSSIntSize> mViewportSize;
Maybe<SVGPreserveAspectRatio> mPreserveAspectRatio;
Maybe<ColorScheme> mColorScheme;
+ nscolor mZenBoostsAccent = 0;
+ float mZenBoostsComplementaryRotation = 0.0f;
+ bool mZenBoostsInverted = false;
};
} // namespace mozilla

View File

@@ -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 <typename PaintBackendData>
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 <typename PaintBackendData>
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 <typename PaintBackendData>
@@ -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);

19
src/widget/Theme-h.patch Normal file
View File

@@ -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 <typename PaintBackendData>
void PaintTextField(PaintBackendData&, const LayoutDeviceRect&,
- const ElementState&, const Colors&, DPIRatio);
+ const ElementState&, const Colors&, DPIRatio,
+ const nsIFrame*);
template <typename PaintBackendData>
void PaintListbox(PaintBackendData&, const LayoutDeviceRect&,
- const ElementState&, const Colors&, DPIRatio);
+ const ElementState&, const Colors&, DPIRatio,
+ const nsIFrame*);
template <typename PaintBackendData>
void PaintMenulist(PaintBackendData&, const LayoutDeviceRect&,
const ElementState&, const Colors&, DPIRatio);

View File

@@ -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();