forked from mirrors/gecko-dev
Bug 1862061 - Remove -moz-font-smoothing-background-color. r=gfx-reviewers,desktop-theme-reviewers,devtools-reviewers,dao,gw
See comments in the bug for reasoning. macOS hasn't used subpixel AA for quite a while. Emulating this macOS AA on vibrant backgrounds was the only point of this feature. This allows to simplify the WebRender code quite a bit, too. Differential Revision: https://phabricator.services.mozilla.com/D192311
This commit is contained in:
parent
df77520266
commit
c25b3b246f
42 changed files with 49 additions and 733 deletions
|
|
@ -280,7 +280,6 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
|||
"color",
|
||||
"column-rule-color",
|
||||
"flood-color",
|
||||
"-moz-font-smoothing-background-color",
|
||||
"lighting-color",
|
||||
"outline-color",
|
||||
"scrollbar-color",
|
||||
|
|
|
|||
|
|
@ -2078,7 +2078,6 @@ class GFX2D_API Factory {
|
|||
#ifdef XP_DARWIN
|
||||
static already_AddRefed<ScaledFont> CreateScaledFontForMacFont(
|
||||
CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor,
|
||||
bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
|
||||
bool aHasColorGlyphs = false);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -594,11 +594,10 @@ already_AddRefed<UnscaledFont> Factory::CreateUnscaledFontFromFontDescriptor(
|
|||
#ifdef XP_DARWIN
|
||||
already_AddRefed<ScaledFont> Factory::CreateScaledFontForMacFont(
|
||||
CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor, bool aUseFontSmoothing,
|
||||
bool aApplySyntheticBold, bool aHasColorGlyphs) {
|
||||
return MakeAndAddRef<ScaledFontMac>(
|
||||
aCGFont, aUnscaledFont, aSize, false, aFontSmoothingBackgroundColor,
|
||||
aUseFontSmoothing, aApplySyntheticBold, aHasColorGlyphs);
|
||||
bool aUseFontSmoothing, bool aApplySyntheticBold, bool aHasColorGlyphs) {
|
||||
return MakeAndAddRef<ScaledFontMac>(aCGFont, aUnscaledFont, aSize, false,
|
||||
aUseFontSmoothing, aApplySyntheticBold,
|
||||
aHasColorGlyphs);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -499,7 +499,6 @@ bool ScaledFontDWrite::GetWRFontInstanceOptions(
|
|||
if (Factory::GetBGRSubpixelOrder()) {
|
||||
options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
|
||||
}
|
||||
options.bg_color = wr::ToColorU(DeviceColor());
|
||||
options.synthetic_italics =
|
||||
wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
|
||||
|
||||
|
|
|
|||
|
|
@ -402,7 +402,6 @@ bool ScaledFontFontconfig::GetWRFontInstanceOptions(
|
|||
if (UseSubpixelPosition()) {
|
||||
options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
|
||||
}
|
||||
options.bg_color = wr::ToColorU(DeviceColor());
|
||||
options.synthetic_italics =
|
||||
wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ bool ScaledFontFreeType::GetWRFontInstanceOptions(
|
|||
options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
|
||||
}
|
||||
options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
|
||||
options.bg_color = wr::ToColorU(DeviceColor());
|
||||
options.synthetic_italics =
|
||||
wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
|
||||
|
||||
|
|
|
|||
|
|
@ -125,12 +125,10 @@ CTFontRef CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize,
|
|||
ScaledFontMac::ScaledFontMac(CGFontRef aFont,
|
||||
const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
Float aSize, bool aOwnsFont,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor,
|
||||
bool aUseFontSmoothing, bool aApplySyntheticBold,
|
||||
bool aHasColorGlyphs)
|
||||
: ScaledFontBase(aUnscaledFont, aSize),
|
||||
mFont(aFont),
|
||||
mFontSmoothingBackgroundColor(aFontSmoothingBackgroundColor),
|
||||
mUseFontSmoothing(aUseFontSmoothing),
|
||||
mApplySyntheticBold(aApplySyntheticBold),
|
||||
mHasColorGlyphs(aHasColorGlyphs) {
|
||||
|
|
@ -146,12 +144,10 @@ ScaledFontMac::ScaledFontMac(CGFontRef aFont,
|
|||
|
||||
ScaledFontMac::ScaledFontMac(CTFontRef aFont,
|
||||
const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor,
|
||||
bool aUseFontSmoothing, bool aApplySyntheticBold,
|
||||
bool aHasColorGlyphs)
|
||||
: ScaledFontBase(aUnscaledFont, CTFontGetSize(aFont)),
|
||||
mCTFont(aFont),
|
||||
mFontSmoothingBackgroundColor(aFontSmoothingBackgroundColor),
|
||||
mUseFontSmoothing(aUseFontSmoothing),
|
||||
mApplySyntheticBold(aApplySyntheticBold),
|
||||
mHasColorGlyphs(aHasColorGlyphs) {
|
||||
|
|
@ -457,7 +453,6 @@ bool ScaledFontMac::GetWRFontInstanceOptions(
|
|||
if (mHasColorGlyphs) {
|
||||
options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
|
||||
}
|
||||
options.bg_color = wr::ToColorU(mFontSmoothingBackgroundColor);
|
||||
options.synthetic_italics =
|
||||
wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
|
||||
*aOutOptions = Some(options);
|
||||
|
|
@ -480,11 +475,6 @@ ScaledFontMac::InstanceData::InstanceData(
|
|||
if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
|
||||
mHasColorGlyphs = true;
|
||||
}
|
||||
if (aOptions->bg_color.a != 0) {
|
||||
mFontSmoothingBackgroundColor =
|
||||
DeviceColor::FromU8(aOptions->bg_color.r, aOptions->bg_color.g,
|
||||
aOptions->bg_color.b, aOptions->bg_color.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -731,10 +721,9 @@ already_AddRefed<ScaledFont> UnscaledFontMac::CreateScaledFont(
|
|||
font = CTFontCreateWithFontDescriptor(fontDesc, aGlyphSize, nullptr);
|
||||
}
|
||||
}
|
||||
scaledFont = new ScaledFontMac(
|
||||
font, this, instanceData.mFontSmoothingBackgroundColor,
|
||||
instanceData.mUseFontSmoothing, instanceData.mApplySyntheticBold,
|
||||
instanceData.mHasColorGlyphs);
|
||||
scaledFont = new ScaledFontMac(font, this, instanceData.mUseFontSmoothing,
|
||||
instanceData.mApplySyntheticBold,
|
||||
instanceData.mHasColorGlyphs);
|
||||
} else {
|
||||
CGFontRef fontRef = mFont;
|
||||
if (aNumVariations > 0) {
|
||||
|
|
@ -746,7 +735,6 @@ already_AddRefed<ScaledFont> UnscaledFontMac::CreateScaledFont(
|
|||
}
|
||||
|
||||
scaledFont = new ScaledFontMac(fontRef, this, aGlyphSize, fontRef != mFont,
|
||||
instanceData.mFontSmoothingBackgroundColor,
|
||||
instanceData.mUseFontSmoothing,
|
||||
instanceData.mApplySyntheticBold,
|
||||
instanceData.mHasColorGlyphs);
|
||||
|
|
|
|||
|
|
@ -34,17 +34,13 @@ class UnscaledFontMac;
|
|||
class ScaledFontMac : public ScaledFontBase {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontMac, override)
|
||||
ScaledFontMac(
|
||||
CGFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
|
||||
bool aOwnsFont = false,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor = DeviceColor(),
|
||||
bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
|
||||
bool aHasColorGlyphs = false);
|
||||
ScaledFontMac(
|
||||
CTFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
const DeviceColor& aFontSmoothingBackgroundColor = DeviceColor(),
|
||||
bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
|
||||
bool aHasColorGlyphs = false);
|
||||
ScaledFontMac(CGFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
Float aSize, bool aOwnsFont = false,
|
||||
bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
|
||||
bool aHasColorGlyphs = false);
|
||||
ScaledFontMac(CTFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
|
||||
bool aHasColorGlyphs = false);
|
||||
~ScaledFontMac();
|
||||
|
||||
FontType GetType() const override { return FontType::MAC; }
|
||||
|
|
@ -66,10 +62,6 @@ class ScaledFontMac : public ScaledFontBase {
|
|||
|
||||
bool UseSubpixelPosition() const override { return true; }
|
||||
|
||||
DeviceColor FontSmoothingBackgroundColor() {
|
||||
return mFontSmoothingBackgroundColor;
|
||||
}
|
||||
|
||||
cairo_font_face_t* CreateCairoFontFace(
|
||||
cairo_font_options_t* aFontOptions) override;
|
||||
|
||||
|
|
@ -81,23 +73,19 @@ class ScaledFontMac : public ScaledFontBase {
|
|||
CTFontRef
|
||||
mCTFont; // only created if CTFontDrawGlyphs is available, otherwise null
|
||||
|
||||
DeviceColor mFontSmoothingBackgroundColor;
|
||||
bool mUseFontSmoothing;
|
||||
bool mApplySyntheticBold;
|
||||
bool mHasColorGlyphs;
|
||||
|
||||
struct InstanceData {
|
||||
explicit InstanceData(ScaledFontMac* aScaledFont)
|
||||
: mFontSmoothingBackgroundColor(
|
||||
aScaledFont->mFontSmoothingBackgroundColor),
|
||||
mUseFontSmoothing(aScaledFont->mUseFontSmoothing),
|
||||
: mUseFontSmoothing(aScaledFont->mUseFontSmoothing),
|
||||
mApplySyntheticBold(aScaledFont->mApplySyntheticBold),
|
||||
mHasColorGlyphs(aScaledFont->mHasColorGlyphs) {}
|
||||
|
||||
InstanceData(const wr::FontInstanceOptions* aOptions,
|
||||
const wr::FontInstancePlatformOptions* aPlatformOptions);
|
||||
|
||||
DeviceColor mFontSmoothingBackgroundColor;
|
||||
bool mUseFontSmoothing;
|
||||
bool mApplySyntheticBold;
|
||||
bool mHasColorGlyphs;
|
||||
|
|
|
|||
|
|
@ -58,8 +58,7 @@ nsFont::MaxDifference nsFont::CalcDifference(const nsFont& aOther) const {
|
|||
return MaxDifference::eLayoutAffecting;
|
||||
}
|
||||
|
||||
if ((smoothing != aOther.smoothing) ||
|
||||
(fontSmoothingBackgroundColor != aOther.fontSmoothingBackgroundColor)) {
|
||||
if (smoothing != aOther.smoothing) {
|
||||
return MaxDifference::eVisual;
|
||||
}
|
||||
|
||||
|
|
@ -267,8 +266,6 @@ void nsFont::AddFontFeaturesToStyle(gfxFontStyle* aStyle,
|
|||
if (smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
|
||||
aStyle->useGrayscaleAntialiasing = true;
|
||||
}
|
||||
|
||||
aStyle->fontSmoothingBackgroundColor = fontSmoothingBackgroundColor.ToColor();
|
||||
}
|
||||
|
||||
void nsFont::AddFontVariationsToStyle(gfxFontStyle* aStyle) const {
|
||||
|
|
|
|||
|
|
@ -41,12 +41,6 @@ struct nsFont final {
|
|||
mozilla::StyleFontSizeAdjust sizeAdjust =
|
||||
mozilla::StyleFontSizeAdjust::None();
|
||||
|
||||
// The estimated background color behind the text. Enables a special
|
||||
// rendering mode when the alpha component > 0. Only used for text in the
|
||||
// chrome.
|
||||
mozilla::StyleAbsoluteColor fontSmoothingBackgroundColor =
|
||||
mozilla::StyleAbsoluteColor::TRANSPARENT_BLACK;
|
||||
|
||||
// Language system tag, to override document language;
|
||||
// this is an OpenType "language system" tag represented as a 32-bit integer
|
||||
// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
|
||||
|
|
|
|||
|
|
@ -582,7 +582,6 @@ class gfxContext final {
|
|||
mozilla::gfx::AntialiasMode aaMode;
|
||||
bool patternTransformChanged;
|
||||
Matrix patternTransform;
|
||||
DeviceColor fontSmoothingBackgroundColor;
|
||||
// This is used solely for using minimal intermediate surface size.
|
||||
Point deviceOffset;
|
||||
#ifdef DEBUG
|
||||
|
|
|
|||
|
|
@ -4583,7 +4583,6 @@ gfxFontStyle::gfxFontStyle()
|
|||
sizeAdjust(0.0f),
|
||||
baselineOffset(0.0f),
|
||||
languageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
fontSmoothingBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
||||
weight(FontWeight::NORMAL),
|
||||
stretch(FontStretch::NORMAL),
|
||||
style(FontSlantStyle::NORMAL),
|
||||
|
|
@ -4610,7 +4609,6 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
|
|||
: size(aSize),
|
||||
baselineOffset(0.0f),
|
||||
languageOverride(aLanguageOverride),
|
||||
fontSmoothingBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
||||
weight(aWeight),
|
||||
stretch(aStretch),
|
||||
style(aStyle),
|
||||
|
|
|
|||
|
|
@ -147,10 +147,6 @@ struct gfxFontStyle {
|
|||
// in order to get correct glyph shapes.)
|
||||
uint32_t languageOverride;
|
||||
|
||||
// The estimated background color behind the text. Enables a special
|
||||
// rendering mode when NS_GET_A(.) > 0. Only used for text in the chrome.
|
||||
nscolor fontSmoothingBackgroundColor;
|
||||
|
||||
// The Font{Weight,Stretch,SlantStyle} fields are each a 16-bit type.
|
||||
|
||||
// The weight of the font: 100, 200, ... 900.
|
||||
|
|
@ -253,8 +249,7 @@ struct gfxFontStyle {
|
|||
(variationSettings == other.variationSettings) &&
|
||||
(languageOverride == other.languageOverride) &&
|
||||
mozilla::NumbersAreBitwiseIdentical(autoOpticalSize,
|
||||
other.autoOpticalSize) &&
|
||||
(fontSmoothingBackgroundColor == other.fontSmoothingBackgroundColor);
|
||||
other.autoOpticalSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ gfxMacFont::gfxMacFont(const RefPtr<UnscaledFontMac>& aUnscaledFont,
|
|||
: gfxFont(aUnscaledFont, aFontEntry, aFontStyle),
|
||||
mCGFont(nullptr),
|
||||
mCTFont(nullptr),
|
||||
mFontSmoothingBackgroundColor(aFontStyle->fontSmoothingBackgroundColor),
|
||||
mVariationFont(aFontEntry->HasVariations()) {
|
||||
mApplySyntheticBold = aFontStyle->NeedsSyntheticBold(aFontEntry);
|
||||
|
||||
|
|
@ -534,7 +533,6 @@ already_AddRefed<ScaledFont> gfxMacFont::GetScaledFont(
|
|||
bool hasColorGlyphs = fe->HasColorBitmapTable() || fe->TryGetColorGlyphs();
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForMacFont(
|
||||
GetCGFontRef(), GetUnscaledFont(), GetAdjustedSize(),
|
||||
ToDeviceColor(mFontSmoothingBackgroundColor),
|
||||
!mStyle.useGrayscaleAntialiasing, ApplySyntheticBold(), hasColorGlyphs);
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ class gfxMacFont final : public gfxFont {
|
|||
mozilla::UniquePtr<gfxFontShaper> mCoreTextShaper;
|
||||
|
||||
Metrics mMetrics;
|
||||
nscolor mFontSmoothingBackgroundColor;
|
||||
|
||||
bool mVariationFont; // true if font has OpenType variations
|
||||
};
|
||||
|
|
|
|||
|
|
@ -314,15 +314,6 @@ static inline wr::ColorF ToColorF(const gfx::DeviceColor& color) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static inline wr::ColorU ToColorU(const gfx::DeviceColor& color) {
|
||||
wr::ColorU c;
|
||||
c.r = uint8_t(color.r * 255.0f);
|
||||
c.g = uint8_t(color.g * 255.0f);
|
||||
c.b = uint8_t(color.b * 255.0f);
|
||||
c.a = uint8_t(color.a * 255.0f);
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline wr::LayoutPoint ToLayoutPoint(
|
||||
const mozilla::LayoutDevicePoint& point) {
|
||||
wr::LayoutPoint p;
|
||||
|
|
|
|||
|
|
@ -366,355 +366,3 @@ in order to fold the two passes into one:
|
|||
Instead of outputting the two different colors in two separate passes, we output them from the same pass,
|
||||
as two separate fragment shader outputs.
|
||||
Those outputs can then be treated as two different sources in the blend equation.
|
||||
|
||||
## Subpixel Text Rendering to Transparent Destinations with a Background Color Hint
|
||||
|
||||
### Motivation
|
||||
|
||||
As we've seen in the previous section, subpixel text drawing has the limitation that it only works on opaque destinations.
|
||||
|
||||
In other words, if you use the `subpixeltextblend` function to draw something to a transparent surface,
|
||||
and then composite that surface onto on opaque background,
|
||||
the result will generally be different from drawing the text directly onto the opaque background.
|
||||
|
||||
Let's express that inequality in code.
|
||||
|
||||
```
|
||||
- vec4 text_color
|
||||
- vec4 mask
|
||||
- vec4 transparency = vec4(0.0, 0.0, 0.0, 0.0)
|
||||
- vec4 background with background.a == 1.0
|
||||
|
||||
over(subpixeltextblend(text_color, mask, transparency), background).rgb
|
||||
is, in general, not equal to
|
||||
subpixeltextblend(text_color, mask, background).rgb
|
||||
```
|
||||
|
||||
However, one interesting observation is that if the background is black, the two *are* equal:
|
||||
|
||||
```
|
||||
vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
over(subpixeltextblend(text_color, mask, transparency), black).r
|
||||
= subpixeltextblend(text_color, mask, transparency).r +
|
||||
(1 - subpixeltextblend(text_color, mask, transparency).a) * black.r
|
||||
= subpixeltextblend(text_color, mask, transparency).r +
|
||||
(1 - subpixeltextblend(text_color, mask, transparency).a) * 0
|
||||
= subpixeltextblend(text_color, mask, transparency).r
|
||||
= text_color.r * mask.r + (1 - text_color.a * mask.r) * transparency.r
|
||||
= text_color.r * mask.r + (1 - text_color.a * mask.r) * 0
|
||||
= text_color.r * mask.r + (1 - text_color.a * mask.r) * black.r
|
||||
= subpixeltextblend(text_color, mask, black).r
|
||||
```
|
||||
|
||||
So it works out for black backgrounds. The further your *actual* background color gets away from black,
|
||||
the more incorrect your result will be.
|
||||
|
||||
If it works for black, is there a way to make it work for other colors?
|
||||
This is the motivating question for this third way of text blending:
|
||||
|
||||
We want to be able to specify an *estimated background color*, and have a blending function
|
||||
`vec4 subpixeltextblend_withbgcolor(vec4 text_color, vec4 mask, vec4 bg_color, vec4 dest)`,
|
||||
in such a way that the error we get by using an intermediate surface is somehow in relation
|
||||
to the error we made when estimating the background color. In particular, if we estimated
|
||||
the background color perfectly, we want the intermediate surface to go unnoticed.
|
||||
|
||||
Expressed as code:
|
||||
|
||||
```
|
||||
over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, transparency), bg_color)
|
||||
should always be equal to
|
||||
subpixeltextblend(text_color, mask, bg_color)
|
||||
```
|
||||
|
||||
This is one of three constraints we'd like `subpixeltextblend_withbgcolor` to satisfy.
|
||||
|
||||
The next constraint is the following: If `dest` is already opaque, `subpixeltextblend_withbgcolor`
|
||||
should have the same results as `subpixeltextblend`, and the background color hint should be ignored.
|
||||
|
||||
```
|
||||
If dest.a == 1.0,
|
||||
subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest)
|
||||
should always be equal to
|
||||
subpixeltextblend(text_color, mask, dest)
|
||||
```
|
||||
|
||||
And there's a third condition we'd like it to fulfill:
|
||||
In places where the mask is zero, the destination should be unaffected.
|
||||
|
||||
```
|
||||
subpixeltextblend_withbgcolor(text_color, transparency, bg_color, dest)
|
||||
should always be equal to
|
||||
dest
|
||||
```
|
||||
|
||||
### Use cases
|
||||
|
||||
The primary use case for such a blend method is text on top of vibrant areas of a window on macOS.
|
||||
|
||||
Vibrant backgrounds with behind-window blending are computed by the window server, and they are tinted
|
||||
in a color that's based on the chosen vibrancy type.
|
||||
|
||||
The window's rgba buffer is transparent in the vibrant areas. Window contents, even text, are drawn onto
|
||||
that transparent rgba buffer. Then the window server composites the window onto an opaque backdrop.
|
||||
So the results on the screen are computed as follows:
|
||||
|
||||
```glsl
|
||||
window_buffer_pixel = subpixeltextblend_withbgcolor(text_color, mask, bg_color, transparency);
|
||||
screen_pixel = over(window_buffer_pixel, window_backdrop);
|
||||
```
|
||||
|
||||
### Prior art
|
||||
|
||||
Apple has implemented such a method of text blending in CoreGraphics, specifically for rendering text onto vibrant backgrounds.
|
||||
It's hidden behind the private API `CGContextSetFontSmoothingBackgroundColor` and is called by AppKit internally before
|
||||
calling the `-[NSView drawRect:]` method of your `NSVisualEffectView`, with the appropriate font smoothing background color
|
||||
for the vibrancy type of that view.
|
||||
|
||||
I'm not aware of any public documentation of this way of text blending.
|
||||
It seems to be considered an implementation detail by Apple, and is probably hidden by default because it can be a footgun:
|
||||
If the font smoothing background color you specify is very different from the actual background that our surface is placed
|
||||
on top of, the text will look glitchy.
|
||||
|
||||
### Deriving the blending function from first principles
|
||||
|
||||
Before we dive into the math, let's repeat our goal once more.
|
||||
|
||||
We want to create a blending function of the form
|
||||
`vec4 subpixeltextblend_withbgcolor(vec4 text_color, vec4 mask, vec4 bg_color, vec4 dest)`
|
||||
(with `bg_color` being an opaque color)
|
||||
which satisfies the following three constraints:
|
||||
|
||||
```
|
||||
Constraint I:
|
||||
over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, transparency), bg_color)
|
||||
should always be equal to
|
||||
subpixeltextblend(text_color, mask, bg_color)
|
||||
|
||||
Constraint II:
|
||||
If dest.a == 1.0,
|
||||
subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest)
|
||||
should always be equal to
|
||||
subpixeltextblend(text_color, mask, dest)
|
||||
|
||||
Constraint II:
|
||||
subpixeltextblend_withbgcolor(text_color, transparency, bg_color, dest)
|
||||
should always be equal to
|
||||
dest
|
||||
```
|
||||
|
||||
Constraint I and constraint II are about what happens depending on the destination's alpha.
|
||||
In particular: If the destination is completely transparent, we should blend into the
|
||||
estimated background color, and if it's completely opaque, we should blend into the destination color.
|
||||
In fact, we really want to blend into `over(dest, bg_color)`: we want `bg_color` to be used
|
||||
as a backdrop *behind* the current destination. So let's combine constraints I and II into a new
|
||||
constraint IV:
|
||||
|
||||
```
|
||||
Constraint IV:
|
||||
over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest), bg_color)
|
||||
should always be equal to
|
||||
subpixeltextblend(text_color, mask, over(dest, bg_color))
|
||||
```
|
||||
|
||||
Let's look at just the left side of that equation and rejiggle it a bit:
|
||||
|
||||
```
|
||||
over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest), bg_color).r
|
||||
= subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).r +
|
||||
(1 - subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a) * bg_color.r
|
||||
|
||||
<=>
|
||||
|
||||
over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest), bg_color).r -
|
||||
(1 - subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a) * bg_color.r
|
||||
= subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).r
|
||||
```
|
||||
|
||||
Now insert the right side of constraint IV:
|
||||
|
||||
```
|
||||
subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).r
|
||||
= over(subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest), bg_color).r -
|
||||
(1 - subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a) * bg_color.r
|
||||
= subpixeltextblend(text_color, mask, over(dest, bg_color)).r -
|
||||
(1 - subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a) * bg_color.r
|
||||
```
|
||||
|
||||
Our blend function is almost finished. We just need select an alpha for our result.
|
||||
Constraints I, II and IV don't really care about the alpha value. But constraint III requires that:
|
||||
|
||||
```
|
||||
subpixeltextblend_withbgcolor(text_color, transparency, bg_color, dest).a
|
||||
should always be equal to
|
||||
dest.a
|
||||
```
|
||||
|
||||
so the computation of the alpha value somehow needs to take into account the mask.
|
||||
|
||||
Let's say we have an unknown function `make_alpha(text_color.a, mask)` which returns
|
||||
a number between 0 and 1 and which is 0 if the mask is entirely zero, and let's defer
|
||||
the actual implementation of that function until later.
|
||||
|
||||
Now we can define the alpha of our overall function using the `over` function:
|
||||
|
||||
```
|
||||
subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a
|
||||
:= make_alpha(text_color.a, mask) + (1 - make_alpha(text_color.a, mask)) * dest.a
|
||||
```
|
||||
|
||||
We can plug this in to our previous result:
|
||||
|
||||
```
|
||||
subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).r
|
||||
= subpixeltextblend(text_color, mask, over(dest, bg_color)).r
|
||||
- (1 - subpixeltextblend_withbgcolor(text_color, mask, bg_color, dest).a) * bg_color.r
|
||||
= subpixeltextblend(text_color, mask, over(dest, bg_color)).r
|
||||
- (1 - (make_alpha(text_color.a, mask) +
|
||||
(1 - make_alpha(text_color.a, mask)) * dest.a)) * bg_color.r
|
||||
= text_color.r * mask.r + (1 - text_color.a * mask.r) * over(dest, bg_color).r
|
||||
- (1 - (make_alpha(text_color.a, mask)
|
||||
+ (1 - make_alpha(text_color.a, mask)) * dest.a)) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * (dest.r + (1 - dest.a) * bg_color.r)
|
||||
- (1 - (make_alpha(text_color.a, mask)
|
||||
+ (1 - make_alpha(text_color.a, mask)) * dest.a)) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * (dest.r + (1 - dest.a) * bg_color.r)
|
||||
- (1 - (make_alpha(text_color.a, mask)
|
||||
+ (1 - make_alpha(text_color.a, mask)) * dest.a)) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (dest.r + (1 - dest.a) * bg_color.r)
|
||||
- (text_color.a * mask.r) * (dest.r + (1 - dest.a) * bg_color.r)
|
||||
- (1 - make_alpha(text_color.a, mask)
|
||||
- (1 - make_alpha(text_color.a, mask)) * dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ dest.r + (1 - dest.a) * bg_color.r
|
||||
- text_color.a * mask.r * dest.r
|
||||
- text_color.a * mask.r * (1 - dest.a) * bg_color.r
|
||||
- (1 - make_alpha(text_color.a, mask)
|
||||
- (1 - make_alpha(text_color.a, mask)) * dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ dest.r + (1 - dest.a) * bg_color.r
|
||||
- text_color.a * mask.r * dest.r
|
||||
- text_color.a * mask.r * (1 - dest.a) * bg_color.r
|
||||
- ((1 - make_alpha(text_color.a, mask)) * 1
|
||||
- (1 - make_alpha(text_color.a, mask)) * dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ dest.r + (1 - dest.a) * bg_color.r
|
||||
- text_color.a * mask.r * dest.r
|
||||
- text_color.a * mask.r * (1 - dest.a) * bg_color.r
|
||||
- ((1 - make_alpha(text_color.a, mask)) * (1 - dest.a)) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ dest.r - text_color.a * mask.r * dest.r
|
||||
+ (1 - dest.a) * bg_color.r
|
||||
- text_color.a * mask.r * (1 - dest.a) * bg_color.r
|
||||
- (1 - make_alpha(text_color.a, mask)) * (1 - dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * dest.r
|
||||
+ (1 - dest.a) * bg_color.r
|
||||
- text_color.a * mask.r * (1 - dest.a) * bg_color.r
|
||||
- (1 - make_alpha(text_color.a, mask)) * (1 - dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * dest.r
|
||||
+ (1 - text_color.a * mask.r) * (1 - dest.a) * bg_color.r
|
||||
- (1 - make_alpha(text_color.a, mask)) * (1 - dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * dest.r
|
||||
+ ((1 - text_color.a * mask.r)
|
||||
- (1 - make_alpha(text_color.a, mask))) * (1 - dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * dest.r
|
||||
+ (1 - text_color.a * mask.r
|
||||
- 1 + make_alpha(text_color.a, mask)) * (1 - dest.a) * bg_color.r
|
||||
= text_color.r * mask.r
|
||||
+ (1 - text_color.a * mask.r) * dest.r
|
||||
+ (make_alpha(text_color.a, mask) - text_color.a * mask.r) * (1 - dest.a) * bg_color.r
|
||||
```
|
||||
|
||||
We now have a term of the form `A + B + C`, with `A` and `B` being guaranteed to
|
||||
be between zero and one.
|
||||
|
||||
We also want `C` to be between zero and one.
|
||||
We can use this restriction to help us decide on an implementation of `make_alpha`.
|
||||
|
||||
If we define `make_alpha` as
|
||||
|
||||
```glsl
|
||||
float make_alpha(text_color_a, mask) {
|
||||
float max_rgb = max(max(mask.r, mask.g), mask.b);
|
||||
return text_color_a * max_rgb;
|
||||
}
|
||||
```
|
||||
|
||||
, then `(make_alpha(text_color.a, mask) - text_color.a * mask.r)` becomes
|
||||
`(text_color.a * max(max(mask.r, mask.g), mask.b) - text_color.a * mask.r)`, which is
|
||||
`text_color.a * (max(max(mask.r, mask.g), mask.b) - mask.r)`, and the subtraction will
|
||||
always yield something that's greater or equal to zero for r, g, and b,
|
||||
because we will subtract each channel from the maximum of the channels.
|
||||
|
||||
Putting this all together, we have:
|
||||
|
||||
```glsl
|
||||
vec4 subpixeltextblend_withbgcolor(vec4 text_color, vec4 mask, vec4 bg_color, vec4 dest) {
|
||||
float max_rgb = max(max(mask.r, mask.g), mask.b);
|
||||
vec4 result;
|
||||
result.r = text_color.r * mask.r + (1 - text_color.a * mask.r) * dest.r +
|
||||
text_color.a * bg_color.r * (max_rgb - mask.r) * (1 - dest.a);
|
||||
result.g = text_color.g * mask.g + (1 - text_color.a * mask.g) * dest.g +
|
||||
text_color.a * bg_color.g * (max_rgb - mask.g) * (1 - dest.a);
|
||||
result.b = text_color.b * mask.b + (1 - text_color.a * mask.b) * dest.b +
|
||||
text_color.a * bg_color.b * (max_rgb - mask.b) * (1 - dest.a);
|
||||
result.a = text_color.a * max_rgb + (1 - text_color.a * max_rgb) * dest.a;
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
This is the final form of this blend function. It satisfies all of the four constraints.
|
||||
|
||||
### Implementing it with OpenGL
|
||||
|
||||
Our color channel equations consist of three pieces:
|
||||
|
||||
- `text_color.r * mask.r`, which simply gets added to the rest.
|
||||
- `(1 - text_color.a * mask.r) * dest.r`, a factor which gets multiplied with the destination color.
|
||||
- `text_color.a * bg_color.r * (max_rgb - mask.r) * (1 - dest.a)`, a factor which gets multiplied
|
||||
with "one minus destination alpha".
|
||||
|
||||
We will need three passes. Each pass modifies the color channels in the destination.
|
||||
This means that the part that uses `dest.r` needs to be applied first.
|
||||
Then we can apply the part that uses `1 - dest.a`.
|
||||
(This means that the first pass needs to leave `dest.a` untouched.)
|
||||
And the final pass can apply the `result.a` equation and modify `dest.a`.
|
||||
|
||||
```
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass0(&self) {
|
||||
self.gl.blend_func_separate(gl::ZERO, gl::ONE_MINUS_SRC_COLOR, gl::ZERO, gl::ONE);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass1(&self) {
|
||||
self.gl.blend_func_separate(gl::ONE_MINUS_DST_ALPHA, gl::ONE, gl::ZERO, gl::ONE);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass2(&self) {
|
||||
self.gl.blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
Pass0:
|
||||
oFragColor = vec4(text.color.a) * mask;
|
||||
Pass1:
|
||||
oFragColor = vec4(text.color.a) * text.bg_color * (vec4(mask.a) - mask);
|
||||
Pass2:
|
||||
oFragColor = text.color * mask;
|
||||
|
||||
result_after_pass0.r = 0 * (text_color.a * mask.r) + (1 - text_color.a * mask.r) * dest.r
|
||||
result_after_pass0.a = 0 * (text_color.a * mask.a) + 1 * dest.a
|
||||
|
||||
result_after_pass1.r = (1 - result_after_pass0.a) * (text_color.a * (mask.max_rgb - mask.r) * bg_color.r) + 1 * result_after_pass0.r
|
||||
result_after_pass1.a = 0 * (text_color.a * (mask.max_rgb - mask.a) * bg_color.a) + 1 * result_after_pass0.a
|
||||
|
||||
result_after_pass2.r = 1 * (text_color.r * mask.r) + 1 * result_after_pass1.r
|
||||
result_after_pass2.a = 1 * (text_color.a * mask.max_rgb) + (1 - text_color.a * mask.max_rgb) * result_after_pass1.a
|
||||
```
|
||||
|
||||
Instead of computing `max_rgb` in the shader, we can just require the font rasterization code to fill
|
||||
`mask.a` with the `max_rgb` value.
|
||||
|
||||
|
|
|
|||
|
|
@ -186,10 +186,6 @@ void brush_vs(
|
|||
int color_mode = prim_user_data.x & 0xffff;
|
||||
int blend_mode = prim_user_data.x >> 16;
|
||||
|
||||
if (color_mode == COLOR_MODE_FROM_PASS) {
|
||||
color_mode = uMode;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Derive the texture coordinates for this image, based on
|
||||
|
|
@ -289,20 +285,14 @@ void brush_vs(
|
|||
v_color = image_data.color;
|
||||
#endif
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS2:
|
||||
case COLOR_MODE_IMAGE:
|
||||
v_mask_swizzle = vec2(1.0, 0.0);
|
||||
v_color = image_data.color;
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS0:
|
||||
case COLOR_MODE_COLOR_BITMAP:
|
||||
v_mask_swizzle = vec2(1.0, 0.0);
|
||||
v_color = vec4(image_data.color.a);
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS1:
|
||||
v_mask_swizzle = vec2(-1.0, 1.0);
|
||||
v_color = vec4(image_data.color.a) * image_data.background_color;
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_DUAL_SOURCE:
|
||||
v_mask_swizzle = vec2(image_data.color.a, 0.0);
|
||||
v_color = image_data.color;
|
||||
|
|
|
|||
|
|
@ -25,16 +25,12 @@ varying highp vec2 vClipMaskUv;
|
|||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
#define COLOR_MODE_FROM_PASS 0
|
||||
#define COLOR_MODE_ALPHA 1
|
||||
#define COLOR_MODE_SUBPX_BG_PASS0 2
|
||||
#define COLOR_MODE_SUBPX_BG_PASS1 3
|
||||
#define COLOR_MODE_SUBPX_BG_PASS2 4
|
||||
#define COLOR_MODE_SUBPX_DUAL_SOURCE 5
|
||||
#define COLOR_MODE_BITMAP_SHADOW 6
|
||||
#define COLOR_MODE_COLOR_BITMAP 7
|
||||
#define COLOR_MODE_IMAGE 8
|
||||
#define COLOR_MODE_MULTIPLY_DUAL_SOURCE 9
|
||||
#define COLOR_MODE_ALPHA 0
|
||||
#define COLOR_MODE_SUBPX_DUAL_SOURCE 1
|
||||
#define COLOR_MODE_BITMAP_SHADOW 2
|
||||
#define COLOR_MODE_COLOR_BITMAP 3
|
||||
#define COLOR_MODE_IMAGE 4
|
||||
#define COLOR_MODE_MULTIPLY_DUAL_SOURCE 5
|
||||
|
||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sPrimitiveHeadersF;
|
||||
uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ varying highp vec4 v_uv_clip;
|
|||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
#define VECS_PER_TEXT_RUN 2
|
||||
#define VECS_PER_TEXT_RUN 1
|
||||
#define GLYPHS_PER_GPU_BLOCK 2U
|
||||
|
||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||
|
|
@ -66,12 +66,11 @@ GlyphResource fetch_glyph_resource(int address) {
|
|||
|
||||
struct TextRun {
|
||||
vec4 color;
|
||||
vec4 bg_color;
|
||||
};
|
||||
|
||||
TextRun fetch_text_run(int address) {
|
||||
vec4 data[2] = fetch_from_gpu_cache_2(address);
|
||||
return TextRun(data[0], data[1]);
|
||||
vec4 data = fetch_from_gpu_cache_1(address);
|
||||
return TextRun(data);
|
||||
}
|
||||
|
||||
vec2 get_snap_bias(int subpx_dir) {
|
||||
|
|
@ -112,10 +111,6 @@ void main() {
|
|||
TextRun text = fetch_text_run(ph.specific_prim_address);
|
||||
vec2 text_offset = ph.local_rect.p1;
|
||||
|
||||
if (color_mode == COLOR_MODE_FROM_PASS) {
|
||||
color_mode = uMode;
|
||||
}
|
||||
|
||||
// Note that the unsnapped reference frame relative offset has already
|
||||
// been subtracted from the prim local rect origin during batching.
|
||||
// It was done this way to avoid pushing both the snapped and the
|
||||
|
|
@ -249,19 +244,10 @@ void main() {
|
|||
v_color = text.color;
|
||||
#endif
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS2:
|
||||
v_mask_swizzle = vec3(1.0, 0.0, 0.0);
|
||||
v_color = text.color;
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS0:
|
||||
case COLOR_MODE_COLOR_BITMAP:
|
||||
v_mask_swizzle = vec3(1.0, 0.0, 0.0);
|
||||
v_color = vec4(text.color.a);
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_BG_PASS1:
|
||||
v_mask_swizzle = vec3(-1.0, 1.0, 0.0);
|
||||
v_color = vec4(text.color.a) * text.bg_color;
|
||||
break;
|
||||
case COLOR_MODE_SUBPX_DUAL_SOURCE:
|
||||
#ifdef SWGL_BLEND
|
||||
swgl_blendSubpixelText(text.color);
|
||||
|
|
|
|||
|
|
@ -50,10 +50,6 @@ uniform bool u_mali_workaround_dummy;
|
|||
// Vertex shader attributes and uniforms
|
||||
//======================================================================================
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
// A generic uniform that shaders can optionally use to configure
|
||||
// an operation mode for this batch.
|
||||
uniform int uMode;
|
||||
|
||||
// Uniform inputs
|
||||
uniform mat4 uTransform; // Orthographic projection
|
||||
|
||||
|
|
|
|||
|
|
@ -347,21 +347,6 @@ impl AlphaBatchList {
|
|||
let mut selected_batch_index = None;
|
||||
|
||||
match key.blend_mode {
|
||||
BlendMode::SubpixelWithBgColor => {
|
||||
for (batch_index, batch) in self.batches.iter().enumerate().rev() {
|
||||
// Some subpixel batches are drawn in two passes. Because of this, we need
|
||||
// to check for overlaps with every batch (which is a bit different
|
||||
// than the normal batching below).
|
||||
if self.batch_rects[batch_index].intersects(z_bounding_rect) {
|
||||
break;
|
||||
}
|
||||
|
||||
if batch.key.is_compatible_with(&key) {
|
||||
selected_batch_index = Some(batch_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
BlendMode::Advanced(_) if self.break_advanced_blend_batches => {
|
||||
// don't try to find a batch
|
||||
}
|
||||
|
|
@ -711,7 +696,6 @@ impl AlphaBatchBuilder {
|
|||
BlendMode::Alpha |
|
||||
BlendMode::PremultipliedAlpha |
|
||||
BlendMode::PremultipliedDestOut |
|
||||
BlendMode::SubpixelWithBgColor |
|
||||
BlendMode::SubpixelDualSource |
|
||||
BlendMode::Advanced(_) |
|
||||
BlendMode::MultiplyDualSource |
|
||||
|
|
@ -1194,18 +1178,11 @@ impl BatchBuilder {
|
|||
let (blend_mode, color_mode) = match glyph_format {
|
||||
GlyphFormat::Subpixel |
|
||||
GlyphFormat::TransformedSubpixel => {
|
||||
if run.used_font.bg_color.a != 0 {
|
||||
(
|
||||
BlendMode::SubpixelWithBgColor,
|
||||
ShaderColorMode::FromRenderPassMode,
|
||||
)
|
||||
} else {
|
||||
debug_assert!(ctx.use_dual_source_blending);
|
||||
(
|
||||
BlendMode::SubpixelDualSource,
|
||||
ShaderColorMode::SubpixelDualSource,
|
||||
)
|
||||
}
|
||||
debug_assert!(ctx.use_dual_source_blending);
|
||||
(
|
||||
BlendMode::SubpixelDualSource,
|
||||
ShaderColorMode::SubpixelDualSource,
|
||||
)
|
||||
}
|
||||
GlyphFormat::Alpha |
|
||||
GlyphFormat::TransformedAlpha |
|
||||
|
|
|
|||
|
|
@ -549,7 +549,6 @@ impl Drop for Texture {
|
|||
pub struct Program {
|
||||
id: gl::GLuint,
|
||||
u_transform: gl::GLint,
|
||||
u_mode: gl::GLint,
|
||||
u_texture_size: gl::GLint,
|
||||
source_info: ProgramSourceInfo,
|
||||
is_initialized: bool,
|
||||
|
|
@ -1074,7 +1073,6 @@ pub struct Device {
|
|||
bound_vao: gl::GLuint,
|
||||
bound_read_fbo: (FBOId, DeviceIntPoint),
|
||||
bound_draw_fbo: FBOId,
|
||||
program_mode_id: UniformLocation,
|
||||
default_read_fbo: FBOId,
|
||||
default_draw_fbo: FBOId,
|
||||
|
||||
|
|
@ -1915,7 +1913,6 @@ impl Device {
|
|||
bound_vao: 0,
|
||||
bound_read_fbo: (FBOId(0), DeviceIntPoint::zero()),
|
||||
bound_draw_fbo: FBOId(0),
|
||||
program_mode_id: UniformLocation::INVALID,
|
||||
default_read_fbo: FBOId(0),
|
||||
default_draw_fbo: FBOId(0),
|
||||
|
||||
|
|
@ -2175,7 +2172,6 @@ impl Device {
|
|||
|
||||
// Shader state
|
||||
self.bound_program = 0;
|
||||
self.program_mode_id = UniformLocation::INVALID;
|
||||
self.gl.use_program(0);
|
||||
|
||||
// Reset common state
|
||||
|
|
@ -2532,7 +2528,6 @@ impl Device {
|
|||
// If we get here, the link succeeded, so get the uniforms.
|
||||
program.is_initialized = true;
|
||||
program.u_transform = self.gl.get_uniform_location(program.id, "uTransform");
|
||||
program.u_mode = self.gl.get_uniform_location(program.id, "uMode");
|
||||
program.u_texture_size = self.gl.get_uniform_location(program.id, "uTextureSize");
|
||||
|
||||
Ok(())
|
||||
|
|
@ -2553,7 +2548,6 @@ impl Device {
|
|||
self.gl.use_program(program.id);
|
||||
self.bound_program = program.id;
|
||||
self.bound_program_name = program.source_info.full_name_cstr.clone();
|
||||
self.program_mode_id = UniformLocation(program.u_mode);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
@ -3044,7 +3038,6 @@ impl Device {
|
|||
let program = Program {
|
||||
id: pid,
|
||||
u_transform: 0,
|
||||
u_mode: 0,
|
||||
u_texture_size: 0,
|
||||
source_info,
|
||||
is_initialized: false,
|
||||
|
|
@ -3104,14 +3097,6 @@ impl Device {
|
|||
.uniform_matrix_4fv(program.u_transform, false, &transform.to_array());
|
||||
}
|
||||
|
||||
pub fn switch_mode(&self, mode: i32) {
|
||||
debug_assert!(self.inside_frame);
|
||||
#[cfg(debug_assertions)]
|
||||
debug_assert!(self.shader_is_ready);
|
||||
|
||||
self.gl.uniform_1i(self.program_mode_id.0, mode);
|
||||
}
|
||||
|
||||
/// Sets the uTextureSize uniform. Most shaders do not require this to be called
|
||||
/// as they use the textureSize GLSL function instead.
|
||||
pub fn set_shader_texture_size(
|
||||
|
|
@ -3933,24 +3918,6 @@ impl Device {
|
|||
(gl::ONE, gl::ONE),
|
||||
);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass0(&mut self) {
|
||||
self.set_blend_factors(
|
||||
(gl::ZERO, gl::ONE_MINUS_SRC_COLOR),
|
||||
(gl::ZERO, gl::ONE),
|
||||
);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass1(&mut self) {
|
||||
self.set_blend_factors(
|
||||
(gl::ONE_MINUS_DST_ALPHA, gl::ONE),
|
||||
(gl::ZERO, gl::ONE),
|
||||
);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_with_bg_color_pass2(&mut self) {
|
||||
self.set_blend_factors(
|
||||
(gl::ONE, gl::ONE),
|
||||
(gl::ONE, gl::ONE_MINUS_SRC_ALPHA),
|
||||
);
|
||||
}
|
||||
pub fn set_blend_mode_subpixel_dual_source(&mut self) {
|
||||
self.set_blend_factors(
|
||||
(gl::ONE, gl::ONE_MINUS_SRC1_COLOR),
|
||||
|
|
|
|||
|
|
@ -109,9 +109,6 @@ impl TextRunTemplate {
|
|||
// corresponds to `fetch_glyph` in the shaders
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
|
||||
request.push(ColorF::from(self.font.color).premultiplied());
|
||||
// this is the only case where we need to provide plain color to GPU
|
||||
let bg_color = ColorF::from(self.font.bg_color);
|
||||
request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]);
|
||||
|
||||
let mut gpu_block = [0.0; 4];
|
||||
for (i, src) in self.glyphs.iter().enumerate() {
|
||||
|
|
@ -244,7 +241,7 @@ impl TextRunPrimitive {
|
|||
surface: &SurfaceInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
transform: &LayoutToWorldTransform,
|
||||
mut allow_subpixel: bool,
|
||||
allow_subpixel: bool,
|
||||
raster_space: RasterSpace,
|
||||
spatial_tree: &SpatialTree,
|
||||
) -> bool {
|
||||
|
|
@ -360,10 +357,6 @@ impl TextRunPrimitive {
|
|||
..specified_font.clone()
|
||||
};
|
||||
|
||||
// If we are using special estimated background subpixel blending, then
|
||||
// we can allow it regardless of what the surface says.
|
||||
allow_subpixel |= self.used_font.bg_color.a != 0;
|
||||
|
||||
// If using local space glyphs, we don't want subpixel AA.
|
||||
if !allow_subpixel || !use_subpixel_aa {
|
||||
self.used_font.disable_subpixel_aa();
|
||||
|
|
|
|||
|
|
@ -302,16 +302,12 @@ fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Op
|
|||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ShaderColorMode {
|
||||
FromRenderPassMode = 0,
|
||||
Alpha = 1,
|
||||
SubpixelWithBgColorPass0 = 2,
|
||||
SubpixelWithBgColorPass1 = 3,
|
||||
SubpixelWithBgColorPass2 = 4,
|
||||
SubpixelDualSource = 5,
|
||||
BitmapShadow = 6,
|
||||
ColorBitmap = 7,
|
||||
Image = 8,
|
||||
MultiplyDualSource = 9,
|
||||
Alpha = 0,
|
||||
SubpixelDualSource = 1,
|
||||
BitmapShadow = 2,
|
||||
ColorBitmap = 3,
|
||||
Image = 4,
|
||||
MultiplyDualSource = 5,
|
||||
}
|
||||
|
||||
impl From<GlyphFormat> for ShaderColorMode {
|
||||
|
|
@ -645,7 +641,6 @@ pub enum BlendMode {
|
|||
PremultipliedAlpha,
|
||||
PremultipliedDestOut,
|
||||
SubpixelDualSource,
|
||||
SubpixelWithBgColor,
|
||||
Advanced(MixBlendMode),
|
||||
MultiplyDualSource,
|
||||
Screen,
|
||||
|
|
@ -2837,23 +2832,6 @@ impl Renderer {
|
|||
BlendMode::SubpixelDualSource => {
|
||||
self.device.set_blend_mode_subpixel_dual_source();
|
||||
}
|
||||
BlendMode::SubpixelWithBgColor => {
|
||||
// Using the three pass "component alpha with font smoothing
|
||||
// background color" rendering technique:
|
||||
//
|
||||
// /webrender/doc/text-rendering.md
|
||||
//
|
||||
self.device.set_blend_mode_subpixel_with_bg_color_pass0();
|
||||
// need to make sure the shader is bound
|
||||
shader.bind(
|
||||
&mut self.device,
|
||||
projection,
|
||||
None,
|
||||
&mut self.renderer_errors,
|
||||
&mut self.profile,
|
||||
);
|
||||
self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
|
||||
}
|
||||
BlendMode::Advanced(mode) => {
|
||||
if self.enable_advanced_blend_barriers {
|
||||
self.device.gl().blend_barrier_khr();
|
||||
|
|
@ -2904,44 +2882,6 @@ impl Renderer {
|
|||
&batch.key.textures,
|
||||
stats
|
||||
);
|
||||
|
||||
if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
|
||||
self.set_blend_mode_subpixel_with_bg_color_pass1(framebuffer_kind);
|
||||
// re-binding the shader after the blend mode change
|
||||
shader.bind(
|
||||
&mut self.device,
|
||||
projection,
|
||||
None,
|
||||
&mut self.renderer_errors,
|
||||
&mut self.profile,
|
||||
);
|
||||
self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass1 as _);
|
||||
|
||||
// When drawing the 2nd and 3rd passes, we know that the VAO, textures etc
|
||||
// are all set up from the previous draw_instanced_batch call,
|
||||
// so just issue a draw call here to avoid re-uploading the
|
||||
// instances and re-binding textures etc.
|
||||
self.device
|
||||
.draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
|
||||
|
||||
self.set_blend_mode_subpixel_with_bg_color_pass2(framebuffer_kind);
|
||||
// re-binding the shader after the blend mode change
|
||||
shader.bind(
|
||||
&mut self.device,
|
||||
projection,
|
||||
None,
|
||||
&mut self.renderer_errors,
|
||||
&mut self.profile,
|
||||
);
|
||||
self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _);
|
||||
|
||||
self.device
|
||||
.draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
|
||||
}
|
||||
|
||||
if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
|
||||
prev_blend_mode = BlendMode::None;
|
||||
}
|
||||
}
|
||||
|
||||
self.set_blend(false, framebuffer_kind);
|
||||
|
|
@ -5454,24 +5394,6 @@ impl Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_blend_mode_subpixel_with_bg_color_pass1(&mut self, framebuffer_kind: FramebufferKind) {
|
||||
if framebuffer_kind == FramebufferKind::Main &&
|
||||
self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
|
||||
self.device.set_blend_mode_show_overdraw();
|
||||
} else {
|
||||
self.device.set_blend_mode_subpixel_with_bg_color_pass1();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_blend_mode_subpixel_with_bg_color_pass2(&mut self, framebuffer_kind: FramebufferKind) {
|
||||
if framebuffer_kind == FramebufferKind::Main &&
|
||||
self.debug_flags.contains(DebugFlags::SHOW_OVERDRAW) {
|
||||
self.device.set_blend_mode_show_overdraw();
|
||||
} else {
|
||||
self.device.set_blend_mode_subpixel_with_bg_color_pass2();
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the texture with a given color.
|
||||
fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
|
||||
self.device.bind_draw_target(DrawTarget::from_texture(
|
||||
|
|
|
|||
|
|
@ -438,7 +438,6 @@ impl BrushShader {
|
|||
BlendMode::Alpha |
|
||||
BlendMode::PremultipliedAlpha |
|
||||
BlendMode::PremultipliedDestOut |
|
||||
BlendMode::SubpixelWithBgColor |
|
||||
BlendMode::Screen |
|
||||
BlendMode::PlusLighter |
|
||||
BlendMode::Exclusion => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use std::sync::Arc;
|
|||
// local imports
|
||||
use crate::IdNamespace;
|
||||
use crate::channel::Sender;
|
||||
use crate::color::ColorU;
|
||||
use crate::units::LayoutPoint;
|
||||
|
||||
/// Hashable floating-point storage for font size.
|
||||
|
|
@ -289,10 +288,6 @@ impl Default for SyntheticItalics {
|
|||
pub struct FontInstanceOptions {
|
||||
pub render_mode: FontRenderMode,
|
||||
pub flags: FontInstanceFlags,
|
||||
/// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel,
|
||||
/// the text will be rendered with bg_color.r/g/b as an opaque estimated
|
||||
/// background color.
|
||||
pub bg_color: ColorU,
|
||||
pub synthetic_italics: SyntheticItalics,
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +296,6 @@ impl Default for FontInstanceOptions {
|
|||
FontInstanceOptions {
|
||||
render_mode: FontRenderMode::Subpixel,
|
||||
flags: Default::default(),
|
||||
bg_color: ColorU::new(0, 0, 0, 0),
|
||||
synthetic_italics: SyntheticItalics::disabled(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -827,7 +827,6 @@ impl FontInstanceMap {
|
|||
options: Some(FontInstanceOptions {
|
||||
render_mode: instance.render_mode,
|
||||
flags: instance.flags,
|
||||
bg_color: instance.bg_color,
|
||||
synthetic_italics: instance.synthetic_italics,
|
||||
}),
|
||||
platform_options: instance.platform_options,
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- text: "A"
|
||||
origin: 30 220
|
||||
size: 200
|
||||
color: black
|
||||
font: "FreeSans.ttf"
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# verify that drawing a text run on an off-screen surface with a
|
||||
# specified background color gives the same result as drawing a
|
||||
# subpixel text run directly on the background.
|
||||
---
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
transform-style: preserve-3d
|
||||
items:
|
||||
- text: "A"
|
||||
origin: 30 220
|
||||
size: 200
|
||||
color: black
|
||||
font: "FreeSans.ttf"
|
||||
bg-color: white
|
||||
|
|
@ -59,7 +59,6 @@ skip_on(android,device) == shadow-partial-glyph.yaml shadow-partial-glyph-ref.ya
|
|||
fuzzy(2,212) platform(linux) == shadow-transforms.yaml shadow-transforms.png
|
||||
fuzzy(2,370) platform(linux) == raster-space.yaml raster-space.png
|
||||
skip_on(android) skip_on(mac,>=10.14) != allow-subpixel.yaml allow-subpixel-ref.yaml # Android: we don't enable sub-px aa on this platform.
|
||||
skip_on(android,device) fuzzy-if(platform(swgl),1,1085) == bg-color.yaml bg-color-ref.yaml # Fails on Pixel2
|
||||
!= large-glyphs.yaml blank.yaml
|
||||
!= large-line-decoration.yaml blank.yaml
|
||||
skip_on(android,device) == snap-text-offset.yaml snap-text-offset-ref.yaml
|
||||
|
|
|
|||
|
|
@ -745,7 +745,6 @@ impl YamlFrameReader {
|
|||
&mut self,
|
||||
font_key: FontKey,
|
||||
size: f32,
|
||||
bg_color: Option<ColorU>,
|
||||
flags: FontInstanceFlags,
|
||||
synthetic_italics: SyntheticItalics,
|
||||
wrench: &mut Wrench,
|
||||
|
|
@ -753,14 +752,13 @@ impl YamlFrameReader {
|
|||
let font_render_mode = self.font_render_mode;
|
||||
|
||||
*self.font_instances
|
||||
.entry((font_key, size.into(), flags, bg_color, synthetic_italics))
|
||||
.entry((font_key, size.into(), flags, synthetic_italics))
|
||||
.or_insert_with(|| {
|
||||
wrench.add_font_instance(
|
||||
font_key,
|
||||
size,
|
||||
flags,
|
||||
font_render_mode,
|
||||
bg_color,
|
||||
synthetic_italics,
|
||||
)
|
||||
})
|
||||
|
|
@ -1350,7 +1348,6 @@ impl YamlFrameReader {
|
|||
) {
|
||||
let size = item["size"].as_pt_to_f32().unwrap_or(16.0);
|
||||
let color = item["color"].as_colorf().unwrap_or(ColorF::BLACK);
|
||||
let bg_color = item["bg-color"].as_colorf().map(|c| c.into());
|
||||
let synthetic_italics = if let Some(angle) = item["synthetic-italics"].as_f32() {
|
||||
SyntheticItalics::from_degrees(angle)
|
||||
} else if item["synthetic-italics"].as_bool().unwrap_or(false) {
|
||||
|
|
@ -1385,7 +1382,6 @@ impl YamlFrameReader {
|
|||
let font_key = self.get_or_create_font(desc, wrench);
|
||||
let font_instance_key = self.get_or_create_font_instance(font_key,
|
||||
size,
|
||||
bg_color,
|
||||
flags,
|
||||
synthetic_italics,
|
||||
wrench);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
/* These properties are not included in 'all'. */
|
||||
-moz-context-properties: initial;
|
||||
-moz-control-character-visibility: initial;
|
||||
-moz-font-smoothing-background-color: initial;
|
||||
-moz-min-font-size-ratio: initial;
|
||||
-moz-box-collapse: initial;
|
||||
|
||||
|
|
|
|||
|
|
@ -98,17 +98,16 @@ const char* gInaccessibleProperties[] = {
|
|||
"-moz-inert",
|
||||
"-moz-script-level", // parsed by UA sheets only
|
||||
"-moz-math-variant",
|
||||
"-moz-math-display", // parsed by UA sheets only
|
||||
"-moz-top-layer", // parsed by UA sheets only
|
||||
"-moz-min-font-size-ratio", // parsed by UA sheets only
|
||||
"-moz-box-collapse", // chrome-only internal properties
|
||||
"-moz-font-smoothing-background-color", // chrome-only internal properties
|
||||
"-moz-subtree-hidden-only-visually", // chrome-only internal properties
|
||||
"-moz-window-input-region-margin", // chrome-only internal properties
|
||||
"-moz-window-opacity", // chrome-only internal properties
|
||||
"-moz-window-transform", // chrome-only internal properties
|
||||
"-moz-window-transform-origin", // chrome-only internal properties
|
||||
"-moz-window-shadow", // chrome-only internal properties
|
||||
"-moz-math-display", // parsed by UA sheets only
|
||||
"-moz-top-layer", // parsed by UA sheets only
|
||||
"-moz-min-font-size-ratio", // parsed by UA sheets only
|
||||
"-moz-box-collapse", // chrome-only internal properties
|
||||
"-moz-subtree-hidden-only-visually", // chrome-only internal properties
|
||||
"-moz-window-input-region-margin", // chrome-only internal properties
|
||||
"-moz-window-opacity", // chrome-only internal properties
|
||||
"-moz-window-transform", // chrome-only internal properties
|
||||
"-moz-window-transform-origin", // chrome-only internal properties
|
||||
"-moz-window-shadow", // chrome-only internal properties
|
||||
};
|
||||
|
||||
inline int is_inaccessible(const char* aPropName) {
|
||||
|
|
|
|||
|
|
@ -13457,15 +13457,6 @@ if (false) {
|
|||
"2px",
|
||||
],
|
||||
};
|
||||
|
||||
gCSSProperties["-moz-font-smoothing-background-color"] = {
|
||||
// domProp: "MozFontSmoothingBackgroundColor",
|
||||
inherited: true,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: ["transparent"],
|
||||
other_values: ["green", "#fc3"],
|
||||
invalid_values: ["000000", "ff00ff"],
|
||||
};
|
||||
}
|
||||
|
||||
gCSSProperties["scrollbar-color"] = {
|
||||
|
|
|
|||
|
|
@ -493,18 +493,6 @@ ${helpers.single_keyword(
|
|||
affects="paint",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"-moz-font-smoothing-background-color",
|
||||
"color::MozFontSmoothingBackgroundColor",
|
||||
"computed::color::MozFontSmoothingBackgroundColor::TRANSPARENT_BLACK",
|
||||
engines="gecko",
|
||||
animation_value_type="none",
|
||||
gecko_ffi_name="mFont.fontSmoothingBackgroundColor",
|
||||
enabled_in="chrome",
|
||||
spec="None (Nonstandard internal property)",
|
||||
affects="paint",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"-moz-min-font-size-ratio",
|
||||
"Percentage",
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@ pub use crate::values::specified::color::{ColorScheme, ForcedColorAdjust, PrintC
|
|||
/// The computed value of the `color` property.
|
||||
pub type ColorPropertyValue = AbsoluteColor;
|
||||
|
||||
/// The computed value of `-moz-font-smoothing-background-color`.
|
||||
pub type MozFontSmoothingBackgroundColor = AbsoluteColor;
|
||||
|
||||
/// A computed value for `<color>`.
|
||||
pub type Color = GenericColor<Percentage>;
|
||||
|
||||
|
|
|
|||
|
|
@ -925,38 +925,6 @@ impl ToComputedValue for Color {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specified color value for `-moz-font-smoothing-background-color`.
|
||||
///
|
||||
/// This property does not support `currentcolor`. We could drop it at
|
||||
/// parse-time, but it's not exposed to the web so it doesn't really matter.
|
||||
///
|
||||
/// We resolve it to `transparent` instead.
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
pub struct MozFontSmoothingBackgroundColor(pub Color);
|
||||
|
||||
impl Parse for MozFontSmoothingBackgroundColor {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
Color::parse(context, input).map(MozFontSmoothingBackgroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for MozFontSmoothingBackgroundColor {
|
||||
type ComputedValue = AbsoluteColor;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
self.0
|
||||
.to_computed_value(context)
|
||||
.resolve_to_absolute(&AbsoluteColor::TRANSPARENT_BLACK)
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
MozFontSmoothingBackgroundColor(Color::from_absolute_color(*computed))
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecifiedValueInfo for Color {
|
||||
const SUPPORTED_TYPES: u8 = CssType::COLOR;
|
||||
|
||||
|
|
|
|||
|
|
@ -379,7 +379,6 @@ tooltip {
|
|||
tooltip {
|
||||
appearance: auto;
|
||||
-moz-default-appearance: tooltip;
|
||||
-moz-font-smoothing-background-color: -moz-mac-tooltip;
|
||||
|
||||
white-space: pre-wrap;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ menubar > menu[_moz-menuactive="true"] {
|
|||
menubar > menu[_moz-menuactive="true"][open="true"] {
|
||||
color: -moz-menuhovertext;
|
||||
background-color: -moz-menuhover;
|
||||
-moz-font-smoothing-background-color: -moz-mac-active-menuitem;
|
||||
}
|
||||
|
||||
/* Internal content */
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ menucaption {
|
|||
flex-shrink: 0;
|
||||
list-style-image: none;
|
||||
max-width: 42em;
|
||||
-moz-font-smoothing-background-color: -moz-mac-menuitem;
|
||||
|
||||
@media (-moz-platform: linux) {
|
||||
padding: 4px 6px;
|
||||
|
|
@ -110,13 +109,11 @@ menuitem {
|
|||
&:where([disabled="true"]) {
|
||||
color: var(--panel-disabled-color);
|
||||
text-shadow: none;
|
||||
-moz-font-smoothing-background-color: -moz-mac-menuitem;
|
||||
}
|
||||
|
||||
&:where([_moz-menuactive]:not([disabled="true"])) {
|
||||
color: -moz-menuhovertext;
|
||||
background-color: -moz-menuhover;
|
||||
-moz-font-smoothing-background-color: -moz-mac-active-menuitem;
|
||||
}
|
||||
|
||||
&:where([_moz-menuactive="true"][disabled="true"]) {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ panel {
|
|||
display: flex;
|
||||
box-sizing: border-box;
|
||||
|
||||
-moz-font-smoothing-background-color: var(--panel-background, -moz-mac-menupopup);
|
||||
padding: var(--panel-padding);
|
||||
color: var(--panel-color);
|
||||
background: var(--panel-background);
|
||||
|
|
|
|||
Loading…
Reference in a new issue