LCOV - code coverage report
Current view: top level - gfx/thebes - gfxFcPlatformFontList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 477 887 53.8 %
Date: 2017-07-14 16:53:18 Functions: 38 61 62.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/Logging.h"
       7             : #include "mozilla/SizePrintfMacros.h"
       8             : 
       9             : #include "gfxFcPlatformFontList.h"
      10             : #include "gfxFont.h"
      11             : #include "gfxFontConstants.h"
      12             : #include "gfxFontFamilyList.h"
      13             : #include "gfxFT2Utils.h"
      14             : #include "gfxPlatform.h"
      15             : #include "mozilla/ArrayUtils.h"
      16             : #include "mozilla/Preferences.h"
      17             : #include "mozilla/Sprintf.h"
      18             : #include "mozilla/TimeStamp.h"
      19             : #include "nsGkAtoms.h"
      20             : #include "nsUnicodeProperties.h"
      21             : #include "nsUnicodeRange.h"
      22             : #include "nsDirectoryServiceUtils.h"
      23             : #include "nsDirectoryServiceDefs.h"
      24             : #include "nsAppDirectoryServiceDefs.h"
      25             : #include "nsCharSeparatedTokenizer.h"
      26             : 
      27             : #include "mozilla/gfx/HelpersCairo.h"
      28             : 
      29             : #include <fontconfig/fcfreetype.h>
      30             : 
      31             : #ifdef MOZ_WIDGET_GTK
      32             : #include <gdk/gdk.h>
      33             : #include "gfxPlatformGtk.h"
      34             : #endif
      35             : 
      36             : #ifdef MOZ_X11
      37             : #include "mozilla/X11Util.h"
      38             : #endif
      39             : 
      40             : using namespace mozilla;
      41             : using namespace mozilla::gfx;
      42             : using namespace mozilla::unicode;
      43             : 
      44             : #ifndef FC_POSTSCRIPT_NAME
      45             : #define FC_POSTSCRIPT_NAME  "postscriptname"      /* String */
      46             : #endif
      47             : 
      48             : #define PRINTING_FC_PROPERTY "gfx.printing"
      49             : 
      50             : #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
      51             :                                LogLevel::Debug, args)
      52             : #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
      53             :                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
      54             :                                    LogLevel::Debug)
      55             : #define LOG_CMAPDATA_ENABLED() MOZ_LOG_TEST( \
      56             :                                    gfxPlatform::GetLog(eGfxLog_cmapdata), \
      57             :                                    LogLevel::Debug)
      58             : 
      59             : static const FcChar8*
      60          38 : ToFcChar8Ptr(const char* aStr)
      61             : {
      62          38 :     return reinterpret_cast<const FcChar8*>(aStr);
      63             : }
      64             : 
      65             : static const char*
      66       12528 : ToCharPtr(const FcChar8 *aStr)
      67             : {
      68       12528 :     return reinterpret_cast<const char*>(aStr);
      69             : }
      70             : 
      71             : FT_Library gfxFcPlatformFontList::sCairoFTLibrary = nullptr;
      72             : 
      73             : static cairo_user_data_key_t sFcFontlistUserFontDataKey;
      74             : 
      75             : // canonical name ==> first en name or first name if no en name
      76             : // This is the required logic for fullname lookups as per CSS3 Fonts spec.
      77             : static uint32_t
      78        3668 : FindCanonicalNameIndex(FcPattern* aFont, const char* aLangField)
      79             : {
      80        3668 :     uint32_t n = 0, en = 0;
      81             :     FcChar8* lang;
      82        5310 :     while (FcPatternGetString(aFont, aLangField, n, &lang) == FcResultMatch) {
      83             :         // look for 'en' or variants, en-US, en-JP etc.
      84        3994 :         uint32_t len = strlen(ToCharPtr(lang));
      85        3994 :         bool enPrefix = (strncmp(ToCharPtr(lang), "en", 2) == 0);
      86        3994 :         if (enPrefix && (len == 2 || (len > 2 && aLangField[2] == '-'))) {
      87        3173 :             en = n;
      88        3173 :             break;
      89             :         }
      90         821 :         n++;
      91             :     }
      92        3668 :     return en;
      93             : }
      94             : 
      95             : static void
      96        1805 : GetFaceNames(FcPattern* aFont, const nsAString& aFamilyName,
      97             :              nsAString& aPostscriptName, nsAString& aFullname)
      98             : {
      99             :     // get the Postscript name
     100             :     FcChar8* psname;
     101        1805 :     if (FcPatternGetString(aFont, FC_POSTSCRIPT_NAME, 0, &psname) == FcResultMatch) {
     102        1805 :         AppendUTF8toUTF16(ToCharPtr(psname), aPostscriptName);
     103             :     }
     104             : 
     105             :     // get the canonical fullname (i.e. en name or first name)
     106        1805 :     uint32_t en = FindCanonicalNameIndex(aFont, FC_FULLNAMELANG);
     107             :     FcChar8* fullname;
     108        1805 :     if (FcPatternGetString(aFont, FC_FULLNAME, en, &fullname) == FcResultMatch) {
     109        1640 :         AppendUTF8toUTF16(ToCharPtr(fullname), aFullname);
     110             :     }
     111             : 
     112             :     // if have fullname, done
     113        1805 :     if (!aFullname.IsEmpty()) {
     114        1640 :         return;
     115             :     }
     116             : 
     117             :     // otherwise, set the fullname to family + style name [en] and use that
     118         165 :     aFullname.Append(aFamilyName);
     119             : 
     120             :     // figure out the en style name
     121         165 :     en = FindCanonicalNameIndex(aFont, FC_STYLELANG);
     122         330 :     nsAutoString style;
     123         165 :     FcChar8* stylename = nullptr;
     124         165 :     FcPatternGetString(aFont, FC_STYLE, en, &stylename);
     125         165 :     if (stylename) {
     126         165 :         AppendUTF8toUTF16(ToCharPtr(stylename), style);
     127             :     }
     128             : 
     129         165 :     if (!style.IsEmpty() && !style.EqualsLiteral("Regular")) {
     130         135 :         aFullname.Append(' ');
     131         135 :         aFullname.Append(style);
     132             :     }
     133             : }
     134             : 
     135             : static uint16_t
     136         107 : MapFcWeight(int aFcWeight)
     137             : {
     138         107 :   if (aFcWeight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) {
     139           0 :     return 100;
     140             :   }
     141         107 :   if (aFcWeight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) {
     142           3 :     return 200;
     143             :   }
     144         104 :   if (aFcWeight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) {
     145           2 :     return 300;
     146             :   }
     147         102 :   if (aFcWeight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) {
     148             :     // This includes FC_WEIGHT_BOOK
     149          50 :     return 400;
     150             :   }
     151          52 :   if (aFcWeight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) {
     152           2 :     return 500;
     153             :   }
     154          50 :   if (aFcWeight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) {
     155           0 :     return 600;
     156             :   }
     157          50 :   if (aFcWeight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) {
     158          50 :     return 700;
     159             :   }
     160           0 :   if (aFcWeight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) {
     161           0 :     return 800;
     162             :   }
     163           0 :   if (aFcWeight <= FC_WEIGHT_BLACK) {
     164           0 :     return 900;
     165             :   }
     166             : 
     167             :   // including FC_WEIGHT_EXTRABLACK
     168           0 :   return 901;
     169             : }
     170             : 
     171             : static int16_t
     172         107 : MapFcWidth(int aFcWidth)
     173             : {
     174         107 :     if (aFcWidth <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) {
     175           0 :         return NS_FONT_STRETCH_ULTRA_CONDENSED;
     176             :     }
     177         107 :     if (aFcWidth <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) {
     178           0 :         return NS_FONT_STRETCH_EXTRA_CONDENSED;
     179             :     }
     180         107 :     if (aFcWidth <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) {
     181           0 :         return NS_FONT_STRETCH_CONDENSED;
     182             :     }
     183         107 :     if (aFcWidth <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) {
     184          20 :         return NS_FONT_STRETCH_SEMI_CONDENSED;
     185             :     }
     186          87 :     if (aFcWidth <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) {
     187          87 :         return NS_FONT_STRETCH_NORMAL;
     188             :     }
     189           0 :     if (aFcWidth <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) {
     190           0 :         return NS_FONT_STRETCH_SEMI_EXPANDED;
     191             :     }
     192           0 :     if (aFcWidth <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) {
     193           0 :         return NS_FONT_STRETCH_EXPANDED;
     194             :     }
     195           0 :     if (aFcWidth <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) {
     196           0 :         return NS_FONT_STRETCH_EXTRA_EXPANDED;
     197             :     }
     198           0 :     return NS_FONT_STRETCH_ULTRA_EXPANDED;
     199             : }
     200             : 
     201         107 : gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
     202             :                                                FcPattern* aFontPattern,
     203         107 :                                                bool aIgnoreFcCharmap)
     204             :         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
     205             :           mFTFace(nullptr), mFTFaceInitialized(false),
     206             :           mIgnoreFcCharmap(aIgnoreFcCharmap),
     207         107 :           mAspect(0.0), mFontData(nullptr)
     208             : {
     209             :     // italic
     210             :     int slant;
     211         107 :     if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, &slant) != FcResultMatch) {
     212           0 :         slant = FC_SLANT_ROMAN;
     213             :     }
     214         107 :     if (slant == FC_SLANT_OBLIQUE) {
     215          18 :         mStyle = NS_FONT_STYLE_OBLIQUE;
     216          89 :     } else if (slant > 0) {
     217          32 :         mStyle = NS_FONT_STYLE_ITALIC;
     218             :     }
     219             : 
     220             :     // weight
     221             :     int weight;
     222         107 :     if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) {
     223           0 :         weight = FC_WEIGHT_REGULAR;
     224             :     }
     225         107 :     mWeight = MapFcWeight(weight);
     226             : 
     227             :     // width
     228             :     int width;
     229         107 :     if (FcPatternGetInteger(aFontPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
     230           0 :         width = FC_WIDTH_NORMAL;
     231             :     }
     232         107 :     mStretch = MapFcWidth(width);
     233         107 : }
     234             : 
     235           0 : gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
     236             :                                                uint16_t aWeight,
     237             :                                                int16_t aStretch,
     238             :                                                uint8_t aStyle,
     239             :                                                const uint8_t *aData,
     240           0 :                                                FT_Face aFace)
     241             :     : gfxFontEntry(aFaceName),
     242             :       mFTFace(aFace), mFTFaceInitialized(true),
     243             :       mIgnoreFcCharmap(true),
     244           0 :       mAspect(0.0), mFontData(aData)
     245             : {
     246           0 :     mWeight = aWeight;
     247           0 :     mStyle = aStyle;
     248           0 :     mStretch = aStretch;
     249           0 :     mIsDataUserFont = true;
     250             : 
     251             :     // Use fontconfig to fill out the pattern from the FTFace.
     252             :     // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at
     253             :     // least). The dummy file passed here is removed below.
     254             :     //
     255             :     // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr)
     256             :     // is passed as the "blanks" argument, which provides that unexpectedly
     257             :     // blank glyphs are elided.  Here, however, we pass nullptr for
     258             :     // "blanks", effectively assuming that, if the font has a blank glyph,
     259             :     // then the author intends any associated character to be rendered
     260             :     // blank.
     261           0 :     mFontPattern = FcFreeTypeQueryFace(mFTFace, ToFcChar8Ptr(""), 0, nullptr);
     262             :     // given that we have a FT_Face, not really sure this is possible...
     263           0 :     if (!mFontPattern) {
     264           0 :         mFontPattern = FcPatternCreate();
     265             :     }
     266           0 :     FcPatternDel(mFontPattern, FC_FILE);
     267           0 :     FcPatternDel(mFontPattern, FC_INDEX);
     268             : 
     269             :     // Make a new pattern and store the face in it so that cairo uses
     270             :     // that when creating a cairo font face.
     271           0 :     FcPatternAddFTFace(mFontPattern, FC_FT_FACE, mFTFace);
     272             : 
     273           0 :     mUserFontData = new FTUserFontData(mFTFace, mFontData);
     274           0 : }
     275             : 
     276           0 : gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
     277             :                                                FcPattern* aFontPattern,
     278             :                                                uint16_t aWeight,
     279             :                                                int16_t aStretch,
     280           0 :                                                uint8_t aStyle)
     281             :         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
     282             :           mFTFace(nullptr), mFTFaceInitialized(false),
     283           0 :           mAspect(0.0), mFontData(nullptr)
     284             : {
     285           0 :     mWeight = aWeight;
     286           0 :     mStyle = aStyle;
     287           0 :     mStretch = aStretch;
     288           0 :     mIsLocalUserFont = true;
     289             : 
     290             :     // The proper setting of mIgnoreFcCharmap is tricky for fonts loaded
     291             :     // via src:local()...
     292             :     // If the local font happens to come from the application fontset,
     293             :     // we want to set it to true so that color/svg fonts will work even
     294             :     // if the default glyphs are blank; but if the local font is a non-
     295             :     // sfnt face (e.g. legacy type 1) then we need to set it to false
     296             :     // because our cmap-reading code will fail and we depend on FT+Fc to
     297             :     // determine the coverage.
     298             :     // We set the flag here, but may flip it the first time TestCharacterMap
     299             :     // is called, at which point we'll look to see whether a 'cmap' is
     300             :     // actually present in the font.
     301           0 :     mIgnoreFcCharmap = true;
     302           0 : }
     303             : 
     304           0 : gfxFontconfigFontEntry::~gfxFontconfigFontEntry()
     305             : {
     306           0 : }
     307             : 
     308             : static bool
     309          15 : PatternHasLang(const FcPattern *aPattern, const FcChar8 *aLang)
     310             : {
     311             :     FcLangSet *langset;
     312             : 
     313          15 :     if (FcPatternGetLangSet(aPattern, FC_LANG, 0, &langset) != FcResultMatch) {
     314           0 :         return false;
     315             :     }
     316             : 
     317          15 :     if (FcLangSetHasLang(langset, aLang) != FcLangDifferentLang) {
     318          15 :         return true;
     319             :     }
     320           0 :     return false;
     321             : }
     322             : 
     323             : bool
     324           0 : gfxFontconfigFontEntry::SupportsLangGroup(nsIAtom *aLangGroup) const
     325             : {
     326           0 :     if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
     327           0 :         return true;
     328             :     }
     329             : 
     330           0 :     nsAutoCString fcLang;
     331           0 :     gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
     332           0 :     pfl->GetSampleLangForGroup(aLangGroup, fcLang);
     333           0 :     if (fcLang.IsEmpty()) {
     334           0 :         return true;
     335             :     }
     336             : 
     337             :     // is lang included in the underlying pattern?
     338           0 :     return PatternHasLang(mFontPattern, ToFcChar8Ptr(fcLang.get()));
     339             : }
     340             : 
     341             : nsresult
     342           0 : gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
     343             : {
     344             :     // attempt this once, if errors occur leave a blank cmap
     345           0 :     if (mCharacterMap) {
     346           0 :         return NS_OK;
     347             :     }
     348             : 
     349           0 :     RefPtr<gfxCharacterMap> charmap;
     350             :     nsresult rv;
     351           0 :     bool symbolFont = false; // currently ignored
     352             : 
     353           0 :     if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
     354             :                                                         mUVSOffset,
     355           0 :                                                         symbolFont))) {
     356           0 :         rv = NS_OK;
     357             :     } else {
     358           0 :         uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
     359           0 :         charmap = new gfxCharacterMap();
     360           0 :         AutoTable cmapTable(this, kCMAP);
     361             : 
     362           0 :         if (cmapTable) {
     363           0 :             bool unicodeFont = false; // currently ignored
     364             :             uint32_t cmapLen;
     365             :             const uint8_t* cmapData =
     366           0 :                 reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
     367           0 :                                                                   &cmapLen));
     368           0 :             rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
     369           0 :                                         *charmap, mUVSOffset,
     370           0 :                                         unicodeFont, symbolFont);
     371             :         } else {
     372           0 :             rv = NS_ERROR_NOT_AVAILABLE;
     373             :         }
     374             :     }
     375             : 
     376           0 :     mHasCmapTable = NS_SUCCEEDED(rv);
     377           0 :     if (mHasCmapTable) {
     378           0 :         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
     379           0 :         mCharacterMap = pfl->FindCharMap(charmap);
     380             :     } else {
     381             :         // if error occurred, initialize to null cmap
     382           0 :         mCharacterMap = new gfxCharacterMap();
     383             :     }
     384             : 
     385           0 :     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %" PRIuSIZE " hash: %8.8x%s\n",
     386             :                   NS_ConvertUTF16toUTF8(mName).get(),
     387             :                   charmap->SizeOfIncludingThis(moz_malloc_size_of),
     388             :                   charmap->mHash, mCharacterMap == charmap ? " new" : ""));
     389           0 :     if (LOG_CMAPDATA_ENABLED()) {
     390             :         char prefix[256];
     391           0 :         SprintfLiteral(prefix, "(cmapdata) name: %.220s",
     392           0 :                        NS_ConvertUTF16toUTF8(mName).get());
     393           0 :         charmap->Dump(prefix, eGfxLog_cmapdata);
     394             :     }
     395             : 
     396           0 :     return rv;
     397             : }
     398             : 
     399             : static bool
     400         860 : HasChar(FcPattern *aFont, FcChar32 aCh)
     401             : {
     402         860 :     FcCharSet *charset = nullptr;
     403         860 :     FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
     404         860 :     return charset && FcCharSetHasChar(charset, aCh);
     405             : }
     406             : 
     407             : bool
     408         860 : gfxFontconfigFontEntry::TestCharacterMap(uint32_t aCh)
     409             : {
     410             :     // For user fonts, or for fonts bundled with the app (which might include
     411             :     // color/svg glyphs where the default glyphs may be blank, and thus confuse
     412             :     // fontconfig/freetype's char map checking), we instead check the cmap
     413             :     // directly for character coverage.
     414         860 :     if (mIgnoreFcCharmap) {
     415             :         // If it does not actually have a cmap, switch our strategy to use
     416             :         // fontconfig's charmap after all (except for data fonts, which must
     417             :         // always have a cmap to have passed OTS validation).
     418           0 :         if (!mIsDataUserFont && !HasFontTable(TRUETYPE_TAG('c','m','a','p'))) {
     419           0 :             mIgnoreFcCharmap = false;
     420             :             // ...and continue with HasChar() below.
     421             :         } else {
     422           0 :             return gfxFontEntry::TestCharacterMap(aCh);
     423             :         }
     424             :     }
     425             :     // otherwise (for system fonts), use the charmap in the pattern
     426         860 :     return HasChar(mFontPattern, aCh);
     427             : }
     428             : 
     429             : hb_blob_t*
     430          22 : gfxFontconfigFontEntry::GetFontTable(uint32_t aTableTag)
     431             : {
     432             :     // for data fonts, read directly from the font data
     433          22 :     if (mFontData) {
     434           0 :         return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag);
     435             :     }
     436             : 
     437          22 :     return gfxFontEntry::GetFontTable(aTableTag);
     438             : }
     439             : 
     440             : void
     441           2 : gfxFontconfigFontEntry::MaybeReleaseFTFace()
     442             : {
     443             :     // don't release if either HB or Gr face still exists
     444           2 :     if (mHBFace || mGrFace) {
     445           0 :         return;
     446             :     }
     447             :     // only close out FT_Face for system fonts, not for data fonts
     448           2 :     if (!mIsDataUserFont) {
     449           2 :         if (mFTFace) {
     450           2 :             Factory::ReleaseFTFace(mFTFace);
     451           2 :             mFTFace = nullptr;
     452             :         }
     453           2 :         mFTFaceInitialized = false;
     454             :     }
     455             : }
     456             : 
     457             : void
     458           2 : gfxFontconfigFontEntry::ForgetHBFace()
     459             : {
     460           2 :     gfxFontEntry::ForgetHBFace();
     461           2 :     MaybeReleaseFTFace();
     462           2 : }
     463             : 
     464             : void
     465           0 : gfxFontconfigFontEntry::ReleaseGrFace(gr_face* aFace)
     466             : {
     467           0 :     gfxFontEntry::ReleaseGrFace(aFace);
     468           0 :     MaybeReleaseFTFace();
     469           0 : }
     470             : 
     471             : double
     472           0 : gfxFontconfigFontEntry::GetAspect()
     473             : {
     474           0 :     if (mAspect != 0.0) {
     475           0 :         return mAspect;
     476             :     }
     477             : 
     478             :     // try to compute aspect from OS/2 metrics if available
     479           0 :     AutoTable os2Table(this, TRUETYPE_TAG('O','S','/','2'));
     480           0 :     if (os2Table) {
     481           0 :         uint16_t upem = UnitsPerEm();
     482           0 :         if (upem != kInvalidUPEM) {
     483             :             uint32_t len;
     484             :             auto os2 = reinterpret_cast<const OS2Table*>
     485           0 :                 (hb_blob_get_data(os2Table, &len));
     486           0 :             if (uint16_t(os2->version) >= 2) {
     487           0 :                 if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
     488           0 :                     int16_t(os2->sxHeight) > 0.1 * upem) {
     489           0 :                     mAspect = double(int16_t(os2->sxHeight)) / upem;
     490           0 :                     return mAspect;
     491             :                 }
     492             :             }
     493             :         }
     494             :     }
     495             : 
     496             :     // default to aspect = 0.5 if the code below fails
     497           0 :     mAspect = 0.5;
     498             : 
     499             :     // create a font to calculate x-height / em-height
     500           0 :     gfxFontStyle s;
     501           0 :     s.size = 100.0; // pick large size to avoid possible hinting artifacts
     502           0 :     RefPtr<gfxFont> font = FindOrMakeFont(&s, false);
     503           0 :     if (font) {
     504             :         const gfxFont::Metrics& metrics =
     505           0 :             font->GetMetrics(gfxFont::eHorizontal);
     506             : 
     507             :         // The factor of 0.1 ensures that xHeight is sane so fonts don't
     508             :         // become huge.  Strictly ">" ensures that xHeight and emHeight are
     509             :         // not both zero.
     510           0 :         if (metrics.xHeight > 0.1 * metrics.emHeight) {
     511           0 :             mAspect = metrics.xHeight / metrics.emHeight;
     512             :         }
     513             :     }
     514             : 
     515           0 :     return mAspect;
     516             : }
     517             : 
     518             : static void
     519           8 : PrepareFontOptions(FcPattern* aPattern,
     520             :                    cairo_font_options_t* aFontOptions)
     521             : {
     522           8 :     NS_ASSERTION(aFontOptions, "null font options passed to PrepareFontOptions");
     523             : 
     524             :     // xxx - taken from the gfxFontconfigFonts code, needs to be reviewed
     525             : 
     526             :     FcBool printing;
     527           8 :     if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) !=
     528             :             FcResultMatch) {
     529           8 :         printing = FcFalse;
     530             :     }
     531             : 
     532             :     // Font options are set explicitly here to improve cairo's caching
     533             :     // behavior and to record the relevant parts of the pattern for
     534             :     // SetupCairoFont (so that the pattern can be released).
     535             :     //
     536             :     // Most font_options have already been set as defaults on the FcPattern
     537             :     // with cairo_ft_font_options_substitute(), then user and system
     538             :     // fontconfig configurations were applied.  The resulting font_options
     539             :     // have been recorded on the face during
     540             :     // cairo_ft_font_face_create_for_pattern().
     541             :     //
     542             :     // None of the settings here cause this scaled_font to behave any
     543             :     // differently from how it would behave if it were created from the same
     544             :     // face with default font_options.
     545             :     //
     546             :     // We set options explicitly so that the same scaled_font will be found in
     547             :     // the cairo_scaled_font_map when cairo loads glyphs from a context with
     548             :     // the same font_face, font_matrix, ctm, and surface font_options.
     549             :     //
     550             :     // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
     551             :     // font_options on the cairo_ft_font_face, and doesn't consider default
     552             :     // option values to not match any explicit values.
     553             :     //
     554             :     // Even after cairo_set_scaled_font is used to set font_options for the
     555             :     // cairo context, when cairo looks for a scaled_font for the context, it
     556             :     // will look for a font with some option values from the target surface if
     557             :     // any values are left default on the context font_options.  If this
     558             :     // scaled_font is created with default font_options, cairo will not find
     559             :     // it.
     560             :     //
     561             :     // The one option not recorded in the pattern is hint_metrics, which will
     562             :     // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
     563             :     // We should be considering the font_options of the surface on which this
     564             :     // font will be used, but currently we don't have different gfxFonts for
     565             :     // different surface font_options, so we'll create a font suitable for the
     566             :     // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
     567           8 :     if (printing) {
     568           0 :         cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
     569             :     } else {
     570           8 :         cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
     571             :     }
     572             : 
     573             :     // The remaining options have been recorded on the pattern and the face.
     574             :     // _cairo_ft_options_merge has some logic to decide which options from the
     575             :     // scaled_font or from the cairo_ft_font_face take priority in the way the
     576             :     // font behaves.
     577             :     //
     578             :     // In the majority of cases, _cairo_ft_options_merge uses the options from
     579             :     // the cairo_ft_font_face, so sometimes it is not so important which
     580             :     // values are set here so long as they are not defaults, but we'll set
     581             :     // them to the exact values that we expect from the font, to be consistent
     582             :     // and to protect against changes in cairo.
     583             :     //
     584             :     // In some cases, _cairo_ft_options_merge uses some options from the
     585             :     // scaled_font's font_options rather than options on the
     586             :     // cairo_ft_font_face (from fontconfig).
     587             :     // https://bugs.freedesktop.org/show_bug.cgi?id=11838
     588             :     //
     589             :     // Surface font options were set on the pattern in
     590             :     // cairo_ft_font_options_substitute.  If fontconfig has changed the
     591             :     // hint_style then that is what the user (or distribution) wants, so we
     592             :     // use the setting from the FcPattern.
     593             :     //
     594             :     // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
     595           8 :     FcBool hinting = FcFalse;
     596           8 :     if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
     597           0 :         hinting = FcTrue;
     598             :     }
     599             : 
     600             :     cairo_hint_style_t hint_style;
     601           8 :     if (printing || !hinting) {
     602           0 :         hint_style = CAIRO_HINT_STYLE_NONE;
     603             :     } else {
     604             :         int fc_hintstyle;
     605           8 :         if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
     606             :                                 0, &fc_hintstyle) != FcResultMatch) {
     607           0 :             fc_hintstyle = FC_HINT_FULL;
     608             :         }
     609           8 :         switch (fc_hintstyle) {
     610             :             case FC_HINT_NONE:
     611           0 :                 hint_style = CAIRO_HINT_STYLE_NONE;
     612           0 :                 break;
     613             :             case FC_HINT_SLIGHT:
     614           8 :                 hint_style = CAIRO_HINT_STYLE_SLIGHT;
     615           8 :                 break;
     616             :             case FC_HINT_MEDIUM:
     617             :             default: // This fallback mirrors _get_pattern_ft_options in cairo.
     618           0 :                 hint_style = CAIRO_HINT_STYLE_MEDIUM;
     619           0 :                 break;
     620             :             case FC_HINT_FULL:
     621           0 :                 hint_style = CAIRO_HINT_STYLE_FULL;
     622           0 :                 break;
     623             :         }
     624             :     }
     625           8 :     cairo_font_options_set_hint_style(aFontOptions, hint_style);
     626             : 
     627             :     int rgba;
     628           8 :     if (FcPatternGetInteger(aPattern,
     629             :                             FC_RGBA, 0, &rgba) != FcResultMatch) {
     630           0 :         rgba = FC_RGBA_UNKNOWN;
     631             :     }
     632           8 :     cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
     633           8 :     switch (rgba) {
     634             :         case FC_RGBA_UNKNOWN:
     635             :         case FC_RGBA_NONE:
     636             :         default:
     637             :             // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
     638             :             // is disabled through cairo_antialias_t.
     639           0 :             rgba = FC_RGBA_NONE;
     640             :             // subpixel_order won't be used by the font as we won't use
     641             :             // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
     642             :             // caching reasons described above.  Fall through:
     643             :             MOZ_FALLTHROUGH;
     644             :         case FC_RGBA_RGB:
     645           8 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
     646           8 :             break;
     647             :         case FC_RGBA_BGR:
     648           0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
     649           0 :             break;
     650             :         case FC_RGBA_VRGB:
     651           0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
     652           0 :             break;
     653             :         case FC_RGBA_VBGR:
     654           0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
     655           0 :             break;
     656             :     }
     657           8 :     cairo_font_options_set_subpixel_order(aFontOptions, subpixel_order);
     658             : 
     659             :     FcBool fc_antialias;
     660           8 :     if (FcPatternGetBool(aPattern,
     661             :                          FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
     662           0 :         fc_antialias = FcTrue;
     663             :     }
     664             :     cairo_antialias_t antialias;
     665           8 :     if (!fc_antialias) {
     666           0 :         antialias = CAIRO_ANTIALIAS_NONE;
     667           8 :     } else if (rgba == FC_RGBA_NONE) {
     668           0 :         antialias = CAIRO_ANTIALIAS_GRAY;
     669             :     } else {
     670           8 :         antialias = CAIRO_ANTIALIAS_SUBPIXEL;
     671             :     }
     672           8 :     cairo_font_options_set_antialias(aFontOptions, antialias);
     673           8 : }
     674             : 
     675             : static void
     676           0 : ReleaseFTUserFontData(void* aData)
     677             : {
     678           0 :   static_cast<FTUserFontData*>(aData)->Release();
     679           0 : }
     680             : 
     681             : cairo_scaled_font_t*
     682           8 : gfxFontconfigFontEntry::CreateScaledFont(FcPattern* aRenderPattern,
     683             :                                          gfxFloat aAdjustedSize,
     684             :                                          const gfxFontStyle *aStyle,
     685             :                                          bool aNeedsBold)
     686             : {
     687           8 :     if (aNeedsBold) {
     688           0 :         FcPatternAddBool(aRenderPattern, FC_EMBOLDEN, FcTrue);
     689             :     }
     690             : 
     691             :     // synthetic oblique by skewing via the font matrix
     692          16 :     bool needsOblique = IsUpright() &&
     693           8 :                         aStyle->style != NS_FONT_STYLE_NORMAL &&
     694           8 :                         aStyle->allowSyntheticStyle;
     695             : 
     696           8 :     if (needsOblique) {
     697             :         // disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
     698           0 :         FcPatternDel(aRenderPattern, FC_EMBEDDED_BITMAP);
     699           0 :         FcPatternAddBool(aRenderPattern, FC_EMBEDDED_BITMAP, FcFalse);
     700             :     }
     701             : 
     702             :     cairo_font_face_t *face =
     703           8 :         cairo_ft_font_face_create_for_pattern(aRenderPattern);
     704             : 
     705           8 :     if (mFontData) {
     706             :         // for data fonts, add the face/data pointer to the cairo font face
     707             :         // so that it gets deleted whenever cairo decides
     708           0 :         NS_ASSERTION(mFTFace, "FT_Face is null when setting user data");
     709           0 :         NS_ASSERTION(mUserFontData, "user font data is null when setting user data");
     710           0 :         if (cairo_font_face_set_user_data(face,
     711             :                                           &sFcFontlistUserFontDataKey,
     712             :                                           mUserFontData,
     713           0 :                                           ReleaseFTUserFontData) != CAIRO_STATUS_SUCCESS) {
     714           0 :             NS_WARNING("Failed binding FTUserFontData to Cairo font face");
     715           0 :             cairo_font_face_destroy(face);
     716           0 :             return nullptr;
     717             :         }
     718           0 :         mUserFontData.get()->AddRef();
     719             :     }
     720             : 
     721           8 :     cairo_scaled_font_t *scaledFont = nullptr;
     722             : 
     723             :     cairo_matrix_t sizeMatrix;
     724             :     cairo_matrix_t identityMatrix;
     725             : 
     726           8 :     cairo_matrix_init_scale(&sizeMatrix, aAdjustedSize, aAdjustedSize);
     727           8 :     cairo_matrix_init_identity(&identityMatrix);
     728             : 
     729           8 :     if (needsOblique) {
     730           0 :         const double kSkewFactor = OBLIQUE_SKEW_FACTOR;
     731             : 
     732             :         cairo_matrix_t style;
     733             :         cairo_matrix_init(&style,
     734             :                           1,                //xx
     735             :                           0,                //yx
     736             :                           -1 * kSkewFactor,  //xy
     737             :                           1,                //yy
     738             :                           0,                //x0
     739           0 :                           0);               //y0
     740           0 :         cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
     741             :     }
     742             : 
     743           8 :     cairo_font_options_t *fontOptions = cairo_font_options_create();
     744           8 :     PrepareFontOptions(aRenderPattern, fontOptions);
     745             : 
     746             :     scaledFont = cairo_scaled_font_create(face, &sizeMatrix,
     747           8 :                                           &identityMatrix, fontOptions);
     748           8 :     cairo_font_options_destroy(fontOptions);
     749             : 
     750           8 :     NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
     751             :                  "Failed to make scaled font");
     752             : 
     753           8 :     cairo_font_face_destroy(face);
     754             : 
     755           8 :     return scaledFont;
     756             : }
     757             : 
     758             : #ifdef MOZ_WIDGET_GTK
     759             : // defintion included below
     760             : static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
     761             : #endif
     762             : 
     763             : #ifdef MOZ_X11
     764             : static bool
     765           0 : GetXftInt(Display* aDisplay, const char* aName, int* aResult)
     766             : {
     767           0 :     if (!aDisplay) {
     768           0 :         return false;
     769             :     }
     770           0 :     char* value = XGetDefault(aDisplay, "Xft", aName);
     771           0 :     if (!value) {
     772           0 :         return false;
     773             :     }
     774           0 :     if (FcNameConstant(const_cast<FcChar8*>(ToFcChar8Ptr(value)), aResult)) {
     775           0 :         return true;
     776             :     }
     777             :     char* end;
     778           0 :     *aResult = strtol(value, &end, 0);
     779           0 :     if (end != value) {
     780           0 :         return true;
     781             :     }
     782           0 :     return false;
     783             : }
     784             : #endif
     785             : 
     786             : static void
     787           8 : PreparePattern(FcPattern* aPattern, bool aIsPrinterFont)
     788             : {
     789           8 :     FcConfigSubstitute(nullptr, aPattern, FcMatchPattern);
     790             : 
     791             :     // This gets cairo_font_options_t for the Screen.  We should have
     792             :     // different font options for printing (no hinting) but we are not told
     793             :     // what we are measuring for.
     794             :     //
     795             :     // If cairo adds support for lcd_filter, gdk will not provide the default
     796             :     // setting for that option.  We could get the default setting by creating
     797             :     // an xlib surface once, recording its font_options, and then merging the
     798             :     // gdk options.
     799             :     //
     800             :     // Using an xlib surface would also be an option to get Screen font
     801             :     // options for non-GTK X11 toolkits, but less efficient than using GDK to
     802             :     // pick up dynamic changes.
     803           8 :     if(aIsPrinterFont) {
     804           0 :        cairo_font_options_t *options = cairo_font_options_create();
     805           0 :        cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
     806           0 :        cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
     807           0 :        cairo_ft_font_options_substitute(options, aPattern);
     808           0 :        cairo_font_options_destroy(options);
     809           0 :        FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue);
     810           8 :     } else if (!gfxPlatform::IsHeadless()) {
     811             : #ifdef MOZ_WIDGET_GTK
     812           8 :         ApplyGdkScreenFontOptions(aPattern);
     813             : 
     814             : #ifdef MOZ_X11
     815             :         FcValue value;
     816             :         int lcdfilter;
     817           8 :         if (FcPatternGet(aPattern, FC_LCD_FILTER, 0, &value) == FcResultNoMatch) {
     818           0 :             GdkDisplay* dpy = gdk_display_get_default();
     819           0 :             if (GDK_IS_X11_DISPLAY(dpy) &&
     820           0 :                 GetXftInt(GDK_DISPLAY_XDISPLAY(dpy), "lcdfilter", &lcdfilter)) {
     821           0 :                 FcPatternAddInteger(aPattern, FC_LCD_FILTER, lcdfilter);
     822             :             }
     823             :         }
     824             : #endif // MOZ_X11
     825             : #endif // MOZ_WIDGET_GTK
     826             :     }
     827             : 
     828           8 :     FcDefaultSubstitute(aPattern);
     829           8 : }
     830             : 
     831             : void
     832           8 : gfxFontconfigFontEntry::UnscaledFontCache::MoveToFront(size_t aIndex) {
     833           8 :     if (aIndex > 0) {
     834             :         WeakPtr<UnscaledFont> front =
     835          12 :             Move(mUnscaledFonts[aIndex]);
     836          18 :         for (size_t i = aIndex; i > 0; i--) {
     837          12 :             mUnscaledFonts[i] = Move(mUnscaledFonts[i-1]);
     838             :         }
     839           6 :         mUnscaledFonts[0] = Move(front);
     840             :     }
     841           8 : }
     842             : 
     843             : already_AddRefed<UnscaledFontFontconfig>
     844           8 : gfxFontconfigFontEntry::UnscaledFontCache::Lookup(const char* aFile, uint32_t aIndex) {
     845          26 :     for (size_t i = 0; i < kNumEntries; i++) {
     846             :         UnscaledFontFontconfig* entry =
     847          20 :             static_cast<UnscaledFontFontconfig*>(mUnscaledFonts[i].get());
     848          22 :         if (entry &&
     849          22 :             !strcmp(entry->GetFile(), aFile) &&
     850           2 :             entry->GetIndex() == aIndex) {
     851           2 :             MoveToFront(i);
     852           2 :             return do_AddRef(entry);
     853             :         }
     854             :     }
     855           6 :     return nullptr;
     856             : }
     857             : 
     858             : static inline gfxFloat
     859           8 : SizeForStyle(gfxFontconfigFontEntry* aEntry, const gfxFontStyle& aStyle)
     860             : {
     861           8 :     return aStyle.sizeAdjust >= 0.0 ?
     862           0 :                 aStyle.GetAdjustedSize(aEntry->GetAspect()) :
     863           8 :                 aStyle.size;
     864             : }
     865             : 
     866             : static double
     867           8 : ChooseFontSize(gfxFontconfigFontEntry* aEntry,
     868             :                const gfxFontStyle& aStyle)
     869             : {
     870           8 :     double requestedSize = SizeForStyle(aEntry, aStyle);
     871           8 :     double bestDist = -1.0;
     872           8 :     double bestSize = requestedSize;
     873             :     double size;
     874           8 :     int v = 0;
     875           8 :     while (FcPatternGetDouble(aEntry->GetPattern(),
     876             :                               FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
     877           0 :         ++v;
     878           0 :         double dist = fabs(size - requestedSize);
     879           0 :         if (bestDist < 0.0 || dist < bestDist) {
     880           0 :             bestDist = dist;
     881           0 :             bestSize = size;
     882             :         }
     883             :     }
     884             :     // If the font has bitmaps but wants to be scaled, then let it scale.
     885           8 :     if (bestSize >= 0.0) {
     886             :         FcBool scalable;
     887          16 :         if (FcPatternGetBool(aEntry->GetPattern(),
     888          16 :                              FC_SCALABLE, 0, &scalable) == FcResultMatch &&
     889           8 :             scalable) {
     890           8 :             return requestedSize;
     891             :         }
     892             :     }
     893           0 :     return bestSize;
     894             : }
     895             : 
     896             : gfxFont*
     897           8 : gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle,
     898             :                                            bool aNeedsBold)
     899             : {
     900          16 :     nsAutoRef<FcPattern> pattern(FcPatternCreate());
     901           8 :     if (!pattern) {
     902           0 :         NS_WARNING("Failed to create Fontconfig pattern for font instance");
     903           0 :         return nullptr;
     904             :     }
     905             : 
     906           8 :     double size = ChooseFontSize(this, *aFontStyle);
     907           8 :     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
     908             : 
     909           8 :     PreparePattern(pattern, aFontStyle->printerFont);
     910             :     nsAutoRef<FcPattern> renderPattern
     911          16 :         (FcFontRenderPrepare(nullptr, pattern, mFontPattern));
     912           8 :     if (!renderPattern) {
     913           0 :         NS_WARNING("Failed to prepare Fontconfig pattern for font instance");
     914           0 :         return nullptr;
     915             :     }
     916             : 
     917             :     cairo_scaled_font_t* scaledFont =
     918           8 :         CreateScaledFont(renderPattern, size, aFontStyle, aNeedsBold);
     919             : 
     920           8 :     const FcChar8* file = ToFcChar8Ptr("");
     921           8 :     int index = 0;
     922           8 :     if (!mFontData) {
     923          16 :         if (FcPatternGetString(renderPattern, FC_FILE, 0,
     924          24 :                                const_cast<FcChar8**>(&file)) != FcResultMatch ||
     925           8 :             FcPatternGetInteger(renderPattern, FC_INDEX, 0, &index) != FcResultMatch) {
     926           0 :             NS_WARNING("No file in Fontconfig pattern for font instance");
     927           0 :             return nullptr;
     928             :         }
     929             :     }
     930             : 
     931             :     RefPtr<UnscaledFontFontconfig> unscaledFont =
     932          16 :         mUnscaledFontCache.Lookup(ToCharPtr(file), index);
     933           8 :     if (!unscaledFont) {
     934             :         unscaledFont =
     935           6 :             mFontData ?
     936           0 :                 new UnscaledFontFontconfig(mFTFace) :
     937          12 :                 new UnscaledFontFontconfig(ToCharPtr(file), index);
     938           6 :         mUnscaledFontCache.Add(unscaledFont);
     939             :     }
     940             : 
     941             :     gfxFont* newFont =
     942             :         new gfxFontconfigFont(unscaledFont, scaledFont,
     943             :                               renderPattern, size,
     944          16 :                               this, aFontStyle, aNeedsBold);
     945           8 :     cairo_scaled_font_destroy(scaledFont);
     946             : 
     947           8 :     return newFont;
     948             : }
     949             : 
     950             : nsresult
     951          21 : gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag,
     952             :                                       nsTArray<uint8_t>& aBuffer)
     953             : {
     954          21 :     NS_ASSERTION(!mIsDataUserFont,
     955             :                  "data fonts should be reading tables directly from memory");
     956             : 
     957          21 :     if (!mFTFaceInitialized) {
     958           4 :         mFTFaceInitialized = true;
     959             :         FcChar8 *filename;
     960           4 :         if (FcPatternGetString(mFontPattern, FC_FILE, 0, &filename) != FcResultMatch) {
     961           0 :             return NS_ERROR_FAILURE;
     962             :         }
     963             :         int index;
     964           4 :         if (FcPatternGetInteger(mFontPattern, FC_INDEX, 0, &index) != FcResultMatch) {
     965           0 :             index = 0; // default to 0 if not found in pattern
     966             :         }
     967           4 :         mFTFace = Factory::NewFTFace(nullptr, ToCharPtr(filename), index);
     968           4 :         if (!mFTFace) {
     969           0 :             return NS_ERROR_FAILURE;
     970             :         }
     971             :     }
     972             : 
     973          21 :     if (!mFTFace) {
     974           0 :         return NS_ERROR_NOT_AVAILABLE;
     975             :     }
     976             : 
     977          21 :     FT_ULong length = 0;
     978          21 :     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
     979           7 :         return NS_ERROR_NOT_AVAILABLE;
     980             :     }
     981          14 :     if (!aBuffer.SetLength(length, fallible)) {
     982           0 :         return NS_ERROR_OUT_OF_MEMORY;
     983             :     }
     984          14 :     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
     985           0 :         aBuffer.Clear();
     986           0 :         return NS_ERROR_FAILURE;
     987             :     }
     988             : 
     989          14 :     return NS_OK;
     990             : }
     991             : 
     992             : void
     993          16 : gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
     994             : {
     995          16 :     if (mHasStyles) {
     996           0 :         return;
     997             :     }
     998             : 
     999             :     // add font entries for each of the faces
    1000          16 :     uint32_t numFonts = mFontPatterns.Length();
    1001          16 :     NS_ASSERTION(numFonts, "font family containing no faces!!");
    1002          16 :     uint32_t numRegularFaces = 0;
    1003         123 :     for (uint32_t i = 0; i < numFonts; i++) {
    1004         107 :         FcPattern* face = mFontPatterns[i];
    1005             : 
    1006             :         // figure out the psname/fullname and choose which to use as the facename
    1007         214 :         nsAutoString psname, fullname;
    1008         107 :         GetFaceNames(face, mName, psname, fullname);
    1009         107 :         const nsAutoString& faceName = !psname.IsEmpty() ? psname : fullname;
    1010             : 
    1011             :         gfxFontconfigFontEntry *fontEntry =
    1012         107 :             new gfxFontconfigFontEntry(faceName, face, mContainsAppFonts);
    1013         107 :         AddFontEntry(fontEntry);
    1014             : 
    1015         271 :         if (fontEntry->IsUpright() &&
    1016         133 :             fontEntry->Weight() == NS_FONT_WEIGHT_NORMAL &&
    1017          26 :             fontEntry->Stretch() == NS_FONT_STRETCH_NORMAL) {
    1018          21 :             numRegularFaces++;
    1019             :         }
    1020             : 
    1021         107 :         if (LOG_FONTLIST_ENABLED()) {
    1022           0 :             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
    1023             :                  " with style: %s weight: %d stretch: %d"
    1024             :                  " psname: %s fullname: %s",
    1025             :                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
    1026             :                  NS_ConvertUTF16toUTF8(Name()).get(),
    1027             :                  (fontEntry->IsItalic()) ?
    1028             :                   "italic" : (fontEntry->IsOblique() ? "oblique" : "normal"),
    1029             :                  fontEntry->Weight(), fontEntry->Stretch(),
    1030             :                  NS_ConvertUTF16toUTF8(psname).get(),
    1031             :                  NS_ConvertUTF16toUTF8(fullname).get()));
    1032             :         }
    1033             :     }
    1034             : 
    1035             :     // somewhat arbitrary, but define a family with two or more regular
    1036             :     // faces as a family for which intra-family fallback should be used
    1037          16 :     if (numRegularFaces > 1) {
    1038           5 :         mCheckForFallbackFaces = true;
    1039             :     }
    1040          16 :     mFaceNamesInitialized = true;
    1041          16 :     mFontPatterns.Clear();
    1042          16 :     SetHasStyles(true);
    1043             : }
    1044             : 
    1045             : void
    1046        1698 : gfxFontconfigFontFamily::AddFontPattern(FcPattern* aFontPattern)
    1047             : {
    1048        1698 :     NS_ASSERTION(!mHasStyles,
    1049             :                  "font patterns must not be added to already enumerated families");
    1050             : 
    1051             :     FcBool outline;
    1052        3396 :     if (FcPatternGetBool(aFontPattern, FC_OUTLINE, 0, &outline) != FcResultMatch ||
    1053        1698 :         !outline) {
    1054           0 :         mHasNonScalableFaces = true;
    1055             : 
    1056             :         FcBool scalable;
    1057           0 :         if (FcPatternGetBool(aFontPattern, FC_SCALABLE, 0, &scalable) == FcResultMatch &&
    1058           0 :             scalable) {
    1059           0 :             mForceScalable = true;
    1060             :         }
    1061             :     }
    1062             : 
    1063        3396 :     nsCountedRef<FcPattern> pattern(aFontPattern);
    1064        1698 :     mFontPatterns.AppendElement(pattern);
    1065        1698 : }
    1066             : 
    1067             : static const double kRejectDistance = 10000.0;
    1068             : 
    1069             : // Calculate a distance score representing the size disparity between the
    1070             : // requested style's size and the font entry's size.
    1071             : static double
    1072           0 : SizeDistance(gfxFontconfigFontEntry* aEntry,
    1073             :              const gfxFontStyle& aStyle,
    1074             :              bool aForceScalable)
    1075             : {
    1076           0 :     double requestedSize = SizeForStyle(aEntry, aStyle);
    1077           0 :     double bestDist = -1.0;
    1078             :     double size;
    1079           0 :     int v = 0;
    1080           0 :     while (FcPatternGetDouble(aEntry->GetPattern(),
    1081             :                               FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
    1082           0 :         ++v;
    1083           0 :         double dist = fabs(size - requestedSize);
    1084           0 :         if (bestDist < 0.0 || dist < bestDist) {
    1085           0 :             bestDist = dist;
    1086             :         }
    1087             :     }
    1088           0 :     if (bestDist < 0.0) {
    1089             :         // No size means scalable
    1090           0 :         return -1.0;
    1091           0 :     } else if (aForceScalable || 5.0 * bestDist < requestedSize) {
    1092             :         // fontconfig prefers a matching family or lang to pixelsize of bitmap
    1093             :         // fonts. CSS suggests a tolerance of 20% on pixelsize.
    1094           0 :         return bestDist;
    1095             :     } else {
    1096             :         // Reject any non-scalable fonts that are not within tolerance.
    1097           0 :         return kRejectDistance;
    1098             :     }
    1099             : }
    1100             : 
    1101             : void
    1102          19 : gfxFontconfigFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
    1103             :                                               nsTArray<gfxFontEntry*>& aFontEntryList,
    1104             :                                               bool& aNeedsSyntheticBold)
    1105             : {
    1106          19 :     gfxFontFamily::FindAllFontsForStyle(aFontStyle,
    1107             :                                         aFontEntryList,
    1108          19 :                                         aNeedsSyntheticBold);
    1109             : 
    1110          19 :     if (!mHasNonScalableFaces) {
    1111          19 :         return;
    1112             :     }
    1113             : 
    1114             :     // Iterate over the the available fonts while compacting any groups
    1115             :     // of unscalable fonts with matching styles into a single entry
    1116             :     // corresponding to the closest available size. If the closest
    1117             :     // available size is rejected for being outside tolernace, then the
    1118             :     // entire group will be skipped.
    1119           0 :     size_t skipped = 0;
    1120           0 :     gfxFontconfigFontEntry* bestEntry = nullptr;
    1121           0 :     double bestDist = -1.0;
    1122           0 :     for (size_t i = 0; i < aFontEntryList.Length(); i++) {
    1123             :         gfxFontconfigFontEntry* entry =
    1124           0 :             static_cast<gfxFontconfigFontEntry*>(aFontEntryList[i]);
    1125           0 :         double dist = SizeDistance(entry, aFontStyle, mForceScalable);
    1126             :         // If the entry is scalable or has a style that does not match
    1127             :         // the group of unscalable fonts, then start a new group.
    1128           0 :         if (dist < 0.0 ||
    1129           0 :             !bestEntry ||
    1130           0 :             bestEntry->Stretch() != entry->Stretch() ||
    1131           0 :             bestEntry->Weight() != entry->Weight() ||
    1132           0 :             bestEntry->mStyle != entry->mStyle) {
    1133             :             // If the best entry in this group is still outside the tolerance,
    1134             :             // then skip the entire group.
    1135           0 :             if (bestDist >= kRejectDistance) {
    1136           0 :                 skipped++;
    1137             :             }
    1138             :             // Remove any compacted entries from the previous group.
    1139           0 :             if (skipped) {
    1140           0 :                 i -= skipped;
    1141           0 :                 aFontEntryList.RemoveElementsAt(i, skipped);
    1142           0 :                 skipped = 0;
    1143             :             }
    1144             :             // Mark the start of the new group.
    1145           0 :             bestEntry = entry;
    1146           0 :             bestDist = dist;
    1147             :         } else {
    1148             :             // If this entry more closely matches the requested size than the
    1149             :             // current best in the group, then take this entry instead.
    1150           0 :             if (dist < bestDist) {
    1151           0 :                 aFontEntryList[i-1-skipped] = entry;
    1152           0 :                 bestEntry = entry;
    1153           0 :                 bestDist = dist;
    1154             :             }
    1155           0 :             skipped++;
    1156             :         }
    1157             :     }
    1158             :     // If the best entry in this group is still outside the tolerance,
    1159             :     // then skip the entire group.
    1160           0 :     if (bestDist >= kRejectDistance) {
    1161           0 :         skipped++;
    1162             :     }
    1163             :     // Remove any compacted entries from the current group.
    1164           0 :     if (skipped) {
    1165           0 :         aFontEntryList.TruncateLength(aFontEntryList.Length() - skipped);
    1166             :     }
    1167             : }
    1168             : 
    1169             : /* virtual */
    1170           0 : gfxFontconfigFontFamily::~gfxFontconfigFontFamily()
    1171             :  {
    1172             :     // Should not be dropped by stylo
    1173           0 :     MOZ_ASSERT(NS_IsMainThread());
    1174           0 : }
    1175             : 
    1176           8 : gfxFontconfigFont::gfxFontconfigFont(const RefPtr<UnscaledFontFontconfig>& aUnscaledFont,
    1177             :                                      cairo_scaled_font_t *aScaledFont,
    1178             :                                      FcPattern *aPattern,
    1179             :                                      gfxFloat aAdjustedSize,
    1180             :                                      gfxFontEntry *aFontEntry,
    1181             :                                      const gfxFontStyle *aFontStyle,
    1182           8 :                                      bool aNeedsBold) :
    1183           8 :     gfxFontconfigFontBase(aUnscaledFont, aScaledFont, aPattern, aFontEntry, aFontStyle)
    1184             : {
    1185           8 :     mAdjustedSize = aAdjustedSize;
    1186           8 : }
    1187             : 
    1188           0 : gfxFontconfigFont::~gfxFontconfigFont()
    1189             : {
    1190           0 : }
    1191             : 
    1192           3 : gfxFcPlatformFontList::gfxFcPlatformFontList()
    1193             :     : mLocalNames(64)
    1194             :     , mGenericMappings(32)
    1195             :     , mFcSubstituteCache(64)
    1196             :     , mLastConfig(nullptr)
    1197           3 :     , mAlwaysUseFontconfigGenerics(true)
    1198             : {
    1199             :     // if the rescan interval is set, start the timer
    1200           3 :     int rescanInterval = FcConfigGetRescanInterval(nullptr);
    1201           3 :     if (rescanInterval) {
    1202           3 :         mLastConfig = FcConfigGetCurrent();
    1203           3 :         mCheckFontUpdatesTimer = do_CreateInstance("@mozilla.org/timer;1");
    1204           3 :         if (mCheckFontUpdatesTimer) {
    1205           6 :           mCheckFontUpdatesTimer->InitWithNamedFuncCallback(
    1206             :             CheckFontUpdates,
    1207             :             this,
    1208           3 :             (rescanInterval + 1) * 1000,
    1209             :             nsITimer::TYPE_REPEATING_SLACK,
    1210           6 :             "gfxFcPlatformFontList::gfxFcPlatformFontList");
    1211             :         } else {
    1212           0 :             NS_WARNING("Failure to create font updates timer");
    1213             :         }
    1214             :     }
    1215             : 
    1216             : #ifdef MOZ_BUNDLED_FONTS
    1217           3 :     mBundledFontsInitialized = false;
    1218             : #endif
    1219           3 : }
    1220             : 
    1221           0 : gfxFcPlatformFontList::~gfxFcPlatformFontList()
    1222             : {
    1223           0 :     if (mCheckFontUpdatesTimer) {
    1224           0 :         mCheckFontUpdatesTimer->Cancel();
    1225           0 :         mCheckFontUpdatesTimer = nullptr;
    1226             :     }
    1227           0 : }
    1228             : 
    1229             : void
    1230           6 : gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts)
    1231             : {
    1232             :     // This iterates over the fonts in a font set and adds in gfxFontFamily
    1233             :     // objects for each family. The patterns for individual fonts are not
    1234             :     // copied here. When a family is actually used, the fonts in the family
    1235             :     // are enumerated and the patterns copied. Note that we're explicitly
    1236             :     // excluding non-scalable fonts such as X11 bitmap fonts, which
    1237             :     // Chrome Skia/Webkit code does also.
    1238             : 
    1239           6 :     if (!aFontSet) {
    1240           0 :         NS_WARNING("AddFontSetFamilies called with a null font set.");
    1241           0 :         return;
    1242             :     }
    1243             : 
    1244           6 :     FcChar8* lastFamilyName = (FcChar8*)"";
    1245          12 :     RefPtr<gfxFontconfigFontFamily> fontFamily;
    1246          12 :     nsAutoString familyName;
    1247        1704 :     for (int f = 0; f < aFontSet->nfont; f++) {
    1248        1698 :         FcPattern* font = aFontSet->fonts[f];
    1249             : 
    1250             :         // get canonical name
    1251        1698 :         uint32_t cIndex = FindCanonicalNameIndex(font, FC_FAMILYLANG);
    1252        1698 :         FcChar8* canonical = nullptr;
    1253        1698 :         FcPatternGetString(font, FC_FAMILY, cIndex, &canonical);
    1254        1698 :         if (!canonical) {
    1255           0 :             continue;
    1256             :         }
    1257             : 
    1258             :         // same as the last one? no need to add a new family, skip
    1259        1698 :         if (FcStrCmp(canonical, lastFamilyName) != 0) {
    1260         684 :             lastFamilyName = canonical;
    1261             : 
    1262             :             // add new family if one doesn't already exist
    1263         684 :             familyName.Truncate();
    1264         684 :             AppendUTF8toUTF16(ToCharPtr(canonical), familyName);
    1265        1368 :             nsAutoString keyName(familyName);
    1266         684 :             ToLowerCase(keyName);
    1267             : 
    1268             :             fontFamily = static_cast<gfxFontconfigFontFamily*>
    1269         684 :                              (mFontFamilies.GetWeak(keyName));
    1270         684 :             if (!fontFamily) {
    1271         558 :                 fontFamily = new gfxFontconfigFontFamily(familyName);
    1272         558 :                 mFontFamilies.Put(keyName, fontFamily);
    1273             :             }
    1274             :             // Record if the family contains fonts from the app font set
    1275             :             // (in which case we won't rely on fontconfig's charmap, due to
    1276             :             // bug 1276594).
    1277         684 :             if (aAppFonts) {
    1278           3 :                 fontFamily->SetFamilyContainsAppFonts(true);
    1279             :             }
    1280             : 
    1281             :             // Add pointers to other localized family names. Most fonts
    1282             :             // only have a single name, so the first call to GetString
    1283             :             // will usually not match
    1284             :             FcChar8* otherName;
    1285         684 :             int n = (cIndex == 0 ? 1 : 0);
    1286        1008 :             while (FcPatternGetString(font, FC_FAMILY, n, &otherName) == FcResultMatch) {
    1287         324 :                 NS_ConvertUTF8toUTF16 otherFamilyName(ToCharPtr(otherName));
    1288         162 :                 AddOtherFamilyName(fontFamily, otherFamilyName);
    1289         162 :                 n++;
    1290         162 :                 if (n == int(cIndex)) {
    1291           0 :                     n++; // skip over canonical name
    1292             :                 }
    1293             :             }
    1294             :         }
    1295             : 
    1296        1698 :         NS_ASSERTION(fontFamily, "font must belong to a font family");
    1297        1698 :         fontFamily->AddFontPattern(font);
    1298             : 
    1299             :         // map the psname, fullname ==> font family for local font lookups
    1300        3396 :         nsAutoString psname, fullname;
    1301        1698 :         GetFaceNames(font, familyName, psname, fullname);
    1302        1698 :         if (!psname.IsEmpty()) {
    1303        1698 :             ToLowerCase(psname);
    1304        1698 :             mLocalNames.Put(psname, font);
    1305             :         }
    1306        1698 :         if (!fullname.IsEmpty()) {
    1307        1698 :             ToLowerCase(fullname);
    1308        1698 :             mLocalNames.Put(fullname, font);
    1309             :         }
    1310             :     }
    1311             : }
    1312             : 
    1313             : nsresult
    1314           3 : gfxFcPlatformFontList::InitFontListForPlatform()
    1315             : {
    1316           3 :     mLastConfig = FcConfigGetCurrent();
    1317             : 
    1318           3 :     mLocalNames.Clear();
    1319           3 :     mFcSubstituteCache.Clear();
    1320             : 
    1321             :     // iterate over available fonts
    1322           3 :     FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem);
    1323           3 :     AddFontSetFamilies(systemFonts, /* aAppFonts = */ false);
    1324           3 :     mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics();
    1325             : 
    1326             : #ifdef MOZ_BUNDLED_FONTS
    1327           3 :     ActivateBundledFonts();
    1328           3 :     FcFontSet* appFonts = FcConfigGetFonts(nullptr, FcSetApplication);
    1329           3 :     AddFontSetFamilies(appFonts, /* aAppFonts = */ true);
    1330             : #endif
    1331             : 
    1332           3 :     mOtherFamilyNamesInitialized = true;
    1333             : 
    1334           3 :     return NS_OK;
    1335             : }
    1336             : 
    1337             : // For displaying the fontlist in UI, use explicit call to FcFontList. Using
    1338             : // FcFontList results in the list containing the localized names as dictated
    1339             : // by system defaults.
    1340             : static void
    1341           0 : GetSystemFontList(nsTArray<nsString>& aListOfFonts, nsIAtom *aLangGroup)
    1342             : {
    1343           0 :     aListOfFonts.Clear();
    1344             : 
    1345           0 :     nsAutoRef<FcPattern> pat(FcPatternCreate());
    1346           0 :     if (!pat) {
    1347           0 :         return;
    1348             :     }
    1349             : 
    1350           0 :     nsAutoRef<FcObjectSet> os(FcObjectSetBuild(FC_FAMILY, nullptr));
    1351           0 :     if (!os) {
    1352           0 :         return;
    1353             :     }
    1354             : 
    1355             :     // add the lang to the pattern
    1356           0 :     nsAutoCString fcLang;
    1357           0 :     gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
    1358           0 :     pfl->GetSampleLangForGroup(aLangGroup, fcLang);
    1359           0 :     if (!fcLang.IsEmpty()) {
    1360           0 :         FcPatternAddString(pat, FC_LANG, ToFcChar8Ptr(fcLang.get()));
    1361             :     }
    1362             : 
    1363           0 :     nsAutoRef<FcFontSet> fs(FcFontList(nullptr, pat, os));
    1364           0 :     if (!fs) {
    1365           0 :         return;
    1366             :     }
    1367             : 
    1368           0 :     for (int i = 0; i < fs->nfont; i++) {
    1369             :         char *family;
    1370             : 
    1371           0 :         if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0,
    1372             :                                (FcChar8 **) &family) != FcResultMatch)
    1373             :         {
    1374           0 :             continue;
    1375             :         }
    1376             : 
    1377             :         // Remove duplicates...
    1378           0 :         nsAutoString strFamily;
    1379           0 :         AppendUTF8toUTF16(family, strFamily);
    1380           0 :         if (aListOfFonts.Contains(strFamily)) {
    1381           0 :             continue;
    1382             :         }
    1383             : 
    1384           0 :         aListOfFonts.AppendElement(strFamily);
    1385             :     }
    1386             : 
    1387           0 :     aListOfFonts.Sort();
    1388             : }
    1389             : 
    1390             : void
    1391           0 : gfxFcPlatformFontList::GetFontList(nsIAtom *aLangGroup,
    1392             :                                    const nsACString& aGenericFamily,
    1393             :                                    nsTArray<nsString>& aListOfFonts)
    1394             : {
    1395             :     // Get the list of font family names using fontconfig
    1396           0 :     GetSystemFontList(aListOfFonts, aLangGroup);
    1397             : 
    1398             :     // Under Linux, the generics "serif", "sans-serif" and "monospace"
    1399             :     // are included in the pref fontlist. These map to whatever fontconfig
    1400             :     // decides they should be for a given language, rather than one of the
    1401             :     // fonts listed in the prefs font lists (e.g. font.name.*, font.name-list.*)
    1402           0 :     bool serif = false, sansSerif = false, monospace = false;
    1403           0 :     if (aGenericFamily.IsEmpty())
    1404           0 :         serif = sansSerif = monospace = true;
    1405           0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("serif"))
    1406           0 :         serif = true;
    1407           0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif"))
    1408           0 :         sansSerif = true;
    1409           0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("monospace"))
    1410           0 :         monospace = true;
    1411           0 :     else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") ||
    1412           0 :              aGenericFamily.LowerCaseEqualsLiteral("fantasy"))
    1413           0 :         serif = sansSerif = true;
    1414             :     else
    1415           0 :         NS_NOTREACHED("unexpected CSS generic font family");
    1416             : 
    1417             :     // The first in the list becomes the default in
    1418             :     // FontBuilder.readFontSelection() if the preference-selected font is not
    1419             :     // available, so put system configured defaults first.
    1420           0 :     if (monospace)
    1421           0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace"));
    1422           0 :     if (sansSerif)
    1423           0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif"));
    1424           0 :     if (serif)
    1425           0 :         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif"));
    1426           0 : }
    1427             : 
    1428             : gfxFontFamily*
    1429           3 : gfxFcPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
    1430             : {
    1431             :     // Get the default font by using a fake name to retrieve the first
    1432             :     // scalable font that fontconfig suggests for the given language.
    1433             :     PrefFontList* prefFonts =
    1434           3 :         FindGenericFamilies(NS_LITERAL_STRING("-moz-default"), aStyle->language);
    1435           3 :     NS_ASSERTION(prefFonts, "null list of generic fonts");
    1436           3 :     if (prefFonts && !prefFonts->IsEmpty()) {
    1437           3 :         return (*prefFonts)[0];
    1438             :     }
    1439           0 :     return nullptr;
    1440             : }
    1441             : 
    1442             : gfxFontEntry*
    1443           0 : gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
    1444             :                                        uint16_t aWeight,
    1445             :                                        int16_t aStretch,
    1446             :                                        uint8_t aStyle)
    1447             : {
    1448           0 :     nsAutoString keyName(aFontName);
    1449           0 :     ToLowerCase(keyName);
    1450             : 
    1451             :     // if name is not in the global list, done
    1452           0 :     FcPattern* fontPattern = mLocalNames.Get(keyName);
    1453           0 :     if (!fontPattern) {
    1454           0 :         return nullptr;
    1455             :     }
    1456             : 
    1457             :     return new gfxFontconfigFontEntry(aFontName, fontPattern,
    1458           0 :                                       aWeight, aStretch, aStyle);
    1459             : }
    1460             : 
    1461             : gfxFontEntry*
    1462           0 : gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
    1463             :                                         uint16_t aWeight,
    1464             :                                         int16_t aStretch,
    1465             :                                         uint8_t aStyle,
    1466             :                                         const uint8_t* aFontData,
    1467             :                                         uint32_t aLength)
    1468             : {
    1469           0 :     FT_Face face = Factory::NewFTFaceFromData(nullptr, aFontData, aLength, 0);
    1470           0 :     if (!face) {
    1471           0 :         NS_Free((void*)aFontData);
    1472           0 :         return nullptr;
    1473             :     }
    1474           0 :     if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE)) {
    1475           0 :         Factory::ReleaseFTFace(face);
    1476           0 :         NS_Free((void*)aFontData);
    1477           0 :         return nullptr;
    1478             :     }
    1479             : 
    1480             :     return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch,
    1481           0 :                                       aStyle, aFontData, face);
    1482             : }
    1483             : 
    1484             : bool
    1485           1 : gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
    1486             :                                           nsTArray<gfxFontFamily*>* aOutput,
    1487             :                                           gfxFontStyle* aStyle,
    1488             :                                           gfxFloat aDevToCssSize)
    1489             : {
    1490           2 :     nsAutoString familyName(aFamily);
    1491           1 :     ToLowerCase(familyName);
    1492           1 :     nsIAtom* language = (aStyle ? aStyle->language.get() : nullptr);
    1493             : 
    1494             :     // deprecated generic names are explicitly converted to standard generics
    1495           1 :     bool isDeprecatedGeneric = false;
    1496           2 :     if (familyName.EqualsLiteral("sans") ||
    1497           1 :         familyName.EqualsLiteral("sans serif")) {
    1498           0 :         familyName.AssignLiteral("sans-serif");
    1499           0 :         isDeprecatedGeneric = true;
    1500           1 :     } else if (familyName.EqualsLiteral("mono")) {
    1501           0 :         familyName.AssignLiteral("monospace");
    1502           0 :         isDeprecatedGeneric = true;
    1503             :     }
    1504             : 
    1505             :     // fontconfig generics? use fontconfig to determine the family for lang
    1506           4 :     if (isDeprecatedGeneric ||
    1507           4 :         mozilla::FontFamilyName::Convert(familyName).IsGeneric()) {
    1508           0 :         PrefFontList* prefFonts = FindGenericFamilies(familyName, language);
    1509           0 :         if (prefFonts && !prefFonts->IsEmpty()) {
    1510           0 :             aOutput->AppendElements(*prefFonts);
    1511           0 :             return true;
    1512             :         }
    1513           0 :         return false;
    1514             :     }
    1515             : 
    1516             :     // fontconfig allows conditional substitutions in such a way that it's
    1517             :     // difficult to distinguish an explicit substitution from other suggested
    1518             :     // choices. To sniff out explicit substitutions, compare the substitutions
    1519             :     // for "font, -moz-sentinel" to "-moz-sentinel" to sniff out the
    1520             :     // substitutions
    1521             :     //
    1522             :     // Example:
    1523             :     //
    1524             :     //   serif ==> DejaVu Serif, ...
    1525             :     //   Helvetica, serif ==> Helvetica, TeX Gyre Heros, Nimbus Sans L, DejaVu Serif
    1526             :     //
    1527             :     // In this case fontconfig is including Tex Gyre Heros and
    1528             :     // Nimbus Sans L as alternatives for Helvetica.
    1529             : 
    1530             :     // Because the FcConfigSubstitute call is quite expensive, we cache the
    1531             :     // actual font families found via this process. So check the cache first:
    1532           2 :     NS_ConvertUTF16toUTF8 familyToFind(familyName);
    1533           2 :     AutoTArray<gfxFontFamily*,10> cachedFamilies;
    1534           1 :     if (mFcSubstituteCache.Get(familyToFind, &cachedFamilies)) {
    1535           0 :         if (cachedFamilies.IsEmpty()) {
    1536           0 :             return false;
    1537             :         }
    1538           0 :         aOutput->AppendElements(cachedFamilies);
    1539           0 :         return true;
    1540             :     }
    1541             : 
    1542             :     // It wasn't in the cache, so we need to ask fontconfig...
    1543           1 :     const FcChar8* kSentinelName = ToFcChar8Ptr("-moz-sentinel");
    1544           1 :     FcChar8* sentinelFirstFamily = nullptr;
    1545           2 :     nsAutoRef<FcPattern> sentinelSubst(FcPatternCreate());
    1546           1 :     FcPatternAddString(sentinelSubst, FC_FAMILY, kSentinelName);
    1547           1 :     FcConfigSubstitute(nullptr, sentinelSubst, FcMatchPattern);
    1548           1 :     FcPatternGetString(sentinelSubst, FC_FAMILY, 0, &sentinelFirstFamily);
    1549             : 
    1550             :     // substitutions for font, -moz-sentinel pattern
    1551           2 :     nsAutoRef<FcPattern> fontWithSentinel(FcPatternCreate());
    1552           1 :     FcPatternAddString(fontWithSentinel, FC_FAMILY,
    1553           1 :                        ToFcChar8Ptr(familyToFind.get()));
    1554           1 :     FcPatternAddString(fontWithSentinel, FC_FAMILY, kSentinelName);
    1555           1 :     FcConfigSubstitute(nullptr, fontWithSentinel, FcMatchPattern);
    1556             : 
    1557             :     // Add all font family matches until reaching the sentinel.
    1558           1 :     FcChar8* substName = nullptr;
    1559           4 :     for (int i = 0;
    1560           2 :          FcPatternGetString(fontWithSentinel, FC_FAMILY,
    1561           2 :                             i, &substName) == FcResultMatch;
    1562             :          i++)
    1563             :     {
    1564           3 :         NS_ConvertUTF8toUTF16 subst(ToCharPtr(substName));
    1565           4 :         if (sentinelFirstFamily &&
    1566           4 :             FcStrCmp(substName, sentinelFirstFamily) == 0) {
    1567           1 :             break;
    1568             :         }
    1569           1 :         gfxPlatformFontList::FindAndAddFamilies(subst, &cachedFamilies);
    1570             :     }
    1571             : 
    1572             :     // Cache the resulting list, so we don't have to do this again.
    1573           1 :     mFcSubstituteCache.Put(familyToFind, cachedFamilies);
    1574             : 
    1575           1 :     if (cachedFamilies.IsEmpty()) {
    1576           0 :         return false;
    1577             :     }
    1578           1 :     aOutput->AppendElements(cachedFamilies);
    1579           1 :     return true;
    1580             : }
    1581             : 
    1582             : bool
    1583           0 : gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName,
    1584             :                                              nsAString& aFamilyName)
    1585             : {
    1586           0 :     aFamilyName.Truncate();
    1587             : 
    1588             :     // The fontconfig list of fonts includes generic family names in the
    1589             :     // font list. For these, just use the generic name.
    1590           0 :     if (aFontName.EqualsLiteral("serif") ||
    1591           0 :         aFontName.EqualsLiteral("sans-serif") ||
    1592           0 :         aFontName.EqualsLiteral("monospace")) {
    1593           0 :         aFamilyName.Assign(aFontName);
    1594           0 :         return true;
    1595             :     }
    1596             : 
    1597           0 :     nsAutoRef<FcPattern> pat(FcPatternCreate());
    1598           0 :     if (!pat) {
    1599           0 :         return true;
    1600             :     }
    1601             : 
    1602           0 :     nsAutoRef<FcObjectSet> os(FcObjectSetBuild(FC_FAMILY, nullptr));
    1603           0 :     if (!os) {
    1604           0 :         return true;
    1605             :     }
    1606             : 
    1607             :     // add the family name to the pattern
    1608           0 :     NS_ConvertUTF16toUTF8 familyName(aFontName);
    1609           0 :     FcPatternAddString(pat, FC_FAMILY, ToFcChar8Ptr(familyName.get()));
    1610             : 
    1611           0 :     nsAutoRef<FcFontSet> givenFS(FcFontList(nullptr, pat, os));
    1612           0 :     if (!givenFS) {
    1613           0 :         return true;
    1614             :     }
    1615             : 
    1616             :     // See if there is a font face with first family equal to the given family
    1617             :     // (needs to be in sync with names coming from GetFontList())
    1618           0 :     nsTArray<nsCString> candidates;
    1619           0 :     for (int i = 0; i < givenFS->nfont; i++) {
    1620             :         char* firstFamily;
    1621             : 
    1622           0 :         if (FcPatternGetString(givenFS->fonts[i], FC_FAMILY, 0,
    1623             :                                (FcChar8 **) &firstFamily) != FcResultMatch)
    1624             :         {
    1625           0 :             continue;
    1626             :         }
    1627             : 
    1628           0 :         nsDependentCString first(firstFamily);
    1629           0 :         if (!candidates.Contains(first)) {
    1630           0 :             candidates.AppendElement(first);
    1631             : 
    1632           0 :             if (familyName.Equals(first)) {
    1633           0 :                 aFamilyName.Assign(aFontName);
    1634           0 :                 return true;
    1635             :             }
    1636             :         }
    1637             :     }
    1638             : 
    1639             :     // Because fontconfig conflates different family name types, need to
    1640             :     // double check that the candidate name is not simply a different
    1641             :     // name type. For example, if a font with nameID=16 "Minion Pro" and
    1642             :     // nameID=21 "Minion Pro Caption" exists, calling FcFontList with
    1643             :     // family="Minion Pro" will return a set of patterns some of which
    1644             :     // will have a first family of "Minion Pro Caption". Ignore these
    1645             :     // patterns and use the first candidate that maps to a font set with
    1646             :     // the same number of faces and an identical set of patterns.
    1647           0 :     for (uint32_t j = 0; j < candidates.Length(); ++j) {
    1648           0 :         FcPatternDel(pat, FC_FAMILY);
    1649           0 :         FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)candidates[j].get());
    1650             : 
    1651           0 :         nsAutoRef<FcFontSet> candidateFS(FcFontList(nullptr, pat, os));
    1652           0 :         if (!candidateFS) {
    1653           0 :             return true;
    1654             :         }
    1655             : 
    1656           0 :         if (candidateFS->nfont != givenFS->nfont) {
    1657           0 :             continue;
    1658             :         }
    1659             : 
    1660           0 :         bool equal = true;
    1661           0 :         for (int i = 0; i < givenFS->nfont; ++i) {
    1662           0 :             if (!FcPatternEqual(candidateFS->fonts[i], givenFS->fonts[i])) {
    1663           0 :                 equal = false;
    1664           0 :                 break;
    1665             :             }
    1666             :         }
    1667           0 :         if (equal) {
    1668           0 :             AppendUTF8toUTF16(candidates[j], aFamilyName);
    1669           0 :             return true;
    1670             :         }
    1671             :     }
    1672             : 
    1673             :     // didn't find localized name, leave family name blank
    1674           0 :     return true;
    1675             : }
    1676             : 
    1677             : void
    1678           5 : gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType,
    1679             :                                        nsIAtom* aLanguage,
    1680             :                                        nsTArray<gfxFontFamily*>& aFamilyList)
    1681             : {
    1682           5 :     bool usePrefFontList = false;
    1683             : 
    1684             :     // treat -moz-fixed as monospace
    1685           5 :     if (aGenericType == eFamily_moz_fixed) {
    1686           0 :         aGenericType = eFamily_monospace;
    1687             :     }
    1688             : 
    1689           5 :     const char* generic = GetGenericName(aGenericType);
    1690           5 :     NS_ASSERTION(generic, "weird generic font type");
    1691           5 :     if (!generic) {
    1692           0 :         return;
    1693             :     }
    1694             : 
    1695             :     // By default, most font prefs on Linux map to "use fontconfig"
    1696             :     // keywords. So only need to explicitly lookup font pref if
    1697             :     // non-default settings exist
    1698          10 :     NS_ConvertASCIItoUTF16 genericToLookup(generic);
    1699           5 :     if ((!mAlwaysUseFontconfigGenerics && aLanguage) ||
    1700           0 :         aLanguage == nsGkAtoms::x_math) {
    1701           5 :         nsIAtom* langGroup = GetLangGroup(aLanguage);
    1702             :         nsAdoptingString fontlistValue =
    1703          10 :             Preferences::GetString(NamePref(generic, langGroup).get());
    1704           5 :         if (fontlistValue.IsEmpty()) {
    1705             :             // The font name list may have two or more family names as comma
    1706             :             // separated list.  In such case, not matching with generic font
    1707             :             // name is fine because if the list prefers specific font, we
    1708             :             // should try to use the pref with complicated path.
    1709             :             fontlistValue =
    1710           5 :                  Preferences::GetString(NameListPref(generic, langGroup).get());
    1711             :         }
    1712           5 :         if (fontlistValue) {
    1713          10 :             if (!fontlistValue.EqualsLiteral("serif") &&
    1714           5 :                 !fontlistValue.EqualsLiteral("sans-serif") &&
    1715           0 :                 !fontlistValue.EqualsLiteral("monospace")) {
    1716           0 :                 usePrefFontList = true;
    1717             :             } else {
    1718             :                 // serif, sans-serif or monospace was specified
    1719           5 :                 genericToLookup.Assign(fontlistValue);
    1720             :             }
    1721             :         }
    1722             :     }
    1723             : 
    1724             :     // when pref fonts exist, use standard pref font lookup
    1725           5 :     if (usePrefFontList) {
    1726           0 :         return gfxPlatformFontList::AddGenericFonts(aGenericType,
    1727             :                                                     aLanguage,
    1728           0 :                                                     aFamilyList);
    1729             :     }
    1730             : 
    1731           5 :     PrefFontList* prefFonts = FindGenericFamilies(genericToLookup, aLanguage);
    1732           5 :     NS_ASSERTION(prefFonts, "null generic font list");
    1733           5 :     aFamilyList.AppendElements(*prefFonts);
    1734             : }
    1735             : 
    1736             : void
    1737           3 : gfxFcPlatformFontList::ClearLangGroupPrefFonts()
    1738             : {
    1739           3 :     ClearGenericMappings();
    1740           3 :     gfxPlatformFontList::ClearLangGroupPrefFonts();
    1741           3 :     mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics();
    1742           3 : }
    1743             : 
    1744             : /* static */ FT_Library
    1745           3 : gfxFcPlatformFontList::GetFTLibrary()
    1746             : {
    1747           3 :     if (!sCairoFTLibrary) {
    1748             :         // Use cairo's FT_Library so that cairo takes care of shutdown of the
    1749             :         // FT_Library after it has destroyed its font_faces, and FT_Done_Face
    1750             :         // has been called on each FT_Face, at least until this bug is fixed:
    1751             :         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
    1752             :         //
    1753             :         // Cairo keeps it's own FT_Library object for creating FT_Face
    1754             :         // instances, so use that. There's no simple API for accessing this
    1755             :         // so use the hacky method below of making a font and extracting
    1756             :         // the library pointer from that.
    1757             : 
    1758             :         bool needsBold;
    1759           6 :         gfxFontStyle style;
    1760           3 :         gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
    1761           3 :         gfxFontFamily* family = pfl->GetDefaultFont(&style);
    1762           3 :         NS_ASSERTION(family, "couldn't find a default font family");
    1763           3 :         gfxFontEntry* fe = family->FindFontForStyle(style, needsBold);
    1764           3 :         if (!fe) {
    1765           0 :             return nullptr;
    1766             :         }
    1767           6 :         RefPtr<gfxFont> font = fe->FindOrMakeFont(&style, false);
    1768           3 :         if (!font) {
    1769           0 :             return nullptr;
    1770             :         }
    1771             : 
    1772           3 :         gfxFT2FontBase* ft2Font = reinterpret_cast<gfxFT2FontBase*>(font.get());
    1773           6 :         gfxFT2LockedFace face(ft2Font);
    1774           3 :         if (!face.get()) {
    1775           0 :             return nullptr;
    1776             :         }
    1777             : 
    1778           3 :         sCairoFTLibrary = face.get()->glyph->library;
    1779             :     }
    1780             : 
    1781           3 :     return sCairoFTLibrary;
    1782             : }
    1783             : 
    1784             : gfxPlatformFontList::PrefFontList*
    1785           8 : gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric,
    1786             :                                            nsIAtom* aLanguage)
    1787             : {
    1788             :     // set up name
    1789          16 :     NS_ConvertUTF16toUTF8 generic(aGeneric);
    1790             : 
    1791          16 :     nsAutoCString fcLang;
    1792           8 :     GetSampleLangForGroup(aLanguage, fcLang);
    1793           8 :     ToLowerCase(fcLang);
    1794             : 
    1795          16 :     nsAutoCString genericLang(generic);
    1796           8 :     if (fcLang.Length() > 0) {
    1797           8 :         genericLang.Append('-');
    1798             :     }
    1799           8 :     genericLang.Append(fcLang);
    1800             : 
    1801             :     // try to get the family from the cache
    1802           8 :     PrefFontList* prefFonts = mGenericMappings.Get(genericLang);
    1803           8 :     if (prefFonts) {
    1804           3 :         return prefFonts;
    1805             :     }
    1806             : 
    1807             :     // if not found, ask fontconfig to pick the appropriate font
    1808          10 :     nsAutoRef<FcPattern> genericPattern(FcPatternCreate());
    1809           5 :     FcPatternAddString(genericPattern, FC_FAMILY,
    1810           5 :                        ToFcChar8Ptr(generic.get()));
    1811             : 
    1812             :     // -- prefer scalable fonts
    1813           5 :     FcPatternAddBool(genericPattern, FC_SCALABLE, FcTrue);
    1814             : 
    1815             :     // -- add the lang to the pattern
    1816           5 :     if (!fcLang.IsEmpty()) {
    1817           5 :         FcPatternAddString(genericPattern, FC_LANG,
    1818           5 :                            ToFcChar8Ptr(fcLang.get()));
    1819             :     }
    1820             : 
    1821             :     // -- perform substitutions
    1822           5 :     FcConfigSubstitute(nullptr, genericPattern, FcMatchPattern);
    1823           5 :     FcDefaultSubstitute(genericPattern);
    1824             : 
    1825             :     // -- sort to get the closest matches
    1826             :     FcResult result;
    1827             :     nsAutoRef<FcFontSet> faces(FcFontSort(nullptr, genericPattern, FcFalse,
    1828          10 :                                           nullptr, &result));
    1829             : 
    1830           5 :     if (!faces) {
    1831           0 :       return nullptr;
    1832             :     }
    1833             : 
    1834             :     // -- select the fonts to be used for the generic
    1835           5 :     prefFonts = new PrefFontList; // can be empty but in practice won't happen
    1836           5 :     uint32_t limit = gfxPlatformGtk::GetPlatform()->MaxGenericSubstitions();
    1837           5 :     bool foundFontWithLang = false;
    1838          64 :     for (int i = 0; i < faces->nfont; i++) {
    1839          64 :         FcPattern* font = faces->fonts[i];
    1840          64 :         FcChar8* mappedGeneric = nullptr;
    1841             : 
    1842          64 :         FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
    1843          64 :         if (mappedGeneric) {
    1844         123 :             NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
    1845         123 :             AutoTArray<gfxFontFamily*,1> genericFamilies;
    1846          64 :             if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName,
    1847             :                                                         &genericFamilies)) {
    1848          64 :                 MOZ_ASSERT(genericFamilies.Length() == 1,
    1849             :                            "expected a single family");
    1850          64 :                 if (!prefFonts->Contains(genericFamilies[0])) {
    1851          15 :                     prefFonts->AppendElement(genericFamilies[0]);
    1852             :                     bool foundLang =
    1853          30 :                         !fcLang.IsEmpty() &&
    1854          30 :                         PatternHasLang(font, ToFcChar8Ptr(fcLang.get()));
    1855          15 :                     foundFontWithLang = foundFontWithLang || foundLang;
    1856             :                     // check to see if the list is full
    1857          15 :                     if (prefFonts->Length() >= limit) {
    1858           5 :                         break;
    1859             :                     }
    1860             :                 }
    1861             :             }
    1862             :         }
    1863             :     }
    1864             : 
    1865             :     // if no font in the list matches the lang, trim all but the first one
    1866           5 :     if (!prefFonts->IsEmpty() && !foundFontWithLang) {
    1867           0 :         prefFonts->TruncateLength(1);
    1868             :     }
    1869             : 
    1870           5 :     mGenericMappings.Put(genericLang, prefFonts);
    1871           5 :     return prefFonts;
    1872             : }
    1873             : 
    1874             : bool
    1875           6 : gfxFcPlatformFontList::PrefFontListsUseOnlyGenerics()
    1876             : {
    1877             :     static const char kFontNamePrefix[] = "font.name.";
    1878             : 
    1879           6 :     bool prefFontsUseOnlyGenerics = true;
    1880             :     uint32_t count;
    1881             :     char** names;
    1882           6 :     nsresult rv = Preferences::GetRootBranch()->
    1883           6 :         GetChildList(kFontNamePrefix, &count, &names);
    1884           6 :     if (NS_SUCCEEDED(rv) && count) {
    1885          42 :         for (size_t i = 0; i < count; i++) {
    1886             :             // Check whether all font.name prefs map to generic keywords
    1887             :             // and that the pref name and keyword match.
    1888             :             //   Ex: font.name.serif.ar ==> "serif" (ok)
    1889             :             //   Ex: font.name.serif.ar ==> "monospace" (return false)
    1890             :             //   Ex: font.name.serif.ar ==> "DejaVu Serif" (return false)
    1891             :             //   Ex: font.name.serif.ar ==> "" and
    1892             :             //       font.name-list.serif.ar ==> "serif" (ok)
    1893             :             //   Ex: font.name.serif.ar ==> "" and
    1894             :             //       font.name-list.serif.ar ==> "Something, serif"
    1895             :             //                                           (return false)
    1896             : 
    1897          42 :             nsDependentCString prefName(names[i] +
    1898          78 :                                         ArrayLength(kFontNamePrefix) - 1);
    1899          42 :             nsCCharSeparatedTokenizer tokenizer(prefName, '.');
    1900          78 :             const nsDependentCSubstring& generic = tokenizer.nextToken();
    1901          78 :             const nsDependentCSubstring& langGroup = tokenizer.nextToken();
    1902          78 :             nsAdoptingCString fontPrefValue = Preferences::GetCString(names[i]);
    1903          42 :             if (fontPrefValue.IsEmpty()) {
    1904             :                 // The font name list may have two or more family names as comma
    1905             :                 // separated list.  In such case, not matching with generic font
    1906             :                 // name is fine because if the list prefers specific font, this
    1907             :                 // should return false.
    1908             :                 fontPrefValue =
    1909          84 :                     Preferences::GetCString(NameListPref(generic,
    1910          42 :                                                          langGroup).get());
    1911             :             }
    1912             : 
    1913          78 :             if (!langGroup.EqualsLiteral("x-math") &&
    1914          36 :                 !generic.Equals(fontPrefValue)) {
    1915           6 :                 prefFontsUseOnlyGenerics = false;
    1916           6 :                 break;
    1917             :             }
    1918             :         }
    1919           6 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, names);
    1920             :     }
    1921           6 :     return prefFontsUseOnlyGenerics;
    1922             : }
    1923             : 
    1924             : /* static */ void
    1925           0 : gfxFcPlatformFontList::CheckFontUpdates(nsITimer *aTimer, void *aThis)
    1926             : {
    1927             :     // check for font updates
    1928           0 :     FcInitBringUptoDate();
    1929             : 
    1930             :     // update fontlist if current config changed
    1931           0 :     gfxFcPlatformFontList *pfl = static_cast<gfxFcPlatformFontList*>(aThis);
    1932           0 :     FcConfig* current = FcConfigGetCurrent();
    1933           0 :     if (current != pfl->GetLastConfig()) {
    1934           0 :         pfl->UpdateFontList();
    1935           0 :         pfl->ForceGlobalReflow();
    1936             :     }
    1937           0 : }
    1938             : 
    1939             : #ifdef MOZ_BUNDLED_FONTS
    1940             : void
    1941           3 : gfxFcPlatformFontList::ActivateBundledFonts()
    1942             : {
    1943           3 :     if (!mBundledFontsInitialized) {
    1944           3 :         mBundledFontsInitialized = true;
    1945           6 :         nsCOMPtr<nsIFile> localDir;
    1946           3 :         nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
    1947           3 :         if (NS_FAILED(rv)) {
    1948           0 :             return;
    1949             :         }
    1950           3 :         if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
    1951           0 :             return;
    1952             :         }
    1953             :         bool isDir;
    1954           3 :         if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
    1955           0 :             return;
    1956             :         }
    1957           3 :         if (NS_FAILED(localDir->GetNativePath(mBundledFontsPath))) {
    1958           0 :             return;
    1959             :         }
    1960             :     }
    1961           3 :     if (!mBundledFontsPath.IsEmpty()) {
    1962           3 :         FcConfigAppFontAddDir(nullptr, ToFcChar8Ptr(mBundledFontsPath.get()));
    1963             :     }
    1964             : }
    1965             : #endif
    1966             : 
    1967             : #ifdef MOZ_WIDGET_GTK
    1968             : /***************************************************************************
    1969             :  *
    1970             :  * This function must be last in the file because it uses the system cairo
    1971             :  * library.  Above this point the cairo library used is the tree cairo if
    1972             :  * MOZ_TREE_CAIRO.
    1973             :  */
    1974             : 
    1975             : #if MOZ_TREE_CAIRO
    1976             : // Tree cairo symbols have different names.  Disable their activation through
    1977             : // preprocessor macros.
    1978             : #undef cairo_ft_font_options_substitute
    1979             : 
    1980             : // The system cairo functions are not declared because the include paths cause
    1981             : // the gdk headers to pick up the tree cairo.h.
    1982             : extern "C" {
    1983             : NS_VISIBILITY_DEFAULT void
    1984             : cairo_ft_font_options_substitute (const cairo_font_options_t *options,
    1985             :                                   FcPattern                  *pattern);
    1986             : }
    1987             : #endif
    1988             : 
    1989             : static void
    1990           8 : ApplyGdkScreenFontOptions(FcPattern *aPattern)
    1991             : {
    1992             :     const cairo_font_options_t *options =
    1993           8 :         gdk_screen_get_font_options(gdk_screen_get_default());
    1994             : 
    1995           8 :     cairo_ft_font_options_substitute(options, aPattern);
    1996           8 : }
    1997             : 
    1998             : #endif // MOZ_WIDGET_GTK

Generated by: LCOV version 1.13