From 8888937e07213b7937fabcab8aae4b708bdb5bfe Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Sat, 22 Oct 2022 09:43:49 +0000 Subject: [PATCH] Bug 1461589 - Handle font-variant-emoji during font matching. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D147495 --- dom/canvas/CanvasRenderingContext2D.cpp | 23 +++++++------- gfx/src/nsFontMetrics.cpp | 4 +-- gfx/thebes/gfxPlatform.cpp | 10 ------ gfx/thebes/gfxPlatform.h | 10 ------ gfx/thebes/gfxTextRun.cpp | 41 +++++++++++++++++-------- gfx/thebes/gfxTextRun.h | 5 ++- 6 files changed, 46 insertions(+), 47 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 873133075ecd..ba0c414d5d8b 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3526,15 +3526,16 @@ bool CanvasRenderingContext2D::SetFontInternalDisconnected( // TODO: For workers, should we be passing a language? Where from? // TODO: Cache fontGroups in the Worker (use an nsFontCache?) - gfxFontGroup* fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( - nullptr, // aPresContext - list, // aFontFamilyList - &fontStyle, // aStyle - language, // aLanguage - explicitLanguage, // aExplicitLanguage - nullptr, // aTextPerf - fontFaceSetImpl, // aUserFontSet - 1.0); // aDevToCssSize + gfxFontGroup* fontGroup = + new gfxFontGroup(nullptr, // aPresContext + list, // aFontFamilyList + &fontStyle, // aStyle + language, // aLanguage + explicitLanguage, // aExplicitLanguage + nullptr, // aTextPerf + fontFaceSetImpl, // aUserFontSet + 1.0, // aDevToCssSize + StyleFontVariantEmoji::Normal); CurrentState().fontGroup = fontGroup; SerializeFontForCanvas(list, fontStyle, CurrentState().font); CurrentState().fontFont = nsFont(StyleFontFamily{list, false, false}, @@ -4327,10 +4328,10 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() { gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel); const auto* sans = Servo_FontFamily_Generic(StyleGenericFontFamily::SansSerif); - fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( + fontGroup = new gfxFontGroup( presContext, sans->families, &style, language, explicitLanguage, presContext ? presContext->GetTextPerfMetrics() : nullptr, nullptr, - devToCssSize); + devToCssSize, StyleFontVariantEmoji::Normal); if (fontGroup) { CurrentState().font = kDefaultFontStyle; } else { diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 441ec05fe76f..6cbef769238b 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -138,9 +138,9 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams, aFont.AddFontVariationsToStyle(&style); gfxFloat devToCssSize = gfxFloat(mP2A) / gfxFloat(AppUnitsPerCSSPixel()); - mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( + mFontGroup = new gfxFontGroup( mPresContext, aFont.family.families, &style, mLanguage, mExplicitLanguage, - aParams.textPerf, aParams.userFontSet, devToCssSize); + aParams.textPerf, aParams.userFontSet, devToCssSize, aFont.variantEmoji); } nsFontMetrics::~nsFontMetrics() { diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index bd415ba6c212..89e7221dff51 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1846,16 +1846,6 @@ bool gfxPlatform::IsFontFormatSupported( return true; } -gfxFontGroup* gfxPlatform::CreateFontGroup( - nsPresContext* aPresContext, const StyleFontFamilyList& aFontFamilyList, - const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage, - gfxTextPerfMetrics* aTextPerf, gfxUserFontSet* aUserFontSet, - gfxFloat aDevToCssSize) const { - return new gfxFontGroup(aPresContext, aFontFamilyList, aStyle, aLanguage, - aExplicitLanguage, aTextPerf, aUserFontSet, - aDevToCssSize); -} - gfxFontEntry* gfxPlatform::LookupLocalFont(nsPresContext* aPresContext, const nsACString& aFontName, WeightRange aWeightForEntry, diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 9ed8ab94e231..ba06615cdb4d 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -398,16 +398,6 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { nsAutoCString GetDefaultFontName(const nsACString& aLangGroup, const nsACString& aGenericFamily); - /** - * Create a gfxFontGroup based on the given family list and style. - */ - gfxFontGroup* CreateFontGroup( - nsPresContext* aPresContext, - const mozilla::StyleFontFamilyList& aFontFamilyList, - const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage, - gfxTextPerfMetrics* aTextPerf, gfxUserFontSet* aUserFontSet, - gfxFloat aDevToCssSize) const; - /** * Look up a local platform font using the full font face name. * (Needed to support @font-face src local().) diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 5a01ee22ecf4..b6f691c099f1 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1884,7 +1884,8 @@ gfxFontGroup::gfxFontGroup(nsPresContext* aPresContext, const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, - gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) + gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize, + StyleFontVariantEmoji aVariantEmoji) : mPresContext(aPresContext), // Note that aPresContext may be null! mFamilyList(aFontFamilyList), mStyle(*aStyle), @@ -1899,6 +1900,17 @@ gfxFontGroup::gfxFontGroup(nsPresContext* aPresContext, mLastPrefFirstFont(false), mSkipDrawing(false), mExplicitLanguage(aExplicitLanguage) { + switch (aVariantEmoji) { + case StyleFontVariantEmoji::Normal: + case StyleFontVariantEmoji::Unicode: + break; + case StyleFontVariantEmoji::Text: + mEmojiPresentation = eFontPresentation::Text; + break; + case StyleFontVariantEmoji::Emoji: + mEmojiPresentation = eFontPresentation::EmojiExplicit; + break; + } // We don't use SetUserFontSet() here, as we want to unconditionally call // BuildFontList() rather than only do UpdateUserFonts() if it changed. mCurrGeneration = GetGeneration(); @@ -3100,24 +3112,27 @@ already_AddRefed gfxFontGroup::FindFontForChar( eFontPresentation presentation = eFontPresentation::Any; EmojiPresentation emojiPresentation = GetEmojiPresentation(aCh); if (emojiPresentation != TextOnly) { - // If the prefer-emoji selector is present, or if it's a default-emoji char - // and the prefer-text selector is NOT present, or if there's a skin-tone - // modifier, we specifically look for a font with a color glyph. - // If the prefer-text selector is present, we specifically look for a font - // that will provide a monochrome glyph. - // Otherwise, we'll accept either color or monochrome font-family entries, - // so that a color font can be explicitly applied via font-family even to - // characters that are not inherently emoji-style. + // Default presentation from the font-variant-emoji property. + presentation = mEmojiPresentation; + // If the prefer-emoji selector is present, or if it's a default-emoji + // char and the prefer-text selector is NOT present, or if there's a + // skin-tone modifier, we specifically look for a font with a color + // glyph. + // If the prefer-text selector is present, we specifically look for a + // font that will provide a monochrome glyph. + // Otherwise, we'll accept either color or monochrome font-family + // entries, so that a color font can be explicitly applied via font- + // family even to characters that are not inherently emoji-style. if (aNextCh == kVariationSelector16 || (aNextCh >= kEmojiSkinToneFirst && aNextCh <= kEmojiSkinToneLast)) { - // Emoji presentation is explicitly requested by a variation selector or - // the presence of a skin-tone codepoint. + // Emoji presentation is explicitly requested by a variation selector + // or the presence of a skin-tone codepoint. presentation = eFontPresentation::EmojiExplicit; } else if (emojiPresentation == EmojiPresentation::EmojiDefault && aNextCh != kVariationSelector15) { // Emoji presentation is the default for this Unicode character. but we - // will allow an explicitly-specified webfont to apply to it, regardless - // of its glyph type. + // will allow an explicitly-specified webfont to apply to it, + // regardless of its glyph type. presentation = eFontPresentation::EmojiDefault; } else if (aNextCh == kVariationSelector15) { // Text presentation is explicitly requested. diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index aafc422e58bb..b959688db692 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -936,7 +936,8 @@ class gfxFontGroup final : public gfxTextRunFactory { const mozilla::StyleFontFamilyList& aFontFamilyList, const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, - gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize); + gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize, + StyleFontVariantEmoji aVariantEmoji); virtual ~gfxFontGroup(); @@ -1420,6 +1421,8 @@ class gfxFontGroup final : public gfxTextRunFactory { bool mExplicitLanguage; // Does mLanguage come from an explicit attribute? + eFontPresentation mEmojiPresentation = eFontPresentation::Any; + // Generic font family used to select among font prefs during fallback. mozilla::StyleGenericFontFamily mFallbackGeneric = mozilla::StyleGenericFontFamily::None;