gfx/thebes/gfxPangoFonts.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #include "prlink.h"
     7 #include "gfxTypes.h"
     9 #include "nsTArray.h"
    11 #include "gfxContext.h"
    12 #ifdef MOZ_WIDGET_GTK
    13 #include "gfxPlatformGtk.h"
    14 #endif
    15 #ifdef MOZ_WIDGET_QT
    16 #include "gfxQtPlatform.h"
    17 #endif
    18 #include "gfxPangoFonts.h"
    19 #include "gfxFT2FontBase.h"
    20 #include "gfxFT2Utils.h"
    21 #include "harfbuzz/hb.h"
    22 #include "harfbuzz/hb-ot.h"
    23 #include "gfxHarfBuzzShaper.h"
    24 #include "gfxGraphiteShaper.h"
    25 #include "nsUnicodeProperties.h"
    26 #include "nsUnicodeScriptCodes.h"
    27 #include "gfxFontconfigUtils.h"
    28 #include "gfxUserFontSet.h"
    29 #include "gfxFontConstants.h"
    31 #include <cairo.h>
    32 #include <cairo-ft.h>
    34 #include <fontconfig/fcfreetype.h>
    35 #include <pango/pango.h>
    37 #include FT_TRUETYPE_TABLES_H
    39 #ifdef MOZ_WIDGET_GTK
    40 #include <gdk/gdk.h>
    41 #endif
    43 #include <math.h>
    45 using namespace mozilla;
    46 using namespace mozilla::unicode;
    48 #define PRINTING_FC_PROPERTY "gfx.printing"
    50 static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage);
    52 static cairo_scaled_font_t *
    53 CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace);
    55 static FT_Library gFTLibrary;
    57 // FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97
    58 // and so fontconfig-2.3.0 (2005).
    59 #ifndef FC_FAMILYLANG
    60 #define FC_FAMILYLANG "familylang"
    61 #endif
    62 #ifndef FC_FULLNAME
    63 #define FC_FULLNAME "fullname"
    64 #endif
    66 static PRFuncPtr
    67 FindFunctionSymbol(const char *name)
    68 {
    69     PRLibrary *lib = nullptr;
    70     PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib);
    71     if (lib) {
    72         PR_UnloadLibrary(lib);
    73     }
    75     return result;
    76 }
    78 static bool HasChar(FcPattern *aFont, FcChar32 wc)
    79 {
    80     FcCharSet *charset = nullptr;
    81     FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
    83     return charset && FcCharSetHasChar(charset, wc);
    84 }
    86 /**
    87  * gfxFcFontEntry:
    88  *
    89  * An abstract base class of for gfxFontEntry implementations used by
    90  * gfxFcFont and gfxUserFontSet.
    91  */
    93 class gfxFcFontEntry : public gfxFontEntry {
    94 public:
    95     // For all FontEntrys attached to gfxFcFonts, there will be only one
    96     // pattern in this array.  This is always a font pattern, not a fully
    97     // resolved pattern.  gfxFcFont only uses this to construct a PangoFont.
    98     //
    99     // FontEntrys for src:local() fonts in gfxUserFontSet may return more than
   100     // one pattern.  (See comment in gfxUserFcFontEntry.)
   101     const nsTArray< nsCountedRef<FcPattern> >& GetPatterns()
   102     {
   103         return mPatterns;
   104     }
   106     static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace)
   107     {
   108         return static_cast<gfxFcFontEntry*>
   109             (cairo_font_face_get_user_data(aFace, &sFontEntryKey));
   110     }
   112     // override the gfxFontEntry impl to read the name from fontconfig
   113     // instead of trying to get the 'name' table, as we don't implement
   114     // GetFontTable() here
   115     virtual nsString RealFaceName();
   117     // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
   118     virtual bool TestCharacterMap(uint32_t aCh)
   119     {
   120         for (uint32_t i = 0; i < mPatterns.Length(); ++i) {
   121             if (HasChar(mPatterns[i], aCh)) {
   122                 return true;
   123             }
   124         }
   125         return false;
   126     }
   128 protected:
   129     gfxFcFontEntry(const nsAString& aName)
   130         : gfxFontEntry(aName)
   131     {
   132     }
   134     // One pattern is the common case and some subclasses rely on successful
   135     // addition of the first element to the array.
   136     AutoFallibleTArray<nsCountedRef<FcPattern>,1> mPatterns;
   138     static cairo_user_data_key_t sFontEntryKey;
   139 };
   141 cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
   143 nsString
   144 gfxFcFontEntry::RealFaceName()
   145 {
   146     FcChar8 *name;
   147     if (!mPatterns.IsEmpty()) {
   148         if (FcPatternGetString(mPatterns[0],
   149                                FC_FULLNAME, 0, &name) == FcResultMatch) {
   150             return NS_ConvertUTF8toUTF16((const char*)name);
   151         }
   152         if (FcPatternGetString(mPatterns[0],
   153                                FC_FAMILY, 0, &name) == FcResultMatch) {
   154             NS_ConvertUTF8toUTF16 result((const char*)name);
   155             if (FcPatternGetString(mPatterns[0],
   156                                    FC_STYLE, 0, &name) == FcResultMatch) {
   157                 result.AppendLiteral(" ");
   158                 AppendUTF8toUTF16((const char*)name, result);
   159             }
   160             return result;
   161         }
   162     }
   163     // fall back to gfxFontEntry implementation (only works for sfnt fonts)
   164     return gfxFontEntry::RealFaceName();
   165 }
   167 /**
   168  * gfxSystemFcFontEntry:
   169  *
   170  * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts,
   171  * including those from regular family-name based font selection as well as
   172  * those from src:local().
   173  *
   174  * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. 
   175  */
   177 class gfxSystemFcFontEntry : public gfxFcFontEntry {
   178 public:
   179     // For memory efficiency, aFontPattern should be a font pattern,
   180     // not a fully resolved pattern.
   181     gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
   182                          FcPattern *aFontPattern,
   183                          const nsAString& aName)
   184         : gfxFcFontEntry(aName), mFontFace(aFontFace),
   185           mFTFace(nullptr), mFTFaceInitialized(false)
   186     {
   187         cairo_font_face_reference(mFontFace);
   188         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr);
   189         mPatterns.AppendElement();
   190         // mPatterns is an nsAutoTArray with 1 space always available, so the
   191         // AppendElement always succeeds.
   192         mPatterns[0] = aFontPattern;
   194         FcChar8 *name;
   195         if (FcPatternGetString(aFontPattern,
   196                                FC_FAMILY, 0, &name) == FcResultMatch) {
   197             mFamilyName = NS_ConvertUTF8toUTF16((const char*)name);
   198         }
   199     }
   201     ~gfxSystemFcFontEntry()
   202     {
   203         cairo_font_face_set_user_data(mFontFace,
   204                                       &sFontEntryKey,
   205                                       nullptr,
   206                                       nullptr);
   207         cairo_font_face_destroy(mFontFace);
   208     }
   210     virtual void ForgetHBFace();
   211     virtual void ReleaseGrFace(gr_face* aFace);
   213 protected:
   214     virtual nsresult
   215     CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
   217     void MaybeReleaseFTFace();
   219 private:
   220     cairo_font_face_t *mFontFace;
   221     FT_Face            mFTFace;
   222     bool               mFTFaceInitialized;
   223 };
   225 nsresult
   226 gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
   227                                     FallibleTArray<uint8_t>& aBuffer)
   228 {
   229     if (!mFTFaceInitialized) {
   230         mFTFaceInitialized = true;
   231         FcChar8 *filename;
   232         if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
   233             return NS_ERROR_FAILURE;
   234         }
   235         int index;
   236         if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
   237             index = 0; // default to 0 if not found in pattern
   238         }
   239         if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
   240                         (const char*)filename, index, &mFTFace) != 0) {
   241             return NS_ERROR_FAILURE;
   242         }
   243     }
   245     if (!mFTFace) {
   246         return NS_ERROR_NOT_AVAILABLE;
   247     }
   249     FT_ULong length = 0;
   250     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
   251         return NS_ERROR_NOT_AVAILABLE;
   252     }
   253     if (!aBuffer.SetLength(length)) {
   254         return NS_ERROR_OUT_OF_MEMORY;
   255     }
   256     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
   257         aBuffer.Clear();
   258         return NS_ERROR_FAILURE;
   259     }
   261     return NS_OK;
   262 }
   264 void
   265 gfxSystemFcFontEntry::MaybeReleaseFTFace()
   266 {
   267     // don't release if either HB or Gr face still exists
   268     if (mHBFace || mGrFace) {
   269         return;
   270     }
   271     if (mFTFace) {
   272         FT_Done_Face(mFTFace);
   273         mFTFace = nullptr;
   274     }
   275     mFTFaceInitialized = false;
   276 }
   278 void
   279 gfxSystemFcFontEntry::ForgetHBFace()
   280 {
   281     gfxFontEntry::ForgetHBFace();
   282     MaybeReleaseFTFace();
   283 }
   285 void
   286 gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
   287 {
   288     gfxFontEntry::ReleaseGrFace(aFace);
   289     MaybeReleaseFTFace();
   290 }
   292 // A namespace for @font-face family names in FcPatterns so that fontconfig
   293 // aliases do not pick up families from @font-face rules and so that
   294 // fontconfig rules can distinguish between web fonts and platform fonts.
   295 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
   296 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
   298 /**
   299  * gfxUserFcFontEntry:
   300  *
   301  * An abstract class for objects in a gfxUserFontSet that can provide
   302  * FcPattern* handles to fonts.
   303  *
   304  * Separate implementations of this class support local fonts from src:local()
   305  * and web fonts from src:url().
   306  */
   308 // There is a one-to-one correspondence between gfxUserFcFontEntry objects and
   309 // @font-face rules, but sometimes a one-to-many correspondence between font
   310 // entries and font patterns.
   311 //
   312 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions
   313 // provided a font-size descriptor to specify the sizes supported by the face,
   314 // but the "Editor's Draft 27 June 2008"
   315 // http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a
   316 // descriptor, and Mozilla does not recognize such a descriptor.
   317 //
   318 // Font face names used in src:local() also do not usually specify a size.
   319 //
   320 // PCF format fonts have each size in a different file, and each of these
   321 // files is referenced by its own pattern, but really these are each
   322 // different sizes of one face with one name.
   323 //
   324 // Multiple patterns in an entry also effectively deals with a set of
   325 // PostScript Type 1 font files that all have the same face name but are in
   326 // several files because of the limit on the number of glyphs in a Type 1 font
   327 // file.  (e.g. Computer Modern.)
   329 class gfxUserFcFontEntry : public gfxFcFontEntry {
   330 protected:
   331     gfxUserFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
   332         : gfxFcFontEntry(aProxyEntry.Name())
   333     {
   334         mItalic = aProxyEntry.mItalic;
   335         mWeight = aProxyEntry.mWeight;
   336         mStretch = aProxyEntry.mStretch;
   337         mIsUserFont = true;
   338     }
   340     // Helper function to change a pattern so that it matches the CSS style
   341     // descriptors and so gets properly sorted in font selection.  This also
   342     // avoids synthetic style effects being added by the renderer when the
   343     // style of the font itself does not match the descriptor provided by the
   344     // author.
   345     void AdjustPatternToCSS(FcPattern *aPattern);
   346 };
   348 void
   349 gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
   350 {
   351     int fontWeight = -1;
   352     FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight);
   353     int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100);
   354     if (cssWeight != fontWeight) {
   355         FcPatternDel(aPattern, FC_WEIGHT);
   356         FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight);
   357     }
   359     int fontSlant;
   360     FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant);
   361     // gfxFontEntry doesn't understand the difference between oblique
   362     // and italic.
   363     if (res != FcResultMatch ||
   364         IsItalic() != (fontSlant != FC_SLANT_ROMAN)) {
   365         FcPatternDel(aPattern, FC_SLANT);
   366         FcPatternAddInteger(aPattern, FC_SLANT,
   367                             IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN);
   368     }
   370     int fontWidth = -1;
   371     FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth);
   372     int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch);
   373     if (cssWidth != fontWidth) {
   374         FcPatternDel(aPattern, FC_WIDTH);
   375         FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth);
   376     }
   378     // Ensure that there is a fullname property (if there is a family
   379     // property) so that fontconfig rules can identify the real name of the
   380     // font, because the family property will be replaced.
   381     FcChar8 *unused;
   382     if (FcPatternGetString(aPattern,
   383                            FC_FULLNAME, 0, &unused) == FcResultNoMatch) {
   384         nsAutoCString fullname;
   385         if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern,
   386                                                               &fullname)) {
   387             FcPatternAddString(aPattern, FC_FULLNAME,
   388                                gfxFontconfigUtils::ToFcChar8(fullname));
   389         }
   390     }
   392     nsAutoCString family;
   393     family.Append(FONT_FACE_FAMILY_PREFIX);
   394     AppendUTF16toUTF8(Name(), family);
   396     FcPatternDel(aPattern, FC_FAMILY);
   397     FcPatternDel(aPattern, FC_FAMILYLANG);
   398     FcPatternAddString(aPattern, FC_FAMILY,
   399                        gfxFontconfigUtils::ToFcChar8(family));
   400 }
   402 /**
   403  * gfxLocalFcFontEntry:
   404  *
   405  * An implementation of gfxUserFcFontEntry for local fonts from src:local().
   406  *
   407  * This class is used only in gfxUserFontSet and for providing FcPattern*
   408  * handles to system fonts for font selection.  gfxFcFonts created from these
   409  * patterns will use gfxSystemFcFontEntrys, which may be shared with
   410  * gfxFcFonts from regular family-name based font selection.
   411  */
   413 class gfxLocalFcFontEntry : public gfxUserFcFontEntry {
   414 public:
   415     gfxLocalFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
   416                         const nsTArray< nsCountedRef<FcPattern> >& aPatterns)
   417         : gfxUserFcFontEntry(aProxyEntry)
   418     {
   419         if (!mPatterns.SetCapacity(aPatterns.Length()))
   420             return; // OOM
   422         for (uint32_t i = 0; i < aPatterns.Length(); ++i) {
   423             FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i));
   424             if (!pattern)
   425                 return; // OOM
   427             AdjustPatternToCSS(pattern);
   429             mPatterns.AppendElement();
   430             mPatterns[i].own(pattern);
   431         }
   432         mIsLocalUserFont = true;
   433     }
   434 };
   436 /**
   437  * gfxDownloadedFcFontEntry:
   438  *
   439  * An implementation of gfxFcFontEntry for web fonts from src:url().
   440  * 
   441  * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t
   442  * keeps a reference to the FontEntry to keep the font data alive.
   443  */
   445 class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry {
   446 public:
   447     // This takes ownership of the face and its underlying data
   448     gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
   449                              const uint8_t *aData, FT_Face aFace)
   450         : gfxUserFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
   451     {
   452         NS_PRECONDITION(aFace != nullptr, "aFace is NULL!");
   453         InitPattern();
   454     }
   456     virtual ~gfxDownloadedFcFontEntry();
   458     // Returns true on success
   459     bool SetCairoFace(cairo_font_face_t *aFace);
   461     virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
   463 protected:
   464     void InitPattern();
   466     // mFontData holds the data used to instantiate the FT_Face;
   467     // this has to persist until we are finished with the face,
   468     // then be released with NS_Free().
   469     const uint8_t* mFontData;
   471     FT_Face mFace;
   472 };
   474 // A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
   475 static const char *kFontEntryFcProp = "-moz-font-entry";
   477 static FcBool AddDownloadedFontEntry(FcPattern *aPattern,
   478                                      gfxDownloadedFcFontEntry *aFontEntry)
   479 {
   480     FcValue value;
   481     value.type = FcTypeFTFace; // void* field of union
   482     value.u.f = aFontEntry;
   484     return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse);
   485 }
   487 static FcBool DelDownloadedFontEntry(FcPattern *aPattern)
   488 {
   489     return FcPatternDel(aPattern, kFontEntryFcProp);
   490 }
   492 static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern)
   493 {
   494     FcValue value;
   495     if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch)
   496         return nullptr;
   498     if (value.type != FcTypeFTFace) {
   499         NS_NOTREACHED("Wrong type for -moz-font-entry font property");
   500         return nullptr;
   501     }
   503     return static_cast<gfxDownloadedFcFontEntry*>(value.u.f);
   504 }
   506 gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
   507 {
   508     if (mPatterns.Length() != 0) {
   509         // Remove back reference to this font entry and the face in case
   510         // anyone holds a reference to the pattern.
   511         NS_ASSERTION(mPatterns.Length() == 1,
   512                      "More than one pattern in gfxDownloadedFcFontEntry!");
   513         DelDownloadedFontEntry(mPatterns[0]);
   514         FcPatternDel(mPatterns[0], FC_FT_FACE);
   515     }
   516     FT_Done_Face(mFace);
   517     NS_Free((void*)mFontData);
   518 }
   520 typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
   521                                         const FcChar8 *file, int id,
   522                                         FcBlanks *blanks);
   524 void
   525 gfxDownloadedFcFontEntry::InitPattern()
   526 {
   527     static QueryFaceFunction sQueryFacePtr =
   528         reinterpret_cast<QueryFaceFunction>
   529         (FindFunctionSymbol("FcFreeTypeQueryFace"));
   530     FcPattern *pattern;
   532     // FcFreeTypeQueryFace is the same function used to construct patterns for
   533     // system fonts and so is the preferred function to use for this purpose.
   534     // This will set up the langset property, which helps with sorting, and
   535     // the foundry, fullname, and fontversion properties, which properly
   536     // identify the font to fontconfig rules.  However, FcFreeTypeQueryFace is
   537     // available only from fontconfig-2.4.2 (December 2006).  (CentOS 5.0 has
   538     // fontconfig-2.4.1.)
   539     if (sQueryFacePtr) {
   540         // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at
   541         // least). The dummy file passed here is removed below.
   542         //
   543         // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr)
   544         // is passed as the "blanks" argument, which provides that unexpectedly
   545         // blank glyphs are elided.  Here, however, we pass nullptr for
   546         // "blanks", effectively assuming that, if the font has a blank glyph,
   547         // then the author intends any associated character to be rendered
   548         // blank.
   549         pattern =
   550             (*sQueryFacePtr)(mFace,
   551                              gfxFontconfigUtils::ToFcChar8(""),
   552                              0,
   553                              nullptr);
   554         if (!pattern)
   555             // Either OOM, or fontconfig chose to skip this font because it
   556             // has "no encoded characters", which I think means "BDF and PCF
   557             // fonts which are not in Unicode (or the effectively equivalent
   558             // ISO Latin-1) encoding".
   559             return;
   561         // These properties don't make sense for this face without a file.
   562         FcPatternDel(pattern, FC_FILE);
   563         FcPatternDel(pattern, FC_INDEX);
   565     } else {
   566         // Do the minimum necessary to construct a pattern for sorting.
   568         // FC_CHARSET is vital to determine which characters are supported.
   569         nsAutoRef<FcCharSet> charset(FcFreeTypeCharSet(mFace, nullptr));
   570         // If there are no characters then assume we don't know how to read
   571         // this font.
   572         if (!charset || FcCharSetCount(charset) == 0)
   573             return;
   575         pattern = FcPatternCreate();
   576         FcPatternAddCharSet(pattern, FC_CHARSET, charset);
   578         // FC_PIXEL_SIZE can be important for font selection of fixed-size
   579         // fonts.
   580         if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) {
   581             for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) {
   582 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
   583                 double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem);
   584 #else
   585                 double size = mFace->available_sizes[i].height;
   586 #endif
   587                 FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
   588             }
   590             // Not sure whether this is important;
   591             // imitating FcFreeTypeQueryFace:
   592             FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse);
   593         }
   595         // Setting up the FC_LANGSET property is very difficult with the APIs
   596         // available prior to FcFreeTypeQueryFace.  Having no FC_LANGSET
   597         // property seems better than having a property with an empty LangSet.
   598         // With no FC_LANGSET property, fontconfig sort functions will
   599         // consider this face to have the same priority as (otherwise equal)
   600         // faces that have support for the primary requested language, but
   601         // will not consider any language to have been satisfied (and so will
   602         // continue to look for a face with language support in fallback
   603         // fonts).
   604     }
   606     AdjustPatternToCSS(pattern);
   608     FcPatternAddFTFace(pattern, FC_FT_FACE, mFace);
   609     AddDownloadedFontEntry(pattern, this);
   611     // There is never more than one pattern
   612     mPatterns.AppendElement();
   613     mPatterns[0].own(pattern);
   614 }
   616 static void ReleaseDownloadedFontEntry(void *data)
   617 {
   618     gfxDownloadedFcFontEntry *downloadedFontEntry =
   619         static_cast<gfxDownloadedFcFontEntry*>(data);
   620     NS_RELEASE(downloadedFontEntry);
   621 }
   623 bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace)
   624 {
   625     if (CAIRO_STATUS_SUCCESS !=
   626         cairo_font_face_set_user_data(aFace, &sFontEntryKey, this,
   627                                       ReleaseDownloadedFontEntry))
   628         return false;
   630     // Hold a reference to this font entry to keep the font face data.
   631     NS_ADDREF(this);
   632     return true;
   633 }
   635 hb_blob_t *
   636 gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
   637 {
   638     // The entry already owns the (sanitized) sfnt data in mFontData,
   639     // so we can just return a blob that "wraps" the appropriate chunk of it.
   640     // The blob should not attempt to free its data, as the entire sfnt data
   641     // will be freed when the font entry is deleted.
   642     return GetTableFromFontData(mFontData, aTableTag);
   643 }
   645 /*
   646  * gfxFcFont
   647  *
   648  * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
   649  * cairo_scaled_font created from an FcPattern.
   650  */
   652 class gfxFcFont : public gfxFT2FontBase {
   653 public:
   654     virtual ~gfxFcFont();
   655     static already_AddRefed<gfxFcFont>
   656     GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
   657                   const gfxFontStyle *aFontStyle);
   659 #ifdef USE_SKIA
   660     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
   661 #endif
   663 protected:
   664     virtual bool ShapeText(gfxContext      *aContext,
   665                            const char16_t *aText,
   666                            uint32_t         aOffset,
   667                            uint32_t         aLength,
   668                            int32_t          aScript,
   669                            gfxShapedText   *aShapedText,
   670                            bool             aPreferPlatformShaping);
   672     bool InitGlyphRunWithPango(const char16_t *aString,
   673                                uint32_t         aOffset,
   674                                uint32_t         aLength,
   675                                int32_t          aScript,
   676                                gfxShapedText   *aShapedText);
   678 private:
   679     gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
   680               const gfxFontStyle *aFontStyle);
   682     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
   683     static cairo_user_data_key_t sGfxFontKey;
   684 };
   686 /**
   687  * gfxFcFontSet:
   688  *
   689  * Translation from a desired FcPattern to a sorted set of font references
   690  * (fontconfig cache data) and (when needed) fonts.
   691  */
   693 class gfxFcFontSet MOZ_FINAL {
   694 public:
   695     NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet)
   697     explicit gfxFcFontSet(FcPattern *aPattern,
   698                                gfxUserFontSet *aUserFontSet)
   699         : mSortPattern(aPattern), mUserFontSet(aUserFontSet),
   700           mFcFontsTrimmed(0),
   701           mHaveFallbackFonts(false)
   702     {
   703         bool waitForUserFont;
   704         mFcFontSet = SortPreferredFonts(waitForUserFont);
   705         mWaitingForUserFont = waitForUserFont;
   706     }
   708     // A reference is held by the FontSet.
   709     // The caller may add a ref to keep the font alive longer than the FontSet.
   710     gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle)
   711     {
   712         if (i >= mFonts.Length() || !mFonts[i].mFont) { 
   713             // GetFontPatternAt sets up mFonts
   714             FcPattern *fontPattern = GetFontPatternAt(i);
   715             if (!fontPattern)
   716                 return nullptr;
   718             mFonts[i].mFont =
   719                 gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern,
   720                                          aFontStyle);
   721         }
   722         return mFonts[i].mFont;
   723     }
   725     FcPattern *GetFontPatternAt(uint32_t i);
   727     bool WaitingForUserFont() const {
   728         return mWaitingForUserFont;
   729     }
   731 private:
   732     // Private destructor, to discourage deletion outside of Release():
   733     ~gfxFcFontSet()
   734     {
   735     }
   737     nsReturnRef<FcFontSet> SortPreferredFonts(bool& aWaitForUserFont);
   738     nsReturnRef<FcFontSet> SortFallbackFonts();
   740     struct FontEntry {
   741         explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {}
   742         nsCountedRef<FcPattern> mPattern;
   743         nsRefPtr<gfxFcFont> mFont;
   744     };
   746     struct LangSupportEntry {
   747         LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) :
   748             mLang(aLang), mBestSupport(aSupport) {}
   749         FcChar8 *mLang;
   750         FcLangResult mBestSupport;
   751     };
   753 public:
   754     // public for nsTArray
   755     class LangComparator {
   756     public:
   757         bool Equals(const LangSupportEntry& a, const FcChar8 *b) const
   758         {
   759             return FcStrCmpIgnoreCase(a.mLang, b) == 0;
   760         }
   761     };
   763 private:
   764     // The requested pattern
   765     nsCountedRef<FcPattern> mSortPattern;
   766     // Fonts from @font-face rules
   767     nsRefPtr<gfxUserFontSet> mUserFontSet;
   768     // A (trimmed) list of font patterns and fonts that is built up as
   769     // required.
   770     nsTArray<FontEntry> mFonts;
   771     // Holds a list of font patterns that will be trimmed.  This is first set
   772     // to a list of preferred fonts.  Then, if/when all the preferred fonts
   773     // have been trimmed and added to mFonts, this is set to a list of
   774     // fallback fonts.
   775     nsAutoRef<FcFontSet> mFcFontSet;
   776     // The set of characters supported by the fonts in mFonts.
   777     nsAutoRef<FcCharSet> mCharSet;
   778     // The index of the next font in mFcFontSet that has not yet been
   779     // considered for mFonts.
   780     int mFcFontsTrimmed;
   781     // True iff fallback fonts are either stored in mFcFontSet or have been
   782     // trimmed and added to mFonts (so that mFcFontSet is nullptr).
   783     bool mHaveFallbackFonts;
   784     // True iff there was a user font set with pending downloads,
   785     // so the set may be updated when downloads complete
   786     bool mWaitingForUserFont;
   787 };
   789 // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
   790 // and style |aStyle| properties.
   791 static const nsTArray< nsCountedRef<FcPattern> >*
   792 FindFontPatterns(gfxUserFontSet *mUserFontSet,
   793                  const nsACString &aFamily, uint8_t aStyle,
   794                  uint16_t aWeight, int16_t aStretch,
   795                  bool& aWaitForUserFont)
   796 {
   797     // Convert to UTF16
   798     NS_ConvertUTF8toUTF16 utf16Family(aFamily);
   800     // needsBold is not used here.  Instead synthetic bold is enabled through
   801     // FcFontRenderPrepare when the weight in the requested pattern is
   802     // compared against the weight in the font pattern.
   803     bool needsBold;
   805     gfxFontStyle style;
   806     style.style = aStyle;
   807     style.weight = aWeight;
   808     style.stretch = aStretch;
   810     gfxUserFcFontEntry *fontEntry = nullptr;
   811     gfxFontFamily *family = mUserFontSet->GetFamily(utf16Family);
   812     if (family) {
   813         fontEntry = static_cast<gfxUserFcFontEntry*>
   814             (mUserFontSet->FindFontEntry(family, style, needsBold,
   815                                          aWaitForUserFont));
   817         // Accept synthetic oblique for italic and oblique.
   818         if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
   819             style.style = NS_FONT_STYLE_NORMAL;
   820             fontEntry = static_cast<gfxUserFcFontEntry*>
   821                 (mUserFontSet->FindFontEntry(family, style, needsBold,
   822                                              aWaitForUserFont));
   823         }
   824     }
   826     if (!fontEntry) {
   827         return nullptr;
   828     }
   830     return &fontEntry->GetPatterns();
   831 }
   833 typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object,
   834                                           int id);
   836 // FcPatternRemove is available in fontconfig-2.3.0 (2005)
   837 static FcBool
   838 moz_FcPatternRemove(FcPattern *p, const char *object, int id)
   839 {
   840     static FcPatternRemoveFunction sFcPatternRemovePtr =
   841         reinterpret_cast<FcPatternRemoveFunction>
   842         (FindFunctionSymbol("FcPatternRemove"));
   844     if (!sFcPatternRemovePtr)
   845         return FcFalse;
   847     return (*sFcPatternRemovePtr)(p, object, id);
   848 }
   850 // fontconfig prefers a matching family or lang to pixelsize of bitmap
   851 // fonts.  CSS suggests a tolerance of 20% on pixelsize.
   852 static bool
   853 SizeIsAcceptable(FcPattern *aFont, double aRequestedSize)
   854 {
   855     double size;
   856     int v = 0;
   857     while (FcPatternGetDouble(aFont,
   858                               FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
   859         ++v;
   860         if (5.0 * fabs(size - aRequestedSize) < aRequestedSize)
   861             return true;
   862     }
   864     // No size means scalable
   865     return v == 0;
   866 }
   868 // Sorting only the preferred fonts first usually saves having to sort through
   869 // every font on the system.
   870 nsReturnRef<FcFontSet>
   871 gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
   872 {
   873     aWaitForUserFont = false;
   875     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
   876     if (!utils)
   877         return nsReturnRef<FcFontSet>();
   879     // The list of families in mSortPattern has values with both weak and
   880     // strong bindings.  Values with strong bindings should be preferred.
   881     // Values with weak bindings are default fonts that should be considered
   882     // only when the font provides the best support for a requested language
   883     // or after other fonts have satisfied all the requested languages.
   884     //
   885     // There are no direct fontconfig APIs to get the binding type.  The
   886     // binding only takes effect in the sort and match functions.
   888     // |requiredLangs| is a list of requested languages that have not yet been
   889     // satisfied.  gfxFontconfigUtils only sets one FC_LANG property value,
   890     // but FcConfigSubstitute may add more values (e.g. prepending "en" to
   891     // "ja" will use western fonts to render Latin/Arabic numerals in Japanese
   892     // text.)
   893     nsAutoTArray<LangSupportEntry,10> requiredLangs;
   894     for (int v = 0; ; ++v) {
   895         FcChar8 *lang;
   896         FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang);
   897         if (result != FcResultMatch) {
   898             // No need to check FcPatternGetLangSet() because
   899             // gfxFontconfigUtils sets only a string value for FC_LANG and
   900             // FcConfigSubstitute cannot add LangSets.
   901             NS_ASSERTION(result != FcResultTypeMismatch,
   902                          "Expected a string for FC_LANG");
   903             break;
   904         }
   906         if (!requiredLangs.Contains(lang, LangComparator())) {
   907             FcLangResult bestLangSupport = utils->GetBestLangSupport(lang);
   908             if (bestLangSupport != FcLangDifferentLang) {
   909                 requiredLangs.
   910                     AppendElement(LangSupportEntry(lang, bestLangSupport));
   911             }
   912         }
   913     }
   915     nsAutoRef<FcFontSet> fontSet(FcFontSetCreate());
   916     if (!fontSet)
   917         return fontSet.out();
   919     // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever
   920     // doesn't happen, Roman will be used.
   921     int requestedSlant = FC_SLANT_ROMAN;
   922     FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant);
   923     double requestedSize = -1.0;
   924     FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize);
   926     nsTHashtable<gfxFontconfigUtils::DepFcStrEntry> existingFamilies(50);
   927     FcChar8 *family;
   928     for (int v = 0;
   929          FcPatternGetString(mSortPattern,
   930                             FC_FAMILY, v, &family) == FcResultMatch; ++v) {
   931         const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nullptr;
   933         // Is this an @font-face family?
   934         // XXX: Make use of this + pass to nsFont??
   935         bool isUserFont = false;
   936         if (mUserFontSet) {
   937             // Have some @font-face definitions
   939             nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family));
   940             NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX);
   942             if (StringBeginsWith(cFamily, userPrefix)) {
   943                 isUserFont = true;
   945                 // Trim off the prefix
   946                 nsDependentCSubstring cssFamily(cFamily, userPrefix.Length());
   948                 uint8_t thebesStyle =
   949                     gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant);
   950                 uint16_t thebesWeight =
   951                     gfxFontconfigUtils::GetThebesWeight(mSortPattern);
   952                 int16_t thebesStretch =
   953                     gfxFontconfigUtils::GetThebesStretch(mSortPattern);
   955                 bool waitForUserFont;
   956                 familyFonts = FindFontPatterns(mUserFontSet, cssFamily,
   957                                                thebesStyle,
   958                                                thebesWeight, thebesStretch,
   959                                                waitForUserFont);
   960                 if (waitForUserFont) {
   961                     aWaitForUserFont = true;
   962                 }
   963             }
   964         }
   966         if (!isUserFont) {
   967             familyFonts = &utils->GetFontsForFamily(family);
   968         }
   970         if (!familyFonts || familyFonts->Length() == 0) {
   971             // There are no fonts matching this family, so there is no point
   972             // in searching for this family in the FontSort.
   973             //
   974             // Perhaps the original pattern should be retained for
   975             // FcFontRenderPrepare.  However, the only a useful config
   976             // substitution test against missing families that i can imagine
   977             // would only be interested in the preferred family
   978             // (qual="first"), so always keep the first family and use the
   979             // same pattern for Sort and RenderPrepare.
   980             if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) {
   981                 --v;
   982             }
   983             continue;
   984         }
   986         // Aliases seem to often end up occurring more than once, but
   987         // duplicate families can't be removed from the sort pattern without
   988         // knowing whether duplicates have the same binding.
   989         gfxFontconfigUtils::DepFcStrEntry *entry =
   990             existingFamilies.PutEntry(family);
   991         if (entry) {
   992             if (entry->mKey) // old entry
   993                 continue;
   995             entry->mKey = family; // initialize new entry
   996         }
   998         for (uint32_t f = 0; f < familyFonts->Length(); ++f) {
   999             FcPattern *font = familyFonts->ElementAt(f);
  1001             // Fix up the family name of user-font patterns, as the same
  1002             // font entry may be used (via the UserFontCache) for multiple
  1003             // CSS family names
  1004             if (isUserFont) {
  1005                 font = FcPatternDuplicate(font);
  1006                 FcPatternDel(font, FC_FAMILY);
  1007                 FcPatternAddString(font, FC_FAMILY, family);
  1010             // User fonts are already filtered by slant (but not size) in
  1011             // mUserFontSet->FindFontEntry().
  1012             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
  1013                 continue;
  1015             for (uint32_t r = 0; r < requiredLangs.Length(); ++r) {
  1016                 const LangSupportEntry& entry = requiredLangs[r];
  1017                 FcLangResult support =
  1018                     gfxFontconfigUtils::GetLangSupport(font, entry.mLang);
  1019                 if (support <= entry.mBestSupport) { // lower is better
  1020                     requiredLangs.RemoveElementAt(r);
  1021                     --r;
  1025             // FcFontSetDestroy will remove a reference but FcFontSetAdd
  1026             // does _not_ take a reference!
  1027             if (FcFontSetAdd(fontSet, font)) {
  1028                 // We don't add a reference here for user fonts, because we're
  1029                 // using a local clone of the pattern (see above) in order to
  1030                 // override the family name
  1031                 if (!isUserFont) {
  1032                     FcPatternReference(font);
  1038     FcPattern *truncateMarker = nullptr;
  1039     for (uint32_t r = 0; r < requiredLangs.Length(); ++r) {
  1040         const nsTArray< nsCountedRef<FcPattern> >& langFonts =
  1041             utils->GetFontsForLang(requiredLangs[r].mLang);
  1043         bool haveLangFont = false;
  1044         for (uint32_t f = 0; f < langFonts.Length(); ++f) {
  1045             FcPattern *font = langFonts[f];
  1046             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
  1047                 continue;
  1049             haveLangFont = true;
  1050             if (FcFontSetAdd(fontSet, font)) {
  1051                 FcPatternReference(font);
  1055         if (!haveLangFont && langFonts.Length() > 0) {
  1056             // There is a font that supports this language but it didn't pass
  1057             // the slant and size criteria.  Weak default font families should
  1058             // not be considered until the language has been satisfied.
  1059             //
  1060             // Insert a font that supports the language so that it will mark
  1061             // the position of fonts from weak families in the sorted set and
  1062             // they can be removed.  The language and weak families will be
  1063             // considered in the fallback fonts, which use fontconfig's
  1064             // algorithm.
  1065             //
  1066             // Of the fonts that don't meet slant and size criteria, strong
  1067             // default font families should be considered before (other) fonts
  1068             // for this language, so this marker font will be removed (as well
  1069             // as the fonts from weak families), and strong families will be
  1070             // reconsidered in the fallback fonts.
  1071             FcPattern *font = langFonts[0];
  1072             if (FcFontSetAdd(fontSet, font)) {
  1073                 FcPatternReference(font);
  1074                 truncateMarker = font;
  1076             break;
  1080     FcFontSet *sets[1] = { fontSet };
  1081     FcResult result;
  1082 #ifdef SOLARIS
  1083     // Get around a crash of FcFontSetSort when FcConfig is nullptr
  1084     // Solaris's FcFontSetSort needs an FcConfig (bug 474758)
  1085     fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern,
  1086                               FcFalse, nullptr, &result));
  1087 #else
  1088     fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern,
  1089                               FcFalse, nullptr, &result));
  1090 #endif
  1092     if (truncateMarker != nullptr && fontSet) {
  1093         nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate());
  1095         for (int f = 0; f < fontSet->nfont; ++f) {
  1096             FcPattern *font = fontSet->fonts[f];
  1097             if (font == truncateMarker)
  1098                 break;
  1100             if (FcFontSetAdd(truncatedSet, font)) {
  1101                 FcPatternReference(font);
  1105         fontSet.steal(truncatedSet);
  1108     return fontSet.out();
  1111 nsReturnRef<FcFontSet>
  1112 gfxFcFontSet::SortFallbackFonts()
  1114     // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet,
  1115     // but would take much longer due to comparing all the character sets.
  1116     //
  1117     // The references to fonts in this FcFontSet are almost free
  1118     // as they are pointers into mmaped cache files.
  1119     //
  1120     // GetFontPatternAt() will trim lazily if and as needed, which will also
  1121     // remove duplicates of preferred fonts.
  1122     FcResult result;
  1123     return nsReturnRef<FcFontSet>(FcFontSort(nullptr, mSortPattern,
  1124                                              FcFalse, nullptr, &result));
  1127 // GetFontAt relies on this setting up all patterns up to |i|.
  1128 FcPattern *
  1129 gfxFcFontSet::GetFontPatternAt(uint32_t i)
  1131     while (i >= mFonts.Length()) {
  1132         while (!mFcFontSet) {
  1133             if (mHaveFallbackFonts)
  1134                 return nullptr;
  1136             mFcFontSet = SortFallbackFonts();
  1137             mHaveFallbackFonts = true;
  1138             mFcFontsTrimmed = 0;
  1139             // Loop to test that mFcFontSet is non-nullptr.
  1142         while (mFcFontsTrimmed < mFcFontSet->nfont) {
  1143             FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed];
  1144             ++mFcFontsTrimmed;
  1146             if (mFonts.Length() != 0) {
  1147                 // See if the next font provides support for any extra
  1148                 // characters.  Most often the next font is not going to
  1149                 // support more characters so check for a SubSet first before
  1150                 // allocating a new CharSet with Union.
  1151                 FcCharSet *supportedChars = mCharSet;
  1152                 if (!supportedChars) {
  1153                     FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern,
  1154                                         FC_CHARSET, 0, &supportedChars);
  1157                 if (supportedChars) {
  1158                     FcCharSet *newChars = nullptr;
  1159                     FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars);
  1160                     if (newChars) {
  1161                         if (FcCharSetIsSubset(newChars, supportedChars))
  1162                             continue;
  1164                         mCharSet.own(FcCharSetUnion(supportedChars, newChars));
  1165                     } else if (!mCharSet) {
  1166                         mCharSet.own(FcCharSetCopy(supportedChars));
  1171             mFonts.AppendElement(font);
  1172             if (mFonts.Length() >= i)
  1173                 break;
  1176         if (mFcFontsTrimmed == mFcFontSet->nfont) {
  1177             // finished with this font set
  1178             mFcFontSet.reset();
  1182     return mFonts[i].mPattern;
  1185 #ifdef MOZ_WIDGET_GTK
  1186 static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
  1187 #endif
  1189 // Apply user settings and defaults to pattern in preparation for matching.
  1190 static void
  1191 PrepareSortPattern(FcPattern *aPattern, double aFallbackSize,
  1192                    double aSizeAdjustFactor, bool aIsPrinterFont)
  1194     FcConfigSubstitute(nullptr, aPattern, FcMatchPattern);
  1196     // This gets cairo_font_options_t for the Screen.  We should have
  1197     // different font options for printing (no hinting) but we are not told
  1198     // what we are measuring for.
  1199     //
  1200     // If cairo adds support for lcd_filter, gdk will not provide the default
  1201     // setting for that option.  We could get the default setting by creating
  1202     // an xlib surface once, recording its font_options, and then merging the
  1203     // gdk options.
  1204     //
  1205     // Using an xlib surface would also be an option to get Screen font
  1206     // options for non-GTK X11 toolkits, but less efficient than using GDK to
  1207     // pick up dynamic changes.
  1208     if(aIsPrinterFont) {
  1209        cairo_font_options_t *options = cairo_font_options_create();
  1210        cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
  1211        cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
  1212        cairo_ft_font_options_substitute(options, aPattern);
  1213        cairo_font_options_destroy(options);
  1214        FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue);
  1215     } else {
  1216 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
  1217        cairo_font_options_t *options = cairo_font_options_create();
  1218        cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
  1219        cairo_ft_font_options_substitute(options, aPattern);
  1220        cairo_font_options_destroy(options);
  1221 #endif
  1222 #ifdef MOZ_WIDGET_GTK
  1223        ApplyGdkScreenFontOptions(aPattern);
  1224 #endif
  1227     // Protect against any fontconfig settings that may have incorrectly
  1228     // modified the pixelsize, and consider aSizeAdjustFactor.
  1229     double size = aFallbackSize;
  1230     if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch
  1231         || aSizeAdjustFactor != 1.0) {
  1232         FcPatternDel(aPattern, FC_PIXEL_SIZE);
  1233         FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor);
  1236     FcDefaultSubstitute(aPattern);
  1239 /**
  1240  ** gfxPangoFontGroup
  1241  **/
  1243 struct FamilyCallbackData {
  1244     FamilyCallbackData(nsTArray<nsString> *aFcFamilyList,
  1245                        gfxUserFontSet *aUserFontSet)
  1246         : mFcFamilyList(aFcFamilyList), mUserFontSet(aUserFontSet)
  1249     nsTArray<nsString> *mFcFamilyList;
  1250     const gfxUserFontSet *mUserFontSet;
  1251 };
  1253 static int
  1254 FFRECountHyphens (const nsAString &aFFREName)
  1256     int h = 0;
  1257     int32_t hyphen = 0;
  1258     while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) {
  1259         ++h;
  1260         ++hyphen;
  1262     return h;
  1265 static bool
  1266 FamilyCallback (const nsAString& fontName, const nsACString& genericName,
  1267                 bool aUseFontSet, void *closure)
  1269     FamilyCallbackData *data = static_cast<FamilyCallbackData*>(closure);
  1270     nsTArray<nsString> *list = data->mFcFamilyList;
  1272     // We ignore prefs that have three hypens since they are X style prefs.
  1273     if (genericName.Length() && FFRECountHyphens(fontName) >= 3)
  1274         return true;
  1276     if (!list->Contains(fontName)) {
  1277         // The family properties of FcPatterns for @font-face fonts have a
  1278         // namespace to identify them among system fonts.  (see
  1279         // FONT_FACE_FAMILY_PREFIX.)
  1280         //
  1281         // Earlier versions of this code allowed the CSS family name to match
  1282         // either the @font-face family or the system font family, so both
  1283         // were added here. This was in accordance with earlier versions of
  1284         // the W3C specifications regarding @font-face.
  1285         //
  1286         // The current (2011-02-27) draft of CSS3 Fonts says
  1287         //
  1288         // (Section 4.2: Font family: the font-family descriptor):
  1289         // "If the font family name is the same as a font family available in
  1290         // a given user's environment, it effectively hides the underlying
  1291         // font for documents that use the stylesheet."
  1292         //
  1293         // (Section 5: Font matching algorithm)
  1294         // "... the user agent attempts to find the family name among fonts
  1295         // defined via @font-face rules and then among available system fonts,
  1296         // .... If a font family defined via @font-face rules contains only
  1297         // invalid font data, it should be considered as if a font was present
  1298         // but contained an empty character map; matching a platform font with
  1299         // the same name must not occur in this case."
  1300         //
  1301         // Therefore, for names present in the user font set, this code no
  1302         // longer includes the family name for matching against system fonts.
  1303         //
  1304         const gfxUserFontSet *userFontSet = data->mUserFontSet;
  1305         if (aUseFontSet && genericName.Length() == 0 &&
  1306             userFontSet && userFontSet->HasFamily(fontName)) {
  1307             nsAutoString userFontName =
  1308                 NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName;
  1309             list->AppendElement(userFontName);
  1310         } else {
  1311             list->AppendElement(fontName);
  1315     return true;
  1318 gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
  1319                                       const gfxFontStyle *aStyle,
  1320                                       gfxUserFontSet *aUserFontSet)
  1321     : gfxFontGroup(families, aStyle, aUserFontSet),
  1322       mPangoLanguage(GuessPangoLanguage(aStyle->language))
  1324     // This language is passed to the font for shaping.
  1325     // Shaping doesn't know about lang groups so make it a real language.
  1326     if (mPangoLanguage) {
  1327         mStyle.language = do_GetAtom(pango_language_to_string(mPangoLanguage));
  1330     // dummy entry, will be replaced when actually needed
  1331     mFonts.AppendElement(FamilyFace());
  1334 gfxPangoFontGroup::~gfxPangoFontGroup()
  1338 gfxFontGroup *
  1339 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
  1341     return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet);
  1344 // An array of family names suitable for fontconfig
  1345 void
  1346 gfxPangoFontGroup::GetFcFamilies(nsTArray<nsString> *aFcFamilyList,
  1347                                  nsIAtom *aLanguage)
  1349     FamilyCallbackData data(aFcFamilyList, mUserFontSet);
  1350     // Leave non-existing fonts in the list so that fontconfig can get the
  1351     // best match.
  1352     ForEachFontInternal(mFamilies, aLanguage, true, false, true,
  1353                         FamilyCallback, &data);
  1356 gfxFcFont *
  1357 gfxPangoFontGroup::GetBaseFont()
  1359     if (mFonts[0].Font() == nullptr) {
  1360         gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle());
  1361         mFonts[0] = FamilyFace(nullptr, font);
  1364     return static_cast<gfxFcFont*>(mFonts[0].Font());
  1367 gfxFont *
  1368 gfxPangoFontGroup::GetFontAt(int32_t i)
  1370     // If it turns out to be hard for all clients that cache font
  1371     // groups to call UpdateFontList at appropriate times, we could
  1372     // instead consider just calling UpdateFontList from someplace
  1373     // more central (such as here).
  1374     NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
  1375                  "Whoever was caching this font group should have "
  1376                  "called UpdateFontList on it");
  1378     NS_PRECONDITION(i == 0, "Only have one font");
  1380     return GetBaseFont();
  1383 void
  1384 gfxPangoFontGroup::UpdateFontList()
  1386     uint64_t newGeneration = GetGeneration();
  1387     if (newGeneration == mCurrGeneration)
  1388         return;
  1390     mFonts[0] = FamilyFace();
  1391     mFontSets.Clear();
  1392     mCachedEllipsisTextRun = nullptr;
  1393     mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
  1394     mCurrGeneration = newGeneration;
  1395     mSkipDrawing = false;
  1398 already_AddRefed<gfxFcFontSet>
  1399 gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
  1400                                nsAutoRef<FcPattern> *aMatchPattern)
  1402     const char *lang = pango_language_to_string(aLang);
  1404     nsRefPtr <nsIAtom> langGroup;
  1405     if (aLang != mPangoLanguage) {
  1406         // Set up langGroup for Mozilla's font prefs.
  1407         langGroup = do_GetAtom(lang);
  1410     nsAutoTArray<nsString, 20> fcFamilyList;
  1411     GetFcFamilies(&fcFamilyList,
  1412                   langGroup ? langGroup.get() : mStyle.language.get());
  1414     // To consider: A fontset cache here could be helpful.
  1416     // Get a pattern suitable for matching.
  1417     nsAutoRef<FcPattern> pattern
  1418         (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang));
  1420     PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont);
  1422     nsRefPtr<gfxFcFontSet> fontset =
  1423         new gfxFcFontSet(pattern, mUserFontSet);
  1425     mSkipDrawing = fontset->WaitingForUserFont();
  1427     if (aMatchPattern)
  1428         aMatchPattern->steal(pattern);
  1430     return fontset.forget();
  1433 gfxPangoFontGroup::
  1434 FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang,
  1435                                        gfxFcFontSet *aFontSet)
  1436     : mLang(aLang), mFontSet(aFontSet)
  1440 gfxFcFontSet *
  1441 gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang)
  1443     GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0]
  1445     if (!aLang)
  1446         return mFontSets[0].mFontSet;
  1448     for (uint32_t i = 0; i < mFontSets.Length(); ++i) {
  1449         if (mFontSets[i].mLang == aLang)
  1450             return mFontSets[i].mFontSet;
  1453     nsRefPtr<gfxFcFontSet> fontSet =
  1454         MakeFontSet(aLang, mSizeAdjustFactor);
  1455     mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet));
  1457     return fontSet;
  1460 already_AddRefed<gfxFont>
  1461 gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
  1462                                    int32_t aRunScript,
  1463                                    gfxFont *aPrevMatchedFont,
  1464                                    uint8_t *aMatchType)
  1466     if (aPrevMatchedFont) {
  1467         // Don't switch fonts for control characters, regardless of
  1468         // whether they are present in the current font, as they won't
  1469         // actually be rendered (see bug 716229)
  1470         uint8_t category = GetGeneralCategory(aCh);
  1471         if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
  1472             return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
  1475         // if this character is a join-control or the previous is a join-causer,
  1476         // use the same font as the previous range if we can
  1477         if (gfxFontUtils::IsJoinControl(aCh) ||
  1478             gfxFontUtils::IsJoinCauser(aPrevCh)) {
  1479             if (aPrevMatchedFont->HasCharacter(aCh)) {
  1480                 return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
  1485     // if this character is a variation selector,
  1486     // use the previous font regardless of whether it supports VS or not.
  1487     // otherwise the text run will be divided.
  1488     if (gfxFontUtils::IsVarSelector(aCh)) {
  1489         if (aPrevMatchedFont) {
  1490             return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
  1492         // VS alone. it's meaningless to search different fonts
  1493         return nullptr;
  1496     // The real fonts that fontconfig provides for generic/fallback families
  1497     // depend on the language used, so a different FontSet is used for each
  1498     // language (except for the variation below).
  1499     //
  1500     //   With most fontconfig configurations any real family names prior to a
  1501     //   fontconfig generic with corresponding fonts installed will still lead
  1502     //   to the same leading fonts in each FontSet.
  1503     //
  1504     //   There is an inefficiency here therefore because the same base FontSet
  1505     //   could often be used if these real families support the character.
  1506     //   However, with fontconfig aliases, it is difficult to distinguish
  1507     //   where exactly alias fonts end and generic/fallback fonts begin.
  1508     //
  1509     // The variation from pure language-based matching used here is that the
  1510     // same primary/base font is always used irrespective of the language.
  1511     // This provides that SCRIPT_COMMON characters are consistently rendered
  1512     // with the same font (bug 339513 and bug 416725).  This is particularly
  1513     // important with the word cache as script can't be reliably determined
  1514     // from surrounding words.  It also often avoids the unnecessary extra
  1515     // FontSet efficiency mentioned above.
  1516     //
  1517     // However, in two situations, the base font is not checked before the
  1518     // language-specific FontSet.
  1519     //
  1520     //   1. When we don't have a language to make a good choice for
  1521     //      the base font.
  1522     //
  1523     //   2. For system fonts, use the default Pango behavior to give
  1524     //      consistency with other apps.  This is relevant when un-localized
  1525     //      builds are run in non-Latin locales.  This special-case probably
  1526     //      wouldn't be necessary but for bug 91190.
  1528     gfxFcFontSet *fontSet = GetBaseFontSet();
  1529     uint32_t nextFont = 0;
  1530     FcPattern *basePattern = nullptr;
  1531     if (!mStyle.systemFont && mPangoLanguage) {
  1532         basePattern = fontSet->GetFontPatternAt(0);
  1533         if (HasChar(basePattern, aCh)) {
  1534             *aMatchType = gfxTextRange::kFontGroup;
  1535             return nsRefPtr<gfxFont>(GetBaseFont()).forget();
  1538         nextFont = 1;
  1541     // Pango, GLib, and Thebes (but not harfbuzz!) all happen to use the same
  1542     // script codes, so we can just cast the value here.
  1543     const PangoScript script = static_cast<PangoScript>(aRunScript);
  1544     // Might be nice to call pango_language_includes_script only once for the
  1545     // run rather than for each character.
  1546     PangoLanguage *scriptLang;
  1547     if ((!basePattern ||
  1548          !pango_language_includes_script(mPangoLanguage, script)) &&
  1549         (scriptLang = pango_script_get_sample_language(script))) {
  1550         fontSet = GetFontSet(scriptLang);
  1551         nextFont = 0;
  1554     for (uint32_t i = nextFont;
  1555          FcPattern *pattern = fontSet->GetFontPatternAt(i);
  1556          ++i) {
  1557         if (pattern == basePattern) {
  1558             continue; // already checked basePattern
  1561         if (HasChar(pattern, aCh)) {
  1562             *aMatchType = gfxTextRange::kFontGroup;
  1563             return nsRefPtr<gfxFont>(fontSet->GetFontAt(i, GetStyle())).forget();
  1567     return nullptr;
  1570 // Sanity-check: spot-check a few constants to confirm that Thebes and
  1571 // Pango script codes really do match
  1572 #define CHECK_SCRIPT_CODE(script) \
  1573     PR_STATIC_ASSERT(int32_t(MOZ_SCRIPT_##script) == \
  1574                      int32_t(PANGO_SCRIPT_##script))
  1576 CHECK_SCRIPT_CODE(COMMON);
  1577 CHECK_SCRIPT_CODE(INHERITED);
  1578 CHECK_SCRIPT_CODE(ARABIC);
  1579 CHECK_SCRIPT_CODE(LATIN);
  1580 CHECK_SCRIPT_CODE(UNKNOWN);
  1581 CHECK_SCRIPT_CODE(NKO);
  1583 /**
  1584  ** gfxFcFont
  1585  **/
  1587 cairo_user_data_key_t gfxFcFont::sGfxFontKey;
  1589 gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
  1590                      gfxFcFontEntry *aFontEntry,
  1591                      const gfxFontStyle *aFontStyle)
  1592     : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
  1594     cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr);
  1597 gfxFcFont::~gfxFcFont()
  1599     cairo_scaled_font_set_user_data(mScaledFont,
  1600                                     &sGfxFontKey,
  1601                                     nullptr,
  1602                                     nullptr);
  1605 bool
  1606 gfxFcFont::ShapeText(gfxContext      *aContext,
  1607                      const char16_t *aText,
  1608                      uint32_t         aOffset,
  1609                      uint32_t         aLength,
  1610                      int32_t          aScript,
  1611                      gfxShapedText   *aShapedText,
  1612                      bool             aPreferPlatformShaping)
  1614     bool ok = false;
  1616     if (FontCanSupportGraphite()) {
  1617         if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
  1618             if (!mGraphiteShaper) {
  1619                 mGraphiteShaper = new gfxGraphiteShaper(this);
  1621             ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
  1622                                             aScript, aShapedText);
  1626     if (!ok) {
  1627         if (!mHarfBuzzShaper) {
  1628             mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
  1630         ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
  1631                                         aScript, aShapedText);
  1634     NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
  1636     PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
  1638     return ok;
  1641 /* static */ void
  1642 gfxPangoFontGroup::Shutdown()
  1644     // Resetting gFTLibrary in case this is wanted again after a
  1645     // cairo_debug_reset_static_data.
  1646     gFTLibrary = nullptr;
  1649 /* static */ gfxFontEntry *
  1650 gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
  1651                                 const nsAString& aFullname)
  1653     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
  1654     if (!utils)
  1655         return nullptr;
  1657     // The font face name from @font-face { src: local() } is not well
  1658     // defined.
  1659     //
  1660     // On MS Windows, this name gets compared with
  1661     // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the
  1662     // full font name from the name table.  For CFF OpenType fonts this is the
  1663     // same as the PostScript name, but for TrueType fonts it is usually
  1664     // different.
  1665     //
  1666     // On Mac, the font face name is compared with the PostScript name, even
  1667     // for TrueType fonts.
  1668     //
  1669     // Fontconfig only records the full font names, so the behavior here
  1670     // follows that on MS Windows.  However, to provide the possibility
  1671     // of aliases to compensate for variations, the font face name is passed
  1672     // through FcConfigSubstitute.
  1674     nsAutoRef<FcPattern> pattern(FcPatternCreate());
  1675     if (!pattern)
  1676         return nullptr;
  1678     NS_ConvertUTF16toUTF8 fullname(aFullname);
  1679     FcPatternAddString(pattern, FC_FULLNAME,
  1680                        gfxFontconfigUtils::ToFcChar8(fullname));
  1681     FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
  1683     FcChar8 *name;
  1684     for (int v = 0;
  1685          FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch;
  1686          ++v) {
  1687         const nsTArray< nsCountedRef<FcPattern> >& fonts =
  1688             utils->GetFontsForFullname(name);
  1690         if (fonts.Length() != 0)
  1691             return new gfxLocalFcFontEntry(aProxyEntry, fonts);
  1694     return nullptr;
  1697 /* static */ FT_Library
  1698 gfxPangoFontGroup::GetFTLibrary()
  1700     if (!gFTLibrary) {
  1701         // Use cairo's FT_Library so that cairo takes care of shutdown of the
  1702         // FT_Library after it has destroyed its font_faces, and FT_Done_Face
  1703         // has been called on each FT_Face, at least until this bug is fixed:
  1704         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
  1705         //
  1706         // Cairo's FT_Library can be obtained from any cairo_scaled_font.  The
  1707         // font properties requested here are chosen to get an FT_Face that is
  1708         // likely to be also used elsewhere.
  1709         gfxFontStyle style;
  1710         nsRefPtr<gfxPangoFontGroup> fontGroup =
  1711             new gfxPangoFontGroup(NS_LITERAL_STRING("sans-serif"),
  1712                                   &style, nullptr);
  1714         gfxFcFont *font = fontGroup->GetBaseFont();
  1715         if (!font)
  1716             return nullptr;
  1718         gfxFT2LockedFace face(font);
  1719         if (!face.get())
  1720             return nullptr;
  1722         gFTLibrary = face.get()->glyph->library;
  1725     return gFTLibrary;
  1728 /* static */ gfxFontEntry *
  1729 gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
  1730                                 const uint8_t *aFontData, uint32_t aLength)
  1732     // Ownership of aFontData is passed in here, and transferred to the
  1733     // new fontEntry, which will release it when no longer needed.
  1735     // Using face_index = 0 for the first face in the font, as we have no
  1736     // other information.  FT_New_Memory_Face checks for a nullptr FT_Library.
  1737     FT_Face face;
  1738     FT_Error error =
  1739         FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face);
  1740     if (error != 0) {
  1741         NS_Free((void*)aFontData);
  1742         return nullptr;
  1745     return new gfxDownloadedFcFontEntry(aProxyEntry, aFontData, face);
  1749 static double
  1750 GetPixelSize(FcPattern *aPattern)
  1752     double size;
  1753     if (FcPatternGetDouble(aPattern,
  1754                            FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
  1755         return size;
  1757     NS_NOTREACHED("No size on pattern");
  1758     return 0.0;
  1761 /**
  1762  * The following gfxFcFonts are accessed from the cairo_scaled_font or created
  1763  * from the FcPattern, not from the gfxFontCache hash table.  The gfxFontCache
  1764  * hash table is keyed by desired family and style, whereas here we only know
  1765  * actual family and style.  There may be more than one of these fonts with
  1766  * the same family and style, but different PangoFont and actual font face.
  1768  * The point of this is to record the exact font face for gfxTextRun glyph
  1769  * indices.  The style of this font does not necessarily represent the exact
  1770  * gfxFontStyle used to build the text run.  Notably, the language is not
  1771  * recorded.
  1772  */
  1774 /* static */
  1775 already_AddRefed<gfxFcFont>
  1776 gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
  1777                          const gfxFontStyle *aFontStyle)
  1779     nsAutoRef<FcPattern> renderPattern
  1780         (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern));
  1781     cairo_font_face_t *face =
  1782         cairo_ft_font_face_create_for_pattern(renderPattern);
  1784     // Reuse an existing font entry if available.
  1785     nsRefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face);
  1786     if (!fe) {
  1787         gfxDownloadedFcFontEntry *downloadedFontEntry =
  1788             GetDownloadedFontEntry(aFontPattern);
  1789         if (downloadedFontEntry) {
  1790             // Web font
  1791             fe = downloadedFontEntry;
  1792             if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) {
  1793                 // cairo_font_face_t is using the web font data.
  1794                 // Hold a reference to the font entry to keep the font face
  1795                 // data.
  1796                 if (!downloadedFontEntry->SetCairoFace(face)) {
  1797                     // OOM.  Let cairo pick a fallback font
  1798                     cairo_font_face_destroy(face);
  1799                     face = cairo_ft_font_face_create_for_pattern(aRequestedPattern);
  1800                     fe = gfxFcFontEntry::LookupFontEntry(face);
  1804         if (!fe) {
  1805             // Get a unique name for the font face from the file and id.
  1806             nsAutoString name;
  1807             FcChar8 *fc_file;
  1808             if (FcPatternGetString(renderPattern,
  1809                                    FC_FILE, 0, &fc_file) == FcResultMatch) {
  1810                 int index;
  1811                 if (FcPatternGetInteger(renderPattern,
  1812                                         FC_INDEX, 0, &index) != FcResultMatch) {
  1813                     // cairo defaults to 0.
  1814                     index = 0;
  1817                 AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name);
  1818                 if (index != 0) {
  1819                     name.AppendLiteral("/");
  1820                     name.AppendInt(index);
  1824             fe = new gfxSystemFcFontEntry(face, aFontPattern, name);
  1828     gfxFontStyle style(*aFontStyle);
  1829     style.size = GetPixelSize(renderPattern);
  1830     style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern);
  1831     style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern);
  1833     nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(fe, &style);
  1834     if (!font) {
  1835         // Note that a file/index pair (or FT_Face) and the gfxFontStyle are
  1836         // not necessarily enough to provide a key that will describe a unique
  1837         // font.  cairoFont contains information from renderPattern, which is a
  1838         // fully resolved pattern from FcFontRenderPrepare.
  1839         // FcFontRenderPrepare takes the requested pattern and the face
  1840         // pattern as input and can modify elements of the resulting pattern
  1841         // that affect rendering but are not included in the gfxFontStyle.
  1842         cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face);
  1843         font = new gfxFcFont(cairoFont, fe, &style);
  1844         gfxFontCache::GetCache()->AddNew(font);
  1845         cairo_scaled_font_destroy(cairoFont);
  1848     cairo_font_face_destroy(face);
  1850     nsRefPtr<gfxFcFont> retval(static_cast<gfxFcFont*>(font.get()));
  1851     return retval.forget();
  1854 gfxFcFontSet *
  1855 gfxPangoFontGroup::GetBaseFontSet()
  1857     if (mFontSets.Length() > 0)
  1858         return mFontSets[0].mFontSet;
  1860     mSizeAdjustFactor = 1.0; // will be adjusted below if necessary
  1861     nsAutoRef<FcPattern> pattern;
  1862     nsRefPtr<gfxFcFontSet> fontSet =
  1863         MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern);
  1865     double size = GetPixelSize(pattern);
  1866     if (size != 0.0 && mStyle.sizeAdjust != 0.0) {
  1867         gfxFcFont *font = fontSet->GetFontAt(0, GetStyle());
  1868         if (font) {
  1869             const gfxFont::Metrics& metrics = font->GetMetrics();
  1871             // The factor of 0.1 ensures that xHeight is sane so fonts don't
  1872             // become huge.  Strictly ">" ensures that xHeight and emHeight are
  1873             // not both zero.
  1874             if (metrics.xHeight > 0.1 * metrics.emHeight) {
  1875                 mSizeAdjustFactor =
  1876                     mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight;
  1878                 size *= mSizeAdjustFactor;
  1879                 FcPatternDel(pattern, FC_PIXEL_SIZE);
  1880                 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
  1882                 fontSet = new gfxFcFontSet(pattern, mUserFontSet);
  1887     PangoLanguage *pangoLang = mPangoLanguage;
  1888     FcChar8 *fcLang;
  1889     if (!pangoLang &&
  1890         FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) {
  1891         pangoLang =
  1892             pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang));
  1895     mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet));
  1897     return fontSet;
  1900 /**
  1901  ** gfxTextRun
  1903  * A serious problem:
  1905  * -- We draw with a font that's hinted for the CTM, but we measure with a font
  1906  * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
  1908  **/
  1910 // This will fetch an existing scaled_font if one exists.
  1911 static cairo_scaled_font_t *
  1912 CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace)
  1914     double size = GetPixelSize(aPattern);
  1916     cairo_matrix_t fontMatrix;
  1917     FcMatrix *fcMatrix;
  1918     if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch)
  1919         cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0);
  1920     else
  1921         cairo_matrix_init_identity(&fontMatrix);
  1922     cairo_matrix_scale(&fontMatrix, size, size);
  1924     FcBool printing;
  1925     if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) {
  1926         printing = FcFalse;
  1929     // The cairo_scaled_font is created with a unit ctm so that metrics and
  1930     // positions are in user space, but this means that hinting effects will
  1931     // not be estimated accurately for non-unit transformations.
  1932     cairo_matrix_t identityMatrix;
  1933     cairo_matrix_init_identity(&identityMatrix);
  1935     // Font options are set explicitly here to improve cairo's caching
  1936     // behavior and to record the relevant parts of the pattern for
  1937     // SetupCairoFont (so that the pattern can be released).
  1938     //
  1939     // Most font_options have already been set as defaults on the FcPattern
  1940     // with cairo_ft_font_options_substitute(), then user and system
  1941     // fontconfig configurations were applied.  The resulting font_options
  1942     // have been recorded on the face during
  1943     // cairo_ft_font_face_create_for_pattern().
  1944     //
  1945     // None of the settings here cause this scaled_font to behave any
  1946     // differently from how it would behave if it were created from the same
  1947     // face with default font_options.
  1948     //
  1949     // We set options explicitly so that the same scaled_font will be found in
  1950     // the cairo_scaled_font_map when cairo loads glyphs from a context with
  1951     // the same font_face, font_matrix, ctm, and surface font_options.
  1952     //
  1953     // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
  1954     // font_options on the cairo_ft_font_face, and doesn't consider default
  1955     // option values to not match any explicit values.
  1956     //
  1957     // Even after cairo_set_scaled_font is used to set font_options for the
  1958     // cairo context, when cairo looks for a scaled_font for the context, it
  1959     // will look for a font with some option values from the target surface if
  1960     // any values are left default on the context font_options.  If this
  1961     // scaled_font is created with default font_options, cairo will not find
  1962     // it.
  1963     cairo_font_options_t *fontOptions = cairo_font_options_create();
  1965     // The one option not recorded in the pattern is hint_metrics, which will
  1966     // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
  1967     // We should be considering the font_options of the surface on which this
  1968     // font will be used, but currently we don't have different gfxFonts for
  1969     // different surface font_options, so we'll create a font suitable for the
  1970     // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
  1971 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
  1972     cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
  1973 #else
  1974     if (printing) {
  1975         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
  1976     } else {
  1977         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON);
  1979 #endif
  1981     // The remaining options have been recorded on the pattern and the face.
  1982     // _cairo_ft_options_merge has some logic to decide which options from the
  1983     // scaled_font or from the cairo_ft_font_face take priority in the way the
  1984     // font behaves.
  1985     //
  1986     // In the majority of cases, _cairo_ft_options_merge uses the options from
  1987     // the cairo_ft_font_face, so sometimes it is not so important which
  1988     // values are set here so long as they are not defaults, but we'll set
  1989     // them to the exact values that we expect from the font, to be consistent
  1990     // and to protect against changes in cairo.
  1991     //
  1992     // In some cases, _cairo_ft_options_merge uses some options from the
  1993     // scaled_font's font_options rather than options on the
  1994     // cairo_ft_font_face (from fontconfig).
  1995     // https://bugs.freedesktop.org/show_bug.cgi?id=11838
  1996     //
  1997     // Surface font options were set on the pattern in
  1998     // cairo_ft_font_options_substitute.  If fontconfig has changed the
  1999     // hint_style then that is what the user (or distribution) wants, so we
  2000     // use the setting from the FcPattern.
  2001     //
  2002     // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
  2003     FcBool hinting = FcFalse;
  2004 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
  2005     if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
  2006         hinting = FcTrue;
  2008 #endif
  2009     cairo_hint_style_t hint_style;
  2010     if (printing || !hinting) {
  2011         hint_style = CAIRO_HINT_STYLE_NONE;
  2012     } else {
  2013 #ifdef FC_HINT_STYLE  // FC_HINT_STYLE is available from fontconfig 2.2.91.
  2014         int fc_hintstyle;
  2015         if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
  2016                                 0, &fc_hintstyle        ) != FcResultMatch) {
  2017             fc_hintstyle = FC_HINT_FULL;
  2019         switch (fc_hintstyle) {
  2020             case FC_HINT_NONE:
  2021                 hint_style = CAIRO_HINT_STYLE_NONE;
  2022                 break;
  2023             case FC_HINT_SLIGHT:
  2024                 hint_style = CAIRO_HINT_STYLE_SLIGHT;
  2025                 break;
  2026             case FC_HINT_MEDIUM:
  2027             default: // This fallback mirrors _get_pattern_ft_options in cairo.
  2028                 hint_style = CAIRO_HINT_STYLE_MEDIUM;
  2029                 break;
  2030             case FC_HINT_FULL:
  2031                 hint_style = CAIRO_HINT_STYLE_FULL;
  2032                 break;
  2034 #else // no FC_HINT_STYLE
  2035         hint_style = CAIRO_HINT_STYLE_FULL;
  2036 #endif
  2038     cairo_font_options_set_hint_style(fontOptions, hint_style);
  2040     int rgba;
  2041     if (FcPatternGetInteger(aPattern,
  2042                             FC_RGBA, 0, &rgba) != FcResultMatch) {
  2043         rgba = FC_RGBA_UNKNOWN;
  2045     cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
  2046     switch (rgba) {
  2047         case FC_RGBA_UNKNOWN:
  2048         case FC_RGBA_NONE:
  2049         default:
  2050             // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
  2051             // is disabled through cairo_antialias_t.
  2052             rgba = FC_RGBA_NONE;
  2053             // subpixel_order won't be used by the font as we won't use
  2054             // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
  2055             // caching reasons described above.  Fall through:
  2056         case FC_RGBA_RGB:
  2057             subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
  2058             break;
  2059         case FC_RGBA_BGR:
  2060             subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
  2061             break;
  2062         case FC_RGBA_VRGB:
  2063             subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
  2064             break;
  2065         case FC_RGBA_VBGR:
  2066             subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
  2067             break;
  2069     cairo_font_options_set_subpixel_order(fontOptions, subpixel_order);
  2071     FcBool fc_antialias;
  2072     if (FcPatternGetBool(aPattern,
  2073                          FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
  2074         fc_antialias = FcTrue;
  2076     cairo_antialias_t antialias;
  2077     if (!fc_antialias) {
  2078         antialias = CAIRO_ANTIALIAS_NONE;
  2079     } else if (rgba == FC_RGBA_NONE) {
  2080         antialias = CAIRO_ANTIALIAS_GRAY;
  2081     } else {
  2082         antialias = CAIRO_ANTIALIAS_SUBPIXEL;
  2084     cairo_font_options_set_antialias(fontOptions, antialias);
  2086     cairo_scaled_font_t *scaledFont =
  2087         cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix,
  2088                                  fontOptions);
  2090     cairo_font_options_destroy(fontOptions);
  2092     NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
  2093                  "Failed to create scaled font");
  2094     return scaledFont;
  2097 /* static */
  2098 PangoLanguage *
  2099 GuessPangoLanguage(nsIAtom *aLanguage)
  2101     if (!aLanguage)
  2102         return nullptr;
  2104     // Pango and fontconfig won't understand mozilla's internal langGroups, so
  2105     // find a real language.
  2106     nsAutoCString lang;
  2107     gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang);
  2108     if (lang.IsEmpty())
  2109         return nullptr;
  2111     return pango_language_from_string(lang.get());
  2114 #ifdef MOZ_WIDGET_GTK
  2115 /***************************************************************************
  2117  * This function must be last in the file because it uses the system cairo
  2118  * library.  Above this point the cairo library used is the tree cairo if
  2119  * MOZ_TREE_CAIRO.
  2120  */
  2122 #if MOZ_TREE_CAIRO
  2123 // Tree cairo symbols have different names.  Disable their activation through
  2124 // preprocessor macros.
  2125 #undef cairo_ft_font_options_substitute
  2127 // The system cairo functions are not declared because the include paths cause
  2128 // the gdk headers to pick up the tree cairo.h.
  2129 extern "C" {
  2130 NS_VISIBILITY_DEFAULT void
  2131 cairo_ft_font_options_substitute (const cairo_font_options_t *options,
  2132                                   FcPattern                  *pattern);
  2134 #endif
  2136 static void
  2137 ApplyGdkScreenFontOptions(FcPattern *aPattern)
  2139     const cairo_font_options_t *options =
  2140         gdk_screen_get_font_options(gdk_screen_get_default());
  2142     cairo_ft_font_options_substitute(options, aPattern);
  2145 #endif // MOZ_WIDGET_GTK2
  2147 #ifdef USE_SKIA
  2148 mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
  2149 gfxFcFont::GetGlyphRenderingOptions()
  2151   cairo_scaled_font_t *scaled_font = CairoScaledFont();
  2152   cairo_font_options_t *options = cairo_font_options_create();
  2153   cairo_scaled_font_get_font_options(scaled_font, options);
  2154   cairo_hint_style_t hint_style = cairo_font_options_get_hint_style(options);     
  2155   cairo_font_options_destroy(options);
  2157   mozilla::gfx::FontHinting hinting;
  2159   switch (hint_style) {
  2160     case CAIRO_HINT_STYLE_NONE:
  2161       hinting = mozilla::gfx::FontHinting::NONE;
  2162       break;
  2163     case CAIRO_HINT_STYLE_SLIGHT:
  2164       hinting = mozilla::gfx::FontHinting::LIGHT;
  2165       break;
  2166     case CAIRO_HINT_STYLE_FULL:
  2167       hinting = mozilla::gfx::FontHinting::FULL;
  2168       break;
  2169     default:
  2170       hinting = mozilla::gfx::FontHinting::NORMAL;
  2171       break;
  2174   // We don't want to force the use of the autohinter over the font's built in hints
  2175   return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false);
  2177 #endif

mercurial