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