1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/Logging.h"
8 #include "gfxFcPlatformFontList.h"
10 #include "gfxFontConstants.h"
11 #include "gfxFontFamilyList.h"
12 #include "gfxFT2Utils.h"
13 #include "gfxPlatform.h"
14 #include "mozilla/ArrayUtils.h"
15 #include "mozilla/dom/ContentChild.h"
16 #include "mozilla/dom/ContentParent.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/Sprintf.h"
19 #include "mozilla/TimeStamp.h"
20 #include "nsGkAtoms.h"
21 #include "nsUnicodeProperties.h"
22 #include "nsUnicodeRange.h"
23 #include "nsDirectoryServiceUtils.h"
24 #include "nsDirectoryServiceDefs.h"
25 #include "nsAppDirectoryServiceDefs.h"
26 #include "nsCharSeparatedTokenizer.h"
27 #include "nsXULAppAPI.h"
29 #include "mozilla/gfx/HelpersCairo.h"
31 #include <fontconfig/fcfreetype.h>
37 #include "gfxPlatformGtk.h"
41 #include "mozilla/X11Util.h"
44 #ifdef MOZ_CONTENT_SANDBOX
45 #include "mozilla/SandboxBrokerPolicyFactory.h"
46 #include "mozilla/SandboxSettings.h"
49 #include FT_MULTIPLE_MASTERS_H
51 using namespace mozilla
;
52 using namespace mozilla::gfx
;
53 using namespace mozilla::unicode
;
55 using mozilla::dom::SystemFontListEntry
;
56 using mozilla::dom::FontPatternListEntry
;
58 #ifndef FC_POSTSCRIPT_NAME
59 #define FC_POSTSCRIPT_NAME "postscriptname" /* String */
62 #define PRINTING_FC_PROPERTY "gfx.printing"
64 #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
65 LogLevel::Debug, args)
66 #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
67 gfxPlatform::GetLog(eGfxLog_fontlist), \
69 #define LOG_CMAPDATA_ENABLED() MOZ_LOG_TEST( \
70 gfxPlatform::GetLog(eGfxLog_cmapdata), \
74 class nsAutoRefTraits
<FcFontSet
> : public nsPointerRefTraits
<FcFontSet
>
77 static void Release(FcFontSet
*ptr
) { FcFontSetDestroy(ptr
); }
81 class nsAutoRefTraits
<FcObjectSet
> : public nsPointerRefTraits
<FcObjectSet
>
84 static void Release(FcObjectSet
*ptr
) { FcObjectSetDestroy(ptr
); }
88 ToFcChar8Ptr(const char* aStr
)
90 return reinterpret_cast<const FcChar8
*>(aStr
);
94 ToCharPtr(const FcChar8
*aStr
)
96 return reinterpret_cast<const char*>(aStr
);
99 FT_Library
gfxFcPlatformFontList::sCairoFTLibrary
= nullptr;
101 static cairo_user_data_key_t sFcFontlistUserFontDataKey
;
103 // canonical name ==> first en name or first name if no en name
104 // This is the required logic for fullname lookups as per CSS3 Fonts spec.
106 FindCanonicalNameIndex(FcPattern
* aFont
, const char* aLangField
)
108 uint32_t n
= 0, en
= 0;
110 while (FcPatternGetString(aFont
, aLangField
, n
, &lang
) == FcResultMatch
) {
111 // look for 'en' or variants, en-US, en-JP etc.
112 uint32_t len
= strlen(ToCharPtr(lang
));
113 bool enPrefix
= (strncmp(ToCharPtr(lang
), "en", 2) == 0);
114 if (enPrefix
&& (len
== 2 || (len
> 2 && aLangField
[2] == '-'))) {
124 GetFaceNames(FcPattern
* aFont
, const nsAString
& aFamilyName
,
125 nsAString
& aPostscriptName
, nsAString
& aFullname
)
127 // get the Postscript name
129 if (FcPatternGetString(aFont
, FC_POSTSCRIPT_NAME
, 0, &psname
) == FcResultMatch
) {
130 AppendUTF8toUTF16(ToCharPtr(psname
), aPostscriptName
);
133 // get the canonical fullname (i.e. en name or first name)
134 uint32_t en
= FindCanonicalNameIndex(aFont
, FC_FULLNAMELANG
);
136 if (FcPatternGetString(aFont
, FC_FULLNAME
, en
, &fullname
) == FcResultMatch
) {
137 AppendUTF8toUTF16(ToCharPtr(fullname
), aFullname
);
140 // if have fullname, done
141 if (!aFullname
.IsEmpty()) {
145 // otherwise, set the fullname to family + style name [en] and use that
146 aFullname
.Append(aFamilyName
);
148 // figure out the en style name
149 en
= FindCanonicalNameIndex(aFont
, FC_STYLELANG
);
151 FcChar8
* stylename
= nullptr;
152 FcPatternGetString(aFont
, FC_STYLE
, en
, &stylename
);
154 AppendUTF8toUTF16(ToCharPtr(stylename
), style
);
157 if (!style
.IsEmpty() && !style
.EqualsLiteral("Regular")) {
158 aFullname
.Append(' ');
159 aFullname
.Append(style
);
164 MapFcWeight(int aFcWeight
)
166 if (aFcWeight
<= (FC_WEIGHT_THIN
+ FC_WEIGHT_EXTRALIGHT
) / 2) {
169 if (aFcWeight
<= (FC_WEIGHT_EXTRALIGHT
+ FC_WEIGHT_LIGHT
) / 2) {
172 if (aFcWeight
<= (FC_WEIGHT_LIGHT
+ FC_WEIGHT_BOOK
) / 2) {
175 if (aFcWeight
<= (FC_WEIGHT_REGULAR
+ FC_WEIGHT_MEDIUM
) / 2) {
176 // This includes FC_WEIGHT_BOOK
179 if (aFcWeight
<= (FC_WEIGHT_MEDIUM
+ FC_WEIGHT_DEMIBOLD
) / 2) {
182 if (aFcWeight
<= (FC_WEIGHT_DEMIBOLD
+ FC_WEIGHT_BOLD
) / 2) {
185 if (aFcWeight
<= (FC_WEIGHT_BOLD
+ FC_WEIGHT_EXTRABOLD
) / 2) {
188 if (aFcWeight
<= (FC_WEIGHT_EXTRABOLD
+ FC_WEIGHT_BLACK
) / 2) {
191 if (aFcWeight
<= FC_WEIGHT_BLACK
) {
195 // including FC_WEIGHT_EXTRABLACK
200 MapFcWidth(int aFcWidth
)
202 if (aFcWidth
<= (FC_WIDTH_ULTRACONDENSED
+ FC_WIDTH_EXTRACONDENSED
) / 2) {
203 return NS_FONT_STRETCH_ULTRA_CONDENSED
;
205 if (aFcWidth
<= (FC_WIDTH_EXTRACONDENSED
+ FC_WIDTH_CONDENSED
) / 2) {
206 return NS_FONT_STRETCH_EXTRA_CONDENSED
;
208 if (aFcWidth
<= (FC_WIDTH_CONDENSED
+ FC_WIDTH_SEMICONDENSED
) / 2) {
209 return NS_FONT_STRETCH_CONDENSED
;
211 if (aFcWidth
<= (FC_WIDTH_SEMICONDENSED
+ FC_WIDTH_NORMAL
) / 2) {
212 return NS_FONT_STRETCH_SEMI_CONDENSED
;
214 if (aFcWidth
<= (FC_WIDTH_NORMAL
+ FC_WIDTH_SEMIEXPANDED
) / 2) {
215 return NS_FONT_STRETCH_NORMAL
;
217 if (aFcWidth
<= (FC_WIDTH_SEMIEXPANDED
+ FC_WIDTH_EXPANDED
) / 2) {
218 return NS_FONT_STRETCH_SEMI_EXPANDED
;
220 if (aFcWidth
<= (FC_WIDTH_EXPANDED
+ FC_WIDTH_EXTRAEXPANDED
) / 2) {
221 return NS_FONT_STRETCH_EXPANDED
;
223 if (aFcWidth
<= (FC_WIDTH_EXTRAEXPANDED
+ FC_WIDTH_ULTRAEXPANDED
) / 2) {
224 return NS_FONT_STRETCH_EXTRA_EXPANDED
;
226 return NS_FONT_STRETCH_ULTRA_EXPANDED
;
229 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString
& aFaceName
,
230 FcPattern
* aFontPattern
,
231 bool aIgnoreFcCharmap
)
232 : gfxFontEntry(aFaceName
), mFontPattern(aFontPattern
),
233 mFTFace(nullptr), mFTFaceInitialized(false),
234 mIgnoreFcCharmap(aIgnoreFcCharmap
),
235 mAspect(0.0), mFontData(nullptr), mLength(0)
239 if (FcPatternGetInteger(aFontPattern
, FC_SLANT
, 0, &slant
) != FcResultMatch
) {
240 slant
= FC_SLANT_ROMAN
;
242 if (slant
== FC_SLANT_OBLIQUE
) {
243 mStyle
= NS_FONT_STYLE_OBLIQUE
;
244 } else if (slant
> 0) {
245 mStyle
= NS_FONT_STYLE_ITALIC
;
250 if (FcPatternGetInteger(aFontPattern
, FC_WEIGHT
, 0, &weight
) != FcResultMatch
) {
251 weight
= FC_WEIGHT_REGULAR
;
253 mWeight
= MapFcWeight(weight
);
257 if (FcPatternGetInteger(aFontPattern
, FC_WIDTH
, 0, &width
) != FcResultMatch
) {
258 width
= FC_WIDTH_NORMAL
;
260 mStretch
= MapFcWidth(width
);
264 gfxFontconfigFontEntry::Clone() const
266 MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
267 return new gfxFontconfigFontEntry(Name(), mFontPattern
, mIgnoreFcCharmap
);
271 CreatePatternForFace(FT_Face aFace
)
273 // Use fontconfig to fill out the pattern from the FTFace.
274 // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at
275 // least). The dummy file passed here is removed below.
277 // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr)
278 // is passed as the "blanks" argument, which provides that unexpectedly
279 // blank glyphs are elided. Here, however, we pass nullptr for
280 // "blanks", effectively assuming that, if the font has a blank glyph,
281 // then the author intends any associated character to be rendered
284 FcFreeTypeQueryFace(aFace
, ToFcChar8Ptr(""), 0, nullptr);
285 // given that we have a FT_Face, not really sure this is possible...
287 pattern
= FcPatternCreate();
289 FcPatternDel(pattern
, FC_FILE
);
290 FcPatternDel(pattern
, FC_INDEX
);
292 // Make a new pattern and store the face in it so that cairo uses
293 // that when creating a cairo font face.
294 FcPatternAddFTFace(pattern
, FC_FT_FACE
, aFace
);
300 CreateFaceForPattern(FcPattern
* aPattern
)
303 if (FcPatternGetString(aPattern
, FC_FILE
, 0, &filename
) != FcResultMatch
) {
307 if (FcPatternGetInteger(aPattern
, FC_INDEX
, 0, &index
) != FcResultMatch
) {
308 index
= 0; // default to 0 if not found in pattern
310 return Factory::NewFTFace(nullptr, ToCharPtr(filename
), index
);
313 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString
& aFaceName
,
317 const uint8_t *aData
,
320 : gfxFontEntry(aFaceName
),
321 mFTFace(aFace
), mFTFaceInitialized(true),
322 mIgnoreFcCharmap(true),
323 mAspect(0.0), mFontData(aData
), mLength(aLength
)
328 mIsDataUserFont
= true;
330 mFontPattern
= CreatePatternForFace(mFTFace
);
332 mUserFontData
= new FTUserFontData(mFTFace
, mFontData
);
335 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString
& aFaceName
,
336 FcPattern
* aFontPattern
,
340 : gfxFontEntry(aFaceName
), mFontPattern(aFontPattern
),
341 mFTFace(nullptr), mFTFaceInitialized(false),
342 mAspect(0.0), mFontData(nullptr), mLength(0)
347 mIsLocalUserFont
= true;
349 // The proper setting of mIgnoreFcCharmap is tricky for fonts loaded
350 // via src:local()...
351 // If the local font happens to come from the application fontset,
352 // we want to set it to true so that color/svg fonts will work even
353 // if the default glyphs are blank; but if the local font is a non-
354 // sfnt face (e.g. legacy type 1) then we need to set it to false
355 // because our cmap-reading code will fail and we depend on FT+Fc to
356 // determine the coverage.
357 // We set the flag here, but may flip it the first time TestCharacterMap
358 // is called, at which point we'll look to see whether a 'cmap' is
359 // actually present in the font.
360 mIgnoreFcCharmap
= true;
363 typedef FT_Error (*GetVarFunc
)(FT_Face
, FT_MM_Var
**);
364 typedef FT_Error (*DoneVarFunc
)(FT_Library
, FT_MM_Var
*);
365 static GetVarFunc sGetVar
;
366 static DoneVarFunc sDoneVar
;
367 static bool sInitializedVarFuncs
= false;
372 if (sInitializedVarFuncs
) {
375 sInitializedVarFuncs
= true;
376 #if MOZ_TREE_FREETYPE
377 sGetVar
= &FT_Get_MM_Var
;
378 sDoneVar
= &FT_Done_MM_Var
;
380 sGetVar
= (GetVarFunc
)dlsym(RTLD_DEFAULT
, "FT_Get_MM_Var");
381 sDoneVar
= (DoneVarFunc
)dlsym(RTLD_DEFAULT
, "FT_Done_MM_Var");
385 gfxFontconfigFontEntry::~gfxFontconfigFontEntry()
388 // Prior to freetype 2.9, there was no specific function to free the
389 // FT_MM_Var record, and the docs just said to use free().
390 // InitializeVarFuncs must have been called in order for mMMVar to be
391 // non-null here, so we don't need to do it again.
393 MOZ_ASSERT(mFTFace
, "How did mMMVar get set without a face?");
394 (*sDoneVar
)(mFTFace
->glyph
->library
, mMMVar
);
402 gfxFontconfigFontEntry::ReadCMAP(FontInfoData
*aFontInfoData
)
404 // attempt this once, if errors occur leave a blank cmap
409 RefPtr
<gfxCharacterMap
> charmap
;
412 if (aFontInfoData
&& (charmap
= GetCMAPFromFontInfo(aFontInfoData
,
416 uint32_t kCMAP
= TRUETYPE_TAG('c','m','a','p');
417 charmap
= new gfxCharacterMap();
418 AutoTable
cmapTable(this, kCMAP
);
422 const uint8_t* cmapData
=
423 reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable
,
425 rv
= gfxFontUtils::ReadCMAP(cmapData
, cmapLen
,
426 *charmap
, mUVSOffset
);
428 rv
= NS_ERROR_NOT_AVAILABLE
;
432 mHasCmapTable
= NS_SUCCEEDED(rv
);
434 gfxPlatformFontList
*pfl
= gfxPlatformFontList::PlatformFontList();
435 mCharacterMap
= pfl
->FindCharMap(charmap
);
437 // if error occurred, initialize to null cmap
438 mCharacterMap
= new gfxCharacterMap();
441 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zu hash: %8.8x%s\n",
442 NS_ConvertUTF16toUTF8(mName
).get(),
443 charmap
->SizeOfIncludingThis(moz_malloc_size_of
),
444 charmap
->mHash
, mCharacterMap
== charmap
? " new" : ""));
445 if (LOG_CMAPDATA_ENABLED()) {
447 SprintfLiteral(prefix
, "(cmapdata) name: %.220s",
448 NS_ConvertUTF16toUTF8(mName
).get());
449 charmap
->Dump(prefix
, eGfxLog_cmapdata
);
456 HasChar(FcPattern
*aFont
, FcChar32 aCh
)
458 FcCharSet
*charset
= nullptr;
459 FcPatternGetCharSet(aFont
, FC_CHARSET
, 0, &charset
);
460 return charset
&& FcCharSetHasChar(charset
, aCh
);
464 gfxFontconfigFontEntry::TestCharacterMap(uint32_t aCh
)
466 // For user fonts, or for fonts bundled with the app (which might include
467 // color/svg glyphs where the default glyphs may be blank, and thus confuse
468 // fontconfig/freetype's char map checking), we instead check the cmap
469 // directly for character coverage.
470 if (mIgnoreFcCharmap
) {
471 // If it does not actually have a cmap, switch our strategy to use
472 // fontconfig's charmap after all (except for data fonts, which must
473 // always have a cmap to have passed OTS validation).
474 if (!mIsDataUserFont
&& !HasFontTable(TRUETYPE_TAG('c','m','a','p'))) {
475 mIgnoreFcCharmap
= false;
476 // ...and continue with HasChar() below.
478 return gfxFontEntry::TestCharacterMap(aCh
);
481 // otherwise (for system fonts), use the charmap in the pattern
482 return HasChar(mFontPattern
, aCh
);
486 gfxFontconfigFontEntry::GetFontTable(uint32_t aTableTag
)
488 // for data fonts, read directly from the font data
490 return gfxFontUtils::GetTableFromFontData(mFontData
, aTableTag
);
493 return gfxFontEntry::GetFontTable(aTableTag
);
497 gfxFontconfigFontEntry::MaybeReleaseFTFace()
499 // don't release if either HB or Gr face still exists
500 if (mHBFace
|| mGrFace
) {
503 // only close out FT_Face for system fonts, not for data fonts
504 if (!mIsDataUserFont
) {
508 (*sDoneVar
)(mFTFace
->glyph
->library
, mMMVar
);
514 Factory::ReleaseFTFace(mFTFace
);
517 mFTFaceInitialized
= false;
522 gfxFontconfigFontEntry::ForgetHBFace()
524 gfxFontEntry::ForgetHBFace();
525 MaybeReleaseFTFace();
529 gfxFontconfigFontEntry::ReleaseGrFace(gr_face
* aFace
)
531 gfxFontEntry::ReleaseGrFace(aFace
);
532 MaybeReleaseFTFace();
536 gfxFontconfigFontEntry::GetAspect()
538 if (mAspect
!= 0.0) {
542 // try to compute aspect from OS/2 metrics if available
543 AutoTable
os2Table(this, TRUETYPE_TAG('O','S','/','2'));
545 uint16_t upem
= UnitsPerEm();
546 if (upem
!= kInvalidUPEM
) {
548 auto os2
= reinterpret_cast<const OS2Table
*>
549 (hb_blob_get_data(os2Table
, &len
));
550 if (uint16_t(os2
->version
) >= 2) {
551 if (len
>= offsetof(OS2Table
, sxHeight
) + sizeof(int16_t) &&
552 int16_t(os2
->sxHeight
) > 0.1 * upem
) {
553 mAspect
= double(int16_t(os2
->sxHeight
)) / upem
;
560 // default to aspect = 0.5 if the code below fails
563 // create a font to calculate x-height / em-height
565 s
.size
= 100.0; // pick large size to avoid possible hinting artifacts
566 RefPtr
<gfxFont
> font
= FindOrMakeFont(&s
, false);
568 const gfxFont::Metrics
& metrics
=
569 font
->GetMetrics(gfxFont::eHorizontal
);
571 // The factor of 0.1 ensures that xHeight is sane so fonts don't
572 // become huge. Strictly ">" ensures that xHeight and emHeight are
574 if (metrics
.xHeight
> 0.1 * metrics
.emHeight
) {
575 mAspect
= metrics
.xHeight
/ metrics
.emHeight
;
583 PrepareFontOptions(FcPattern
* aPattern
,
584 cairo_font_options_t
* aFontOptions
)
586 NS_ASSERTION(aFontOptions
, "null font options passed to PrepareFontOptions");
588 // xxx - taken from the gfxFontconfigFonts code, needs to be reviewed
591 if (FcPatternGetBool(aPattern
, PRINTING_FC_PROPERTY
, 0, &printing
) !=
596 // Font options are set explicitly here to improve cairo's caching
597 // behavior and to record the relevant parts of the pattern for
598 // SetupCairoFont (so that the pattern can be released).
600 // Most font_options have already been set as defaults on the FcPattern
601 // with cairo_ft_font_options_substitute(), then user and system
602 // fontconfig configurations were applied. The resulting font_options
603 // have been recorded on the face during
604 // cairo_ft_font_face_create_for_pattern().
606 // None of the settings here cause this scaled_font to behave any
607 // differently from how it would behave if it were created from the same
608 // face with default font_options.
610 // We set options explicitly so that the same scaled_font will be found in
611 // the cairo_scaled_font_map when cairo loads glyphs from a context with
612 // the same font_face, font_matrix, ctm, and surface font_options.
614 // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
615 // font_options on the cairo_ft_font_face, and doesn't consider default
616 // option values to not match any explicit values.
618 // Even after cairo_set_scaled_font is used to set font_options for the
619 // cairo context, when cairo looks for a scaled_font for the context, it
620 // will look for a font with some option values from the target surface if
621 // any values are left default on the context font_options. If this
622 // scaled_font is created with default font_options, cairo will not find
625 // The one option not recorded in the pattern is hint_metrics, which will
626 // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON.
627 // We should be considering the font_options of the surface on which this
628 // font will be used, but currently we don't have different gfxFonts for
629 // different surface font_options, so we'll create a font suitable for the
630 // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
632 cairo_font_options_set_hint_metrics(aFontOptions
, CAIRO_HINT_METRICS_OFF
);
634 cairo_font_options_set_hint_metrics(aFontOptions
, CAIRO_HINT_METRICS_ON
);
637 // The remaining options have been recorded on the pattern and the face.
638 // _cairo_ft_options_merge has some logic to decide which options from the
639 // scaled_font or from the cairo_ft_font_face take priority in the way the
642 // In the majority of cases, _cairo_ft_options_merge uses the options from
643 // the cairo_ft_font_face, so sometimes it is not so important which
644 // values are set here so long as they are not defaults, but we'll set
645 // them to the exact values that we expect from the font, to be consistent
646 // and to protect against changes in cairo.
648 // In some cases, _cairo_ft_options_merge uses some options from the
649 // scaled_font's font_options rather than options on the
650 // cairo_ft_font_face (from fontconfig).
651 // https://bugs.freedesktop.org/show_bug.cgi?id=11838
653 // Surface font options were set on the pattern in
654 // cairo_ft_font_options_substitute. If fontconfig has changed the
655 // hint_style then that is what the user (or distribution) wants, so we
656 // use the setting from the FcPattern.
658 // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
659 FcBool hinting
= FcFalse
;
660 if (FcPatternGetBool(aPattern
, FC_HINTING
, 0, &hinting
) != FcResultMatch
) {
664 cairo_hint_style_t hint_style
;
665 if (printing
|| !hinting
) {
666 hint_style
= CAIRO_HINT_STYLE_NONE
;
669 if (FcPatternGetInteger(aPattern
, FC_HINT_STYLE
,
670 0, &fc_hintstyle
) != FcResultMatch
) {
671 fc_hintstyle
= FC_HINT_FULL
;
673 switch (fc_hintstyle
) {
675 hint_style
= CAIRO_HINT_STYLE_NONE
;
678 hint_style
= CAIRO_HINT_STYLE_SLIGHT
;
681 default: // This fallback mirrors _get_pattern_ft_options in cairo.
682 hint_style
= CAIRO_HINT_STYLE_MEDIUM
;
685 hint_style
= CAIRO_HINT_STYLE_FULL
;
689 cairo_font_options_set_hint_style(aFontOptions
, hint_style
);
692 if (FcPatternGetInteger(aPattern
,
693 FC_RGBA
, 0, &rgba
) != FcResultMatch
) {
694 rgba
= FC_RGBA_UNKNOWN
;
696 cairo_subpixel_order_t subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
698 case FC_RGBA_UNKNOWN
:
701 // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing
702 // is disabled through cairo_antialias_t.
704 // subpixel_order won't be used by the font as we won't use
705 // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
706 // caching reasons described above. Fall through:
709 subpixel_order
= CAIRO_SUBPIXEL_ORDER_RGB
;
712 subpixel_order
= CAIRO_SUBPIXEL_ORDER_BGR
;
715 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VRGB
;
718 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VBGR
;
721 cairo_font_options_set_subpixel_order(aFontOptions
, subpixel_order
);
724 if (FcPatternGetBool(aPattern
,
725 FC_ANTIALIAS
, 0, &fc_antialias
) != FcResultMatch
) {
726 fc_antialias
= FcTrue
;
728 cairo_antialias_t antialias
;
730 antialias
= CAIRO_ANTIALIAS_NONE
;
731 } else if (rgba
== FC_RGBA_NONE
) {
732 antialias
= CAIRO_ANTIALIAS_GRAY
;
734 antialias
= CAIRO_ANTIALIAS_SUBPIXEL
;
736 cairo_font_options_set_antialias(aFontOptions
, antialias
);
740 ReleaseFTUserFontData(void* aData
)
742 static_cast<FTUserFontData
*>(aData
)->Release();
746 gfxFontconfigFontEntry::CreateScaledFont(FcPattern
* aRenderPattern
,
747 gfxFloat aAdjustedSize
,
748 const gfxFontStyle
*aStyle
,
752 FcPatternAddBool(aRenderPattern
, FC_EMBOLDEN
, FcTrue
);
755 // will synthetic oblique be applied using a transform?
756 bool needsOblique
= IsUpright() &&
757 aStyle
->style
!= NS_FONT_STYLE_NORMAL
&&
758 aStyle
->allowSyntheticStyle
;
761 // disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
762 FcPatternDel(aRenderPattern
, FC_EMBEDDED_BITMAP
);
763 FcPatternAddBool(aRenderPattern
, FC_EMBEDDED_BITMAP
, FcFalse
);
766 AutoTArray
<FT_Fixed
,8> coords
;
767 if (!aStyle
->variationSettings
.IsEmpty() || !mVariationSettings
.IsEmpty()) {
768 FT_Face ftFace
= GetFTFace();
770 const nsTArray
<gfxFontVariation
>* settings
;
771 AutoTArray
<gfxFontVariation
,8> mergedSettings
;
772 if (mVariationSettings
.IsEmpty()) {
773 settings
= &aStyle
->variationSettings
;
774 } else if (aStyle
->variationSettings
.IsEmpty()) {
775 settings
= &mVariationSettings
;
777 gfxFontUtils::MergeVariations(mVariationSettings
,
778 aStyle
->variationSettings
,
780 settings
= &mergedSettings
;
782 gfxFT2FontBase::SetupVarCoords(ftFace
, *settings
, &coords
);
786 cairo_font_face_t
*face
=
787 cairo_ft_font_face_create_for_pattern(aRenderPattern
,
792 // for data fonts, add the face/data pointer to the cairo font face
793 // so that it gets deleted whenever cairo decides
794 NS_ASSERTION(mFTFace
, "FT_Face is null when setting user data");
795 NS_ASSERTION(mUserFontData
, "user font data is null when setting user data");
796 mUserFontData
.get()->AddRef();
797 if (cairo_font_face_set_user_data(face
,
798 &sFcFontlistUserFontDataKey
,
800 ReleaseFTUserFontData
) != CAIRO_STATUS_SUCCESS
) {
801 NS_WARNING("Failed binding FTUserFontData to Cairo font face");
802 mUserFontData
.get()->Release();
803 cairo_font_face_destroy(face
);
808 cairo_scaled_font_t
*scaledFont
= nullptr;
810 cairo_matrix_t sizeMatrix
;
811 cairo_matrix_t identityMatrix
;
813 cairo_matrix_init_scale(&sizeMatrix
, aAdjustedSize
, aAdjustedSize
);
814 cairo_matrix_init_identity(&identityMatrix
);
816 cairo_font_options_t
*fontOptions
= cairo_font_options_create();
817 PrepareFontOptions(aRenderPattern
, fontOptions
);
819 scaledFont
= cairo_scaled_font_create(face
, &sizeMatrix
,
820 &identityMatrix
, fontOptions
);
821 cairo_font_options_destroy(fontOptions
);
823 NS_ASSERTION(cairo_scaled_font_status(scaledFont
) == CAIRO_STATUS_SUCCESS
,
824 "Failed to make scaled font");
826 cairo_font_face_destroy(face
);
831 #ifdef MOZ_WIDGET_GTK
832 // defintion included below
833 static void ApplyGdkScreenFontOptions(FcPattern
*aPattern
);
838 GetXftInt(Display
* aDisplay
, const char* aName
, int* aResult
)
843 char* value
= XGetDefault(aDisplay
, "Xft", aName
);
847 if (FcNameConstant(const_cast<FcChar8
*>(ToFcChar8Ptr(value
)), aResult
)) {
851 *aResult
= strtol(value
, &end
, 0);
860 PreparePattern(FcPattern
* aPattern
, bool aIsPrinterFont
)
862 FcConfigSubstitute(nullptr, aPattern
, FcMatchPattern
);
864 // This gets cairo_font_options_t for the Screen. We should have
865 // different font options for printing (no hinting) but we are not told
866 // what we are measuring for.
868 // If cairo adds support for lcd_filter, gdk will not provide the default
869 // setting for that option. We could get the default setting by creating
870 // an xlib surface once, recording its font_options, and then merging the
873 // Using an xlib surface would also be an option to get Screen font
874 // options for non-GTK X11 toolkits, but less efficient than using GDK to
875 // pick up dynamic changes.
877 cairo_font_options_t
*options
= cairo_font_options_create();
878 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
879 cairo_font_options_set_antialias (options
, CAIRO_ANTIALIAS_GRAY
);
880 cairo_ft_font_options_substitute(options
, aPattern
);
881 cairo_font_options_destroy(options
);
882 FcPatternAddBool(aPattern
, PRINTING_FC_PROPERTY
, FcTrue
);
883 } else if (!gfxPlatform::IsHeadless()) {
884 #ifdef MOZ_WIDGET_GTK
885 ApplyGdkScreenFontOptions(aPattern
);
890 if (FcPatternGet(aPattern
, FC_LCD_FILTER
, 0, &value
) == FcResultNoMatch
) {
891 GdkDisplay
* dpy
= gdk_display_get_default();
892 if (GDK_IS_X11_DISPLAY(dpy
) &&
893 GetXftInt(GDK_DISPLAY_XDISPLAY(dpy
), "lcdfilter", &lcdfilter
)) {
894 FcPatternAddInteger(aPattern
, FC_LCD_FILTER
, lcdfilter
);
898 #endif // MOZ_WIDGET_GTK
901 FcDefaultSubstitute(aPattern
);
905 gfxFontconfigFontEntry::UnscaledFontCache::MoveToFront(size_t aIndex
) {
907 ThreadSafeWeakPtr
<UnscaledFontFontconfig
> front
=
908 Move(mUnscaledFonts
[aIndex
]);
909 for (size_t i
= aIndex
; i
> 0; i
--) {
910 mUnscaledFonts
[i
] = Move(mUnscaledFonts
[i
-1]);
912 mUnscaledFonts
[0] = Move(front
);
916 already_AddRefed
<UnscaledFontFontconfig
>
917 gfxFontconfigFontEntry::UnscaledFontCache::Lookup(const char* aFile
, uint32_t aIndex
) {
918 for (size_t i
= 0; i
< kNumEntries
; i
++) {
919 RefPtr
<UnscaledFontFontconfig
> entry(mUnscaledFonts
[i
]);
921 !strcmp(entry
->GetFile(), aFile
) &&
922 entry
->GetIndex() == aIndex
) {
924 return entry
.forget();
930 static inline gfxFloat
931 SizeForStyle(gfxFontconfigFontEntry
* aEntry
, const gfxFontStyle
& aStyle
)
933 return aStyle
.sizeAdjust
>= 0.0 ?
934 aStyle
.GetAdjustedSize(aEntry
->GetAspect()) :
939 ChooseFontSize(gfxFontconfigFontEntry
* aEntry
,
940 const gfxFontStyle
& aStyle
)
942 double requestedSize
= SizeForStyle(aEntry
, aStyle
);
943 double bestDist
= -1.0;
944 double bestSize
= requestedSize
;
947 while (FcPatternGetDouble(aEntry
->GetPattern(),
948 FC_PIXEL_SIZE
, v
, &size
) == FcResultMatch
) {
950 double dist
= fabs(size
- requestedSize
);
951 if (bestDist
< 0.0 || dist
< bestDist
) {
956 // If the font has bitmaps but wants to be scaled, then let it scale.
957 if (bestSize
>= 0.0) {
959 if (FcPatternGetBool(aEntry
->GetPattern(),
960 FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&&
962 return requestedSize
;
969 gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle
*aFontStyle
,
972 nsAutoRef
<FcPattern
> pattern(FcPatternCreate());
974 NS_WARNING("Failed to create Fontconfig pattern for font instance");
978 double size
= ChooseFontSize(this, *aFontStyle
);
979 FcPatternAddDouble(pattern
, FC_PIXEL_SIZE
, size
);
981 FT_Face face
= mFTFace
;
982 FcPattern
* fontPattern
= mFontPattern
;
983 if (face
&& face
->face_flags
& FT_FACE_FLAG_MULTIPLE_MASTERS
) {
984 // For variation fonts, we create a new FT_Face and FcPattern here
985 // so that variation coordinates from the style can be applied
986 // without affecting other font instances created from the same
987 // entry (font resource).
989 // For user fonts: create a new FT_Face from the font data, and then
990 // make a pattern from that.
991 face
= Factory::NewFTFaceFromData(nullptr, mFontData
, mLength
, 0);
992 fontPattern
= CreatePatternForFace(face
);
994 // For system fonts: create a new FT_Face and store it in a copy of
995 // the original mFontPattern.
996 fontPattern
= FcPatternDuplicate(mFontPattern
);
997 face
= CreateFaceForPattern(fontPattern
);
999 FcPatternAddFTFace(fontPattern
, FC_FT_FACE
, face
);
1001 // I don't think CreateFaceForPattern above should ever fail,
1002 // but just in case let's fall back here.
1008 PreparePattern(pattern
, aFontStyle
->printerFont
);
1009 nsAutoRef
<FcPattern
> renderPattern
1010 (FcFontRenderPrepare(nullptr, pattern
, fontPattern
));
1011 if (fontPattern
!= mFontPattern
) {
1012 // Discard temporary pattern used for variation support
1013 FcPatternDestroy(fontPattern
);
1015 if (!renderPattern
) {
1016 NS_WARNING("Failed to prepare Fontconfig pattern for font instance");
1020 cairo_scaled_font_t
* scaledFont
=
1021 CreateScaledFont(renderPattern
, size
, aFontStyle
, aNeedsBold
);
1023 const FcChar8
* file
= ToFcChar8Ptr("");
1026 if (FcPatternGetString(renderPattern
, FC_FILE
, 0,
1027 const_cast<FcChar8
**>(&file
)) != FcResultMatch
||
1028 FcPatternGetInteger(renderPattern
, FC_INDEX
, 0, &index
) != FcResultMatch
) {
1029 NS_WARNING("No file in Fontconfig pattern for font instance");
1034 RefPtr
<UnscaledFontFontconfig
> unscaledFont
=
1035 mUnscaledFontCache
.Lookup(ToCharPtr(file
), index
);
1036 if (!unscaledFont
) {
1039 new UnscaledFontFontconfig(face
) :
1040 new UnscaledFontFontconfig(ToCharPtr(file
), index
);
1041 mUnscaledFontCache
.Add(unscaledFont
);
1045 new gfxFontconfigFont(unscaledFont
, scaledFont
,
1046 renderPattern
, size
,
1047 this, aFontStyle
, aNeedsBold
);
1048 cairo_scaled_font_destroy(scaledFont
);
1054 gfxFontconfigFontEntry::GetFTFace()
1056 if (!mFTFaceInitialized
) {
1057 mFTFaceInitialized
= true;
1058 mFTFace
= CreateFaceForPattern(mFontPattern
);
1064 gfxFontconfigFontEntry::HasVariations()
1066 FT_Face face
= GetFTFace();
1068 return face
->face_flags
& FT_FACE_FLAG_MULTIPLE_MASTERS
;
1074 gfxFontconfigFontEntry::GetMMVar()
1076 if (mMMVarInitialized
) {
1079 mMMVarInitialized
= true;
1080 InitializeVarFuncs();
1084 FT_Face face
= GetFTFace();
1088 if (FT_Err_Ok
!= (*sGetVar
)(face
, &mMMVar
)) {
1095 gfxFontconfigFontEntry::GetVariationAxes(nsTArray
<gfxFontVariationAxis
>& aAxes
)
1097 MOZ_ASSERT(aAxes
.IsEmpty());
1098 FT_MM_Var
* mmVar
= GetMMVar();
1102 aAxes
.SetCapacity(mmVar
->num_axis
);
1103 for (unsigned i
= 0; i
< mmVar
->num_axis
; i
++) {
1104 const auto& a
= mmVar
->axis
[i
];
1105 gfxFontVariationAxis axis
;
1106 axis
.mMinValue
= a
.minimum
/ 65536.0;
1107 axis
.mMaxValue
= a
.maximum
/ 65536.0;
1108 axis
.mDefaultValue
= a
.def
/ 65536.0;
1110 axis
.mName
.Assign(NS_ConvertUTF8toUTF16(a
.name
));
1111 aAxes
.AppendElement(axis
);
1116 gfxFontconfigFontEntry::GetVariationInstances(
1117 nsTArray
<gfxFontVariationInstance
>& aInstances
)
1119 MOZ_ASSERT(aInstances
.IsEmpty());
1120 FT_MM_Var
* mmVar
= GetMMVar();
1124 hb_blob_t
* nameTable
= GetFontTable(TRUETYPE_TAG('n','a','m','e'));
1128 aInstances
.SetCapacity(mmVar
->num_namedstyles
);
1129 for (unsigned i
= 0; i
< mmVar
->num_namedstyles
; i
++) {
1130 const auto& ns
= mmVar
->namedstyle
[i
];
1131 gfxFontVariationInstance inst
;
1133 gfxFontUtils::ReadCanonicalName(nameTable
, ns
.strid
, inst
.mName
);
1134 if (NS_FAILED(rv
)) {
1137 inst
.mValues
.SetCapacity(mmVar
->num_axis
);
1138 for (unsigned j
= 0; j
< mmVar
->num_axis
; j
++) {
1139 gfxFontVariationValue value
;
1140 value
.mAxis
= mmVar
->axis
[j
].tag
;
1141 value
.mValue
= ns
.coords
[j
] / 65536.0;
1142 inst
.mValues
.AppendElement(value
);
1144 aInstances
.AppendElement(inst
);
1146 hb_blob_destroy(nameTable
);
1150 gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag
,
1151 nsTArray
<uint8_t>& aBuffer
)
1153 NS_ASSERTION(!mIsDataUserFont
,
1154 "data fonts should be reading tables directly from memory");
1156 FT_Face face
= GetFTFace();
1158 return NS_ERROR_NOT_AVAILABLE
;
1161 FT_ULong length
= 0;
1162 if (FT_Load_Sfnt_Table(face
, aTableTag
, 0, nullptr, &length
) != 0) {
1163 return NS_ERROR_NOT_AVAILABLE
;
1165 if (!aBuffer
.SetLength(length
, fallible
)) {
1166 return NS_ERROR_OUT_OF_MEMORY
;
1168 if (FT_Load_Sfnt_Table(face
, aTableTag
, 0, aBuffer
.Elements(), &length
) != 0) {
1170 return NS_ERROR_FAILURE
;
1177 gfxFontconfigFontFamily::FindStyleVariations(FontInfoData
*aFontInfoData
)
1183 // add font entries for each of the faces
1184 uint32_t numFonts
= mFontPatterns
.Length();
1185 NS_ASSERTION(numFonts
, "font family containing no faces!!");
1186 uint32_t numRegularFaces
= 0;
1187 for (uint32_t i
= 0; i
< numFonts
; i
++) {
1188 FcPattern
* face
= mFontPatterns
[i
];
1190 // figure out the psname/fullname and choose which to use as the facename
1191 nsAutoString psname
, fullname
;
1192 GetFaceNames(face
, mName
, psname
, fullname
);
1193 const nsAutoString
& faceName
= !psname
.IsEmpty() ? psname
: fullname
;
1195 gfxFontconfigFontEntry
*fontEntry
=
1196 new gfxFontconfigFontEntry(faceName
, face
, mContainsAppFonts
);
1197 AddFontEntry(fontEntry
);
1199 if (fontEntry
->IsNormalStyle()) {
1203 if (LOG_FONTLIST_ENABLED()) {
1204 LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
1205 " with style: %s weight: %d stretch: %d"
1206 " psname: %s fullname: %s",
1207 NS_ConvertUTF16toUTF8(fontEntry
->Name()).get(),
1208 NS_ConvertUTF16toUTF8(Name()).get(),
1209 (fontEntry
->IsItalic()) ?
1210 "italic" : (fontEntry
->IsOblique() ? "oblique" : "normal"),
1211 fontEntry
->Weight(), fontEntry
->Stretch(),
1212 NS_ConvertUTF16toUTF8(psname
).get(),
1213 NS_ConvertUTF16toUTF8(fullname
).get()));
1217 // somewhat arbitrary, but define a family with two or more regular
1218 // faces as a family for which intra-family fallback should be used
1219 if (numRegularFaces
> 1) {
1220 mCheckForFallbackFaces
= true;
1222 mFaceNamesInitialized
= true;
1223 mFontPatterns
.Clear();
1228 gfxFontconfigFontFamily::AddFontPattern(FcPattern
* aFontPattern
)
1230 NS_ASSERTION(!mHasStyles
,
1231 "font patterns must not be added to already enumerated families");
1234 if (FcPatternGetBool(aFontPattern
, FC_OUTLINE
, 0, &outline
) != FcResultMatch
||
1236 mHasNonScalableFaces
= true;
1239 if (FcPatternGetBool(aFontPattern
, FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&&
1241 mForceScalable
= true;
1245 nsCountedRef
<FcPattern
> pattern(aFontPattern
);
1246 mFontPatterns
.AppendElement(pattern
);
1249 static const double kRejectDistance
= 10000.0;
1251 // Calculate a distance score representing the size disparity between the
1252 // requested style's size and the font entry's size.
1254 SizeDistance(gfxFontconfigFontEntry
* aEntry
,
1255 const gfxFontStyle
& aStyle
,
1256 bool aForceScalable
)
1258 double requestedSize
= SizeForStyle(aEntry
, aStyle
);
1259 double bestDist
= -1.0;
1262 while (FcPatternGetDouble(aEntry
->GetPattern(),
1263 FC_PIXEL_SIZE
, v
, &size
) == FcResultMatch
) {
1265 double dist
= fabs(size
- requestedSize
);
1266 if (bestDist
< 0.0 || dist
< bestDist
) {
1270 if (bestDist
< 0.0) {
1271 // No size means scalable
1273 } else if (aForceScalable
|| 5.0 * bestDist
< requestedSize
) {
1274 // fontconfig prefers a matching family or lang to pixelsize of bitmap
1275 // fonts. CSS suggests a tolerance of 20% on pixelsize.
1278 // Reject any non-scalable fonts that are not within tolerance.
1279 return kRejectDistance
;
1284 gfxFontconfigFontFamily::FindAllFontsForStyle(const gfxFontStyle
& aFontStyle
,
1285 nsTArray
<gfxFontEntry
*>& aFontEntryList
,
1286 bool& aNeedsSyntheticBold
,
1287 bool aIgnoreSizeTolerance
)
1289 gfxFontFamily::FindAllFontsForStyle(aFontStyle
,
1291 aNeedsSyntheticBold
,
1292 aIgnoreSizeTolerance
);
1294 if (!mHasNonScalableFaces
) {
1298 // Iterate over the the available fonts while compacting any groups
1299 // of unscalable fonts with matching styles into a single entry
1300 // corresponding to the closest available size. If the closest
1301 // available size is rejected for being outside tolerance, then the
1302 // entire group will be skipped.
1304 gfxFontconfigFontEntry
* bestEntry
= nullptr;
1305 double bestDist
= -1.0;
1306 for (size_t i
= 0; i
< aFontEntryList
.Length(); i
++) {
1307 gfxFontconfigFontEntry
* entry
=
1308 static_cast<gfxFontconfigFontEntry
*>(aFontEntryList
[i
]);
1309 double dist
= SizeDistance(entry
, aFontStyle
,
1310 mForceScalable
|| aIgnoreSizeTolerance
);
1311 // If the entry is scalable or has a style that does not match
1312 // the group of unscalable fonts, then start a new group.
1315 bestEntry
->Stretch() != entry
->Stretch() ||
1316 bestEntry
->Weight() != entry
->Weight() ||
1317 bestEntry
->mStyle
!= entry
->mStyle
) {
1318 // If the best entry in this group is still outside the tolerance,
1319 // then skip the entire group.
1320 if (bestDist
>= kRejectDistance
) {
1323 // Remove any compacted entries from the previous group.
1326 aFontEntryList
.RemoveElementsAt(i
, skipped
);
1329 // Mark the start of the new group.
1333 // If this entry more closely matches the requested size than the
1334 // current best in the group, then take this entry instead.
1335 if (dist
< bestDist
) {
1336 aFontEntryList
[i
-1-skipped
] = entry
;
1343 // If the best entry in this group is still outside the tolerance,
1344 // then skip the entire group.
1345 if (bestDist
>= kRejectDistance
) {
1348 // Remove any compacted entries from the current group.
1350 aFontEntryList
.TruncateLength(aFontEntryList
.Length() - skipped
);
1355 PatternHasLang(const FcPattern
*aPattern
, const FcChar8
*aLang
)
1359 if (FcPatternGetLangSet(aPattern
, FC_LANG
, 0, &langset
) != FcResultMatch
) {
1363 if (FcLangSetHasLang(langset
, aLang
) != FcLangDifferentLang
) {
1370 gfxFontconfigFontFamily::SupportsLangGroup(nsAtom
*aLangGroup
) const
1372 if (!aLangGroup
|| aLangGroup
== nsGkAtoms::Unicode
) {
1376 nsAutoCString fcLang
;
1377 gfxFcPlatformFontList
* pfl
= gfxFcPlatformFontList::PlatformFontList();
1378 pfl
->GetSampleLangForGroup(aLangGroup
, fcLang
);
1379 if (fcLang
.IsEmpty()) {
1383 // Before FindStyleVariations has been called, mFontPatterns will contain
1384 // the font patterns. Afterward, it'll be empty, but mAvailableFonts
1385 // will contain the font entries, each of which holds a reference to its
1386 // pattern. We only check the first pattern in each list, because support
1387 // for langs is considered to be consistent across all faces in a family.
1388 FcPattern
* fontPattern
;
1389 if (mFontPatterns
.Length()) {
1390 fontPattern
= mFontPatterns
[0];
1391 } else if (mAvailableFonts
.Length()) {
1392 fontPattern
= static_cast<gfxFontconfigFontEntry
*>
1393 (mAvailableFonts
[0].get())->GetPattern();
1398 // is lang included in the underlying pattern?
1399 return PatternHasLang(fontPattern
, ToFcChar8Ptr(fcLang
.get()));
1403 gfxFontconfigFontFamily::~gfxFontconfigFontFamily()
1405 // Should not be dropped by stylo
1406 MOZ_ASSERT(NS_IsMainThread());
1409 template<typename Func
>
1411 gfxFontconfigFontFamily::AddFacesToFontList(Func aAddPatternFunc
)
1414 for (auto& fe
: mAvailableFonts
) {
1418 auto fce
= static_cast<gfxFontconfigFontEntry
*>(fe
.get());
1419 aAddPatternFunc(fce
->GetPattern(), mContainsAppFonts
);
1422 for (auto& pat
: mFontPatterns
) {
1423 aAddPatternFunc(pat
, mContainsAppFonts
);
1428 gfxFontconfigFont::gfxFontconfigFont(const RefPtr
<UnscaledFontFontconfig
>& aUnscaledFont
,
1429 cairo_scaled_font_t
*aScaledFont
,
1430 FcPattern
*aPattern
,
1431 gfxFloat aAdjustedSize
,
1432 gfxFontEntry
*aFontEntry
,
1433 const gfxFontStyle
*aFontStyle
,
1435 : gfxFT2FontBase(aUnscaledFont
, aScaledFont
, aFontEntry
, aFontStyle
, aNeedsBold
)
1436 , mPattern(aPattern
)
1438 mAdjustedSize
= aAdjustedSize
;
1441 gfxFontconfigFont::~gfxFontconfigFont()
1445 already_AddRefed
<ScaledFont
>
1446 gfxFontconfigFont::GetScaledFont(mozilla::gfx::DrawTarget
*aTarget
)
1448 if (!mAzureScaledFont
) {
1450 Factory::CreateScaledFontForFontconfigFont(GetCairoScaledFont(),
1456 RefPtr
<ScaledFont
> scaledFont(mAzureScaledFont
);
1457 return scaledFont
.forget();
1460 gfxFcPlatformFontList::gfxFcPlatformFontList()
1462 , mGenericMappings(32)
1463 , mFcSubstituteCache(64)
1464 , mLastConfig(nullptr)
1465 , mAlwaysUseFontconfigGenerics(true)
1467 if (XRE_IsParentProcess()) {
1468 // if the rescan interval is set, start the timer
1469 int rescanInterval
= FcConfigGetRescanInterval(nullptr);
1470 if (rescanInterval
) {
1471 mLastConfig
= FcConfigGetCurrent();
1472 NS_NewTimerWithFuncCallback(getter_AddRefs(mCheckFontUpdatesTimer
),
1475 (rescanInterval
+ 1) * 1000,
1476 nsITimer::TYPE_REPEATING_SLACK
,
1477 "gfxFcPlatformFontList::gfxFcPlatformFontList");
1478 if (!mCheckFontUpdatesTimer
) {
1479 NS_WARNING("Failure to create font updates timer");
1484 #ifdef MOZ_BUNDLED_FONTS
1485 mBundledFontsInitialized
= false;
1489 gfxFcPlatformFontList::~gfxFcPlatformFontList()
1491 if (mCheckFontUpdatesTimer
) {
1492 mCheckFontUpdatesTimer
->Cancel();
1493 mCheckFontUpdatesTimer
= nullptr;
1498 gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet
* aFontSet
,
1499 const SandboxPolicy
* aPolicy
,
1502 // This iterates over the fonts in a font set and adds in gfxFontFamily
1503 // objects for each family. Individual gfxFontEntry objects for each face
1504 // are not created here; the patterns are just stored in the family. When
1505 // a family is actually used, it will be populated with gfxFontEntry
1506 // records and the patterns moved to those.
1509 NS_WARNING("AddFontSetFamilies called with a null font set.");
1513 FcChar8
* lastFamilyName
= (FcChar8
*)"";
1514 RefPtr
<gfxFontconfigFontFamily
> fontFamily
;
1515 nsAutoString familyName
;
1516 for (int f
= 0; f
< aFontSet
->nfont
; f
++) {
1517 FcPattern
* pattern
= aFontSet
->fonts
[f
];
1519 // Skip any fonts that aren't readable for us (e.g. due to restrictive
1520 // file ownership/permissions).
1522 if (FcPatternGetString(pattern
, FC_FILE
, 0, &path
) != FcResultMatch
) {
1525 if (access(reinterpret_cast<const char*>(path
), F_OK
| R_OK
) != 0) {
1529 #ifdef MOZ_CONTENT_SANDBOX
1530 // Skip any fonts that will be blocked by the content-process sandbox
1532 if (aPolicy
&& !(aPolicy
->Lookup(reinterpret_cast<const char*>(path
)) &
1533 SandboxBroker::Perms::MAY_READ
)) {
1538 AddPatternToFontList(pattern
, lastFamilyName
,
1539 familyName
, fontFamily
, aAppFonts
);
1544 gfxFcPlatformFontList::AddPatternToFontList(FcPattern
* aFont
,
1545 FcChar8
*& aLastFamilyName
,
1546 nsAString
& aFamilyName
,
1547 RefPtr
<gfxFontconfigFontFamily
>& aFontFamily
,
1550 // get canonical name
1551 uint32_t cIndex
= FindCanonicalNameIndex(aFont
, FC_FAMILYLANG
);
1552 FcChar8
* canonical
= nullptr;
1553 FcPatternGetString(aFont
, FC_FAMILY
, cIndex
, &canonical
);
1558 // same as the last one? no need to add a new family, skip
1559 if (FcStrCmp(canonical
, aLastFamilyName
) != 0) {
1560 aLastFamilyName
= canonical
;
1562 // add new family if one doesn't already exist
1563 aFamilyName
.Truncate();
1564 AppendUTF8toUTF16(ToCharPtr(canonical
), aFamilyName
);
1565 nsAutoString
keyName(aFamilyName
);
1566 ToLowerCase(keyName
);
1568 aFontFamily
= static_cast<gfxFontconfigFontFamily
*>
1569 (mFontFamilies
.GetWeak(keyName
));
1571 aFontFamily
= new gfxFontconfigFontFamily(aFamilyName
);
1572 mFontFamilies
.Put(keyName
, aFontFamily
);
1574 // Record if the family contains fonts from the app font set
1575 // (in which case we won't rely on fontconfig's charmap, due to
1578 aFontFamily
->SetFamilyContainsAppFonts(true);
1581 // Add pointers to other localized family names. Most fonts
1582 // only have a single name, so the first call to GetString
1583 // will usually not match
1585 int n
= (cIndex
== 0 ? 1 : 0);
1586 while (FcPatternGetString(aFont
, FC_FAMILY
, n
, &otherName
) ==
1588 NS_ConvertUTF8toUTF16
otherFamilyName(ToCharPtr(otherName
));
1589 AddOtherFamilyName(aFontFamily
, otherFamilyName
);
1591 if (n
== int(cIndex
)) {
1592 n
++; // skip over canonical name
1597 MOZ_ASSERT(aFontFamily
, "font must belong to a font family");
1598 aFontFamily
->AddFontPattern(aFont
);
1600 // map the psname, fullname ==> font family for local font lookups
1601 nsAutoString psname
, fullname
;
1602 GetFaceNames(aFont
, aFamilyName
, psname
, fullname
);
1603 if (!psname
.IsEmpty()) {
1604 ToLowerCase(psname
);
1605 mLocalNames
.Put(psname
, aFont
);
1607 if (!fullname
.IsEmpty()) {
1608 ToLowerCase(fullname
);
1609 mLocalNames
.Put(fullname
, aFont
);
1614 gfxFcPlatformFontList::InitFontListForPlatform()
1616 #ifdef MOZ_BUNDLED_FONTS
1617 ActivateBundledFonts();
1620 mLocalNames
.Clear();
1621 mFcSubstituteCache
.Clear();
1623 mAlwaysUseFontconfigGenerics
= PrefFontListsUseOnlyGenerics();
1624 mOtherFamilyNamesInitialized
= true;
1626 if (XRE_IsContentProcess()) {
1627 // Content process: use the font list passed from the chrome process,
1628 // because we can't rely on fontconfig in the presence of sandboxing;
1629 // it may report fonts that we can't actually access.
1631 FcChar8
* lastFamilyName
= (FcChar8
*)"";
1632 RefPtr
<gfxFontconfigFontFamily
> fontFamily
;
1633 nsAutoString familyName
;
1635 // Get font list that was passed during XPCOM startup
1636 // or in an UpdateFontList message.
1637 auto& fontList
= dom::ContentChild::GetSingleton()->SystemFontList();
1639 // For fontconfig versions between 2.10.94 and 2.11.1 inclusive,
1640 // we need to escape any leading space in the charset element,
1641 // otherwise FcNameParse will fail. :(
1643 // The bug was introduced on 2013-05-24 by
1644 // https://cgit.freedesktop.org/fontconfig/commit/?id=cd9b1033a68816a7acfbba1718ba0aa5888f6ec7
1645 // "Bug 64906 - FcNameParse() should ignore leading whitespace in parameters"
1646 // because ignoring a leading space in the encoded value of charset
1647 // causes erroneous decoding of the whole element.
1648 // This first shipped in version 2.10.94, and was eventually fixed as
1649 // a side-effect of switching to the "human-readable" representation of
1650 // charsets on 2014-07-03 in
1651 // https://cgit.freedesktop.org/fontconfig/commit/?id=e708e97c351d3bc9f7030ef22ac2f007d5114730
1652 // "Change charset parse/unparse format to be human readable"
1653 // (with a followup fix next day) which means a leading space is no
1654 // longer significant. This fix landed after 2.11.1 had been shipped,
1655 // so the first version tag without the bug is 2.11.91.
1656 int fcVersion
= FcGetVersion();
1657 bool fcCharsetParseBug
= fcVersion
>= 21094 && fcVersion
<= 21101;
1659 for (SystemFontListEntry
& fle
: fontList
) {
1660 MOZ_ASSERT(fle
.type() ==
1661 SystemFontListEntry::Type::TFontPatternListEntry
);
1662 FontPatternListEntry
& fpe(fle
);
1663 nsCString
& patternStr
= fpe
.pattern();
1664 if (fcCharsetParseBug
) {
1665 int32_t index
= patternStr
.Find(":charset= ");
1666 if (index
!= kNotFound
) {
1667 // insert backslash after the =, before the space
1668 patternStr
.Insert('\\', index
+ 9);
1671 FcPattern
* pattern
=
1672 FcNameParse((const FcChar8
*)patternStr
.get());
1673 AddPatternToFontList(pattern
, lastFamilyName
, familyName
,
1674 fontFamily
, fpe
.appFontFamily());
1675 FcPatternDestroy(pattern
);
1678 LOG_FONTLIST(("got font list from chrome process: "
1679 "%u faces in %u families",
1680 (unsigned)fontList
.Length(), mFontFamilies
.Count()));
1687 mLastConfig
= FcConfigGetCurrent();
1689 UniquePtr
<SandboxPolicy
> policy
;
1691 #ifdef MOZ_CONTENT_SANDBOX
1692 // If read sandboxing is enabled, create a temporary SandboxPolicy to
1693 // check font paths; use a fake PID to avoid picking up any PID-specific
1694 // rules by accident.
1695 SandboxBrokerPolicyFactory policyFactory
;
1696 if (GetEffectiveContentSandboxLevel() > 2 &&
1697 !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
1698 policy
= policyFactory
.GetContentPolicy(-1, false);
1702 // iterate over available fonts
1703 FcFontSet
* systemFonts
= FcConfigGetFonts(nullptr, FcSetSystem
);
1704 AddFontSetFamilies(systemFonts
, policy
.get(), /* aAppFonts = */ false);
1706 #ifdef MOZ_BUNDLED_FONTS
1707 FcFontSet
* appFonts
= FcConfigGetFonts(nullptr, FcSetApplication
);
1708 AddFontSetFamilies(appFonts
, policy
.get(), /* aAppFonts = */ true);
1715 gfxFcPlatformFontList::ReadSystemFontList(
1716 InfallibleTArray
<SystemFontListEntry
>* retValue
)
1718 // Fontconfig versions below 2.9 drop the FC_FILE element in FcNameUnparse
1719 // (see https://bugs.freedesktop.org/show_bug.cgi?id=26718), so when using
1720 // an older version, we manually append it to the unparsed pattern.
1721 if (FcGetVersion() < 20900) {
1722 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
1724 static_cast<gfxFontconfigFontFamily
*>(iter
.Data().get());
1725 family
->AddFacesToFontList([&](FcPattern
* aPat
, bool aAppFonts
) {
1726 char* s
= (char*)FcNameUnparse(aPat
);
1727 nsAutoCString
patternStr(s
);
1729 if (FcResultMatch
==
1730 FcPatternGetString(aPat
, FC_FILE
, 0, (FcChar8
**)&s
)) {
1731 patternStr
.Append(":file=");
1732 patternStr
.Append(s
);
1734 retValue
->AppendElement(FontPatternListEntry(patternStr
,
1739 for (auto iter
= mFontFamilies
.Iter(); !iter
.Done(); iter
.Next()) {
1741 static_cast<gfxFontconfigFontFamily
*>(iter
.Data().get());
1742 family
->AddFacesToFontList([&](FcPattern
* aPat
, bool aAppFonts
) {
1743 char* s
= (char*)FcNameUnparse(aPat
);
1744 nsDependentCString
patternStr(s
);
1745 retValue
->AppendElement(FontPatternListEntry(patternStr
,
1753 // For displaying the fontlist in UI, use explicit call to FcFontList. Using
1754 // FcFontList results in the list containing the localized names as dictated
1755 // by system defaults.
1757 GetSystemFontList(nsTArray
<nsString
>& aListOfFonts
, nsAtom
*aLangGroup
)
1759 aListOfFonts
.Clear();
1761 nsAutoRef
<FcPattern
> pat(FcPatternCreate());
1766 nsAutoRef
<FcObjectSet
> os(FcObjectSetBuild(FC_FAMILY
, nullptr));
1771 // add the lang to the pattern
1772 nsAutoCString fcLang
;
1773 gfxFcPlatformFontList
* pfl
= gfxFcPlatformFontList::PlatformFontList();
1774 pfl
->GetSampleLangForGroup(aLangGroup
, fcLang
);
1775 if (!fcLang
.IsEmpty()) {
1776 FcPatternAddString(pat
, FC_LANG
, ToFcChar8Ptr(fcLang
.get()));
1779 nsAutoRef
<FcFontSet
> fs(FcFontList(nullptr, pat
, os
));
1784 for (int i
= 0; i
< fs
->nfont
; i
++) {
1787 if (FcPatternGetString(fs
->fonts
[i
], FC_FAMILY
, 0,
1788 (FcChar8
**) &family
) != FcResultMatch
)
1793 // Remove duplicates...
1794 nsAutoString strFamily
;
1795 AppendUTF8toUTF16(family
, strFamily
);
1796 if (aListOfFonts
.Contains(strFamily
)) {
1800 aListOfFonts
.AppendElement(strFamily
);
1803 aListOfFonts
.Sort();
1807 gfxFcPlatformFontList::GetFontList(nsAtom
*aLangGroup
,
1808 const nsACString
& aGenericFamily
,
1809 nsTArray
<nsString
>& aListOfFonts
)
1811 // Get the list of font family names using fontconfig
1812 GetSystemFontList(aListOfFonts
, aLangGroup
);
1814 // Under Linux, the generics "serif", "sans-serif" and "monospace"
1815 // are included in the pref fontlist. These map to whatever fontconfig
1816 // decides they should be for a given language, rather than one of the
1817 // fonts listed in the prefs font lists (e.g. font.name.*, font.name-list.*)
1818 bool serif
= false, sansSerif
= false, monospace
= false;
1819 if (aGenericFamily
.IsEmpty())
1820 serif
= sansSerif
= monospace
= true;
1821 else if (aGenericFamily
.LowerCaseEqualsLiteral("serif"))
1823 else if (aGenericFamily
.LowerCaseEqualsLiteral("sans-serif"))
1825 else if (aGenericFamily
.LowerCaseEqualsLiteral("monospace"))
1827 else if (aGenericFamily
.LowerCaseEqualsLiteral("cursive") ||
1828 aGenericFamily
.LowerCaseEqualsLiteral("fantasy"))
1829 serif
= sansSerif
= true;
1831 NS_NOTREACHED("unexpected CSS generic font family");
1833 // The first in the list becomes the default in
1834 // FontBuilder.readFontSelection() if the preference-selected font is not
1835 // available, so put system configured defaults first.
1837 aListOfFonts
.InsertElementAt(0, NS_LITERAL_STRING("monospace"));
1839 aListOfFonts
.InsertElementAt(0, NS_LITERAL_STRING("sans-serif"));
1841 aListOfFonts
.InsertElementAt(0, NS_LITERAL_STRING("serif"));
1845 gfxFcPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle
* aStyle
)
1847 // Get the default font by using a fake name to retrieve the first
1848 // scalable font that fontconfig suggests for the given language.
1849 PrefFontList
* prefFonts
=
1850 FindGenericFamilies(NS_LITERAL_STRING("-moz-default"), aStyle
->language
);
1851 NS_ASSERTION(prefFonts
, "null list of generic fonts");
1852 if (prefFonts
&& !prefFonts
->IsEmpty()) {
1853 return (*prefFonts
)[0];
1859 gfxFcPlatformFontList::LookupLocalFont(const nsAString
& aFontName
,
1864 nsAutoString
keyName(aFontName
);
1865 ToLowerCase(keyName
);
1867 // if name is not in the global list, done
1868 FcPattern
* fontPattern
= mLocalNames
.Get(keyName
);
1873 return new gfxFontconfigFontEntry(aFontName
, fontPattern
,
1874 aWeight
, aStretch
, aStyle
);
1878 gfxFcPlatformFontList::MakePlatformFont(const nsAString
& aFontName
,
1882 const uint8_t* aFontData
,
1885 FT_Face face
= Factory::NewFTFaceFromData(nullptr, aFontData
, aLength
, 0);
1887 free((void*)aFontData
);
1890 if (FT_Err_Ok
!= FT_Select_Charmap(face
, FT_ENCODING_UNICODE
)) {
1891 Factory::ReleaseFTFace(face
);
1892 free((void*)aFontData
);
1896 return new gfxFontconfigFontEntry(aFontName
, aWeight
, aStretch
,
1897 aStyle
, aFontData
, aLength
, face
);
1901 gfxFcPlatformFontList::FindAndAddFamilies(const nsAString
& aFamily
,
1902 nsTArray
<gfxFontFamily
*>* aOutput
,
1903 FindFamiliesFlags aFlags
,
1904 gfxFontStyle
* aStyle
,
1905 gfxFloat aDevToCssSize
)
1907 nsAutoString
familyName(aFamily
);
1908 ToLowerCase(familyName
);
1909 nsAtom
* language
= (aStyle
? aStyle
->language
.get() : nullptr);
1911 // deprecated generic names are explicitly converted to standard generics
1912 bool isDeprecatedGeneric
= false;
1913 if (familyName
.EqualsLiteral("sans") ||
1914 familyName
.EqualsLiteral("sans serif")) {
1915 familyName
.AssignLiteral("sans-serif");
1916 isDeprecatedGeneric
= true;
1917 } else if (familyName
.EqualsLiteral("mono")) {
1918 familyName
.AssignLiteral("monospace");
1919 isDeprecatedGeneric
= true;
1922 // fontconfig generics? use fontconfig to determine the family for lang
1923 if (isDeprecatedGeneric
||
1924 mozilla::FontFamilyName::Convert(familyName
).IsGeneric()) {
1925 PrefFontList
* prefFonts
= FindGenericFamilies(familyName
, language
);
1926 if (prefFonts
&& !prefFonts
->IsEmpty()) {
1927 aOutput
->AppendElements(*prefFonts
);
1933 // fontconfig allows conditional substitutions in such a way that it's
1934 // difficult to distinguish an explicit substitution from other suggested
1935 // choices. To sniff out explicit substitutions, compare the substitutions
1936 // for "font, -moz-sentinel" to "-moz-sentinel" to sniff out the
1941 // serif ==> DejaVu Serif, ...
1942 // Helvetica, serif ==> Helvetica, TeX Gyre Heros, Nimbus Sans L, DejaVu Serif
1944 // In this case fontconfig is including Tex Gyre Heros and
1945 // Nimbus Sans L as alternatives for Helvetica.
1947 // Because the FcConfigSubstitute call is quite expensive, we cache the
1948 // actual font families found via this process. So check the cache first:
1949 NS_ConvertUTF16toUTF8
familyToFind(familyName
);
1950 AutoTArray
<gfxFontFamily
*,10> cachedFamilies
;
1951 if (mFcSubstituteCache
.Get(familyToFind
, &cachedFamilies
)) {
1952 if (cachedFamilies
.IsEmpty()) {
1955 aOutput
->AppendElements(cachedFamilies
);
1959 // It wasn't in the cache, so we need to ask fontconfig...
1960 const FcChar8
* kSentinelName
= ToFcChar8Ptr("-moz-sentinel");
1961 FcChar8
* sentinelFirstFamily
= nullptr;
1962 nsAutoRef
<FcPattern
> sentinelSubst(FcPatternCreate());
1963 FcPatternAddString(sentinelSubst
, FC_FAMILY
, kSentinelName
);
1964 FcConfigSubstitute(nullptr, sentinelSubst
, FcMatchPattern
);
1965 FcPatternGetString(sentinelSubst
, FC_FAMILY
, 0, &sentinelFirstFamily
);
1967 // substitutions for font, -moz-sentinel pattern
1968 nsAutoRef
<FcPattern
> fontWithSentinel(FcPatternCreate());
1969 FcPatternAddString(fontWithSentinel
, FC_FAMILY
,
1970 ToFcChar8Ptr(familyToFind
.get()));
1971 FcPatternAddString(fontWithSentinel
, FC_FAMILY
, kSentinelName
);
1972 FcConfigSubstitute(nullptr, fontWithSentinel
, FcMatchPattern
);
1974 // Add all font family matches until reaching the sentinel.
1975 FcChar8
* substName
= nullptr;
1977 FcPatternGetString(fontWithSentinel
, FC_FAMILY
,
1978 i
, &substName
) == FcResultMatch
;
1981 NS_ConvertUTF8toUTF16
subst(ToCharPtr(substName
));
1982 if (sentinelFirstFamily
&&
1983 FcStrCmp(substName
, sentinelFirstFamily
) == 0) {
1986 gfxPlatformFontList::FindAndAddFamilies(subst
,
1991 // Cache the resulting list, so we don't have to do this again.
1992 mFcSubstituteCache
.Put(familyToFind
, cachedFamilies
);
1994 if (cachedFamilies
.IsEmpty()) {
1997 aOutput
->AppendElements(cachedFamilies
);
2002 gfxFcPlatformFontList::GetStandardFamilyName(const nsAString
& aFontName
,
2003 nsAString
& aFamilyName
)
2005 aFamilyName
.Truncate();
2007 // The fontconfig list of fonts includes generic family names in the
2008 // font list. For these, just use the generic name.
2009 if (aFontName
.EqualsLiteral("serif") ||
2010 aFontName
.EqualsLiteral("sans-serif") ||
2011 aFontName
.EqualsLiteral("monospace")) {
2012 aFamilyName
.Assign(aFontName
);
2016 nsAutoRef
<FcPattern
> pat(FcPatternCreate());
2021 nsAutoRef
<FcObjectSet
> os(FcObjectSetBuild(FC_FAMILY
, nullptr));
2026 // add the family name to the pattern
2027 NS_ConvertUTF16toUTF8
familyName(aFontName
);
2028 FcPatternAddString(pat
, FC_FAMILY
, ToFcChar8Ptr(familyName
.get()));
2030 nsAutoRef
<FcFontSet
> givenFS(FcFontList(nullptr, pat
, os
));
2035 // See if there is a font face with first family equal to the given family
2036 // (needs to be in sync with names coming from GetFontList())
2037 nsTArray
<nsCString
> candidates
;
2038 for (int i
= 0; i
< givenFS
->nfont
; i
++) {
2041 if (FcPatternGetString(givenFS
->fonts
[i
], FC_FAMILY
, 0,
2042 (FcChar8
**) &firstFamily
) != FcResultMatch
)
2047 nsDependentCString
first(firstFamily
);
2048 if (!candidates
.Contains(first
)) {
2049 candidates
.AppendElement(first
);
2051 if (familyName
.Equals(first
)) {
2052 aFamilyName
.Assign(aFontName
);
2058 // Because fontconfig conflates different family name types, need to
2059 // double check that the candidate name is not simply a different
2060 // name type. For example, if a font with nameID=16 "Minion Pro" and
2061 // nameID=21 "Minion Pro Caption" exists, calling FcFontList with
2062 // family="Minion Pro" will return a set of patterns some of which
2063 // will have a first family of "Minion Pro Caption". Ignore these
2064 // patterns and use the first candidate that maps to a font set with
2065 // the same number of faces and an identical set of patterns.
2066 for (uint32_t j
= 0; j
< candidates
.Length(); ++j
) {
2067 FcPatternDel(pat
, FC_FAMILY
);
2068 FcPatternAddString(pat
, FC_FAMILY
, (FcChar8
*)candidates
[j
].get());
2070 nsAutoRef
<FcFontSet
> candidateFS(FcFontList(nullptr, pat
, os
));
2075 if (candidateFS
->nfont
!= givenFS
->nfont
) {
2080 for (int i
= 0; i
< givenFS
->nfont
; ++i
) {
2081 if (!FcPatternEqual(candidateFS
->fonts
[i
], givenFS
->fonts
[i
])) {
2087 AppendUTF8toUTF16(candidates
[j
], aFamilyName
);
2092 // didn't find localized name, leave family name blank
2097 gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType
,
2099 nsTArray
<gfxFontFamily
*>& aFamilyList
)
2101 bool usePrefFontList
= false;
2103 // treat -moz-fixed as monospace
2104 if (aGenericType
== eFamily_moz_fixed
) {
2105 aGenericType
= eFamily_monospace
;
2108 const char* generic
= GetGenericName(aGenericType
);
2109 NS_ASSERTION(generic
, "weird generic font type");
2114 // By default, most font prefs on Linux map to "use fontconfig"
2115 // keywords. So only need to explicitly lookup font pref if
2116 // non-default settings exist
2117 NS_ConvertASCIItoUTF16
genericToLookup(generic
);
2118 if ((!mAlwaysUseFontconfigGenerics
&& aLanguage
) ||
2119 aLanguage
== nsGkAtoms::x_math
) {
2120 nsAtom
* langGroup
= GetLangGroup(aLanguage
);
2121 nsAutoString fontlistValue
;
2122 Preferences::GetString(NamePref(generic
, langGroup
).get(),
2125 if (fontlistValue
.IsEmpty()) {
2126 // The font name list may have two or more family names as comma
2127 // separated list. In such case, not matching with generic font
2128 // name is fine because if the list prefers specific font, we
2129 // should try to use the pref with complicated path.
2130 rv
= Preferences::GetString(NameListPref(generic
, langGroup
).get(),
2135 if (NS_SUCCEEDED(rv
)) {
2136 if (!fontlistValue
.EqualsLiteral("serif") &&
2137 !fontlistValue
.EqualsLiteral("sans-serif") &&
2138 !fontlistValue
.EqualsLiteral("monospace")) {
2139 usePrefFontList
= true;
2141 // serif, sans-serif or monospace was specified
2142 genericToLookup
.Assign(fontlistValue
);
2147 // when pref fonts exist, use standard pref font lookup
2148 if (usePrefFontList
) {
2149 return gfxPlatformFontList::AddGenericFonts(aGenericType
,
2154 PrefFontList
* prefFonts
= FindGenericFamilies(genericToLookup
, aLanguage
);
2155 NS_ASSERTION(prefFonts
, "null generic font list");
2156 aFamilyList
.AppendElements(*prefFonts
);
2160 gfxFcPlatformFontList::ClearLangGroupPrefFonts()
2162 ClearGenericMappings();
2163 gfxPlatformFontList::ClearLangGroupPrefFonts();
2164 mAlwaysUseFontconfigGenerics
= PrefFontListsUseOnlyGenerics();
2167 /* static */ FT_Library
2168 gfxFcPlatformFontList::GetFTLibrary()
2170 if (!sCairoFTLibrary
) {
2171 // Use cairo's FT_Library so that cairo takes care of shutdown of the
2172 // FT_Library after it has destroyed its font_faces, and FT_Done_Face
2173 // has been called on each FT_Face, at least until this bug is fixed:
2174 // https://bugs.freedesktop.org/show_bug.cgi?id=18857
2176 // Cairo keeps it's own FT_Library object for creating FT_Face
2177 // instances, so use that. There's no simple API for accessing this
2178 // so use the hacky method below of making a font and extracting
2179 // the library pointer from that.
2183 gfxPlatformFontList
* pfl
= gfxPlatformFontList::PlatformFontList();
2184 gfxFontFamily
* family
= pfl
->GetDefaultFont(&style
);
2185 NS_ASSERTION(family
, "couldn't find a default font family");
2186 gfxFontEntry
* fe
= family
->FindFontForStyle(style
, needsBold
, true);
2190 RefPtr
<gfxFont
> font
= fe
->FindOrMakeFont(&style
, false);
2195 gfxFT2FontBase
* ft2Font
= reinterpret_cast<gfxFT2FontBase
*>(font
.get());
2196 gfxFT2LockedFace
face(ft2Font
);
2201 sCairoFTLibrary
= face
.get()->glyph
->library
;
2204 return sCairoFTLibrary
;
2207 gfxPlatformFontList::PrefFontList
*
2208 gfxFcPlatformFontList::FindGenericFamilies(const nsAString
& aGeneric
,
2212 NS_ConvertUTF16toUTF8
generic(aGeneric
);
2214 nsAutoCString fcLang
;
2215 GetSampleLangForGroup(aLanguage
, fcLang
);
2216 ToLowerCase(fcLang
);
2218 nsAutoCString
genericLang(generic
);
2219 if (fcLang
.Length() > 0) {
2220 genericLang
.Append('-');
2222 genericLang
.Append(fcLang
);
2224 // try to get the family from the cache
2225 PrefFontList
* prefFonts
= mGenericMappings
.Get(genericLang
);
2230 // if not found, ask fontconfig to pick the appropriate font
2231 nsAutoRef
<FcPattern
> genericPattern(FcPatternCreate());
2232 FcPatternAddString(genericPattern
, FC_FAMILY
,
2233 ToFcChar8Ptr(generic
.get()));
2235 // -- prefer scalable fonts
2236 FcPatternAddBool(genericPattern
, FC_SCALABLE
, FcTrue
);
2238 // -- add the lang to the pattern
2239 if (!fcLang
.IsEmpty()) {
2240 FcPatternAddString(genericPattern
, FC_LANG
,
2241 ToFcChar8Ptr(fcLang
.get()));
2244 // -- perform substitutions
2245 FcConfigSubstitute(nullptr, genericPattern
, FcMatchPattern
);
2246 FcDefaultSubstitute(genericPattern
);
2248 // -- sort to get the closest matches
2250 nsAutoRef
<FcFontSet
> faces(FcFontSort(nullptr, genericPattern
, FcFalse
,
2257 // -- select the fonts to be used for the generic
2258 prefFonts
= new PrefFontList
; // can be empty but in practice won't happen
2259 uint32_t limit
= gfxPlatformGtk::GetPlatform()->MaxGenericSubstitions();
2260 bool foundFontWithLang
= false;
2261 for (int i
= 0; i
< faces
->nfont
; i
++) {
2262 FcPattern
* font
= faces
->fonts
[i
];
2263 FcChar8
* mappedGeneric
= nullptr;
2265 FcPatternGetString(font
, FC_FAMILY
, 0, &mappedGeneric
);
2266 if (mappedGeneric
) {
2267 NS_ConvertUTF8toUTF16
mappedGenericName(ToCharPtr(mappedGeneric
));
2268 AutoTArray
<gfxFontFamily
*,1> genericFamilies
;
2269 if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName
,
2271 FindFamiliesFlags(0))) {
2272 MOZ_ASSERT(genericFamilies
.Length() == 1,
2273 "expected a single family");
2274 if (!prefFonts
->Contains(genericFamilies
[0])) {
2275 prefFonts
->AppendElement(genericFamilies
[0]);
2277 !fcLang
.IsEmpty() &&
2278 PatternHasLang(font
, ToFcChar8Ptr(fcLang
.get()));
2279 foundFontWithLang
= foundFontWithLang
|| foundLang
;
2280 // check to see if the list is full
2281 if (prefFonts
->Length() >= limit
) {
2289 // if no font in the list matches the lang, trim all but the first one
2290 if (!prefFonts
->IsEmpty() && !foundFontWithLang
) {
2291 prefFonts
->TruncateLength(1);
2294 mGenericMappings
.Put(genericLang
, prefFonts
);
2299 gfxFcPlatformFontList::PrefFontListsUseOnlyGenerics()
2301 static const char kFontNamePrefix
[] = "font.name.";
2303 bool prefFontsUseOnlyGenerics
= true;
2306 nsresult rv
= Preferences::GetRootBranch()->
2307 GetChildList(kFontNamePrefix
, &count
, &names
);
2308 if (NS_SUCCEEDED(rv
) && count
) {
2309 for (size_t i
= 0; i
< count
; i
++) {
2310 // Check whether all font.name prefs map to generic keywords
2311 // and that the pref name and keyword match.
2312 // Ex: font.name.serif.ar ==> "serif" (ok)
2313 // Ex: font.name.serif.ar ==> "monospace" (return false)
2314 // Ex: font.name.serif.ar ==> "DejaVu Serif" (return false)
2315 // Ex: font.name.serif.ar ==> "" and
2316 // font.name-list.serif.ar ==> "serif" (ok)
2317 // Ex: font.name.serif.ar ==> "" and
2318 // font.name-list.serif.ar ==> "Something, serif"
2321 nsDependentCString
prefName(names
[i
] +
2322 ArrayLength(kFontNamePrefix
) - 1);
2323 nsCCharSeparatedTokenizer
tokenizer(prefName
, '.');
2324 const nsDependentCSubstring
& generic
= tokenizer
.nextToken();
2325 const nsDependentCSubstring
& langGroup
= tokenizer
.nextToken();
2326 nsAutoCString fontPrefValue
;
2327 Preferences::GetCString(names
[i
], fontPrefValue
);
2328 if (fontPrefValue
.IsEmpty()) {
2329 // The font name list may have two or more family names as comma
2330 // separated list. In such case, not matching with generic font
2331 // name is fine because if the list prefers specific font, this
2332 // should return false.
2333 Preferences::GetCString(NameListPref(generic
, langGroup
).get(),
2337 if (!langGroup
.EqualsLiteral("x-math") &&
2338 !generic
.Equals(fontPrefValue
)) {
2339 prefFontsUseOnlyGenerics
= false;
2343 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count
, names
);
2345 return prefFontsUseOnlyGenerics
;
2349 gfxFcPlatformFontList::CheckFontUpdates(nsITimer
*aTimer
, void *aThis
)
2351 // A content process is not supposed to check this directly;
2352 // it will be notified by the parent when the font list changes.
2353 MOZ_ASSERT(XRE_IsParentProcess());
2355 // check for font updates
2356 FcInitBringUptoDate();
2358 // update fontlist if current config changed
2359 gfxFcPlatformFontList
*pfl
= static_cast<gfxFcPlatformFontList
*>(aThis
);
2360 FcConfig
* current
= FcConfigGetCurrent();
2361 if (current
!= pfl
->GetLastConfig()) {
2362 pfl
->UpdateFontList();
2363 pfl
->ForceGlobalReflow();
2365 mozilla::dom::ContentParent::NotifyUpdatedFonts();
2370 gfxFcPlatformFontList::CreateFontFamily(const nsAString
& aName
) const
2372 return new gfxFontconfigFontFamily(aName
);
2375 #ifdef MOZ_BUNDLED_FONTS
2377 gfxFcPlatformFontList::ActivateBundledFonts()
2379 if (!mBundledFontsInitialized
) {
2380 mBundledFontsInitialized
= true;
2381 nsCOMPtr
<nsIFile
> localDir
;
2382 nsresult rv
= NS_GetSpecialDirectory(NS_GRE_DIR
, getter_AddRefs(localDir
));
2383 if (NS_FAILED(rv
)) {
2386 if (NS_FAILED(localDir
->Append(NS_LITERAL_STRING("fonts")))) {
2390 if (NS_FAILED(localDir
->IsDirectory(&isDir
)) || !isDir
) {
2393 if (NS_FAILED(localDir
->GetNativePath(mBundledFontsPath
))) {
2397 if (!mBundledFontsPath
.IsEmpty()) {
2398 FcConfigAppFontAddDir(nullptr, ToFcChar8Ptr(mBundledFontsPath
.get()));
2403 #ifdef MOZ_WIDGET_GTK
2404 /***************************************************************************
2406 * This function must be last in the file because it uses the system cairo
2407 * library. Above this point the cairo library used is the tree cairo if
2412 // Tree cairo symbols have different names. Disable their activation through
2413 // preprocessor macros.
2414 #undef cairo_ft_font_options_substitute
2416 // The system cairo functions are not declared because the include paths cause
2417 // the gdk headers to pick up the tree cairo.h.
2419 NS_VISIBILITY_DEFAULT
void
2420 cairo_ft_font_options_substitute (const cairo_font_options_t
*options
,
2421 FcPattern
*pattern
);
2426 ApplyGdkScreenFontOptions(FcPattern
*aPattern
)
2428 const cairo_font_options_t
*options
=
2429 gdk_screen_get_font_options(gdk_screen_get_default());
2431 cairo_ft_font_options_substitute(options
, aPattern
);
2434 #endif // MOZ_WIDGET_GTK