diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index ece32af1de4b..a6240702cad9 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -2348,6 +2348,12 @@ bool gfxFcPlatformFontList::FindAndAddFamiliesLocked( cacheKey.Append(':'); } + // Include the generic family in the cache key, to maintain the distinction + // between fonts explicitly requested by name and the results of resolving + // CSS generics. + cacheKey.AppendInt(int(aGeneric)); + cacheKey.Append(':'); + cacheKey.Append(familyName); auto vis = aPresContext ? aPresContext->GetFontVisibility() : FontVisibility::User; diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 702020350b2e..af89054e703f 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -123,6 +123,11 @@ inline bool PrefersColor(FontPresentation aPresentation) { return aPresentation >= FontPresentation::EmojiDefault; } +inline bool IsExplicitPresentation(FontPresentation aPresentation) { + return aPresentation == FontPresentation::TextExplicit || + aPresentation == FontPresentation::EmojiExplicit; +} + // when searching through pref langs, max number of pref langs const uint32_t kMaxLenPrefLangList = 32; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 434a399207f0..fd4c401e2ca9 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1856,18 +1856,8 @@ gfxFontGroup::gfxFontGroup(nsPresContext* aPresContext, mUserFontSet(aUserFontSet), mTextPerf(aTextPerf), mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aLanguage)), - mExplicitLanguage(aExplicitLanguage) { - switch (aVariantEmoji) { - case StyleFontVariantEmoji::Normal: - case StyleFontVariantEmoji::Unicode: - break; - case StyleFontVariantEmoji::Text: - mEmojiPresentation = FontPresentation::TextExplicit; - break; - case StyleFontVariantEmoji::Emoji: - mEmojiPresentation = FontPresentation::EmojiExplicit; - break; - } + mExplicitLanguage(aExplicitLanguage), + mFontVariantEmoji(aVariantEmoji) { // We don't use SetUserFontSet() here, as we want to unconditionally call // EnsureFontList() rather than only do UpdateUserFonts() if it changed. } @@ -3209,7 +3199,11 @@ already_AddRefed gfxFontGroup::FindFontForChar( if (EmojiPresentation emojiPresentation = GetEmojiPresentation(aCh); emojiPresentation != TextOnly) { // Default presentation from the font-variant-emoji property. - presentation = mEmojiPresentation; + if (mFontVariantEmoji == StyleFontVariantEmoji::Emoji) { + presentation = FontPresentation::EmojiExplicit; + } else if (mFontVariantEmoji == StyleFontVariantEmoji::Text) { + presentation = FontPresentation::TextExplicit; + } // If there wasn't an explicit font-variant-emoji setting, default to // what Unicode prefers for this character. if (presentation == FontPresentation::Any) { @@ -3225,8 +3219,7 @@ already_AddRefed gfxFontGroup::FindFontForChar( // glyph. // If the prefer-text selector is present, we specifically look for a // font that will provide a monochrome glyph. - if (aNextCh == kVariationSelector16 || - (aNextCh >= kEmojiSkinToneFirst && aNextCh <= kEmojiSkinToneLast) || + if (aNextCh == kVariationSelector16 || IsEmojiSkinToneModifier(aNextCh) || gfxFontUtils::IsEmojiFlagAndTag(aCh, aNextCh)) { // Emoji presentation is explicitly requested by a variation selector // or the presence of a skin-tone codepoint. @@ -3305,8 +3298,14 @@ already_AddRefed gfxFontGroup::FindFontForChar( // Handle a candidate font that could support the character, returning true // if we should go ahead and return |f|, false to continue searching. auto CheckCandidate = [&](gfxFont* f, FontMatchType t) -> bool { - // If no preference, then just accept the font. - if (presentation == FontPresentation::Any) { + // If no preference, or if it's an explicitly-named family in the fontgroup + // and font-variant-emoji is 'normal', then we accept the font. + if (presentation == FontPresentation::Any || + (!IsExplicitPresentation(presentation) && + t.kind == FontMatchType::Kind::kFontGroup && + t.generic == StyleGenericFontFamily::None && + mFontVariantEmoji == StyleFontVariantEmoji::Normal && + !gfxFontUtils::IsRegionalIndicator(aCh))) { *aMatchType = t; return true; } @@ -3447,21 +3446,6 @@ already_AddRefed gfxFontGroup::FindFontForChar( } } - // If it's an emoji codepoint and we found a named-family candidate (not a - // generic) in the font list, we accept it even if it doesn't match the - // presentation (so authors can deliberately request fonts that do not match - // the Unicode emoji default presentation style for a given character). But - // don't do this if a particular presentation was explicitly requested in the - // text, or for Regional Indicator chars (because of Segoe UI Emoji). - if (candidateFont && - candidateMatchType.generic == StyleGenericFontFamily::None && - presentation != FontPresentation::EmojiExplicit && - presentation != FontPresentation::TextExplicit && - !gfxFontUtils::IsRegionalIndicator(aCh)) { - *aMatchType = candidateMatchType; - return candidateFont.forget(); - } - if (fontListLength == 0) { RefPtr defaultFont = GetDefaultFont(); if (defaultFont->HasCharacter(aCh) || @@ -3612,19 +3596,26 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, const T* aString, // the font selected for an adjacent character, and does not need to // consider emoji vs text presentation. if ((font = GetFontAt(0, ch)) != nullptr && font->HasCharacter(ch) && - // In 8-bit text, the only time emoji presentation might be needed - // is if it is explicitly requested with font-variant, as no 8-bit - // chars are emoji by default. - ((sizeof(T) == sizeof(uint8_t) && - (mEmojiPresentation != FontPresentation::EmojiExplicit || - GetEmojiPresentation(ch) == TextOnly)) || - // For 16-bit text, we need to consider cluster extenders etc. - (sizeof(T) == sizeof(char16_t) && - (!IsClusterExtender(ch) && ch != NARROW_NO_BREAK_SPACE && - !gfxFontUtils::IsJoinControl(ch) && - !gfxFontUtils::IsJoinCauser(prevCh) && - !gfxFontUtils::IsVarSelector(ch) && - GetEmojiPresentation(ch) == TextOnly)))) { + ( + // In 8-bit text, we can unconditionally accept the first font if + // font-variant-emoji is 'normal', or if the character does not + // have the emoji property; there cannot be adjacent characters + // that would affect it. + (sizeof(T) == sizeof(uint8_t) && + (mFontVariantEmoji == StyleFontVariantEmoji::Normal || + GetEmojiPresentation(ch) == TextOnly)) || + // For 16-bit text, we need to consider cluster extenders etc. + (sizeof(T) == sizeof(char16_t) && + (!IsClusterExtender(ch) && ch != NARROW_NO_BREAK_SPACE && + !gfxFontUtils::IsJoinControl(ch) && + !gfxFontUtils::IsJoinCauser(prevCh) && + !gfxFontUtils::IsVarSelector(ch) && + (GetEmojiPresentation(ch) == TextOnly || + (!(IsEmojiPresentationSelector(nextCh) || + IsEmojiSkinToneModifier(nextCh) || + gfxFontUtils::IsEmojiFlagAndTag(ch, nextCh)) && + mFontVariantEmoji == StyleFontVariantEmoji::Normal && + mFonts[0].Generic() == StyleGenericFontFamily::None)))))) { matchType = {FontMatchType::Kind::kFontGroup, mFonts[0].Generic()}; } else { font = diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index dd9c2d74a3ea..6a2e35e068be 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -1399,7 +1399,7 @@ class gfxFontGroup final : public gfxTextRunFactory { bool mResolvedFonts = false; // Whether the mFonts array has been set up. - FontPresentation mEmojiPresentation = FontPresentation::Any; + StyleFontVariantEmoji mFontVariantEmoji = StyleFontVariantEmoji::Normal; // Generic font family used to select among font prefs during fallback. mozilla::StyleGenericFontFamily mFallbackGeneric = diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h index cafce5538185..1b25f7b5c2c2 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -56,10 +56,16 @@ enum EmojiPresentation { TextOnly = 0, TextDefault = 1, EmojiDefault = 2 }; const uint32_t kVariationSelector15 = 0xFE0E; // text presentation const uint32_t kVariationSelector16 = 0xFE0F; // emoji presentation +static inline bool IsEmojiPresentationSelector(uint32_t aCh) { + return aCh >= kVariationSelector15 && aCh <= kVariationSelector16; +} // Unicode values for EMOJI MODIFIER FITZPATRICK TYPE-* const uint32_t kEmojiSkinToneFirst = 0x1f3fb; const uint32_t kEmojiSkinToneLast = 0x1f3ff; +static inline bool IsEmojiSkinToneModifier(uint32_t aCh) { + return aCh >= kEmojiSkinToneFirst && aCh <= kEmojiSkinToneLast; +} extern const hb_unicode_general_category_t sICUtoHBcategory[]; diff --git a/layout/reftests/font-matching/1971148-digits-color-font-01-ref.html b/layout/reftests/font-matching/1971148-digits-color-font-01-ref.html new file mode 100644 index 000000000000..2faa16eb0048 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-01-ref.html @@ -0,0 +1,17 @@ + + + + +

Expect digits to be rendered from the emoji font:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-01.html b/layout/reftests/font-matching/1971148-digits-color-font-01.html new file mode 100644 index 000000000000..242f0029eb00 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-01.html @@ -0,0 +1,14 @@ + + + + +

Expect digits to be rendered from the emoji font:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-02.html b/layout/reftests/font-matching/1971148-digits-color-font-02.html new file mode 100644 index 000000000000..82bc3605572b --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-02.html @@ -0,0 +1,14 @@ + + + + +

Expect digits to be rendered from the emoji font:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-03-ref.html b/layout/reftests/font-matching/1971148-digits-color-font-03-ref.html new file mode 100644 index 000000000000..285e8d7f79ba --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-03-ref.html @@ -0,0 +1,18 @@ + + + + +

Expect digits to be rendered from Ahem:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-03.html b/layout/reftests/font-matching/1971148-digits-color-font-03.html new file mode 100644 index 000000000000..0a116de7eb3a --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-03.html @@ -0,0 +1,14 @@ + + + + +

Expect digits to be rendered from Ahem:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-04.html b/layout/reftests/font-matching/1971148-digits-color-font-04.html new file mode 100644 index 000000000000..66cb665ff45b --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-04.html @@ -0,0 +1,14 @@ + + + + +

Expect digits to be rendered from Ahem:

+
abc123xyz
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-05.html b/layout/reftests/font-matching/1971148-digits-color-font-05.html new file mode 100644 index 000000000000..7f91dc27f3b1 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-05.html @@ -0,0 +1,16 @@ + + + + + + +

Expect digits to be rendered from the emoji font:

+
abc123xyz​
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-06.html b/layout/reftests/font-matching/1971148-digits-color-font-06.html new file mode 100644 index 000000000000..b544f7dfdfd2 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-06.html @@ -0,0 +1,16 @@ + + + + + + +

Expect digits to be rendered from the emoji font:

+
abc123xyz​
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-07.html b/layout/reftests/font-matching/1971148-digits-color-font-07.html new file mode 100644 index 000000000000..c37f504b6af0 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-07.html @@ -0,0 +1,16 @@ + + + + + + +

Expect digits to be rendered from Ahem:

+
abc123xyz​
diff --git a/layout/reftests/font-matching/1971148-digits-color-font-08.html b/layout/reftests/font-matching/1971148-digits-color-font-08.html new file mode 100644 index 000000000000..7f4985f8d314 --- /dev/null +++ b/layout/reftests/font-matching/1971148-digits-color-font-08.html @@ -0,0 +1,16 @@ + + + + + + +

Expect digits to be rendered from Ahem:

+
abc123xyz​
diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list index 72b264a2e142..e058387dab03 100644 --- a/layout/reftests/font-matching/reftest.list +++ b/layout/reftests/font-matching/reftest.list @@ -213,3 +213,12 @@ test-pref(privacy.resistFingerprinting,true) == system-font-rfp.html system-font # Bug 1970980 - Test for regional-indicator emoji handling with Windows-specific fonts skip-if(!winWidget) pref(layout.css.font-variant-emoji.enabled,true) == 1970980-regional-indicators.html 1970980-regional-indicators-ref.html + +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-01.html 1971148-digits-color-font-01-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-02.html 1971148-digits-color-font-01-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-03.html 1971148-digits-color-font-03-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-04.html 1971148-digits-color-font-03-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-05.html 1971148-digits-color-font-01-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-06.html 1971148-digits-color-font-01-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-07.html 1971148-digits-color-font-03-ref.html +pref(layout.css.font-variant-emoji.enabled,true) == 1971148-digits-color-font-08.html 1971148-digits-color-font-03-ref.html