Bug 1032671 - Part 2. Use font.name-list.emoji preference for emoji presenration. r?jfkthame
MozReview-Commit-ID: DbrGeXzCpNT
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -179,14 +179,15 @@
// pref lang id's for font prefs
enum eFontPrefLang {
#define FONT_PREF_LANG(enum_id_, str_, atom_id_) eFontPrefLang_ ## enum_id_
#include "gfxFontPrefLangList.h"
#undef FONT_PREF_LANG
, eFontPrefLang_CJKSet // special code for CJK set
+ , eFontPrefLang_Emoji // special code for emoji presentation
, eFontPrefLang_First = eFontPrefLang_Western
, eFontPrefLang_Last = eFontPrefLang_Others
, eFontPrefLang_Count = (eFontPrefLang_Last - eFontPrefLang_First + 1)
};
#endif
--- a/gfx/thebes/gfxFontFamilyList.h
+++ b/gfx/thebes/gfxFontFamilyList.h
@@ -35,16 +35,17 @@ enum FontFamilyType : uint32_t {
eFamily_sans_serif,
eFamily_monospace,
eFamily_cursive,
eFamily_fantasy,
// special
eFamily_moz_variable,
eFamily_moz_fixed,
+ eFamily_moz_emoji,
eFamily_generic_first = eFamily_serif,
eFamily_generic_last = eFamily_fantasy,
eFamily_generic_count = (eFamily_fantasy - eFamily_serif + 1)
};
enum QuotedName { eQuotedName, eUnquotedName };
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -955,50 +955,87 @@ gfxPlatformFontList::ResolveGenericFontN
// load fonts for "font.name-list.generic.lang"
gfxFontUtils::AppendPrefsFontList(
NameListPref(generic, langGroupStr).get(), genericFamilies);
nsAtom* langGroup = GetLangGroupForPrefLang(aPrefLang);
NS_ASSERTION(langGroup, "null lang group for pref lang");
- // lookup and add platform fonts uniquely
- for (const nsString& genericFamily : genericFamilies) {
- gfxFontStyle style;
- style.language = langGroup;
- style.systemFont = false;
- AutoTArray<gfxFontFamily*,10> families;
- FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0),
- &style);
- for (gfxFontFamily* f : families) {
- if (!aGenericFamilies->Contains(f)) {
- aGenericFamilies->AppendElement(f);
- }
- }
- }
+ gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies,
+ langGroup,
+ aGenericFamilies);
#if 0 // dump out generic mappings
printf("%s ===> ", prefFontName.get());
for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) {
if (k > 0) printf(", ");
printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]->Name()).get());
}
printf("\n");
#endif
}
+void
+gfxPlatformFontList::ResolveEmojiFontNames(
+ nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
+{
+ // emoji preference has no lang name
+ AutoTArray<nsString,4> genericFamilies;
+
+ nsAutoCString prefFontListName("font.name-list.emoji");
+ gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), genericFamilies);
+
+ gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(genericFamilies,
+ nullptr,
+ aGenericFamilies);
+}
+
+void
+gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
+ nsTArray<nsString>& aGenericNameFamilies,
+ nsAtom* aLangGroup,
+ nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies)
+{
+ // lookup and add platform fonts uniquely
+ for (const nsString& genericFamily : aGenericNameFamilies) {
+ gfxFontStyle style;
+ style.language = aLangGroup;
+ style.systemFont = false;
+ AutoTArray<gfxFontFamily*,10> families;
+ FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0),
+ &style);
+ for (gfxFontFamily* f : families) {
+ if (!aGenericFamilies->Contains(f)) {
+ aGenericFamilies->AppendElement(f);
+ }
+ }
+ }
+}
+
nsTArray<RefPtr<gfxFontFamily>>*
gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType,
eFontPrefLang aPrefLang)
{
// treat -moz-fixed as monospace
if (aGenericType == eFamily_moz_fixed) {
aGenericType = eFamily_monospace;
}
+ if (aGenericType == eFamily_moz_emoji) {
+ // Emoji font has no lang
+ PrefFontList* prefFonts = mEmojiPrefFont.get();
+ if (MOZ_UNLIKELY(!prefFonts)) {
+ prefFonts = new PrefFontList;
+ ResolveEmojiFontNames(prefFonts);
+ mEmojiPrefFont.reset(prefFonts);
+ }
+ return prefFonts;
+ }
+
PrefFontList* prefFonts =
mLangGroupPrefFonts[aPrefLang][aGenericType].get();
if (MOZ_UNLIKELY(!prefFonts)) {
prefFonts = new PrefFontList;
ResolveGenericFontNames(aGenericType, aPrefLang, prefFonts);
mLangGroupPrefFonts[aPrefLang][aGenericType].reset(prefFonts);
}
return prefFonts;
@@ -1293,16 +1330,20 @@ gfxPlatformFontList::AppendPrefLang(eFon
aPrefLangs[aLen] = aAddLang;
aLen++;
}
}
mozilla::FontFamilyType
gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang)
{
+ if (aLang == eFontPrefLang_Emoji) {
+ return eFamily_moz_emoji;
+ }
+
// initialize lang group pref font defaults (i.e. serif/sans-serif)
if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) {
mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames));
for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); i++) {
nsAutoCString prefDefaultFontType("font.default.");
prefDefaultFontType.Append(GetPrefLangName(eFontPrefLang(i)));
nsAutoCString serifOrSans;
Preferences::GetCString(prefDefaultFontType.get(), serifOrSans);
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -492,16 +492,25 @@ protected:
void RebuildLocalFonts();
void
ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
eFontPrefLang aPrefLang,
nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies);
+ void
+ ResolveEmojiFontNames(nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies);
+
+ void
+ GetFontFamiliesFromGenericFamilies(
+ nsTArray<nsString>& aGenericFamilies,
+ nsAtom* aLangGroup,
+ nsTArray<RefPtr<gfxFontFamily>>* aFontFamilies);
+
virtual nsresult InitFontListForPlatform() = 0;
void ApplyWhitelist();
// Create a new gfxFontFamily of the appropriate subclass for the platform,
// used when AddWithLegacyFamilyName needs to create a new family.
virtual gfxFontFamily* CreateFontFamily(const nsAString& aName) const = 0;
@@ -557,16 +566,17 @@ protected:
typedef nsTArray<RefPtr<gfxFontFamily>> PrefFontList;
typedef mozilla::RangedArray<mozilla::UniquePtr<PrefFontList>,
mozilla::eFamily_generic_first,
mozilla::eFamily_generic_count> PrefFontsForLangGroup;
mozilla::RangedArray<PrefFontsForLangGroup,
eFontPrefLang_First,
eFontPrefLang_Count> mLangGroupPrefFonts;
+ mozilla::UniquePtr<PrefFontList> mEmojiPrefFont;
// when system-wide font lookup fails for a character, cache it to skip future searches
gfxSparseBitSet mCodepointsWithNoFonts;
// the family to use for U+FFFD fallback, to avoid expensive search every time
// on pages with lots of problems
RefPtr<gfxFontFamily> mReplacementCharFallbackFamily;
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -32,16 +32,19 @@
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::unicode;
using mozilla::services::GetObserverService;
static const char16_t kEllipsisChar[] = { 0x2026, 0x0 };
static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
+const uint32_t kVariationSelector15 = 0xFE0E; // text presentation
+const uint32_t kVariationSelector16 = 0xFE0F; // emoji presentation
+
#ifdef DEBUG_roc
#define DEBUG_TEXT_RUN_STORAGE_METRICS
#endif
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
extern uint32_t gTextRunStorageHighWaterMark;
extern uint32_t gTextRunStorage;
extern uint32_t gFontCount;
@@ -3051,17 +3054,17 @@ gfxFontGroup::FindFontForChar(uint32_t a
}
}
// if character is in Private Use Area, don't do matching against pref or system fonts
if ((aCh >= 0xE000 && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
return nullptr;
// 2. search pref fonts
- gfxFont* font = WhichPrefFontSupportsChar(aCh);
+ gfxFont* font = WhichPrefFontSupportsChar(aCh, aNextCh);
if (font) {
*aMatchType = gfxTextRange::kPrefsFallback;
return font;
}
// 3. use fallback fonts
// -- before searching for something else check the font used for the previous character
if (aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
@@ -3332,22 +3335,32 @@ gfxFontGroup::ContainsUserFont(const gfx
if (ff.EqualsUserFont(aUserFont)) {
return true;
}
}
return false;
}
gfxFont*
-gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh)
+gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh, uint32_t aNextCh)
{
- // get the pref font list if it hasn't been set up already
- uint32_t unicodeRange = FindCharUnicodeRange(aCh);
+ eFontPrefLang charLang;
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
- eFontPrefLang charLang = pfl->GetFontPrefLangFor(unicodeRange);
+
+ EmojiPresentation emoji = GetEmojiPresentation(aCh);
+ if ((emoji != EmojiPresentation::TextOnly &&
+ (aNextCh == kVariationSelector16 ||
+ (emoji == EmojiPresentation::EmojiDefault &&
+ aNextCh != kVariationSelector15)))) {
+ charLang = eFontPrefLang_Emoji;
+ } else {
+ // get the pref font list if it hasn't been set up already
+ uint32_t unicodeRange = FindCharUnicodeRange(aCh);
+ charLang = pfl->GetFontPrefLangFor(unicodeRange);
+ }
// if the last pref font was the first family in the pref list, no need to recheck through a list of families
if (mLastPrefFont && charLang == mLastPrefLang &&
mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) {
return mLastPrefFont;
}
// based on char lang and page lang, set up list of pref lang fonts to check
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -996,17 +996,18 @@ public:
// group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
// Get it/use it/forget it :) - don't keep a reference that might go stale.
gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
mozilla::gfx::ShapedTextFlags aFlags,
LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
protected:
// search through pref fonts for a character, return nullptr if no matching pref font
- gfxFont* WhichPrefFontSupportsChar(uint32_t aCh);
+ gfxFont* WhichPrefFontSupportsChar(uint32_t aCh,
+ uint32_t aNextCh);
gfxFont* WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
Script aRunScript);
template<typename T>
void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
const T *aString, uint32_t aLength,
Script aRunScript,