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
This commit is contained in:
committed by
dmeehan@mozilla.com
parent
38ca6718c3
commit
753cdf7af0
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<gfxFont> 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<gfxFont> 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<gfxFont> 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<gfxFont> 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<gfxFont> defaultFont = GetDefaultFont();
|
||||
if (defaultFont->HasCharacter(aCh) ||
|
||||
@@ -3612,19 +3596,26 @@ void gfxFontGroup::ComputeRanges(nsTArray<TextRange>& 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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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[];
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
span.emoji {
|
||||
font-variant-emoji: emoji;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from the emoji font:</p>
|
||||
<div>abc<span class=emoji>123</span>xyz</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from the emoji font:</p>
|
||||
<div>abc123xyz</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from the emoji font:</p>
|
||||
<div style="font-variant-emoji: emoji">abc123xyz</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
span.text {
|
||||
font-family: Ahem;
|
||||
font-variant-emoji: text;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from Ahem:</p>
|
||||
<div style="font-variant-emoji: text">abc<span class=text>123</span>xyz</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from Ahem:</p>
|
||||
<div style="font-variant-emoji: text">abc123xyz</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Expect digits to be rendered from Ahem:</p>
|
||||
<div style="font-variant-emoji: unicode">abc123xyz</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- presence of ZWSP should not affect font selection -->
|
||||
|
||||
<p>Expect digits to be rendered from the emoji font:</p>
|
||||
<div>abc123xyz​</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- presence of ZWSP should not affect font selection -->
|
||||
|
||||
<p>Expect digits to be rendered from the emoji font:</p>
|
||||
<div style="font-variant-emoji: emoji">abc123xyz​</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- presence of ZWSP should not affect font selection -->
|
||||
|
||||
<p>Expect digits to be rendered from Ahem:</p>
|
||||
<div style="font-variant-emoji: text">abc123xyz​</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url(../fonts/Ahem.ttf);
|
||||
}
|
||||
div {
|
||||
font: 25px/2 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", Ahem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- presence of ZWSP should not affect font selection -->
|
||||
|
||||
<p>Expect digits to be rendered from Ahem:</p>
|
||||
<div style="font-variant-emoji: unicode">abc123xyz​</div>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user