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 "prlink.h"
7 #include "gfxTypes.h"
8 
9 #include "nsTArray.h"
10 
11 #include "gfxContext.h"
12 #ifdef MOZ_WIDGET_GTK
13 #include "gfxPlatformGtk.h"
14 #endif
15 #include "gfxFontconfigFonts.h"
16 #include "gfxFT2FontBase.h"
17 #include "gfxFT2Utils.h"
18 #include "harfbuzz/hb.h"
19 #include "harfbuzz/hb-glib.h"
20 #include "harfbuzz/hb-ot.h"
21 #include "nsUnicodeProperties.h"
22 #include "nsUnicodeScriptCodes.h"
23 #include "gfxFontconfigUtils.h"
24 #include "gfxUserFontSet.h"
25 #include "gfxFontConstants.h"
26 #include "nsGkAtoms.h"
27 #include "nsILanguageAtomService.h"
28 #include "nsServiceManagerUtils.h"
29 
30 #include <cairo.h>
31 #include <cairo-ft.h>
32 #include "mozilla/gfx/HelpersCairo.h"
33 
34 #include <fontconfig/fcfreetype.h>
35 #include <pango/pango.h>
36 
37 #include FT_TRUETYPE_TABLES_H
38 
39 #ifdef MOZ_WIDGET_GTK
40 #include <gdk/gdk.h>
41 #endif
42 
43 #include <math.h>
44 
45 using namespace mozilla;
46 using namespace mozilla::unicode;
47 
48 #define PRINTING_FC_PROPERTY "gfx.printing"
49 
50 static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage);
51 
52 static cairo_scaled_font_t *
53 CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace);
54 
55 static FT_Library gFTLibrary;
56 
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
65 
66 static PRFuncPtr
FindFunctionSymbol(const char * name)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     }
74 
75     return result;
76 }
77 
HasChar(FcPattern * aFont,FcChar32 wc)78 static bool HasChar(FcPattern *aFont, FcChar32 wc)
79 {
80     FcCharSet *charset = nullptr;
81     FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
82 
83     return charset && FcCharSetHasChar(charset, wc);
84 }
85 
86 /**
87  * gfxFcFontEntry:
88  *
89  * An abstract base class of for gfxFontEntry implementations used by
90  * gfxFcFont and gfxUserFontSet.
91  */
92 
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.)
GetPatterns()101     const nsTArray< nsCountedRef<FcPattern> >& GetPatterns()
102     {
103         return mPatterns;
104     }
105 
LookupFontEntry(cairo_font_face_t * aFace)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     }
111 
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();
116 
117     // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
TestCharacterMap(uint32_t aCh)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     }
127 
128 protected:
gfxFcFontEntry(const nsAString & aName)129     explicit gfxFcFontEntry(const nsAString& aName)
130         : gfxFontEntry(aName)
131     {
132     }
133 
134     // One pattern is the common case and some subclasses rely on successful
135     // addition of the first element to the array.
136     AutoTArray<nsCountedRef<FcPattern>,1> mPatterns;
137 
138     static cairo_user_data_key_t sFontEntryKey;
139 };
140 
141 cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
142 
143 nsString
RealFaceName()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.Append(' ');
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 }
166 
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  */
176 
177 class gfxSystemFcFontEntry : public gfxFcFontEntry {
178 public:
179     // For memory efficiency, aFontPattern should be a font pattern,
180     // not a fully resolved pattern.
gfxSystemFcFontEntry(cairo_font_face_t * aFontFace,FcPattern * aFontPattern,const nsAString & aName)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 
190         // mPatterns is an AutoTArray with 1 space always available, so the
191         // AppendElement always succeeds.
192         // FIXME: Make this infallible after bug 968520 is done.
193         MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
194         mPatterns[0] = aFontPattern;
195 
196         FcChar8 *name;
197         if (FcPatternGetString(aFontPattern,
198                                FC_FAMILY, 0, &name) == FcResultMatch) {
199             mFamilyName = NS_ConvertUTF8toUTF16((const char*)name);
200         }
201     }
202 
~gfxSystemFcFontEntry()203     ~gfxSystemFcFontEntry()
204     {
205         cairo_font_face_set_user_data(mFontFace,
206                                       &sFontEntryKey,
207                                       nullptr,
208                                       nullptr);
209         cairo_font_face_destroy(mFontFace);
210     }
211 
212     virtual void ForgetHBFace() override;
213     virtual void ReleaseGrFace(gr_face* aFace) override;
214 
215 protected:
216     virtual nsresult
217     CopyFontTable(uint32_t aTableTag, nsTArray<uint8_t>& aBuffer) override;
218 
219     void MaybeReleaseFTFace();
220 
221 private:
222     cairo_font_face_t *mFontFace;
223     FT_Face            mFTFace;
224     bool               mFTFaceInitialized;
225 };
226 
227 nsresult
CopyFontTable(uint32_t aTableTag,nsTArray<uint8_t> & aBuffer)228 gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
229                                     nsTArray<uint8_t>& aBuffer)
230 {
231     if (!mFTFaceInitialized) {
232         mFTFaceInitialized = true;
233         FcChar8 *filename;
234         if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
235             return NS_ERROR_FAILURE;
236         }
237         int index;
238         if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
239             index = 0; // default to 0 if not found in pattern
240         }
241         if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
242                         (const char*)filename, index, &mFTFace) != 0) {
243             return NS_ERROR_FAILURE;
244         }
245     }
246 
247     if (!mFTFace) {
248         return NS_ERROR_NOT_AVAILABLE;
249     }
250 
251     FT_ULong length = 0;
252     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
253         return NS_ERROR_NOT_AVAILABLE;
254     }
255     if (!aBuffer.SetLength(length, fallible)) {
256         return NS_ERROR_OUT_OF_MEMORY;
257     }
258     if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
259         aBuffer.Clear();
260         return NS_ERROR_FAILURE;
261     }
262 
263     return NS_OK;
264 }
265 
266 void
MaybeReleaseFTFace()267 gfxSystemFcFontEntry::MaybeReleaseFTFace()
268 {
269     // don't release if either HB or Gr face still exists
270     if (mHBFace || mGrFace) {
271         return;
272     }
273     if (mFTFace) {
274         FT_Done_Face(mFTFace);
275         mFTFace = nullptr;
276     }
277     mFTFaceInitialized = false;
278 }
279 
280 void
ForgetHBFace()281 gfxSystemFcFontEntry::ForgetHBFace()
282 {
283     gfxFontEntry::ForgetHBFace();
284     MaybeReleaseFTFace();
285 }
286 
287 void
ReleaseGrFace(gr_face * aFace)288 gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
289 {
290     gfxFontEntry::ReleaseGrFace(aFace);
291     MaybeReleaseFTFace();
292 }
293 
294 // A namespace for @font-face family names in FcPatterns so that fontconfig
295 // aliases do not pick up families from @font-face rules and so that
296 // fontconfig rules can distinguish between web fonts and platform fonts.
297 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
298 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
299 
300 /**
301  * gfxUserFcFontEntry:
302  *
303  * An abstract class for objects in a gfxUserFontSet that can provide
304  * FcPattern* handles to fonts.
305  *
306  * Separate implementations of this class support local fonts from src:local()
307  * and web fonts from src:url().
308  */
309 
310 // There is a one-to-one correspondence between gfxUserFcFontEntry objects and
311 // @font-face rules, but sometimes a one-to-many correspondence between font
312 // entries and font patterns.
313 //
314 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions
315 // provided a font-size descriptor to specify the sizes supported by the face,
316 // but the "Editor's Draft 27 June 2008"
317 // http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a
318 // descriptor, and Mozilla does not recognize such a descriptor.
319 //
320 // Font face names used in src:local() also do not usually specify a size.
321 //
322 // PCF format fonts have each size in a different file, and each of these
323 // files is referenced by its own pattern, but really these are each
324 // different sizes of one face with one name.
325 //
326 // Multiple patterns in an entry also effectively deals with a set of
327 // PostScript Type 1 font files that all have the same face name but are in
328 // several files because of the limit on the number of glyphs in a Type 1 font
329 // file.  (e.g. Computer Modern.)
330 
331 class gfxUserFcFontEntry : public gfxFcFontEntry {
332 protected:
gfxUserFcFontEntry(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle)333     explicit gfxUserFcFontEntry(const nsAString& aFontName,
334                        uint16_t aWeight,
335                        int16_t aStretch,
336                        uint8_t aStyle)
337         : gfxFcFontEntry(aFontName)
338     {
339         mStyle = aStyle;
340         mWeight = aWeight;
341         mStretch = aStretch;
342     }
343 
344     // Helper function to change a pattern so that it matches the CSS style
345     // descriptors and so gets properly sorted in font selection.  This also
346     // avoids synthetic style effects being added by the renderer when the
347     // style of the font itself does not match the descriptor provided by the
348     // author.
349     void AdjustPatternToCSS(FcPattern *aPattern);
350 };
351 
352 void
AdjustPatternToCSS(FcPattern * aPattern)353 gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
354 {
355     int fontWeight = -1;
356     FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight);
357     int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100);
358     if (cssWeight != fontWeight) {
359         FcPatternDel(aPattern, FC_WEIGHT);
360         FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight);
361     }
362 
363     int fontSlant;
364     FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant);
365     // gfxFontEntry doesn't understand the difference between oblique
366     // and italic.
367     if (res != FcResultMatch ||
368         IsItalic() != (fontSlant != FC_SLANT_ROMAN)) {
369         FcPatternDel(aPattern, FC_SLANT);
370         FcPatternAddInteger(aPattern, FC_SLANT,
371                             IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN);
372     }
373 
374     int fontWidth = -1;
375     FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth);
376     int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch);
377     if (cssWidth != fontWidth) {
378         FcPatternDel(aPattern, FC_WIDTH);
379         FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth);
380     }
381 
382     // Ensure that there is a fullname property (if there is a family
383     // property) so that fontconfig rules can identify the real name of the
384     // font, because the family property will be replaced.
385     FcChar8 *unused;
386     if (FcPatternGetString(aPattern,
387                            FC_FULLNAME, 0, &unused) == FcResultNoMatch) {
388         nsAutoCString fullname;
389         if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern,
390                                                               &fullname)) {
391             FcPatternAddString(aPattern, FC_FULLNAME,
392                                gfxFontconfigUtils::ToFcChar8(fullname));
393         }
394     }
395 
396     nsAutoCString family;
397     family.Append(FONT_FACE_FAMILY_PREFIX);
398     AppendUTF16toUTF8(Name(), family);
399 
400     FcPatternDel(aPattern, FC_FAMILY);
401     FcPatternDel(aPattern, FC_FAMILYLANG);
402     FcPatternAddString(aPattern, FC_FAMILY,
403                        gfxFontconfigUtils::ToFcChar8(family));
404 }
405 
406 /**
407  * gfxLocalFcFontEntry:
408  *
409  * An implementation of gfxUserFcFontEntry for local fonts from src:local().
410  *
411  * This class is used only in gfxUserFontSet and for providing FcPattern*
412  * handles to system fonts for font selection.  gfxFcFonts created from these
413  * patterns will use gfxSystemFcFontEntrys, which may be shared with
414  * gfxFcFonts from regular family-name based font selection.
415  */
416 
417 class gfxLocalFcFontEntry : public gfxUserFcFontEntry {
418 public:
gfxLocalFcFontEntry(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle,const nsTArray<nsCountedRef<FcPattern>> & aPatterns)419     gfxLocalFcFontEntry(const nsAString& aFontName,
420                         uint16_t aWeight,
421                         int16_t aStretch,
422                         uint8_t aStyle,
423                         const nsTArray< nsCountedRef<FcPattern> >& aPatterns)
424         : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle)
425     {
426         if (!mPatterns.SetCapacity(aPatterns.Length(), fallible))
427             return; // OOM
428 
429         for (uint32_t i = 0; i < aPatterns.Length(); ++i) {
430             FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i));
431             if (!pattern)
432                 return; // OOM
433 
434             AdjustPatternToCSS(pattern);
435 
436             // FIXME: Make this infallible after bug 968520 is done.
437             MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
438             mPatterns[i].own(pattern);
439         }
440         mIsLocalUserFont = true;
441     }
442 };
443 
444 /**
445  * gfxDownloadedFcFontEntry:
446  *
447  * An implementation of gfxFcFontEntry for web fonts from src:url().
448  *
449  * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t
450  * keeps a reference to the FontEntry to keep the font data alive.
451  */
452 
453 class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry {
454 public:
455     // This takes ownership of the face and its underlying data
gfxDownloadedFcFontEntry(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle,const uint8_t * aData,FT_Face aFace)456     gfxDownloadedFcFontEntry(const nsAString& aFontName,
457                              uint16_t aWeight,
458                              int16_t aStretch,
459                              uint8_t aStyle,
460                              const uint8_t *aData, FT_Face aFace)
461         : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle),
462           mFontData(aData), mFace(aFace)
463     {
464         NS_PRECONDITION(aFace != nullptr, "aFace is NULL!");
465         mIsDataUserFont = true;
466         InitPattern();
467     }
468 
469     virtual ~gfxDownloadedFcFontEntry();
470 
471     // Returns true on success
472     bool SetCairoFace(cairo_font_face_t *aFace);
473 
474     virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override;
475 
476 protected:
477     void InitPattern();
478 
479     // mFontData holds the data used to instantiate the FT_Face;
480     // this has to persist until we are finished with the face,
481     // then be released with free().
482     const uint8_t* mFontData;
483 
484     FT_Face mFace;
485 };
486 
487 // A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
488 static const char *kFontEntryFcProp = "-moz-font-entry";
489 
AddDownloadedFontEntry(FcPattern * aPattern,gfxDownloadedFcFontEntry * aFontEntry)490 static FcBool AddDownloadedFontEntry(FcPattern *aPattern,
491                                      gfxDownloadedFcFontEntry *aFontEntry)
492 {
493     FcValue value;
494     value.type = FcTypeFTFace; // void* field of union
495     value.u.f = aFontEntry;
496 
497     return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse);
498 }
499 
DelDownloadedFontEntry(FcPattern * aPattern)500 static FcBool DelDownloadedFontEntry(FcPattern *aPattern)
501 {
502     return FcPatternDel(aPattern, kFontEntryFcProp);
503 }
504 
GetDownloadedFontEntry(FcPattern * aPattern)505 static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern)
506 {
507     FcValue value;
508     if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch)
509         return nullptr;
510 
511     if (value.type != FcTypeFTFace) {
512         NS_NOTREACHED("Wrong type for -moz-font-entry font property");
513         return nullptr;
514     }
515 
516     return static_cast<gfxDownloadedFcFontEntry*>(value.u.f);
517 }
518 
~gfxDownloadedFcFontEntry()519 gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
520 {
521     if (mPatterns.Length() != 0) {
522         // Remove back reference to this font entry and the face in case
523         // anyone holds a reference to the pattern.
524         NS_ASSERTION(mPatterns.Length() == 1,
525                      "More than one pattern in gfxDownloadedFcFontEntry!");
526         DelDownloadedFontEntry(mPatterns[0]);
527         FcPatternDel(mPatterns[0], FC_FT_FACE);
528     }
529     FT_Done_Face(mFace);
530     free((void*)mFontData);
531 }
532 
533 typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
534                                         const FcChar8 *file, int id,
535                                         FcBlanks *blanks);
536 
537 void
InitPattern()538 gfxDownloadedFcFontEntry::InitPattern()
539 {
540     static QueryFaceFunction sQueryFacePtr =
541         reinterpret_cast<QueryFaceFunction>
542         (FindFunctionSymbol("FcFreeTypeQueryFace"));
543     FcPattern *pattern;
544 
545     // FcFreeTypeQueryFace is the same function used to construct patterns for
546     // system fonts and so is the preferred function to use for this purpose.
547     // This will set up the langset property, which helps with sorting, and
548     // the foundry, fullname, and fontversion properties, which properly
549     // identify the font to fontconfig rules.  However, FcFreeTypeQueryFace is
550     // available only from fontconfig-2.4.2 (December 2006).  (CentOS 5.0 has
551     // fontconfig-2.4.1.)
552     if (sQueryFacePtr) {
553         // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at
554         // least). The dummy file passed here is removed below.
555         //
556         // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr)
557         // is passed as the "blanks" argument, which provides that unexpectedly
558         // blank glyphs are elided.  Here, however, we pass nullptr for
559         // "blanks", effectively assuming that, if the font has a blank glyph,
560         // then the author intends any associated character to be rendered
561         // blank.
562         pattern =
563             (*sQueryFacePtr)(mFace,
564                              gfxFontconfigUtils::ToFcChar8(""),
565                              0,
566                              nullptr);
567         if (!pattern)
568             // Either OOM, or fontconfig chose to skip this font because it
569             // has "no encoded characters", which I think means "BDF and PCF
570             // fonts which are not in Unicode (or the effectively equivalent
571             // ISO Latin-1) encoding".
572             return;
573 
574         // These properties don't make sense for this face without a file.
575         FcPatternDel(pattern, FC_FILE);
576         FcPatternDel(pattern, FC_INDEX);
577 
578     } else {
579         // Do the minimum necessary to construct a pattern for sorting.
580 
581         // FC_CHARSET is vital to determine which characters are supported.
582         nsAutoRef<FcCharSet> charset(FcFreeTypeCharSet(mFace, nullptr));
583         // If there are no characters then assume we don't know how to read
584         // this font.
585         if (!charset || FcCharSetCount(charset) == 0)
586             return;
587 
588         pattern = FcPatternCreate();
589         FcPatternAddCharSet(pattern, FC_CHARSET, charset);
590 
591         // FC_PIXEL_SIZE can be important for font selection of fixed-size
592         // fonts.
593         if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) {
594             for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) {
595 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
596                 double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem);
597 #else
598                 double size = mFace->available_sizes[i].height;
599 #endif
600                 FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
601             }
602 
603             // Not sure whether this is important;
604             // imitating FcFreeTypeQueryFace:
605             FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse);
606         }
607 
608         // Setting up the FC_LANGSET property is very difficult with the APIs
609         // available prior to FcFreeTypeQueryFace.  Having no FC_LANGSET
610         // property seems better than having a property with an empty LangSet.
611         // With no FC_LANGSET property, fontconfig sort functions will
612         // consider this face to have the same priority as (otherwise equal)
613         // faces that have support for the primary requested language, but
614         // will not consider any language to have been satisfied (and so will
615         // continue to look for a face with language support in fallback
616         // fonts).
617     }
618 
619     AdjustPatternToCSS(pattern);
620 
621     FcPatternAddFTFace(pattern, FC_FT_FACE, mFace);
622     AddDownloadedFontEntry(pattern, this);
623 
624     // There is never more than one pattern
625     // FIXME: Make this infallible after bug 968520 is done.
626     MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
627     mPatterns[0].own(pattern);
628 }
629 
ReleaseDownloadedFontEntry(void * data)630 static void ReleaseDownloadedFontEntry(void *data)
631 {
632     gfxDownloadedFcFontEntry *downloadedFontEntry =
633         static_cast<gfxDownloadedFcFontEntry*>(data);
634     NS_RELEASE(downloadedFontEntry);
635 }
636 
SetCairoFace(cairo_font_face_t * aFace)637 bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace)
638 {
639     if (CAIRO_STATUS_SUCCESS !=
640         cairo_font_face_set_user_data(aFace, &sFontEntryKey, this,
641                                       ReleaseDownloadedFontEntry))
642         return false;
643 
644     // Hold a reference to this font entry to keep the font face data.
645     NS_ADDREF(this);
646     return true;
647 }
648 
649 hb_blob_t *
GetFontTable(uint32_t aTableTag)650 gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
651 {
652     // The entry already owns the (sanitized) sfnt data in mFontData,
653     // so we can just return a blob that "wraps" the appropriate chunk of it.
654     // The blob should not attempt to free its data, as the entire sfnt data
655     // will be freed when the font entry is deleted.
656     return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag);
657 }
658 
659 /*
660  * gfxFcFont
661  *
662  * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
663  * cairo_scaled_font created from an FcPattern.
664  */
665 
666 class gfxFcFont : public gfxFontconfigFontBase {
667 public:
668     virtual ~gfxFcFont();
669     static already_AddRefed<gfxFcFont>
670     GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
671                   const gfxFontStyle *aFontStyle);
672 
673     // return a cloned font resized and offset to simulate sub/superscript glyphs
674     virtual already_AddRefed<gfxFont>
675     GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) override;
676 
677 protected:
678     virtual already_AddRefed<gfxFont> MakeScaledFont(gfxFontStyle *aFontStyle,
679                                                      gfxFloat aFontScale);
680     virtual already_AddRefed<gfxFont> GetSmallCapsFont() override;
681 
682 private:
683     gfxFcFont(cairo_scaled_font_t *aCairoFont,
684               FcPattern *aPattern,
685               gfxFcFontEntry *aFontEntry,
686               const gfxFontStyle *aFontStyle);
687 
688     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
689     static cairo_user_data_key_t sGfxFontKey;
690 };
691 
692 /**
693  * gfxFcFontSet:
694  *
695  * Translation from a desired FcPattern to a sorted set of font references
696  * (fontconfig cache data) and (when needed) fonts.
697  */
698 
699 class gfxFcFontSet final {
700 public:
701     NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet)
702 
gfxFcFontSet(FcPattern * aPattern,gfxUserFontSet * aUserFontSet)703     explicit gfxFcFontSet(FcPattern *aPattern,
704                                gfxUserFontSet *aUserFontSet)
705         : mSortPattern(aPattern), mUserFontSet(aUserFontSet),
706           mFcFontsTrimmed(0),
707           mHaveFallbackFonts(false)
708     {
709         bool waitForUserFont;
710         mFcFontSet = SortPreferredFonts(waitForUserFont);
711         mWaitingForUserFont = waitForUserFont;
712     }
713 
714     // A reference is held by the FontSet.
715     // The caller may add a ref to keep the font alive longer than the FontSet.
GetFontAt(uint32_t i,const gfxFontStyle * aFontStyle)716     gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle)
717     {
718         if (i >= mFonts.Length() || !mFonts[i].mFont) {
719             // GetFontPatternAt sets up mFonts
720             FcPattern *fontPattern = GetFontPatternAt(i);
721             if (!fontPattern)
722                 return nullptr;
723 
724             mFonts[i].mFont =
725                 gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern,
726                                          aFontStyle);
727         }
728         return mFonts[i].mFont;
729     }
730 
731     FcPattern *GetFontPatternAt(uint32_t i);
732 
WaitingForUserFont() const733     bool WaitingForUserFont() const {
734         return mWaitingForUserFont;
735     }
736 
737 private:
738     // Private destructor, to discourage deletion outside of Release():
~gfxFcFontSet()739     ~gfxFcFontSet()
740     {
741     }
742 
743     nsReturnRef<FcFontSet> SortPreferredFonts(bool& aWaitForUserFont);
744     nsReturnRef<FcFontSet> SortFallbackFonts();
745 
746     struct FontEntry {
FontEntrygfxFcFontSet::FontEntry747         explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {}
748         nsCountedRef<FcPattern> mPattern;
749         RefPtr<gfxFcFont> mFont;
750     };
751 
752     struct LangSupportEntry {
LangSupportEntrygfxFcFontSet::LangSupportEntry753         LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) :
754             mLang(aLang), mBestSupport(aSupport) {}
755         FcChar8 *mLang;
756         FcLangResult mBestSupport;
757     };
758 
759 public:
760     // public for nsTArray
761     class LangComparator {
762     public:
Equals(const LangSupportEntry & a,const FcChar8 * b) const763         bool Equals(const LangSupportEntry& a, const FcChar8 *b) const
764         {
765             return FcStrCmpIgnoreCase(a.mLang, b) == 0;
766         }
767     };
768 
769 private:
770     // The requested pattern
771     nsCountedRef<FcPattern> mSortPattern;
772     // Fonts from @font-face rules
773     RefPtr<gfxUserFontSet> mUserFontSet;
774     // A (trimmed) list of font patterns and fonts that is built up as
775     // required.
776     nsTArray<FontEntry> mFonts;
777     // Holds a list of font patterns that will be trimmed.  This is first set
778     // to a list of preferred fonts.  Then, if/when all the preferred fonts
779     // have been trimmed and added to mFonts, this is set to a list of
780     // fallback fonts.
781     nsAutoRef<FcFontSet> mFcFontSet;
782     // The set of characters supported by the fonts in mFonts.
783     nsAutoRef<FcCharSet> mCharSet;
784     // The index of the next font in mFcFontSet that has not yet been
785     // considered for mFonts.
786     int mFcFontsTrimmed;
787     // True iff fallback fonts are either stored in mFcFontSet or have been
788     // trimmed and added to mFonts (so that mFcFontSet is nullptr).
789     bool mHaveFallbackFonts;
790     // True iff there was a user font set with pending downloads,
791     // so the set may be updated when downloads complete
792     bool mWaitingForUserFont;
793 };
794 
795 // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
796 // and style |aStyle| properties.
797 static const nsTArray< nsCountedRef<FcPattern> >*
FindFontPatterns(gfxUserFontSet * mUserFontSet,const nsACString & aFamily,uint8_t aStyle,uint16_t aWeight,int16_t aStretch,bool & aWaitForUserFont)798 FindFontPatterns(gfxUserFontSet *mUserFontSet,
799                  const nsACString &aFamily, uint8_t aStyle,
800                  uint16_t aWeight, int16_t aStretch,
801                  bool& aWaitForUserFont)
802 {
803     // Convert to UTF16
804     NS_ConvertUTF8toUTF16 utf16Family(aFamily);
805 
806     // needsBold is not used here.  Instead synthetic bold is enabled through
807     // FcFontRenderPrepare when the weight in the requested pattern is
808     // compared against the weight in the font pattern.
809     bool needsBold;
810 
811     gfxFontStyle style;
812     style.style = aStyle;
813     style.weight = aWeight;
814     style.stretch = aStretch;
815 
816     gfxUserFcFontEntry *fontEntry = nullptr;
817     gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family);
818     if (family) {
819         gfxUserFontEntry* userFontEntry =
820             mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold,
821                                                    aWaitForUserFont);
822         if (userFontEntry) {
823             fontEntry = static_cast<gfxUserFcFontEntry*>
824                 (userFontEntry->GetPlatformFontEntry());
825         }
826 
827         // Accept synthetic oblique for italic and oblique.
828         // xxx - this isn't really ideal behavior, for docs that only use a
829         //       single italic face it will also pull down the normal face
830         //       and probably never use it
831         if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
832             style.style = NS_FONT_STYLE_NORMAL;
833             userFontEntry =
834                 mUserFontSet->FindUserFontEntryAndLoad(family, style,
835                                                        needsBold,
836                                                        aWaitForUserFont);
837             if (userFontEntry) {
838                 fontEntry = static_cast<gfxUserFcFontEntry*>
839                     (userFontEntry->GetPlatformFontEntry());
840             }
841         }
842     }
843 
844     if (!fontEntry) {
845         return nullptr;
846     }
847 
848     return &fontEntry->GetPatterns();
849 }
850 
851 typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object,
852                                           int id);
853 
854 // FcPatternRemove is available in fontconfig-2.3.0 (2005)
855 static FcBool
moz_FcPatternRemove(FcPattern * p,const char * object,int id)856 moz_FcPatternRemove(FcPattern *p, const char *object, int id)
857 {
858     static FcPatternRemoveFunction sFcPatternRemovePtr =
859         reinterpret_cast<FcPatternRemoveFunction>
860         (FindFunctionSymbol("FcPatternRemove"));
861 
862     if (!sFcPatternRemovePtr)
863         return FcFalse;
864 
865     return (*sFcPatternRemovePtr)(p, object, id);
866 }
867 
868 // fontconfig prefers a matching family or lang to pixelsize of bitmap
869 // fonts.  CSS suggests a tolerance of 20% on pixelsize.
870 static bool
SizeIsAcceptable(FcPattern * aFont,double aRequestedSize)871 SizeIsAcceptable(FcPattern *aFont, double aRequestedSize)
872 {
873     double size;
874     int v = 0;
875     while (FcPatternGetDouble(aFont,
876                               FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
877         ++v;
878         if (5.0 * fabs(size - aRequestedSize) < aRequestedSize)
879             return true;
880     }
881 
882     // No size means scalable
883     return v == 0;
884 }
885 
886 // Sorting only the preferred fonts first usually saves having to sort through
887 // every font on the system.
888 nsReturnRef<FcFontSet>
SortPreferredFonts(bool & aWaitForUserFont)889 gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
890 {
891     aWaitForUserFont = false;
892 
893     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
894     if (!utils)
895         return nsReturnRef<FcFontSet>();
896 
897     // The list of families in mSortPattern has values with both weak and
898     // strong bindings.  Values with strong bindings should be preferred.
899     // Values with weak bindings are default fonts that should be considered
900     // only when the font provides the best support for a requested language
901     // or after other fonts have satisfied all the requested languages.
902     //
903     // There are no direct fontconfig APIs to get the binding type.  The
904     // binding only takes effect in the sort and match functions.
905 
906     // |requiredLangs| is a list of requested languages that have not yet been
907     // satisfied.  gfxFontconfigUtils only sets one FC_LANG property value,
908     // but FcConfigSubstitute may add more values (e.g. prepending "en" to
909     // "ja" will use western fonts to render Latin/Arabic numerals in Japanese
910     // text.)
911     AutoTArray<LangSupportEntry,10> requiredLangs;
912     for (int v = 0; ; ++v) {
913         FcChar8 *lang;
914         FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang);
915         if (result != FcResultMatch) {
916             // No need to check FcPatternGetLangSet() because
917             // gfxFontconfigUtils sets only a string value for FC_LANG and
918             // FcConfigSubstitute cannot add LangSets.
919             NS_ASSERTION(result != FcResultTypeMismatch,
920                          "Expected a string for FC_LANG");
921             break;
922         }
923 
924         if (!requiredLangs.Contains(lang, LangComparator())) {
925             FcLangResult bestLangSupport = utils->GetBestLangSupport(lang);
926             if (bestLangSupport != FcLangDifferentLang) {
927                 requiredLangs.
928                     AppendElement(LangSupportEntry(lang, bestLangSupport));
929             }
930         }
931     }
932 
933     nsAutoRef<FcFontSet> fontSet(FcFontSetCreate());
934     if (!fontSet)
935         return fontSet.out();
936 
937     // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever
938     // doesn't happen, Roman will be used.
939     int requestedSlant = FC_SLANT_ROMAN;
940     FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant);
941     double requestedSize = -1.0;
942     FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize);
943 
944     nsTHashtable<gfxFontconfigUtils::DepFcStrEntry> existingFamilies(32);
945     FcChar8 *family;
946     for (int v = 0;
947          FcPatternGetString(mSortPattern,
948                             FC_FAMILY, v, &family) == FcResultMatch; ++v) {
949         const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nullptr;
950 
951         // Is this an @font-face family?
952         bool isUserFont = false;
953         if (mUserFontSet) {
954             // Have some @font-face definitions
955 
956             nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family));
957             NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX);
958 
959             if (StringBeginsWith(cFamily, userPrefix)) {
960                 isUserFont = true;
961 
962                 // Trim off the prefix
963                 nsDependentCSubstring cssFamily(cFamily, userPrefix.Length());
964 
965                 uint8_t thebesStyle =
966                     gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant);
967                 uint16_t thebesWeight =
968                     gfxFontconfigUtils::GetThebesWeight(mSortPattern);
969                 int16_t thebesStretch =
970                     gfxFontconfigUtils::GetThebesStretch(mSortPattern);
971 
972                 bool waitForUserFont;
973                 familyFonts = FindFontPatterns(mUserFontSet, cssFamily,
974                                                thebesStyle,
975                                                thebesWeight, thebesStretch,
976                                                waitForUserFont);
977                 if (waitForUserFont) {
978                     aWaitForUserFont = true;
979                 }
980             }
981         }
982 
983         if (!isUserFont) {
984             familyFonts = &utils->GetFontsForFamily(family);
985         }
986 
987         if (!familyFonts || familyFonts->Length() == 0) {
988             // There are no fonts matching this family, so there is no point
989             // in searching for this family in the FontSort.
990             //
991             // Perhaps the original pattern should be retained for
992             // FcFontRenderPrepare.  However, the only a useful config
993             // substitution test against missing families that i can imagine
994             // would only be interested in the preferred family
995             // (qual="first"), so always keep the first family and use the
996             // same pattern for Sort and RenderPrepare.
997             if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) {
998                 --v;
999             }
1000             continue;
1001         }
1002 
1003         // Aliases seem to often end up occurring more than once, but
1004         // duplicate families can't be removed from the sort pattern without
1005         // knowing whether duplicates have the same binding.
1006         gfxFontconfigUtils::DepFcStrEntry *familyEntry =
1007             existingFamilies.PutEntry(family);
1008         if (familyEntry) {
1009             if (familyEntry->mKey) // old entry
1010                 continue;
1011 
1012             familyEntry->mKey = family; // initialize new entry
1013         }
1014 
1015         for (uint32_t f = 0; f < familyFonts->Length(); ++f) {
1016             FcPattern *font = familyFonts->ElementAt(f);
1017 
1018             // Fix up the family name of user-font patterns, as the same
1019             // font entry may be used (via the UserFontCache) for multiple
1020             // CSS family names
1021             if (isUserFont) {
1022                 font = FcPatternDuplicate(font);
1023                 FcPatternDel(font, FC_FAMILY);
1024                 FcPatternAddString(font, FC_FAMILY, family);
1025             }
1026 
1027             // User fonts are already filtered by slant (but not size) in
1028             // mUserFontSet->FindUserFontEntry().
1029             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
1030                 continue;
1031 
1032             for (uint32_t r = 0; r < requiredLangs.Length(); ++r) {
1033                 const LangSupportEntry& langEntry = requiredLangs[r];
1034                 FcLangResult support =
1035                     gfxFontconfigUtils::GetLangSupport(font, langEntry.mLang);
1036                 if (support <= langEntry.mBestSupport) { // lower is better
1037                     requiredLangs.RemoveElementAt(r);
1038                     --r;
1039                 }
1040             }
1041 
1042             // FcFontSetDestroy will remove a reference but FcFontSetAdd
1043             // does _not_ take a reference!
1044             if (FcFontSetAdd(fontSet, font)) {
1045                 // We don't add a reference here for user fonts, because we're
1046                 // using a local clone of the pattern (see above) in order to
1047                 // override the family name
1048                 if (!isUserFont) {
1049                     FcPatternReference(font);
1050                 }
1051             }
1052         }
1053     }
1054 
1055     FcPattern *truncateMarker = nullptr;
1056     for (uint32_t r = 0; r < requiredLangs.Length(); ++r) {
1057         const nsTArray< nsCountedRef<FcPattern> >& langFonts =
1058             utils->GetFontsForLang(requiredLangs[r].mLang);
1059 
1060         bool haveLangFont = false;
1061         for (uint32_t f = 0; f < langFonts.Length(); ++f) {
1062             FcPattern *font = langFonts[f];
1063             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
1064                 continue;
1065 
1066             haveLangFont = true;
1067             if (FcFontSetAdd(fontSet, font)) {
1068                 FcPatternReference(font);
1069             }
1070         }
1071 
1072         if (!haveLangFont && langFonts.Length() > 0) {
1073             // There is a font that supports this language but it didn't pass
1074             // the slant and size criteria.  Weak default font families should
1075             // not be considered until the language has been satisfied.
1076             //
1077             // Insert a font that supports the language so that it will mark
1078             // the position of fonts from weak families in the sorted set and
1079             // they can be removed.  The language and weak families will be
1080             // considered in the fallback fonts, which use fontconfig's
1081             // algorithm.
1082             //
1083             // Of the fonts that don't meet slant and size criteria, strong
1084             // default font families should be considered before (other) fonts
1085             // for this language, so this marker font will be removed (as well
1086             // as the fonts from weak families), and strong families will be
1087             // reconsidered in the fallback fonts.
1088             FcPattern *font = langFonts[0];
1089             if (FcFontSetAdd(fontSet, font)) {
1090                 FcPatternReference(font);
1091                 truncateMarker = font;
1092             }
1093             break;
1094         }
1095     }
1096 
1097     FcFontSet *sets[1] = { fontSet };
1098     FcResult result;
1099 #ifdef SOLARIS
1100     // Get around a crash of FcFontSetSort when FcConfig is nullptr
1101     // Solaris's FcFontSetSort needs an FcConfig (bug 474758)
1102     fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern,
1103                               FcFalse, nullptr, &result));
1104 #else
1105     fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern,
1106                               FcFalse, nullptr, &result));
1107 #endif
1108 
1109     if (truncateMarker != nullptr && fontSet) {
1110         nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate());
1111 
1112         for (int f = 0; f < fontSet->nfont; ++f) {
1113             FcPattern *font = fontSet->fonts[f];
1114             if (font == truncateMarker)
1115                 break;
1116 
1117             if (FcFontSetAdd(truncatedSet, font)) {
1118                 FcPatternReference(font);
1119             }
1120         }
1121 
1122         fontSet.steal(truncatedSet);
1123     }
1124 
1125     return fontSet.out();
1126 }
1127 
1128 nsReturnRef<FcFontSet>
SortFallbackFonts()1129 gfxFcFontSet::SortFallbackFonts()
1130 {
1131     // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet,
1132     // but would take much longer due to comparing all the character sets.
1133     //
1134     // The references to fonts in this FcFontSet are almost free
1135     // as they are pointers into mmaped cache files.
1136     //
1137     // GetFontPatternAt() will trim lazily if and as needed, which will also
1138     // remove duplicates of preferred fonts.
1139     FcResult result;
1140     return nsReturnRef<FcFontSet>(FcFontSort(nullptr, mSortPattern,
1141                                              FcFalse, nullptr, &result));
1142 }
1143 
1144 // GetFontAt relies on this setting up all patterns up to |i|.
1145 FcPattern *
GetFontPatternAt(uint32_t i)1146 gfxFcFontSet::GetFontPatternAt(uint32_t i)
1147 {
1148     while (i >= mFonts.Length()) {
1149         while (!mFcFontSet) {
1150             if (mHaveFallbackFonts)
1151                 return nullptr;
1152 
1153             mFcFontSet = SortFallbackFonts();
1154             mHaveFallbackFonts = true;
1155             mFcFontsTrimmed = 0;
1156             // Loop to test that mFcFontSet is non-nullptr.
1157         }
1158 
1159         while (mFcFontsTrimmed < mFcFontSet->nfont) {
1160             FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed];
1161             ++mFcFontsTrimmed;
1162 
1163             if (mFonts.Length() != 0) {
1164                 // See if the next font provides support for any extra
1165                 // characters.  Most often the next font is not going to
1166                 // support more characters so check for a SubSet first before
1167                 // allocating a new CharSet with Union.
1168                 FcCharSet *supportedChars = mCharSet;
1169                 if (!supportedChars) {
1170                     FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern,
1171                                         FC_CHARSET, 0, &supportedChars);
1172                 }
1173 
1174                 if (supportedChars) {
1175                     FcCharSet *newChars = nullptr;
1176                     FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars);
1177                     if (newChars) {
1178                         if (FcCharSetIsSubset(newChars, supportedChars))
1179                             continue;
1180 
1181                         mCharSet.own(FcCharSetUnion(supportedChars, newChars));
1182                     } else if (!mCharSet) {
1183                         mCharSet.own(FcCharSetCopy(supportedChars));
1184                     }
1185                 }
1186             }
1187 
1188             mFonts.AppendElement(font);
1189             if (mFonts.Length() >= i)
1190                 break;
1191         }
1192 
1193         if (mFcFontsTrimmed == mFcFontSet->nfont) {
1194             // finished with this font set
1195             mFcFontSet.reset();
1196         }
1197     }
1198 
1199     return mFonts[i].mPattern;
1200 }
1201 
1202 #ifdef MOZ_WIDGET_GTK
1203 static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
1204 #endif
1205 
1206 // Apply user settings and defaults to pattern in preparation for matching.
1207 static void
PrepareSortPattern(FcPattern * aPattern,double aFallbackSize,double aSizeAdjustFactor,bool aIsPrinterFont)1208 PrepareSortPattern(FcPattern *aPattern, double aFallbackSize,
1209                    double aSizeAdjustFactor, bool aIsPrinterFont)
1210 {
1211     FcConfigSubstitute(nullptr, aPattern, FcMatchPattern);
1212 
1213     // This gets cairo_font_options_t for the Screen.  We should have
1214     // different font options for printing (no hinting) but we are not told
1215     // what we are measuring for.
1216     //
1217     // If cairo adds support for lcd_filter, gdk will not provide the default
1218     // setting for that option.  We could get the default setting by creating
1219     // an xlib surface once, recording its font_options, and then merging the
1220     // gdk options.
1221     //
1222     // Using an xlib surface would also be an option to get Screen font
1223     // options for non-GTK X11 toolkits, but less efficient than using GDK to
1224     // pick up dynamic changes.
1225     if(aIsPrinterFont) {
1226        cairo_font_options_t *options = cairo_font_options_create();
1227        cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
1228        cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
1229        cairo_ft_font_options_substitute(options, aPattern);
1230        cairo_font_options_destroy(options);
1231        FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue);
1232     } else {
1233 #ifdef MOZ_WIDGET_GTK
1234        ApplyGdkScreenFontOptions(aPattern);
1235 #endif
1236     }
1237 
1238     // Protect against any fontconfig settings that may have incorrectly
1239     // modified the pixelsize, and consider aSizeAdjustFactor.
1240     double size = aFallbackSize;
1241     if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch
1242         || aSizeAdjustFactor != 1.0) {
1243         FcPatternDel(aPattern, FC_PIXEL_SIZE);
1244         FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor);
1245     }
1246 
1247     FcDefaultSubstitute(aPattern);
1248 }
1249 
1250 /**
1251  ** gfxPangoFontGroup
1252  **/
1253 
gfxPangoFontGroup(const FontFamilyList & aFontFamilyList,const gfxFontStyle * aStyle,gfxUserFontSet * aUserFontSet,gfxFloat aDevToCssSize)1254 gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList,
1255                                      const gfxFontStyle *aStyle,
1256                                      gfxUserFontSet *aUserFontSet,
1257                                      gfxFloat aDevToCssSize)
1258     : gfxFontGroup(aFontFamilyList, aStyle, nullptr, aUserFontSet, aDevToCssSize),
1259       mPangoLanguage(GuessPangoLanguage(aStyle->language))
1260 {
1261     // This language is passed to the font for shaping.
1262     // Shaping doesn't know about lang groups so make it a real language.
1263     if (mPangoLanguage) {
1264         mStyle.language = NS_Atomize(pango_language_to_string(mPangoLanguage));
1265     }
1266 
1267     // dummy entry, will be replaced when actually needed
1268     mFonts.AppendElement(FamilyFace());
1269     mSkipUpdateUserFonts = true;
1270 }
1271 
~gfxPangoFontGroup()1272 gfxPangoFontGroup::~gfxPangoFontGroup()
1273 {
1274 }
1275 
1276 gfxFontGroup *
Copy(const gfxFontStyle * aStyle)1277 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
1278 {
1279     return new gfxPangoFontGroup(mFamilyList, aStyle, mUserFontSet, mDevToCssSize);
1280 }
1281 
1282 void
FindGenericFontsPFG(FontFamilyType aGenericType,nsIAtom * aLanguage,void * aClosure)1283 gfxPangoFontGroup::FindGenericFontsPFG(FontFamilyType aGenericType,
1284                                        nsIAtom *aLanguage,
1285                                        void *aClosure)
1286 {
1287     AutoTArray<nsString, 5> resolvedGenerics;
1288     ResolveGenericFontNamesPFG(aGenericType, aLanguage, resolvedGenerics);
1289     uint32_t g = 0, numGenerics = resolvedGenerics.Length();
1290     for (g = 0; g < numGenerics; g++) {
1291         FindPlatformFontPFG(resolvedGenerics[g], false, aClosure);
1292     }
1293 }
1294 
1295 /* static */ void
ResolveGenericFontNamesPFG(FontFamilyType aGenericType,nsIAtom * aLanguage,nsTArray<nsString> & aGenericFamilies)1296 gfxPangoFontGroup::ResolveGenericFontNamesPFG(FontFamilyType aGenericType,
1297                                               nsIAtom *aLanguage,
1298                                               nsTArray<nsString>& aGenericFamilies)
1299 {
1300     static const char kGeneric_serif[] = "serif";
1301     static const char kGeneric_sans_serif[] = "sans-serif";
1302     static const char kGeneric_monospace[] = "monospace";
1303     static const char kGeneric_cursive[] = "cursive";
1304     static const char kGeneric_fantasy[] = "fantasy";
1305 
1306     // treat -moz-fixed as monospace
1307     if (aGenericType == eFamily_moz_fixed) {
1308         aGenericType = eFamily_monospace;
1309     }
1310 
1311     // type should be standard generic type at this point
1312     NS_ASSERTION(aGenericType >= eFamily_serif &&
1313                  aGenericType <= eFamily_fantasy,
1314                  "standard generic font family type required");
1315 
1316     // create the lang string
1317     nsIAtom *langGroupAtom = nullptr;
1318     nsAutoCString langGroupString;
1319     if (aLanguage) {
1320         if (!gLangService) {
1321             CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService);
1322         }
1323         if (gLangService) {
1324             nsresult rv;
1325             langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv);
1326         }
1327     }
1328     if (!langGroupAtom) {
1329         langGroupAtom = nsGkAtoms::Unicode;
1330     }
1331     langGroupAtom->ToUTF8String(langGroupString);
1332 
1333     // map generic type to string
1334     const char *generic = nullptr;
1335     switch (aGenericType) {
1336         case eFamily_serif:
1337             generic = kGeneric_serif;
1338             break;
1339         case eFamily_sans_serif:
1340             generic = kGeneric_sans_serif;
1341             break;
1342         case eFamily_monospace:
1343             generic = kGeneric_monospace;
1344             break;
1345         case eFamily_cursive:
1346             generic = kGeneric_cursive;
1347             break;
1348         case eFamily_fantasy:
1349             generic = kGeneric_fantasy;
1350             break;
1351         default:
1352             break;
1353     }
1354 
1355     if (!generic) {
1356         return;
1357     }
1358 
1359     aGenericFamilies.Clear();
1360 
1361     // load family for "font.name.generic.lang"
1362     nsAutoCString prefFontName("font.name.");
1363     prefFontName.Append(generic);
1364     prefFontName.Append('.');
1365     prefFontName.Append(langGroupString);
1366     gfxFontUtils::AppendPrefsFontList(prefFontName.get(),
1367                                       aGenericFamilies);
1368 
1369     // if lang has pref fonts, also load fonts for "font.name-list.generic.lang"
1370     if (!aGenericFamilies.IsEmpty()) {
1371         nsAutoCString prefFontListName("font.name-list.");
1372         prefFontListName.Append(generic);
1373         prefFontListName.Append('.');
1374         prefFontListName.Append(langGroupString);
1375         gfxFontUtils::AppendPrefsFontList(prefFontListName.get(),
1376                                           aGenericFamilies);
1377     }
1378 
1379 #if 0  // dump out generic mappings
1380     printf("%s ===> ", prefFontName.get());
1381     for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) {
1382         if (k > 0) printf(", ");
1383         printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get());
1384     }
1385     printf("\n");
1386 #endif
1387 }
1388 
EnumerateFontListPFG(nsIAtom * aLanguage,void * aClosure)1389 void gfxPangoFontGroup::EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure)
1390 {
1391     // initialize fonts in the font family list
1392     const nsTArray<FontFamilyName>& fontlist = mFamilyList.GetFontlist();
1393 
1394     // lookup fonts in the fontlist
1395     uint32_t i, numFonts = fontlist.Length();
1396     for (i = 0; i < numFonts; i++) {
1397         const FontFamilyName& name = fontlist[i];
1398         if (name.IsNamed()) {
1399             FindPlatformFontPFG(name.mName, true, aClosure);
1400         } else {
1401             FindGenericFontsPFG(name.mType, aLanguage, aClosure);
1402         }
1403     }
1404 
1405     // if necessary, append default generic onto the end
1406     if (mFamilyList.GetDefaultFontType() != eFamily_none &&
1407         !mFamilyList.HasDefaultGeneric()) {
1408         FindGenericFontsPFG(mFamilyList.GetDefaultFontType(),
1409                             aLanguage, aClosure);
1410     }
1411 }
1412 
1413 void
FindPlatformFontPFG(const nsAString & fontName,bool aUseFontSet,void * aClosure)1414 gfxPangoFontGroup::FindPlatformFontPFG(const nsAString& fontName,
1415                                        bool aUseFontSet,
1416                                        void *aClosure)
1417 {
1418     nsTArray<nsString> *list = static_cast<nsTArray<nsString>*>(aClosure);
1419 
1420     if (!list->Contains(fontName)) {
1421         // names present in the user fontset are not matched against system fonts
1422         if (aUseFontSet && mUserFontSet && mUserFontSet->HasFamily(fontName)) {
1423             nsAutoString userFontName =
1424                 NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName;
1425             list->AppendElement(userFontName);
1426         } else {
1427             list->AppendElement(fontName);
1428         }
1429     }
1430 }
1431 
1432 gfxFcFont *
GetBaseFont()1433 gfxPangoFontGroup::GetBaseFont()
1434 {
1435     if (mFonts[0].Font() == nullptr) {
1436         gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle());
1437         mFonts[0] = FamilyFace(nullptr, font);
1438     }
1439 
1440     return static_cast<gfxFcFont*>(mFonts[0].Font());
1441 }
1442 
1443 gfxFont*
GetFirstValidFont(uint32_t aCh)1444 gfxPangoFontGroup::GetFirstValidFont(uint32_t aCh)
1445 {
1446     return GetFontAt(0);
1447 }
1448 
1449 gfxFont *
GetFontAt(int32_t i,uint32_t aCh)1450 gfxPangoFontGroup::GetFontAt(int32_t i, uint32_t aCh)
1451 {
1452     // If it turns out to be hard for all clients that cache font
1453     // groups to call UpdateUserFonts at appropriate times, we could
1454     // instead consider just calling UpdateUserFonts from someplace
1455     // more central (such as here).
1456     NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
1457                  "Whoever was caching this font group should have "
1458                  "called UpdateUserFonts on it");
1459 
1460     NS_PRECONDITION(i == 0, "Only have one font");
1461 
1462     return GetBaseFont();
1463 }
1464 
1465 void
UpdateUserFonts()1466 gfxPangoFontGroup::UpdateUserFonts()
1467 {
1468     uint64_t newGeneration = GetGeneration();
1469     if (newGeneration == mCurrGeneration)
1470         return;
1471 
1472     mFonts[0] = FamilyFace();
1473     mFontSets.Clear();
1474     ClearCachedData();
1475     mCurrGeneration = newGeneration;
1476 }
1477 
1478 already_AddRefed<gfxFcFontSet>
MakeFontSet(PangoLanguage * aLang,gfxFloat aSizeAdjustFactor,nsAutoRef<FcPattern> * aMatchPattern)1479 gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
1480                                nsAutoRef<FcPattern> *aMatchPattern)
1481 {
1482     const char *lang = pango_language_to_string(aLang);
1483 
1484     RefPtr<nsIAtom> langGroup;
1485     if (aLang != mPangoLanguage) {
1486         // Set up langGroup for Mozilla's font prefs.
1487         langGroup = NS_Atomize(lang);
1488     }
1489 
1490     AutoTArray<nsString, 20> fcFamilyList;
1491     EnumerateFontListPFG(langGroup ? langGroup.get() : mStyle.language.get(),
1492                          &fcFamilyList);
1493 
1494     // To consider: A fontset cache here could be helpful.
1495 
1496     // Get a pattern suitable for matching.
1497     nsAutoRef<FcPattern> pattern
1498         (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang));
1499 
1500     PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont);
1501 
1502     RefPtr<gfxFcFontSet> fontset =
1503         new gfxFcFontSet(pattern, mUserFontSet);
1504 
1505     mSkipDrawing = fontset->WaitingForUserFont();
1506 
1507     if (aMatchPattern)
1508         aMatchPattern->steal(pattern);
1509 
1510     return fontset.forget();
1511 }
1512 
1513 gfxPangoFontGroup::
FontSetByLangEntry(PangoLanguage * aLang,gfxFcFontSet * aFontSet)1514 FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang,
1515                                        gfxFcFontSet *aFontSet)
1516     : mLang(aLang), mFontSet(aFontSet)
1517 {
1518 }
1519 
1520 gfxFcFontSet *
GetFontSet(PangoLanguage * aLang)1521 gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang)
1522 {
1523     GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0]
1524 
1525     if (!aLang)
1526         return mFontSets[0].mFontSet;
1527 
1528     for (uint32_t i = 0; i < mFontSets.Length(); ++i) {
1529         if (mFontSets[i].mLang == aLang)
1530             return mFontSets[i].mFontSet;
1531     }
1532 
1533     RefPtr<gfxFcFontSet> fontSet =
1534         MakeFontSet(aLang, mSizeAdjustFactor);
1535     mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet));
1536 
1537     return fontSet;
1538 }
1539 
1540 already_AddRefed<gfxFont>
FindFontForChar(uint32_t aCh,uint32_t aPrevCh,uint32_t aNextCh,Script aRunScript,gfxFont * aPrevMatchedFont,uint8_t * aMatchType)1541 gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
1542                                    uint32_t aNextCh, Script aRunScript,
1543                                    gfxFont *aPrevMatchedFont,
1544                                    uint8_t *aMatchType)
1545 {
1546     if (aPrevMatchedFont) {
1547         // Don't switch fonts for control characters, regardless of
1548         // whether they are present in the current font, as they won't
1549         // actually be rendered (see bug 716229)
1550         uint8_t category = GetGeneralCategory(aCh);
1551         if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
1552             return RefPtr<gfxFont>(aPrevMatchedFont).forget();
1553         }
1554 
1555         // if this character is a join-control or the previous is a join-causer,
1556         // use the same font as the previous range if we can
1557         if (gfxFontUtils::IsJoinControl(aCh) ||
1558             gfxFontUtils::IsJoinCauser(aPrevCh)) {
1559             if (aPrevMatchedFont->HasCharacter(aCh)) {
1560                 return RefPtr<gfxFont>(aPrevMatchedFont).forget();
1561             }
1562         }
1563     }
1564 
1565     // if this character is a variation selector,
1566     // use the previous font regardless of whether it supports VS or not.
1567     // otherwise the text run will be divided.
1568     if (gfxFontUtils::IsVarSelector(aCh)) {
1569         if (aPrevMatchedFont) {
1570             return RefPtr<gfxFont>(aPrevMatchedFont).forget();
1571         }
1572         // VS alone. it's meaningless to search different fonts
1573         return nullptr;
1574     }
1575 
1576     // The real fonts that fontconfig provides for generic/fallback families
1577     // depend on the language used, so a different FontSet is used for each
1578     // language (except for the variation below).
1579     //
1580     //   With most fontconfig configurations any real family names prior to a
1581     //   fontconfig generic with corresponding fonts installed will still lead
1582     //   to the same leading fonts in each FontSet.
1583     //
1584     //   There is an inefficiency here therefore because the same base FontSet
1585     //   could often be used if these real families support the character.
1586     //   However, with fontconfig aliases, it is difficult to distinguish
1587     //   where exactly alias fonts end and generic/fallback fonts begin.
1588     //
1589     // The variation from pure language-based matching used here is that the
1590     // same primary/base font is always used irrespective of the language.
1591     // This provides that SCRIPT_COMMON characters are consistently rendered
1592     // with the same font (bug 339513 and bug 416725).  This is particularly
1593     // important with the word cache as script can't be reliably determined
1594     // from surrounding words.  It also often avoids the unnecessary extra
1595     // FontSet efficiency mentioned above.
1596     //
1597     // However, in two situations, the base font is not checked before the
1598     // language-specific FontSet.
1599     //
1600     //   1. When we don't have a language to make a good choice for
1601     //      the base font.
1602     //
1603     //   2. For system fonts, use the default Pango behavior to give
1604     //      consistency with other apps.  This is relevant when un-localized
1605     //      builds are run in non-Latin locales.  This special-case probably
1606     //      wouldn't be necessary but for bug 91190.
1607 
1608     gfxFcFontSet *fontSet = GetBaseFontSet();
1609     uint32_t nextFont = 0;
1610     FcPattern *basePattern = nullptr;
1611     if (!mStyle.systemFont && mPangoLanguage) {
1612         basePattern = fontSet->GetFontPatternAt(0);
1613         if (HasChar(basePattern, aCh)) {
1614             *aMatchType = gfxTextRange::kFontGroup;
1615             return RefPtr<gfxFont>(GetBaseFont()).forget();
1616         }
1617 
1618         nextFont = 1;
1619     }
1620 
1621     // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values
1622     // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag.
1623     // Note that PangoScript is defined to be compatible with GUnicodeScript:
1624     // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript
1625     const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript);
1626     const PangoScript script =
1627       (const PangoScript)hb_glib_script_from_script(hb_script_from_iso15924_tag(scriptTag));
1628 
1629     // Might be nice to call pango_language_includes_script only once for the
1630     // run rather than for each character.
1631     PangoLanguage *scriptLang;
1632     if ((!basePattern ||
1633          !pango_language_includes_script(mPangoLanguage, script)) &&
1634         (scriptLang = pango_script_get_sample_language(script))) {
1635         fontSet = GetFontSet(scriptLang);
1636         nextFont = 0;
1637     }
1638 
1639     for (uint32_t i = nextFont;
1640          FcPattern *pattern = fontSet->GetFontPatternAt(i);
1641          ++i) {
1642         if (pattern == basePattern) {
1643             continue; // already checked basePattern
1644         }
1645 
1646         if (HasChar(pattern, aCh)) {
1647             *aMatchType = gfxTextRange::kFontGroup;
1648             return RefPtr<gfxFont>(fontSet->GetFontAt(i, GetStyle())).forget();
1649         }
1650     }
1651 
1652     return nullptr;
1653 }
1654 
1655 /**
1656  ** gfxFcFont
1657  **/
1658 
1659 cairo_user_data_key_t gfxFcFont::sGfxFontKey;
1660 
gfxFcFont(cairo_scaled_font_t * aCairoFont,FcPattern * aPattern,gfxFcFontEntry * aFontEntry,const gfxFontStyle * aFontStyle)1661 gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
1662                      FcPattern *aPattern,
1663                      gfxFcFontEntry *aFontEntry,
1664                      const gfxFontStyle *aFontStyle)
1665     : gfxFontconfigFontBase(aCairoFont, aPattern, aFontEntry, aFontStyle)
1666 {
1667     cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr);
1668 }
1669 
~gfxFcFont()1670 gfxFcFont::~gfxFcFont()
1671 {
1672     cairo_scaled_font_set_user_data(mScaledFont,
1673                                     &sGfxFontKey,
1674                                     nullptr,
1675                                     nullptr);
1676 }
1677 
1678 already_AddRefed<gfxFont>
GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel)1679 gfxFcFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel)
1680 {
1681     gfxFontStyle style(*GetStyle());
1682     style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
1683     return MakeScaledFont(&style, style.size / GetStyle()->size);
1684 }
1685 
1686 already_AddRefed<gfxFont>
MakeScaledFont(gfxFontStyle * aFontStyle,gfxFloat aScaleFactor)1687 gfxFcFont::MakeScaledFont(gfxFontStyle *aFontStyle, gfxFloat aScaleFactor)
1688 {
1689     gfxFcFontEntry* fe = static_cast<gfxFcFontEntry*>(GetFontEntry());
1690     RefPtr<gfxFont> font =
1691         gfxFontCache::GetCache()->Lookup(fe, aFontStyle, nullptr);
1692     if (font) {
1693         return font.forget();
1694     }
1695 
1696     cairo_matrix_t fontMatrix;
1697     cairo_scaled_font_get_font_matrix(mScaledFont, &fontMatrix);
1698     cairo_matrix_scale(&fontMatrix, aScaleFactor, aScaleFactor);
1699 
1700     cairo_matrix_t ctm;
1701     cairo_scaled_font_get_ctm(mScaledFont, &ctm);
1702 
1703     cairo_font_options_t *options = cairo_font_options_create();
1704     cairo_scaled_font_get_font_options(mScaledFont, options);
1705 
1706     cairo_scaled_font_t *newFont =
1707         cairo_scaled_font_create(cairo_scaled_font_get_font_face(mScaledFont),
1708                                  &fontMatrix, &ctm, options);
1709     cairo_font_options_destroy(options);
1710 
1711     font = new gfxFcFont(newFont, GetPattern(), fe, aFontStyle);
1712     gfxFontCache::GetCache()->AddNew(font);
1713     cairo_scaled_font_destroy(newFont);
1714 
1715     return font.forget();
1716 }
1717 
1718 already_AddRefed<gfxFont>
GetSmallCapsFont()1719 gfxFcFont::GetSmallCapsFont()
1720 {
1721     gfxFontStyle style(*GetStyle());
1722     style.size *= SMALL_CAPS_SCALE_FACTOR;
1723     style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
1724     return MakeScaledFont(&style, SMALL_CAPS_SCALE_FACTOR);
1725 }
1726 
1727 /* static */ void
Shutdown()1728 gfxPangoFontGroup::Shutdown()
1729 {
1730     // Resetting gFTLibrary in case this is wanted again after a
1731     // cairo_debug_reset_static_data.
1732     gFTLibrary = nullptr;
1733 }
1734 
1735 /* static */ gfxFontEntry *
NewFontEntry(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle)1736 gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName,
1737                                 uint16_t aWeight,
1738                                 int16_t aStretch,
1739                                 uint8_t aStyle)
1740 {
1741     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
1742     if (!utils)
1743         return nullptr;
1744 
1745     // The font face name from @font-face { src: local() } is not well
1746     // defined.
1747     //
1748     // On MS Windows, this name gets compared with
1749     // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the
1750     // full font name from the name table.  For CFF OpenType fonts this is the
1751     // same as the PostScript name, but for TrueType fonts it is usually
1752     // different.
1753     //
1754     // On Mac, the font face name is compared with the PostScript name, even
1755     // for TrueType fonts.
1756     //
1757     // Fontconfig only records the full font names, so the behavior here
1758     // follows that on MS Windows.  However, to provide the possibility
1759     // of aliases to compensate for variations, the font face name is passed
1760     // through FcConfigSubstitute.
1761 
1762     nsAutoRef<FcPattern> pattern(FcPatternCreate());
1763     if (!pattern)
1764         return nullptr;
1765 
1766     NS_ConvertUTF16toUTF8 fullname(aFontName);
1767     FcPatternAddString(pattern, FC_FULLNAME,
1768                        gfxFontconfigUtils::ToFcChar8(fullname));
1769     FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
1770 
1771     FcChar8 *name;
1772     for (int v = 0;
1773          FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch;
1774          ++v) {
1775         const nsTArray< nsCountedRef<FcPattern> >& fonts =
1776             utils->GetFontsForFullname(name);
1777 
1778         if (fonts.Length() != 0)
1779             return new gfxLocalFcFontEntry(aFontName,
1780                                            aWeight,
1781                                            aStretch,
1782                                            aStyle,
1783                                            fonts);
1784     }
1785 
1786     return nullptr;
1787 }
1788 
1789 /* static */ FT_Library
GetFTLibrary()1790 gfxPangoFontGroup::GetFTLibrary()
1791 {
1792     if (!gFTLibrary) {
1793         // Use cairo's FT_Library so that cairo takes care of shutdown of the
1794         // FT_Library after it has destroyed its font_faces, and FT_Done_Face
1795         // has been called on each FT_Face, at least until this bug is fixed:
1796         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
1797         //
1798         // Cairo's FT_Library can be obtained from any cairo_scaled_font.  The
1799         // font properties requested here are chosen to get an FT_Face that is
1800         // likely to be also used elsewhere.
1801         gfxFontStyle style;
1802         RefPtr<gfxPangoFontGroup> fontGroup =
1803             new gfxPangoFontGroup(FontFamilyList(eFamily_sans_serif),
1804                                   &style, nullptr, 1.0);
1805 
1806         gfxFcFont *font = fontGroup->GetBaseFont();
1807         if (!font)
1808             return nullptr;
1809 
1810         gfxFT2LockedFace face(font);
1811         if (!face.get())
1812             return nullptr;
1813 
1814         gFTLibrary = face.get()->glyph->library;
1815     }
1816 
1817     return gFTLibrary;
1818 }
1819 
1820 /* static */ gfxFontEntry *
NewFontEntry(const nsAString & aFontName,uint16_t aWeight,int16_t aStretch,uint8_t aStyle,const uint8_t * aFontData,uint32_t aLength)1821 gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName,
1822                                 uint16_t aWeight,
1823                                 int16_t aStretch,
1824                                 uint8_t aStyle,
1825                                 const uint8_t* aFontData,
1826                                 uint32_t aLength)
1827 {
1828     // Ownership of aFontData is passed in here, and transferred to the
1829     // new fontEntry, which will release it when no longer needed.
1830 
1831     // Using face_index = 0 for the first face in the font, as we have no
1832     // other information.  FT_New_Memory_Face checks for a nullptr FT_Library.
1833     FT_Face face;
1834     FT_Error error =
1835         FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face);
1836     if (error != 0) {
1837         free((void*)aFontData);
1838         return nullptr;
1839     }
1840 
1841     return new gfxDownloadedFcFontEntry(aFontName, aWeight,
1842                                         aStretch, aStyle,
1843                                         aFontData, face);
1844 }
1845 
1846 
1847 static double
GetPixelSize(FcPattern * aPattern)1848 GetPixelSize(FcPattern *aPattern)
1849 {
1850     double size;
1851     if (FcPatternGetDouble(aPattern,
1852                            FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1853         return size;
1854 
1855     NS_NOTREACHED("No size on pattern");
1856     return 0.0;
1857 }
1858 
1859 /**
1860  * The following gfxFcFonts are accessed from the cairo_scaled_font or created
1861  * from the FcPattern, not from the gfxFontCache hash table.  The gfxFontCache
1862  * hash table is keyed by desired family and style, whereas here we only know
1863  * actual family and style.  There may be more than one of these fonts with
1864  * the same family and style, but different PangoFont and actual font face.
1865  *
1866  * The point of this is to record the exact font face for gfxTextRun glyph
1867  * indices.  The style of this font does not necessarily represent the exact
1868  * gfxFontStyle used to build the text run.  Notably, the language is not
1869  * recorded.
1870  */
1871 
1872 /* static */
1873 already_AddRefed<gfxFcFont>
GetOrMakeFont(FcPattern * aRequestedPattern,FcPattern * aFontPattern,const gfxFontStyle * aFontStyle)1874 gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
1875                          const gfxFontStyle *aFontStyle)
1876 {
1877     nsAutoRef<FcPattern> renderPattern
1878         (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern));
1879 
1880     // If synthetic bold/italic is not allowed by the style, adjust the
1881     // resulting pattern to match the actual properties of the font.
1882     if (!aFontStyle->allowSyntheticWeight) {
1883         int weight;
1884         if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0,
1885                                 &weight) == FcResultMatch) {
1886             FcPatternDel(renderPattern, FC_WEIGHT);
1887             FcPatternAddInteger(renderPattern, FC_WEIGHT, weight);
1888         }
1889     }
1890     if (!aFontStyle->allowSyntheticStyle) {
1891         int slant;
1892         if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0,
1893                                 &slant) == FcResultMatch) {
1894             FcPatternDel(renderPattern, FC_SLANT);
1895             FcPatternAddInteger(renderPattern, FC_SLANT, slant);
1896         }
1897     }
1898 
1899     cairo_font_face_t *face =
1900         cairo_ft_font_face_create_for_pattern(renderPattern);
1901 
1902     // Reuse an existing font entry if available.
1903     RefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face);
1904     if (!fe) {
1905         gfxDownloadedFcFontEntry *downloadedFontEntry =
1906             GetDownloadedFontEntry(aFontPattern);
1907         if (downloadedFontEntry) {
1908             // Web font
1909             fe = downloadedFontEntry;
1910             if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) {
1911                 // cairo_font_face_t is using the web font data.
1912                 // Hold a reference to the font entry to keep the font face
1913                 // data.
1914                 if (!downloadedFontEntry->SetCairoFace(face)) {
1915                     // OOM.  Let cairo pick a fallback font
1916                     cairo_font_face_destroy(face);
1917                     face = cairo_ft_font_face_create_for_pattern(aRequestedPattern);
1918                     fe = gfxFcFontEntry::LookupFontEntry(face);
1919                 }
1920             }
1921         }
1922         if (!fe) {
1923             // Get a unique name for the font face from the file and id.
1924             nsAutoString name;
1925             FcChar8 *fc_file;
1926             if (FcPatternGetString(renderPattern,
1927                                    FC_FILE, 0, &fc_file) == FcResultMatch) {
1928                 int index;
1929                 if (FcPatternGetInteger(renderPattern,
1930                                         FC_INDEX, 0, &index) != FcResultMatch) {
1931                     // cairo defaults to 0.
1932                     index = 0;
1933                 }
1934 
1935                 AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name);
1936                 if (index != 0) {
1937                     name.Append('/');
1938                     name.AppendInt(index);
1939                 }
1940             }
1941 
1942             fe = new gfxSystemFcFontEntry(face, aFontPattern, name);
1943         }
1944     }
1945 
1946     gfxFontStyle style(*aFontStyle);
1947     style.size = GetPixelSize(renderPattern);
1948     style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern);
1949     style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern);
1950 
1951     RefPtr<gfxFont> font =
1952         gfxFontCache::GetCache()->Lookup(fe, &style, nullptr);
1953     if (!font) {
1954         // Note that a file/index pair (or FT_Face) and the gfxFontStyle are
1955         // not necessarily enough to provide a key that will describe a unique
1956         // font.  cairoFont contains information from renderPattern, which is a
1957         // fully resolved pattern from FcFontRenderPrepare.
1958         // FcFontRenderPrepare takes the requested pattern and the face
1959         // pattern as input and can modify elements of the resulting pattern
1960         // that affect rendering but are not included in the gfxFontStyle.
1961         cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face);
1962         font = new gfxFcFont(cairoFont, renderPattern, fe, &style);
1963         gfxFontCache::GetCache()->AddNew(font);
1964         cairo_scaled_font_destroy(cairoFont);
1965     }
1966 
1967     cairo_font_face_destroy(face);
1968 
1969     RefPtr<gfxFcFont> retval(static_cast<gfxFcFont*>(font.get()));
1970     return retval.forget();
1971 }
1972 
1973 gfxFcFontSet *
GetBaseFontSet()1974 gfxPangoFontGroup::GetBaseFontSet()
1975 {
1976     if (mFontSets.Length() > 0)
1977         return mFontSets[0].mFontSet;
1978 
1979     mSizeAdjustFactor = 1.0; // will be adjusted below if necessary
1980     nsAutoRef<FcPattern> pattern;
1981     RefPtr<gfxFcFontSet> fontSet =
1982         MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern);
1983 
1984     double size = GetPixelSize(pattern);
1985     if (size != 0.0 && mStyle.sizeAdjust > 0.0) {
1986         gfxFcFont *font = fontSet->GetFontAt(0, GetStyle());
1987         if (font) {
1988             const gfxFont::Metrics& metrics =
1989                 font->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
1990 
1991             // The factor of 0.1 ensures that xHeight is sane so fonts don't
1992             // become huge.  Strictly ">" ensures that xHeight and emHeight are
1993             // not both zero.
1994             if (metrics.xHeight > 0.1 * metrics.emHeight) {
1995                 mSizeAdjustFactor =
1996                     mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight;
1997 
1998                 size *= mSizeAdjustFactor;
1999                 FcPatternDel(pattern, FC_PIXEL_SIZE);
2000                 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
2001 
2002                 fontSet = new gfxFcFontSet(pattern, mUserFontSet);
2003             }
2004         }
2005     }
2006 
2007     PangoLanguage *pangoLang = mPangoLanguage;
2008     FcChar8 *fcLang;
2009     if (!pangoLang &&
2010         FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) {
2011         pangoLang =
2012             pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang));
2013     }
2014 
2015     mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet));
2016 
2017     return fontSet;
2018 }
2019 
2020 /**
2021  ** gfxTextRun
2022  *
2023  * A serious problem:
2024  *
2025  * -- We draw with a font that's hinted for the CTM, but we measure with a font
2026  * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
2027  *
2028  **/
2029 
2030 // This will fetch an existing scaled_font if one exists.
2031 static cairo_scaled_font_t *
CreateScaledFont(FcPattern * aPattern,cairo_font_face_t * aFace)2032 CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace)
2033 {
2034     double size = GetPixelSize(aPattern);
2035 
2036     cairo_matrix_t fontMatrix;
2037     FcMatrix *fcMatrix;
2038     if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch)
2039         cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0);
2040     else
2041         cairo_matrix_init_identity(&fontMatrix);
2042     cairo_matrix_scale(&fontMatrix, size, size);
2043 
2044     FcBool printing;
2045     if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) {
2046         printing = FcFalse;
2047     }
2048 
2049     // The cairo_scaled_font is created with a unit ctm so that metrics and
2050     // positions are in user space, but this means that hinting effects will
2051     // not be estimated accurately for non-unit transformations.
2052     cairo_matrix_t identityMatrix;
2053     cairo_matrix_init_identity(&identityMatrix);
2054 
2055     // Font options are set explicitly here to improve cairo's caching
2056     // behavior and to record the relevant parts of the pattern for
2057     // SetupCairoFont (so that the pattern can be released).
2058     //
2059     // Most font_options have already been set as defaults on the FcPattern
2060     // with cairo_ft_font_options_substitute(), then user and system
2061     // fontconfig configurations were applied.  The resulting font_options
2062     // have been recorded on the face during
2063     // cairo_ft_font_face_create_for_pattern().
2064     //
2065     // None of the settings here cause this scaled_font to behave any
2066     // differently from how it would behave if it were created from the same
2067     // face with default font_options.
2068     //
2069     // We set options explicitly so that the same scaled_font will be found in
2070     // the cairo_scaled_font_map when cairo loads glyphs from a context with
2071     // the same font_face, font_matrix, ctm, and surface font_options.
2072     //
2073     // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
2074     // font_options on the cairo_ft_font_face, and doesn't consider default
2075     // option values to not match any explicit values.
2076     //
2077     // Even after cairo_set_scaled_font is used to set font_options for the
2078     // cairo context, when cairo looks for a scaled_font for the context, it
2079     // will look for a font with some option values from the target surface if
2080     // any values are left default on the context font_options.  If this
2081     // scaled_font is created with default font_options, cairo will not find
2082     // it.
2083     cairo_font_options_t *fontOptions = cairo_font_options_create();
2084 
2085     // The one option not recorded in the pattern is hint_metrics, which will
2086     // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
2087     // We should be considering the font_options of the surface on which this
2088     // font will be used, but currently we don't have different gfxFonts for
2089     // different surface font_options, so we'll create a font suitable for the
2090     // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
2091     if (printing) {
2092         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
2093     } else {
2094         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON);
2095     }
2096 
2097     // The remaining options have been recorded on the pattern and the face.
2098     // _cairo_ft_options_merge has some logic to decide which options from the
2099     // scaled_font or from the cairo_ft_font_face take priority in the way the
2100     // font behaves.
2101     //
2102     // In the majority of cases, _cairo_ft_options_merge uses the options from
2103     // the cairo_ft_font_face, so sometimes it is not so important which
2104     // values are set here so long as they are not defaults, but we'll set
2105     // them to the exact values that we expect from the font, to be consistent
2106     // and to protect against changes in cairo.
2107     //
2108     // In some cases, _cairo_ft_options_merge uses some options from the
2109     // scaled_font's font_options rather than options on the
2110     // cairo_ft_font_face (from fontconfig).
2111     // https://bugs.freedesktop.org/show_bug.cgi?id=11838
2112     //
2113     // Surface font options were set on the pattern in
2114     // cairo_ft_font_options_substitute.  If fontconfig has changed the
2115     // hint_style then that is what the user (or distribution) wants, so we
2116     // use the setting from the FcPattern.
2117     //
2118     // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
2119     FcBool hinting = FcFalse;
2120     if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
2121         hinting = FcTrue;
2122     }
2123 
2124     cairo_hint_style_t hint_style;
2125     if (printing || !hinting) {
2126         hint_style = CAIRO_HINT_STYLE_NONE;
2127     } else {
2128 #ifdef FC_HINT_STYLE  // FC_HINT_STYLE is available from fontconfig 2.2.91.
2129         int fc_hintstyle;
2130         if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
2131                                 0, &fc_hintstyle        ) != FcResultMatch) {
2132             fc_hintstyle = FC_HINT_FULL;
2133         }
2134         switch (fc_hintstyle) {
2135             case FC_HINT_NONE:
2136                 hint_style = CAIRO_HINT_STYLE_NONE;
2137                 break;
2138             case FC_HINT_SLIGHT:
2139                 hint_style = CAIRO_HINT_STYLE_SLIGHT;
2140                 break;
2141             case FC_HINT_MEDIUM:
2142             default: // This fallback mirrors _get_pattern_ft_options in cairo.
2143                 hint_style = CAIRO_HINT_STYLE_MEDIUM;
2144                 break;
2145             case FC_HINT_FULL:
2146                 hint_style = CAIRO_HINT_STYLE_FULL;
2147                 break;
2148         }
2149 #else // no FC_HINT_STYLE
2150         hint_style = CAIRO_HINT_STYLE_FULL;
2151 #endif
2152     }
2153     cairo_font_options_set_hint_style(fontOptions, hint_style);
2154 
2155     int rgba;
2156     if (FcPatternGetInteger(aPattern,
2157                             FC_RGBA, 0, &rgba) != FcResultMatch) {
2158         rgba = FC_RGBA_UNKNOWN;
2159     }
2160     cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
2161     switch (rgba) {
2162         case FC_RGBA_UNKNOWN:
2163         case FC_RGBA_NONE:
2164         default:
2165             // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
2166             // is disabled through cairo_antialias_t.
2167             rgba = FC_RGBA_NONE;
2168             // subpixel_order won't be used by the font as we won't use
2169             // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
2170             // caching reasons described above.  Fall through:
2171             MOZ_FALLTHROUGH;
2172         case FC_RGBA_RGB:
2173             subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
2174             break;
2175         case FC_RGBA_BGR:
2176             subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
2177             break;
2178         case FC_RGBA_VRGB:
2179             subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
2180             break;
2181         case FC_RGBA_VBGR:
2182             subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
2183             break;
2184     }
2185     cairo_font_options_set_subpixel_order(fontOptions, subpixel_order);
2186 
2187     FcBool fc_antialias;
2188     if (FcPatternGetBool(aPattern,
2189                          FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
2190         fc_antialias = FcTrue;
2191     }
2192     cairo_antialias_t antialias;
2193     if (!fc_antialias) {
2194         antialias = CAIRO_ANTIALIAS_NONE;
2195     } else if (rgba == FC_RGBA_NONE) {
2196         antialias = CAIRO_ANTIALIAS_GRAY;
2197     } else {
2198         antialias = CAIRO_ANTIALIAS_SUBPIXEL;
2199     }
2200     cairo_font_options_set_antialias(fontOptions, antialias);
2201 
2202     cairo_scaled_font_t *scaledFont =
2203         cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix,
2204                                  fontOptions);
2205 
2206     cairo_font_options_destroy(fontOptions);
2207 
2208     NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
2209                  "Failed to create scaled font");
2210     return scaledFont;
2211 }
2212 
2213 /* static */
2214 PangoLanguage *
GuessPangoLanguage(nsIAtom * aLanguage)2215 GuessPangoLanguage(nsIAtom *aLanguage)
2216 {
2217     if (!aLanguage)
2218         return nullptr;
2219 
2220     // Pango and fontconfig won't understand mozilla's internal langGroups, so
2221     // find a real language.
2222     nsAutoCString lang;
2223     gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang);
2224     if (lang.IsEmpty())
2225         return nullptr;
2226 
2227     return pango_language_from_string(lang.get());
2228 }
2229 
2230 #ifdef MOZ_WIDGET_GTK
2231 /***************************************************************************
2232  *
2233  * This function must be last in the file because it uses the system cairo
2234  * library.  Above this point the cairo library used is the tree cairo if
2235  * MOZ_TREE_CAIRO.
2236  */
2237 
2238 #if MOZ_TREE_CAIRO
2239 // Tree cairo symbols have different names.  Disable their activation through
2240 // preprocessor macros.
2241 #undef cairo_ft_font_options_substitute
2242 
2243 // The system cairo functions are not declared because the include paths cause
2244 // the gdk headers to pick up the tree cairo.h.
2245 extern "C" {
2246 NS_VISIBILITY_DEFAULT void
2247 cairo_ft_font_options_substitute (const cairo_font_options_t *options,
2248                                   FcPattern                  *pattern);
2249 }
2250 #endif
2251 
2252 static void
ApplyGdkScreenFontOptions(FcPattern * aPattern)2253 ApplyGdkScreenFontOptions(FcPattern *aPattern)
2254 {
2255     const cairo_font_options_t *options =
2256         gdk_screen_get_font_options(gdk_screen_get_default());
2257 
2258     cairo_ft_font_options_substitute(options, aPattern);
2259 }
2260 
2261 #endif // MOZ_WIDGET_GTK
2262 
2263