Skip to content

Commit 631af72

Browse files
jfkthameDonalMe
authored andcommitted
Bug 1971053 - patch 2 - Prefer to use the specified font from CSS for potentially-emoji characters unless a specific presentation is explicitly requested. a=dmeehan
Original Revision: https://phabricator.services.mozilla.com/D253740 Differential Revision: https://phabricator.services.mozilla.com/D253939
1 parent 8896bad commit 631af72

16 files changed

+218
-46
lines changed

gfx/thebes/gfxFcPlatformFontList.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,12 @@ bool gfxFcPlatformFontList::FindAndAddFamiliesLocked(
23482348
cacheKey.Append(':');
23492349
}
23502350

2351+
// Include the generic family in the cache key, to maintain the distinction
2352+
// between fonts explicitly requested by name and the results of resolving
2353+
// CSS generics.
2354+
cacheKey.AppendInt(int(aGeneric));
2355+
cacheKey.Append(':');
2356+
23512357
cacheKey.Append(familyName);
23522358
auto vis =
23532359
aPresContext ? aPresContext->GetFontVisibility() : FontVisibility::User;

gfx/thebes/gfxPlatform.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ inline bool PrefersColor(FontPresentation aPresentation) {
123123
return aPresentation >= FontPresentation::EmojiDefault;
124124
}
125125

126+
inline bool IsExplicitPresentation(FontPresentation aPresentation) {
127+
return aPresentation == FontPresentation::TextExplicit ||
128+
aPresentation == FontPresentation::EmojiExplicit;
129+
}
130+
126131
// when searching through pref langs, max number of pref langs
127132
const uint32_t kMaxLenPrefLangList = 32;
128133

gfx/thebes/gfxTextRun.cpp

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,18 +1856,8 @@ gfxFontGroup::gfxFontGroup(nsPresContext* aPresContext,
18561856
mUserFontSet(aUserFontSet),
18571857
mTextPerf(aTextPerf),
18581858
mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aLanguage)),
1859-
mExplicitLanguage(aExplicitLanguage) {
1860-
switch (aVariantEmoji) {
1861-
case StyleFontVariantEmoji::Normal:
1862-
case StyleFontVariantEmoji::Unicode:
1863-
break;
1864-
case StyleFontVariantEmoji::Text:
1865-
mEmojiPresentation = FontPresentation::TextExplicit;
1866-
break;
1867-
case StyleFontVariantEmoji::Emoji:
1868-
mEmojiPresentation = FontPresentation::EmojiExplicit;
1869-
break;
1870-
}
1859+
mExplicitLanguage(aExplicitLanguage),
1860+
mFontVariantEmoji(aVariantEmoji) {
18711861
// We don't use SetUserFontSet() here, as we want to unconditionally call
18721862
// EnsureFontList() rather than only do UpdateUserFonts() if it changed.
18731863
}
@@ -3209,7 +3199,11 @@ already_AddRefed<gfxFont> gfxFontGroup::FindFontForChar(
32093199
if (EmojiPresentation emojiPresentation = GetEmojiPresentation(aCh);
32103200
emojiPresentation != TextOnly) {
32113201
// Default presentation from the font-variant-emoji property.
3212-
presentation = mEmojiPresentation;
3202+
if (mFontVariantEmoji == StyleFontVariantEmoji::Emoji) {
3203+
presentation = FontPresentation::EmojiExplicit;
3204+
} else if (mFontVariantEmoji == StyleFontVariantEmoji::Text) {
3205+
presentation = FontPresentation::TextExplicit;
3206+
}
32133207
// If there wasn't an explicit font-variant-emoji setting, default to
32143208
// what Unicode prefers for this character.
32153209
if (presentation == FontPresentation::Any) {
@@ -3225,8 +3219,7 @@ already_AddRefed<gfxFont> gfxFontGroup::FindFontForChar(
32253219
// glyph.
32263220
// If the prefer-text selector is present, we specifically look for a
32273221
// font that will provide a monochrome glyph.
3228-
if (aNextCh == kVariationSelector16 ||
3229-
(aNextCh >= kEmojiSkinToneFirst && aNextCh <= kEmojiSkinToneLast) ||
3222+
if (aNextCh == kVariationSelector16 || IsEmojiSkinToneModifier(aNextCh) ||
32303223
gfxFontUtils::IsEmojiFlagAndTag(aCh, aNextCh)) {
32313224
// Emoji presentation is explicitly requested by a variation selector
32323225
// or the presence of a skin-tone codepoint.
@@ -3305,8 +3298,14 @@ already_AddRefed<gfxFont> gfxFontGroup::FindFontForChar(
33053298
// Handle a candidate font that could support the character, returning true
33063299
// if we should go ahead and return |f|, false to continue searching.
33073300
auto CheckCandidate = [&](gfxFont* f, FontMatchType t) -> bool {
3308-
// If no preference, then just accept the font.
3309-
if (presentation == FontPresentation::Any) {
3301+
// If no preference, or if it's an explicitly-named family in the fontgroup
3302+
// and font-variant-emoji is 'normal', then we accept the font.
3303+
if (presentation == FontPresentation::Any ||
3304+
(!IsExplicitPresentation(presentation) &&
3305+
t.kind == FontMatchType::Kind::kFontGroup &&
3306+
t.generic == StyleGenericFontFamily::None &&
3307+
mFontVariantEmoji == StyleFontVariantEmoji::Normal &&
3308+
!gfxFontUtils::IsRegionalIndicator(aCh))) {
33103309
*aMatchType = t;
33113310
return true;
33123311
}
@@ -3447,21 +3446,6 @@ already_AddRefed<gfxFont> gfxFontGroup::FindFontForChar(
34473446
}
34483447
}
34493448

3450-
// If it's an emoji codepoint and we found a named-family candidate (not a
3451-
// generic) in the font list, we accept it even if it doesn't match the
3452-
// presentation (so authors can deliberately request fonts that do not match
3453-
// the Unicode emoji default presentation style for a given character). But
3454-
// don't do this if a particular presentation was explicitly requested in the
3455-
// text, or for Regional Indicator chars (because of Segoe UI Emoji).
3456-
if (candidateFont &&
3457-
candidateMatchType.generic == StyleGenericFontFamily::None &&
3458-
presentation != FontPresentation::EmojiExplicit &&
3459-
presentation != FontPresentation::TextExplicit &&
3460-
!gfxFontUtils::IsRegionalIndicator(aCh)) {
3461-
*aMatchType = candidateMatchType;
3462-
return candidateFont.forget();
3463-
}
3464-
34653449
if (fontListLength == 0) {
34663450
RefPtr<gfxFont> defaultFont = GetDefaultFont();
34673451
if (defaultFont->HasCharacter(aCh) ||
@@ -3612,19 +3596,26 @@ void gfxFontGroup::ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString,
36123596
// the font selected for an adjacent character, and does not need to
36133597
// consider emoji vs text presentation.
36143598
if ((font = GetFontAt(0, ch)) != nullptr && font->HasCharacter(ch) &&
3615-
// In 8-bit text, the only time emoji presentation might be needed
3616-
// is if it is explicitly requested with font-variant, as no 8-bit
3617-
// chars are emoji by default.
3618-
((sizeof(T) == sizeof(uint8_t) &&
3619-
(mEmojiPresentation != FontPresentation::EmojiExplicit ||
3620-
GetEmojiPresentation(ch) == TextOnly)) ||
3621-
// For 16-bit text, we need to consider cluster extenders etc.
3622-
(sizeof(T) == sizeof(char16_t) &&
3623-
(!IsClusterExtender(ch) && ch != NARROW_NO_BREAK_SPACE &&
3624-
!gfxFontUtils::IsJoinControl(ch) &&
3625-
!gfxFontUtils::IsJoinCauser(prevCh) &&
3626-
!gfxFontUtils::IsVarSelector(ch) &&
3627-
GetEmojiPresentation(ch) == TextOnly)))) {
3599+
(
3600+
// In 8-bit text, we can unconditionally accept the first font if
3601+
// font-variant-emoji is 'normal', or if the character does not
3602+
// have the emoji property; there cannot be adjacent characters
3603+
// that would affect it.
3604+
(sizeof(T) == sizeof(uint8_t) &&
3605+
(mFontVariantEmoji == StyleFontVariantEmoji::Normal ||
3606+
GetEmojiPresentation(ch) == TextOnly)) ||
3607+
// For 16-bit text, we need to consider cluster extenders etc.
3608+
(sizeof(T) == sizeof(char16_t) &&
3609+
(!IsClusterExtender(ch) && ch != NARROW_NO_BREAK_SPACE &&
3610+
!gfxFontUtils::IsJoinControl(ch) &&
3611+
!gfxFontUtils::IsJoinCauser(prevCh) &&
3612+
!gfxFontUtils::IsVarSelector(ch) &&
3613+
(GetEmojiPresentation(ch) == TextOnly ||
3614+
(!(IsEmojiPresentationSelector(nextCh) ||
3615+
IsEmojiSkinToneModifier(nextCh) ||
3616+
gfxFontUtils::IsEmojiFlagAndTag(ch, nextCh)) &&
3617+
mFontVariantEmoji == StyleFontVariantEmoji::Normal &&
3618+
mFonts[0].Generic() == StyleGenericFontFamily::None)))))) {
36283619
matchType = {FontMatchType::Kind::kFontGroup, mFonts[0].Generic()};
36293620
} else {
36303621
font =

gfx/thebes/gfxTextRun.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,7 @@ class gfxFontGroup final : public gfxTextRunFactory {
13991399

14001400
bool mResolvedFonts = false; // Whether the mFonts array has been set up.
14011401

1402-
FontPresentation mEmojiPresentation = FontPresentation::Any;
1402+
StyleFontVariantEmoji mFontVariantEmoji = StyleFontVariantEmoji::Normal;
14031403

14041404
// Generic font family used to select among font prefs during fallback.
14051405
mozilla::StyleGenericFontFamily mFallbackGeneric =

intl/unicharutil/util/nsUnicodeProperties.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,16 @@ enum EmojiPresentation { TextOnly = 0, TextDefault = 1, EmojiDefault = 2 };
5656

5757
const uint32_t kVariationSelector15 = 0xFE0E; // text presentation
5858
const uint32_t kVariationSelector16 = 0xFE0F; // emoji presentation
59+
static inline bool IsEmojiPresentationSelector(uint32_t aCh) {
60+
return aCh >= kVariationSelector15 && aCh <= kVariationSelector16;
61+
}
5962

6063
// Unicode values for EMOJI MODIFIER FITZPATRICK TYPE-*
6164
const uint32_t kEmojiSkinToneFirst = 0x1f3fb;
6265
const uint32_t kEmojiSkinToneLast = 0x1f3ff;
66+
static inline bool IsEmojiSkinToneModifier(uint32_t aCh) {
67+
return aCh >= kEmojiSkinToneFirst && aCh <= kEmojiSkinToneLast;
68+
}
6369

6470
extern const hb_unicode_general_category_t sICUtoHBcategory[];
6571

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
3+
<style>
4+
@font-face {
5+
font-family: Ahem;
6+
src: url(../fonts/Ahem.ttf);
7+
}
8+
div {
9+
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
10+
}
11+
span.emoji {
12+
font-variant-emoji: emoji;
13+
}
14+
</style>
15+
16+
<p>Expect digits to be rendered from the emoji font:</p>
17+
<div>abc<span class=emoji>123</span>xyz</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
3+
<style>
4+
@font-face {
5+
font-family: Ahem;
6+
src: url(../fonts/Ahem.ttf);
7+
}
8+
div {
9+
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
10+
}
11+
</style>
12+
13+
<p>Expect digits to be rendered from the emoji font:</p>
14+
<div>abc123xyz</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
3+
<style>
4+
@font-face {
5+
font-family: Ahem;
6+
src: url(../fonts/Ahem.ttf);
7+
}
8+
div {
9+
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
10+
}
11+
</style>
12+
13+
<p>Expect digits to be rendered from the emoji font:</p>
14+
<div style="font-variant-emoji: emoji">abc123xyz</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE html>
2+
3+
<style>
4+
@font-face {
5+
font-family: Ahem;
6+
src: url(../fonts/Ahem.ttf);
7+
}
8+
div {
9+
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
10+
}
11+
span.text {
12+
font-family: Ahem;
13+
font-variant-emoji: text;
14+
}
15+
</style>
16+
17+
<p>Expect digits to be rendered from Ahem:</p>
18+
<div style="font-variant-emoji: text">abc<span class=text>123</span>xyz</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
3+
<style>
4+
@font-face {
5+
font-family: Ahem;
6+
src: url(../fonts/Ahem.ttf);
7+
}
8+
div {
9+
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
10+
}
11+
</style>
12+
13+
<p>Expect digits to be rendered from Ahem:</p>
14+
<div style="font-variant-emoji: text">abc123xyz</div>

0 commit comments

Comments
 (0)