diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 784ff5accb5..7e005e5dff6 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -847,6 +847,7 @@ gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) // add font entries for each of the faces uint32_t numFonts = mFontPatterns.Length(); NS_ASSERTION(numFonts, "font family containing no faces!!"); + uint32_t numRegularFaces = 0; for (uint32_t i = 0; i < numFonts; i++) { FcPattern* face = mFontPatterns[i]; @@ -859,6 +860,12 @@ gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) new gfxFontconfigFontEntry(faceName, face); AddFontEntry(fontEntry); + if (fontEntry->IsUpright() && + fontEntry->Weight() == NS_FONT_WEIGHT_NORMAL && + fontEntry->Stretch() == NS_FONT_STRETCH_NORMAL) { + numRegularFaces++; + } + if (LOG_FONTLIST_ENABLED()) { LOG_FONTLIST(("(fontlist) added (%s) to family (%s)" " with style: %s weight: %d stretch: %d" @@ -872,6 +879,12 @@ gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) NS_ConvertUTF16toUTF8(fullname).get())); } } + + // somewhat arbitrary, but define a family with two or more regular + // faces as a family for which intra-family fallback should be used + if (numRegularFaces > 1) { + mCheckForFallbackFaces = true; + } mFaceNamesInitialized = true; mFontPatterns.Clear(); SetHasStyles(true); diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index d11f117b14c..87a7eaab408 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -663,7 +663,8 @@ public: mIsSimpleFamily(false), mIsBadUnderlineFamily(false), mFamilyCharacterMapInitialized(false), - mSkipDefaultFeatureSpaceCheck(false) + mSkipDefaultFeatureSpaceCheck(false), + mCheckForFallbackFaces(false) { } const nsString& Name() { return mName; } @@ -767,6 +768,7 @@ public: } bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; } + bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; } // sort available fonts to put preferred (standard) faces towards the end void SortAvailableFonts(); @@ -822,6 +824,7 @@ protected: bool mIsBadUnderlineFamily : 1; bool mFamilyCharacterMapInitialized : 1; bool mSkipDefaultFeatureSpaceCheck : 1; + bool mCheckForFallbackFaces : 1; // check other faces for character enum { // for "simple" families, the faces are stored in mAvailableFonts diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 63f4b6912bf..c26023c30bf 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1648,6 +1648,12 @@ gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) mFonts.AppendElement(ff); } } + // for a family marked as "check fallback faces", only mark the last + // entry so that fallbacks for a family are only checked once + if (aFamily->CheckForFallbackFaces() && + !fontEntryList.IsEmpty() && !mFonts.IsEmpty()) { + mFonts.LastElement().SetCheckForFallbackFaces(); + } } bool @@ -2555,6 +2561,23 @@ gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh) return font.forget(); } +already_AddRefed +gfxFontGroup::FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh, + int32_t aRunScript) +{ + GlobalFontMatch data(aCh, aRunScript, &mStyle); + aFamily->SearchAllFontsForChar(&data); + gfxFontEntry* fe = data.mBestMatch; + if (!fe) { + return nullptr; + } + + bool needsBold = mStyle.weight >= 600 && !fe->IsBold() && + mStyle.allowSyntheticWeight; + RefPtr font = fe->FindOrMakeFont(&mStyle, needsBold); + return font.forget(); +} + gfxFloat gfxFontGroup::GetUnderlineOffset() { @@ -2619,10 +2642,17 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, return firstFont.forget(); } - // If italic, test the regular face to see if it supports character. - // Only do this for platform fonts, not userfonts. - if (mStyle.style != NS_FONT_STYLE_NORMAL && - !firstFont->GetFontEntry()->IsUserFont()) { + if (mFonts[0].CheckForFallbackFaces()) { + RefPtr font = + FindFallbackFaceForChar(mFonts[0].Family(), aCh, aRunScript); + if (font) { + *aMatchType = gfxTextRange::kFontGroup; + return font.forget(); + } + } else if (mStyle.style != NS_FONT_STYLE_NORMAL && + !firstFont->GetFontEntry()->IsUserFont()) { + // If italic, test the regular face to see if it supports + // character. Only do this for platform fonts, not userfonts. RefPtr font = FindNonItalicFaceForChar(mFonts[0].Family(), aCh); if (font) { @@ -2722,17 +2752,30 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, } } - // If italic, test the regular face to see if it supports the character. - // Only do this for platform fonts, not userfonts. - fe = ff.FontEntry(); - if (mStyle.style != NS_FONT_STYLE_NORMAL && - !fe->mIsUserFontContainer && - !fe->IsUserFont()) { - font = FindNonItalicFaceForChar(ff.Family(), aCh); + // check other family faces if needed + if (ff.CheckForFallbackFaces()) { + NS_ASSERTION(i == 0 ? true : + !mFonts[i-1].CheckForFallbackFaces() || + !mFonts[i-1].Family()->Name().Equals(ff.Family()->Name()), + "should only do fallback once per font family"); + font = FindFallbackFaceForChar(ff.Family(), aCh, aRunScript); if (font) { *aMatchType = gfxTextRange::kFontGroup; return font.forget(); } + } else { + // If italic, test the regular face to see if it supports the + // character. Only do this for platform fonts, not userfonts. + fe = ff.FontEntry(); + if (mStyle.style != NS_FONT_STYLE_NORMAL && + !fe->mIsUserFontContainer && + !fe->IsUserFont()) { + font = FindNonItalicFaceForChar(ff.Family(), aCh); + if (font) { + *aMatchType = gfxTextRange::kFontGroup; + return font.forget(); + } + } } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 176f9b58fb7..f24810563cb 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -882,12 +882,13 @@ protected: public: FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), mNeedsBold(false), mFontCreated(false), - mLoading(false), mInvalid(false) + mLoading(false), mInvalid(false), + mCheckForFallbackFaces(false) { } FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) : mFamily(aFamily), mNeedsBold(false), mFontCreated(true), - mLoading(false), mInvalid(false) + mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFont, "font pointer must not be null"); NS_ASSERTION(!aFamily || @@ -900,7 +901,7 @@ protected: FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, bool aNeedsBold) : mFamily(aFamily), mNeedsBold(aNeedsBold), mFontCreated(false), - mLoading(false), mInvalid(false) + mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); NS_ASSERTION(!aFamily || @@ -915,7 +916,8 @@ protected: mNeedsBold(aOtherFamilyFace.mNeedsBold), mFontCreated(aOtherFamilyFace.mFontCreated), mLoading(aOtherFamilyFace.mLoading), - mInvalid(aOtherFamilyFace.mInvalid) + mInvalid(aOtherFamilyFace.mInvalid), + mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces) { if (mFontCreated) { mFont = aOtherFamilyFace.mFont; @@ -978,6 +980,8 @@ protected: void CheckState(bool& aSkipDrawing); void SetLoading(bool aIsLoading) { mLoading = aIsLoading; } void SetInvalid() { mInvalid = true; } + bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; } + void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; } void SetFont(gfxFont* aFont) { @@ -1006,6 +1010,7 @@ protected: bool mFontCreated : 1; bool mLoading : 1; bool mInvalid : 1; + bool mCheckForFallbackFaces : 1; }; // List of font families, either named or generic. @@ -1102,7 +1107,13 @@ protected: already_AddRefed FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh); - // helper methods for looking up fonts + // search all faces in a family for a fallback in cases where it's unclear + // whether the family might have a font for a given character + already_AddRefed + FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh, + int32_t aRunScript); + + // helper methods for looking up fonts // lookup and add a font with a given name (i.e. *not* a generic!) void AddPlatformFont(const nsAString& aName,