1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxPangoFonts.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2178 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "prlink.h" 1.10 +#include "gfxTypes.h" 1.11 + 1.12 +#include "nsTArray.h" 1.13 + 1.14 +#include "gfxContext.h" 1.15 +#ifdef MOZ_WIDGET_GTK 1.16 +#include "gfxPlatformGtk.h" 1.17 +#endif 1.18 +#ifdef MOZ_WIDGET_QT 1.19 +#include "gfxQtPlatform.h" 1.20 +#endif 1.21 +#include "gfxPangoFonts.h" 1.22 +#include "gfxFT2FontBase.h" 1.23 +#include "gfxFT2Utils.h" 1.24 +#include "harfbuzz/hb.h" 1.25 +#include "harfbuzz/hb-ot.h" 1.26 +#include "gfxHarfBuzzShaper.h" 1.27 +#include "gfxGraphiteShaper.h" 1.28 +#include "nsUnicodeProperties.h" 1.29 +#include "nsUnicodeScriptCodes.h" 1.30 +#include "gfxFontconfigUtils.h" 1.31 +#include "gfxUserFontSet.h" 1.32 +#include "gfxFontConstants.h" 1.33 + 1.34 +#include <cairo.h> 1.35 +#include <cairo-ft.h> 1.36 + 1.37 +#include <fontconfig/fcfreetype.h> 1.38 +#include <pango/pango.h> 1.39 + 1.40 +#include FT_TRUETYPE_TABLES_H 1.41 + 1.42 +#ifdef MOZ_WIDGET_GTK 1.43 +#include <gdk/gdk.h> 1.44 +#endif 1.45 + 1.46 +#include <math.h> 1.47 + 1.48 +using namespace mozilla; 1.49 +using namespace mozilla::unicode; 1.50 + 1.51 +#define PRINTING_FC_PROPERTY "gfx.printing" 1.52 + 1.53 +static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage); 1.54 + 1.55 +static cairo_scaled_font_t * 1.56 +CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace); 1.57 + 1.58 +static FT_Library gFTLibrary; 1.59 + 1.60 +// FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97 1.61 +// and so fontconfig-2.3.0 (2005). 1.62 +#ifndef FC_FAMILYLANG 1.63 +#define FC_FAMILYLANG "familylang" 1.64 +#endif 1.65 +#ifndef FC_FULLNAME 1.66 +#define FC_FULLNAME "fullname" 1.67 +#endif 1.68 + 1.69 +static PRFuncPtr 1.70 +FindFunctionSymbol(const char *name) 1.71 +{ 1.72 + PRLibrary *lib = nullptr; 1.73 + PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib); 1.74 + if (lib) { 1.75 + PR_UnloadLibrary(lib); 1.76 + } 1.77 + 1.78 + return result; 1.79 +} 1.80 + 1.81 +static bool HasChar(FcPattern *aFont, FcChar32 wc) 1.82 +{ 1.83 + FcCharSet *charset = nullptr; 1.84 + FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset); 1.85 + 1.86 + return charset && FcCharSetHasChar(charset, wc); 1.87 +} 1.88 + 1.89 +/** 1.90 + * gfxFcFontEntry: 1.91 + * 1.92 + * An abstract base class of for gfxFontEntry implementations used by 1.93 + * gfxFcFont and gfxUserFontSet. 1.94 + */ 1.95 + 1.96 +class gfxFcFontEntry : public gfxFontEntry { 1.97 +public: 1.98 + // For all FontEntrys attached to gfxFcFonts, there will be only one 1.99 + // pattern in this array. This is always a font pattern, not a fully 1.100 + // resolved pattern. gfxFcFont only uses this to construct a PangoFont. 1.101 + // 1.102 + // FontEntrys for src:local() fonts in gfxUserFontSet may return more than 1.103 + // one pattern. (See comment in gfxUserFcFontEntry.) 1.104 + const nsTArray< nsCountedRef<FcPattern> >& GetPatterns() 1.105 + { 1.106 + return mPatterns; 1.107 + } 1.108 + 1.109 + static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace) 1.110 + { 1.111 + return static_cast<gfxFcFontEntry*> 1.112 + (cairo_font_face_get_user_data(aFace, &sFontEntryKey)); 1.113 + } 1.114 + 1.115 + // override the gfxFontEntry impl to read the name from fontconfig 1.116 + // instead of trying to get the 'name' table, as we don't implement 1.117 + // GetFontTable() here 1.118 + virtual nsString RealFaceName(); 1.119 + 1.120 + // This is needed to make gfxFontEntry::HasCharacter(aCh) work. 1.121 + virtual bool TestCharacterMap(uint32_t aCh) 1.122 + { 1.123 + for (uint32_t i = 0; i < mPatterns.Length(); ++i) { 1.124 + if (HasChar(mPatterns[i], aCh)) { 1.125 + return true; 1.126 + } 1.127 + } 1.128 + return false; 1.129 + } 1.130 + 1.131 +protected: 1.132 + gfxFcFontEntry(const nsAString& aName) 1.133 + : gfxFontEntry(aName) 1.134 + { 1.135 + } 1.136 + 1.137 + // One pattern is the common case and some subclasses rely on successful 1.138 + // addition of the first element to the array. 1.139 + AutoFallibleTArray<nsCountedRef<FcPattern>,1> mPatterns; 1.140 + 1.141 + static cairo_user_data_key_t sFontEntryKey; 1.142 +}; 1.143 + 1.144 +cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey; 1.145 + 1.146 +nsString 1.147 +gfxFcFontEntry::RealFaceName() 1.148 +{ 1.149 + FcChar8 *name; 1.150 + if (!mPatterns.IsEmpty()) { 1.151 + if (FcPatternGetString(mPatterns[0], 1.152 + FC_FULLNAME, 0, &name) == FcResultMatch) { 1.153 + return NS_ConvertUTF8toUTF16((const char*)name); 1.154 + } 1.155 + if (FcPatternGetString(mPatterns[0], 1.156 + FC_FAMILY, 0, &name) == FcResultMatch) { 1.157 + NS_ConvertUTF8toUTF16 result((const char*)name); 1.158 + if (FcPatternGetString(mPatterns[0], 1.159 + FC_STYLE, 0, &name) == FcResultMatch) { 1.160 + result.AppendLiteral(" "); 1.161 + AppendUTF8toUTF16((const char*)name, result); 1.162 + } 1.163 + return result; 1.164 + } 1.165 + } 1.166 + // fall back to gfxFontEntry implementation (only works for sfnt fonts) 1.167 + return gfxFontEntry::RealFaceName(); 1.168 +} 1.169 + 1.170 +/** 1.171 + * gfxSystemFcFontEntry: 1.172 + * 1.173 + * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts, 1.174 + * including those from regular family-name based font selection as well as 1.175 + * those from src:local(). 1.176 + * 1.177 + * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. 1.178 + */ 1.179 + 1.180 +class gfxSystemFcFontEntry : public gfxFcFontEntry { 1.181 +public: 1.182 + // For memory efficiency, aFontPattern should be a font pattern, 1.183 + // not a fully resolved pattern. 1.184 + gfxSystemFcFontEntry(cairo_font_face_t *aFontFace, 1.185 + FcPattern *aFontPattern, 1.186 + const nsAString& aName) 1.187 + : gfxFcFontEntry(aName), mFontFace(aFontFace), 1.188 + mFTFace(nullptr), mFTFaceInitialized(false) 1.189 + { 1.190 + cairo_font_face_reference(mFontFace); 1.191 + cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr); 1.192 + mPatterns.AppendElement(); 1.193 + // mPatterns is an nsAutoTArray with 1 space always available, so the 1.194 + // AppendElement always succeeds. 1.195 + mPatterns[0] = aFontPattern; 1.196 + 1.197 + FcChar8 *name; 1.198 + if (FcPatternGetString(aFontPattern, 1.199 + FC_FAMILY, 0, &name) == FcResultMatch) { 1.200 + mFamilyName = NS_ConvertUTF8toUTF16((const char*)name); 1.201 + } 1.202 + } 1.203 + 1.204 + ~gfxSystemFcFontEntry() 1.205 + { 1.206 + cairo_font_face_set_user_data(mFontFace, 1.207 + &sFontEntryKey, 1.208 + nullptr, 1.209 + nullptr); 1.210 + cairo_font_face_destroy(mFontFace); 1.211 + } 1.212 + 1.213 + virtual void ForgetHBFace(); 1.214 + virtual void ReleaseGrFace(gr_face* aFace); 1.215 + 1.216 +protected: 1.217 + virtual nsresult 1.218 + CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE; 1.219 + 1.220 + void MaybeReleaseFTFace(); 1.221 + 1.222 +private: 1.223 + cairo_font_face_t *mFontFace; 1.224 + FT_Face mFTFace; 1.225 + bool mFTFaceInitialized; 1.226 +}; 1.227 + 1.228 +nsresult 1.229 +gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag, 1.230 + FallibleTArray<uint8_t>& aBuffer) 1.231 +{ 1.232 + if (!mFTFaceInitialized) { 1.233 + mFTFaceInitialized = true; 1.234 + FcChar8 *filename; 1.235 + if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) { 1.236 + return NS_ERROR_FAILURE; 1.237 + } 1.238 + int index; 1.239 + if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) { 1.240 + index = 0; // default to 0 if not found in pattern 1.241 + } 1.242 + if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(), 1.243 + (const char*)filename, index, &mFTFace) != 0) { 1.244 + return NS_ERROR_FAILURE; 1.245 + } 1.246 + } 1.247 + 1.248 + if (!mFTFace) { 1.249 + return NS_ERROR_NOT_AVAILABLE; 1.250 + } 1.251 + 1.252 + FT_ULong length = 0; 1.253 + if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) { 1.254 + return NS_ERROR_NOT_AVAILABLE; 1.255 + } 1.256 + if (!aBuffer.SetLength(length)) { 1.257 + return NS_ERROR_OUT_OF_MEMORY; 1.258 + } 1.259 + if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) { 1.260 + aBuffer.Clear(); 1.261 + return NS_ERROR_FAILURE; 1.262 + } 1.263 + 1.264 + return NS_OK; 1.265 +} 1.266 + 1.267 +void 1.268 +gfxSystemFcFontEntry::MaybeReleaseFTFace() 1.269 +{ 1.270 + // don't release if either HB or Gr face still exists 1.271 + if (mHBFace || mGrFace) { 1.272 + return; 1.273 + } 1.274 + if (mFTFace) { 1.275 + FT_Done_Face(mFTFace); 1.276 + mFTFace = nullptr; 1.277 + } 1.278 + mFTFaceInitialized = false; 1.279 +} 1.280 + 1.281 +void 1.282 +gfxSystemFcFontEntry::ForgetHBFace() 1.283 +{ 1.284 + gfxFontEntry::ForgetHBFace(); 1.285 + MaybeReleaseFTFace(); 1.286 +} 1.287 + 1.288 +void 1.289 +gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace) 1.290 +{ 1.291 + gfxFontEntry::ReleaseGrFace(aFace); 1.292 + MaybeReleaseFTFace(); 1.293 +} 1.294 + 1.295 +// A namespace for @font-face family names in FcPatterns so that fontconfig 1.296 +// aliases do not pick up families from @font-face rules and so that 1.297 +// fontconfig rules can distinguish between web fonts and platform fonts. 1.298 +// http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html 1.299 +#define FONT_FACE_FAMILY_PREFIX "@font-face:" 1.300 + 1.301 +/** 1.302 + * gfxUserFcFontEntry: 1.303 + * 1.304 + * An abstract class for objects in a gfxUserFontSet that can provide 1.305 + * FcPattern* handles to fonts. 1.306 + * 1.307 + * Separate implementations of this class support local fonts from src:local() 1.308 + * and web fonts from src:url(). 1.309 + */ 1.310 + 1.311 +// There is a one-to-one correspondence between gfxUserFcFontEntry objects and 1.312 +// @font-face rules, but sometimes a one-to-many correspondence between font 1.313 +// entries and font patterns. 1.314 +// 1.315 +// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions 1.316 +// provided a font-size descriptor to specify the sizes supported by the face, 1.317 +// but the "Editor's Draft 27 June 2008" 1.318 +// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a 1.319 +// descriptor, and Mozilla does not recognize such a descriptor. 1.320 +// 1.321 +// Font face names used in src:local() also do not usually specify a size. 1.322 +// 1.323 +// PCF format fonts have each size in a different file, and each of these 1.324 +// files is referenced by its own pattern, but really these are each 1.325 +// different sizes of one face with one name. 1.326 +// 1.327 +// Multiple patterns in an entry also effectively deals with a set of 1.328 +// PostScript Type 1 font files that all have the same face name but are in 1.329 +// several files because of the limit on the number of glyphs in a Type 1 font 1.330 +// file. (e.g. Computer Modern.) 1.331 + 1.332 +class gfxUserFcFontEntry : public gfxFcFontEntry { 1.333 +protected: 1.334 + gfxUserFcFontEntry(const gfxProxyFontEntry &aProxyEntry) 1.335 + : gfxFcFontEntry(aProxyEntry.Name()) 1.336 + { 1.337 + mItalic = aProxyEntry.mItalic; 1.338 + mWeight = aProxyEntry.mWeight; 1.339 + mStretch = aProxyEntry.mStretch; 1.340 + mIsUserFont = true; 1.341 + } 1.342 + 1.343 + // Helper function to change a pattern so that it matches the CSS style 1.344 + // descriptors and so gets properly sorted in font selection. This also 1.345 + // avoids synthetic style effects being added by the renderer when the 1.346 + // style of the font itself does not match the descriptor provided by the 1.347 + // author. 1.348 + void AdjustPatternToCSS(FcPattern *aPattern); 1.349 +}; 1.350 + 1.351 +void 1.352 +gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) 1.353 +{ 1.354 + int fontWeight = -1; 1.355 + FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight); 1.356 + int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100); 1.357 + if (cssWeight != fontWeight) { 1.358 + FcPatternDel(aPattern, FC_WEIGHT); 1.359 + FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight); 1.360 + } 1.361 + 1.362 + int fontSlant; 1.363 + FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant); 1.364 + // gfxFontEntry doesn't understand the difference between oblique 1.365 + // and italic. 1.366 + if (res != FcResultMatch || 1.367 + IsItalic() != (fontSlant != FC_SLANT_ROMAN)) { 1.368 + FcPatternDel(aPattern, FC_SLANT); 1.369 + FcPatternAddInteger(aPattern, FC_SLANT, 1.370 + IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); 1.371 + } 1.372 + 1.373 + int fontWidth = -1; 1.374 + FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth); 1.375 + int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch); 1.376 + if (cssWidth != fontWidth) { 1.377 + FcPatternDel(aPattern, FC_WIDTH); 1.378 + FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth); 1.379 + } 1.380 + 1.381 + // Ensure that there is a fullname property (if there is a family 1.382 + // property) so that fontconfig rules can identify the real name of the 1.383 + // font, because the family property will be replaced. 1.384 + FcChar8 *unused; 1.385 + if (FcPatternGetString(aPattern, 1.386 + FC_FULLNAME, 0, &unused) == FcResultNoMatch) { 1.387 + nsAutoCString fullname; 1.388 + if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern, 1.389 + &fullname)) { 1.390 + FcPatternAddString(aPattern, FC_FULLNAME, 1.391 + gfxFontconfigUtils::ToFcChar8(fullname)); 1.392 + } 1.393 + } 1.394 + 1.395 + nsAutoCString family; 1.396 + family.Append(FONT_FACE_FAMILY_PREFIX); 1.397 + AppendUTF16toUTF8(Name(), family); 1.398 + 1.399 + FcPatternDel(aPattern, FC_FAMILY); 1.400 + FcPatternDel(aPattern, FC_FAMILYLANG); 1.401 + FcPatternAddString(aPattern, FC_FAMILY, 1.402 + gfxFontconfigUtils::ToFcChar8(family)); 1.403 +} 1.404 + 1.405 +/** 1.406 + * gfxLocalFcFontEntry: 1.407 + * 1.408 + * An implementation of gfxUserFcFontEntry for local fonts from src:local(). 1.409 + * 1.410 + * This class is used only in gfxUserFontSet and for providing FcPattern* 1.411 + * handles to system fonts for font selection. gfxFcFonts created from these 1.412 + * patterns will use gfxSystemFcFontEntrys, which may be shared with 1.413 + * gfxFcFonts from regular family-name based font selection. 1.414 + */ 1.415 + 1.416 +class gfxLocalFcFontEntry : public gfxUserFcFontEntry { 1.417 +public: 1.418 + gfxLocalFcFontEntry(const gfxProxyFontEntry &aProxyEntry, 1.419 + const nsTArray< nsCountedRef<FcPattern> >& aPatterns) 1.420 + : gfxUserFcFontEntry(aProxyEntry) 1.421 + { 1.422 + if (!mPatterns.SetCapacity(aPatterns.Length())) 1.423 + return; // OOM 1.424 + 1.425 + for (uint32_t i = 0; i < aPatterns.Length(); ++i) { 1.426 + FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i)); 1.427 + if (!pattern) 1.428 + return; // OOM 1.429 + 1.430 + AdjustPatternToCSS(pattern); 1.431 + 1.432 + mPatterns.AppendElement(); 1.433 + mPatterns[i].own(pattern); 1.434 + } 1.435 + mIsLocalUserFont = true; 1.436 + } 1.437 +}; 1.438 + 1.439 +/** 1.440 + * gfxDownloadedFcFontEntry: 1.441 + * 1.442 + * An implementation of gfxFcFontEntry for web fonts from src:url(). 1.443 + * 1.444 + * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t 1.445 + * keeps a reference to the FontEntry to keep the font data alive. 1.446 + */ 1.447 + 1.448 +class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry { 1.449 +public: 1.450 + // This takes ownership of the face and its underlying data 1.451 + gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry, 1.452 + const uint8_t *aData, FT_Face aFace) 1.453 + : gfxUserFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace) 1.454 + { 1.455 + NS_PRECONDITION(aFace != nullptr, "aFace is NULL!"); 1.456 + InitPattern(); 1.457 + } 1.458 + 1.459 + virtual ~gfxDownloadedFcFontEntry(); 1.460 + 1.461 + // Returns true on success 1.462 + bool SetCairoFace(cairo_font_face_t *aFace); 1.463 + 1.464 + virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE; 1.465 + 1.466 +protected: 1.467 + void InitPattern(); 1.468 + 1.469 + // mFontData holds the data used to instantiate the FT_Face; 1.470 + // this has to persist until we are finished with the face, 1.471 + // then be released with NS_Free(). 1.472 + const uint8_t* mFontData; 1.473 + 1.474 + FT_Face mFace; 1.475 +}; 1.476 + 1.477 +// A property for recording gfxDownloadedFcFontEntrys on FcPatterns. 1.478 +static const char *kFontEntryFcProp = "-moz-font-entry"; 1.479 + 1.480 +static FcBool AddDownloadedFontEntry(FcPattern *aPattern, 1.481 + gfxDownloadedFcFontEntry *aFontEntry) 1.482 +{ 1.483 + FcValue value; 1.484 + value.type = FcTypeFTFace; // void* field of union 1.485 + value.u.f = aFontEntry; 1.486 + 1.487 + return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse); 1.488 +} 1.489 + 1.490 +static FcBool DelDownloadedFontEntry(FcPattern *aPattern) 1.491 +{ 1.492 + return FcPatternDel(aPattern, kFontEntryFcProp); 1.493 +} 1.494 + 1.495 +static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern) 1.496 +{ 1.497 + FcValue value; 1.498 + if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch) 1.499 + return nullptr; 1.500 + 1.501 + if (value.type != FcTypeFTFace) { 1.502 + NS_NOTREACHED("Wrong type for -moz-font-entry font property"); 1.503 + return nullptr; 1.504 + } 1.505 + 1.506 + return static_cast<gfxDownloadedFcFontEntry*>(value.u.f); 1.507 +} 1.508 + 1.509 +gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry() 1.510 +{ 1.511 + if (mPatterns.Length() != 0) { 1.512 + // Remove back reference to this font entry and the face in case 1.513 + // anyone holds a reference to the pattern. 1.514 + NS_ASSERTION(mPatterns.Length() == 1, 1.515 + "More than one pattern in gfxDownloadedFcFontEntry!"); 1.516 + DelDownloadedFontEntry(mPatterns[0]); 1.517 + FcPatternDel(mPatterns[0], FC_FT_FACE); 1.518 + } 1.519 + FT_Done_Face(mFace); 1.520 + NS_Free((void*)mFontData); 1.521 +} 1.522 + 1.523 +typedef FcPattern* (*QueryFaceFunction)(const FT_Face face, 1.524 + const FcChar8 *file, int id, 1.525 + FcBlanks *blanks); 1.526 + 1.527 +void 1.528 +gfxDownloadedFcFontEntry::InitPattern() 1.529 +{ 1.530 + static QueryFaceFunction sQueryFacePtr = 1.531 + reinterpret_cast<QueryFaceFunction> 1.532 + (FindFunctionSymbol("FcFreeTypeQueryFace")); 1.533 + FcPattern *pattern; 1.534 + 1.535 + // FcFreeTypeQueryFace is the same function used to construct patterns for 1.536 + // system fonts and so is the preferred function to use for this purpose. 1.537 + // This will set up the langset property, which helps with sorting, and 1.538 + // the foundry, fullname, and fontversion properties, which properly 1.539 + // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is 1.540 + // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has 1.541 + // fontconfig-2.4.1.) 1.542 + if (sQueryFacePtr) { 1.543 + // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at 1.544 + // least). The dummy file passed here is removed below. 1.545 + // 1.546 + // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr) 1.547 + // is passed as the "blanks" argument, which provides that unexpectedly 1.548 + // blank glyphs are elided. Here, however, we pass nullptr for 1.549 + // "blanks", effectively assuming that, if the font has a blank glyph, 1.550 + // then the author intends any associated character to be rendered 1.551 + // blank. 1.552 + pattern = 1.553 + (*sQueryFacePtr)(mFace, 1.554 + gfxFontconfigUtils::ToFcChar8(""), 1.555 + 0, 1.556 + nullptr); 1.557 + if (!pattern) 1.558 + // Either OOM, or fontconfig chose to skip this font because it 1.559 + // has "no encoded characters", which I think means "BDF and PCF 1.560 + // fonts which are not in Unicode (or the effectively equivalent 1.561 + // ISO Latin-1) encoding". 1.562 + return; 1.563 + 1.564 + // These properties don't make sense for this face without a file. 1.565 + FcPatternDel(pattern, FC_FILE); 1.566 + FcPatternDel(pattern, FC_INDEX); 1.567 + 1.568 + } else { 1.569 + // Do the minimum necessary to construct a pattern for sorting. 1.570 + 1.571 + // FC_CHARSET is vital to determine which characters are supported. 1.572 + nsAutoRef<FcCharSet> charset(FcFreeTypeCharSet(mFace, nullptr)); 1.573 + // If there are no characters then assume we don't know how to read 1.574 + // this font. 1.575 + if (!charset || FcCharSetCount(charset) == 0) 1.576 + return; 1.577 + 1.578 + pattern = FcPatternCreate(); 1.579 + FcPatternAddCharSet(pattern, FC_CHARSET, charset); 1.580 + 1.581 + // FC_PIXEL_SIZE can be important for font selection of fixed-size 1.582 + // fonts. 1.583 + if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) { 1.584 + for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) { 1.585 +#if HAVE_FT_BITMAP_SIZE_Y_PPEM 1.586 + double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem); 1.587 +#else 1.588 + double size = mFace->available_sizes[i].height; 1.589 +#endif 1.590 + FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size); 1.591 + } 1.592 + 1.593 + // Not sure whether this is important; 1.594 + // imitating FcFreeTypeQueryFace: 1.595 + FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse); 1.596 + } 1.597 + 1.598 + // Setting up the FC_LANGSET property is very difficult with the APIs 1.599 + // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET 1.600 + // property seems better than having a property with an empty LangSet. 1.601 + // With no FC_LANGSET property, fontconfig sort functions will 1.602 + // consider this face to have the same priority as (otherwise equal) 1.603 + // faces that have support for the primary requested language, but 1.604 + // will not consider any language to have been satisfied (and so will 1.605 + // continue to look for a face with language support in fallback 1.606 + // fonts). 1.607 + } 1.608 + 1.609 + AdjustPatternToCSS(pattern); 1.610 + 1.611 + FcPatternAddFTFace(pattern, FC_FT_FACE, mFace); 1.612 + AddDownloadedFontEntry(pattern, this); 1.613 + 1.614 + // There is never more than one pattern 1.615 + mPatterns.AppendElement(); 1.616 + mPatterns[0].own(pattern); 1.617 +} 1.618 + 1.619 +static void ReleaseDownloadedFontEntry(void *data) 1.620 +{ 1.621 + gfxDownloadedFcFontEntry *downloadedFontEntry = 1.622 + static_cast<gfxDownloadedFcFontEntry*>(data); 1.623 + NS_RELEASE(downloadedFontEntry); 1.624 +} 1.625 + 1.626 +bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace) 1.627 +{ 1.628 + if (CAIRO_STATUS_SUCCESS != 1.629 + cairo_font_face_set_user_data(aFace, &sFontEntryKey, this, 1.630 + ReleaseDownloadedFontEntry)) 1.631 + return false; 1.632 + 1.633 + // Hold a reference to this font entry to keep the font face data. 1.634 + NS_ADDREF(this); 1.635 + return true; 1.636 +} 1.637 + 1.638 +hb_blob_t * 1.639 +gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag) 1.640 +{ 1.641 + // The entry already owns the (sanitized) sfnt data in mFontData, 1.642 + // so we can just return a blob that "wraps" the appropriate chunk of it. 1.643 + // The blob should not attempt to free its data, as the entire sfnt data 1.644 + // will be freed when the font entry is deleted. 1.645 + return GetTableFromFontData(mFontData, aTableTag); 1.646 +} 1.647 + 1.648 +/* 1.649 + * gfxFcFont 1.650 + * 1.651 + * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT 1.652 + * cairo_scaled_font created from an FcPattern. 1.653 + */ 1.654 + 1.655 +class gfxFcFont : public gfxFT2FontBase { 1.656 +public: 1.657 + virtual ~gfxFcFont(); 1.658 + static already_AddRefed<gfxFcFont> 1.659 + GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, 1.660 + const gfxFontStyle *aFontStyle); 1.661 + 1.662 +#ifdef USE_SKIA 1.663 + virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions(); 1.664 +#endif 1.665 + 1.666 +protected: 1.667 + virtual bool ShapeText(gfxContext *aContext, 1.668 + const char16_t *aText, 1.669 + uint32_t aOffset, 1.670 + uint32_t aLength, 1.671 + int32_t aScript, 1.672 + gfxShapedText *aShapedText, 1.673 + bool aPreferPlatformShaping); 1.674 + 1.675 + bool InitGlyphRunWithPango(const char16_t *aString, 1.676 + uint32_t aOffset, 1.677 + uint32_t aLength, 1.678 + int32_t aScript, 1.679 + gfxShapedText *aShapedText); 1.680 + 1.681 +private: 1.682 + gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry, 1.683 + const gfxFontStyle *aFontStyle); 1.684 + 1.685 + // key for locating a gfxFcFont corresponding to a cairo_scaled_font 1.686 + static cairo_user_data_key_t sGfxFontKey; 1.687 +}; 1.688 + 1.689 +/** 1.690 + * gfxFcFontSet: 1.691 + * 1.692 + * Translation from a desired FcPattern to a sorted set of font references 1.693 + * (fontconfig cache data) and (when needed) fonts. 1.694 + */ 1.695 + 1.696 +class gfxFcFontSet MOZ_FINAL { 1.697 +public: 1.698 + NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet) 1.699 + 1.700 + explicit gfxFcFontSet(FcPattern *aPattern, 1.701 + gfxUserFontSet *aUserFontSet) 1.702 + : mSortPattern(aPattern), mUserFontSet(aUserFontSet), 1.703 + mFcFontsTrimmed(0), 1.704 + mHaveFallbackFonts(false) 1.705 + { 1.706 + bool waitForUserFont; 1.707 + mFcFontSet = SortPreferredFonts(waitForUserFont); 1.708 + mWaitingForUserFont = waitForUserFont; 1.709 + } 1.710 + 1.711 + // A reference is held by the FontSet. 1.712 + // The caller may add a ref to keep the font alive longer than the FontSet. 1.713 + gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle) 1.714 + { 1.715 + if (i >= mFonts.Length() || !mFonts[i].mFont) { 1.716 + // GetFontPatternAt sets up mFonts 1.717 + FcPattern *fontPattern = GetFontPatternAt(i); 1.718 + if (!fontPattern) 1.719 + return nullptr; 1.720 + 1.721 + mFonts[i].mFont = 1.722 + gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern, 1.723 + aFontStyle); 1.724 + } 1.725 + return mFonts[i].mFont; 1.726 + } 1.727 + 1.728 + FcPattern *GetFontPatternAt(uint32_t i); 1.729 + 1.730 + bool WaitingForUserFont() const { 1.731 + return mWaitingForUserFont; 1.732 + } 1.733 + 1.734 +private: 1.735 + // Private destructor, to discourage deletion outside of Release(): 1.736 + ~gfxFcFontSet() 1.737 + { 1.738 + } 1.739 + 1.740 + nsReturnRef<FcFontSet> SortPreferredFonts(bool& aWaitForUserFont); 1.741 + nsReturnRef<FcFontSet> SortFallbackFonts(); 1.742 + 1.743 + struct FontEntry { 1.744 + explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {} 1.745 + nsCountedRef<FcPattern> mPattern; 1.746 + nsRefPtr<gfxFcFont> mFont; 1.747 + }; 1.748 + 1.749 + struct LangSupportEntry { 1.750 + LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) : 1.751 + mLang(aLang), mBestSupport(aSupport) {} 1.752 + FcChar8 *mLang; 1.753 + FcLangResult mBestSupport; 1.754 + }; 1.755 + 1.756 +public: 1.757 + // public for nsTArray 1.758 + class LangComparator { 1.759 + public: 1.760 + bool Equals(const LangSupportEntry& a, const FcChar8 *b) const 1.761 + { 1.762 + return FcStrCmpIgnoreCase(a.mLang, b) == 0; 1.763 + } 1.764 + }; 1.765 + 1.766 +private: 1.767 + // The requested pattern 1.768 + nsCountedRef<FcPattern> mSortPattern; 1.769 + // Fonts from @font-face rules 1.770 + nsRefPtr<gfxUserFontSet> mUserFontSet; 1.771 + // A (trimmed) list of font patterns and fonts that is built up as 1.772 + // required. 1.773 + nsTArray<FontEntry> mFonts; 1.774 + // Holds a list of font patterns that will be trimmed. This is first set 1.775 + // to a list of preferred fonts. Then, if/when all the preferred fonts 1.776 + // have been trimmed and added to mFonts, this is set to a list of 1.777 + // fallback fonts. 1.778 + nsAutoRef<FcFontSet> mFcFontSet; 1.779 + // The set of characters supported by the fonts in mFonts. 1.780 + nsAutoRef<FcCharSet> mCharSet; 1.781 + // The index of the next font in mFcFontSet that has not yet been 1.782 + // considered for mFonts. 1.783 + int mFcFontsTrimmed; 1.784 + // True iff fallback fonts are either stored in mFcFontSet or have been 1.785 + // trimmed and added to mFonts (so that mFcFontSet is nullptr). 1.786 + bool mHaveFallbackFonts; 1.787 + // True iff there was a user font set with pending downloads, 1.788 + // so the set may be updated when downloads complete 1.789 + bool mWaitingForUserFont; 1.790 +}; 1.791 + 1.792 +// Find the FcPattern for an @font-face font suitable for CSS family |aFamily| 1.793 +// and style |aStyle| properties. 1.794 +static const nsTArray< nsCountedRef<FcPattern> >* 1.795 +FindFontPatterns(gfxUserFontSet *mUserFontSet, 1.796 + const nsACString &aFamily, uint8_t aStyle, 1.797 + uint16_t aWeight, int16_t aStretch, 1.798 + bool& aWaitForUserFont) 1.799 +{ 1.800 + // Convert to UTF16 1.801 + NS_ConvertUTF8toUTF16 utf16Family(aFamily); 1.802 + 1.803 + // needsBold is not used here. Instead synthetic bold is enabled through 1.804 + // FcFontRenderPrepare when the weight in the requested pattern is 1.805 + // compared against the weight in the font pattern. 1.806 + bool needsBold; 1.807 + 1.808 + gfxFontStyle style; 1.809 + style.style = aStyle; 1.810 + style.weight = aWeight; 1.811 + style.stretch = aStretch; 1.812 + 1.813 + gfxUserFcFontEntry *fontEntry = nullptr; 1.814 + gfxFontFamily *family = mUserFontSet->GetFamily(utf16Family); 1.815 + if (family) { 1.816 + fontEntry = static_cast<gfxUserFcFontEntry*> 1.817 + (mUserFontSet->FindFontEntry(family, style, needsBold, 1.818 + aWaitForUserFont)); 1.819 + 1.820 + // Accept synthetic oblique for italic and oblique. 1.821 + if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) { 1.822 + style.style = NS_FONT_STYLE_NORMAL; 1.823 + fontEntry = static_cast<gfxUserFcFontEntry*> 1.824 + (mUserFontSet->FindFontEntry(family, style, needsBold, 1.825 + aWaitForUserFont)); 1.826 + } 1.827 + } 1.828 + 1.829 + if (!fontEntry) { 1.830 + return nullptr; 1.831 + } 1.832 + 1.833 + return &fontEntry->GetPatterns(); 1.834 +} 1.835 + 1.836 +typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object, 1.837 + int id); 1.838 + 1.839 +// FcPatternRemove is available in fontconfig-2.3.0 (2005) 1.840 +static FcBool 1.841 +moz_FcPatternRemove(FcPattern *p, const char *object, int id) 1.842 +{ 1.843 + static FcPatternRemoveFunction sFcPatternRemovePtr = 1.844 + reinterpret_cast<FcPatternRemoveFunction> 1.845 + (FindFunctionSymbol("FcPatternRemove")); 1.846 + 1.847 + if (!sFcPatternRemovePtr) 1.848 + return FcFalse; 1.849 + 1.850 + return (*sFcPatternRemovePtr)(p, object, id); 1.851 +} 1.852 + 1.853 +// fontconfig prefers a matching family or lang to pixelsize of bitmap 1.854 +// fonts. CSS suggests a tolerance of 20% on pixelsize. 1.855 +static bool 1.856 +SizeIsAcceptable(FcPattern *aFont, double aRequestedSize) 1.857 +{ 1.858 + double size; 1.859 + int v = 0; 1.860 + while (FcPatternGetDouble(aFont, 1.861 + FC_PIXEL_SIZE, v, &size) == FcResultMatch) { 1.862 + ++v; 1.863 + if (5.0 * fabs(size - aRequestedSize) < aRequestedSize) 1.864 + return true; 1.865 + } 1.866 + 1.867 + // No size means scalable 1.868 + return v == 0; 1.869 +} 1.870 + 1.871 +// Sorting only the preferred fonts first usually saves having to sort through 1.872 +// every font on the system. 1.873 +nsReturnRef<FcFontSet> 1.874 +gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont) 1.875 +{ 1.876 + aWaitForUserFont = false; 1.877 + 1.878 + gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); 1.879 + if (!utils) 1.880 + return nsReturnRef<FcFontSet>(); 1.881 + 1.882 + // The list of families in mSortPattern has values with both weak and 1.883 + // strong bindings. Values with strong bindings should be preferred. 1.884 + // Values with weak bindings are default fonts that should be considered 1.885 + // only when the font provides the best support for a requested language 1.886 + // or after other fonts have satisfied all the requested languages. 1.887 + // 1.888 + // There are no direct fontconfig APIs to get the binding type. The 1.889 + // binding only takes effect in the sort and match functions. 1.890 + 1.891 + // |requiredLangs| is a list of requested languages that have not yet been 1.892 + // satisfied. gfxFontconfigUtils only sets one FC_LANG property value, 1.893 + // but FcConfigSubstitute may add more values (e.g. prepending "en" to 1.894 + // "ja" will use western fonts to render Latin/Arabic numerals in Japanese 1.895 + // text.) 1.896 + nsAutoTArray<LangSupportEntry,10> requiredLangs; 1.897 + for (int v = 0; ; ++v) { 1.898 + FcChar8 *lang; 1.899 + FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang); 1.900 + if (result != FcResultMatch) { 1.901 + // No need to check FcPatternGetLangSet() because 1.902 + // gfxFontconfigUtils sets only a string value for FC_LANG and 1.903 + // FcConfigSubstitute cannot add LangSets. 1.904 + NS_ASSERTION(result != FcResultTypeMismatch, 1.905 + "Expected a string for FC_LANG"); 1.906 + break; 1.907 + } 1.908 + 1.909 + if (!requiredLangs.Contains(lang, LangComparator())) { 1.910 + FcLangResult bestLangSupport = utils->GetBestLangSupport(lang); 1.911 + if (bestLangSupport != FcLangDifferentLang) { 1.912 + requiredLangs. 1.913 + AppendElement(LangSupportEntry(lang, bestLangSupport)); 1.914 + } 1.915 + } 1.916 + } 1.917 + 1.918 + nsAutoRef<FcFontSet> fontSet(FcFontSetCreate()); 1.919 + if (!fontSet) 1.920 + return fontSet.out(); 1.921 + 1.922 + // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever 1.923 + // doesn't happen, Roman will be used. 1.924 + int requestedSlant = FC_SLANT_ROMAN; 1.925 + FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant); 1.926 + double requestedSize = -1.0; 1.927 + FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize); 1.928 + 1.929 + nsTHashtable<gfxFontconfigUtils::DepFcStrEntry> existingFamilies(50); 1.930 + FcChar8 *family; 1.931 + for (int v = 0; 1.932 + FcPatternGetString(mSortPattern, 1.933 + FC_FAMILY, v, &family) == FcResultMatch; ++v) { 1.934 + const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nullptr; 1.935 + 1.936 + // Is this an @font-face family? 1.937 + // XXX: Make use of this + pass to nsFont?? 1.938 + bool isUserFont = false; 1.939 + if (mUserFontSet) { 1.940 + // Have some @font-face definitions 1.941 + 1.942 + nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family)); 1.943 + NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX); 1.944 + 1.945 + if (StringBeginsWith(cFamily, userPrefix)) { 1.946 + isUserFont = true; 1.947 + 1.948 + // Trim off the prefix 1.949 + nsDependentCSubstring cssFamily(cFamily, userPrefix.Length()); 1.950 + 1.951 + uint8_t thebesStyle = 1.952 + gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant); 1.953 + uint16_t thebesWeight = 1.954 + gfxFontconfigUtils::GetThebesWeight(mSortPattern); 1.955 + int16_t thebesStretch = 1.956 + gfxFontconfigUtils::GetThebesStretch(mSortPattern); 1.957 + 1.958 + bool waitForUserFont; 1.959 + familyFonts = FindFontPatterns(mUserFontSet, cssFamily, 1.960 + thebesStyle, 1.961 + thebesWeight, thebesStretch, 1.962 + waitForUserFont); 1.963 + if (waitForUserFont) { 1.964 + aWaitForUserFont = true; 1.965 + } 1.966 + } 1.967 + } 1.968 + 1.969 + if (!isUserFont) { 1.970 + familyFonts = &utils->GetFontsForFamily(family); 1.971 + } 1.972 + 1.973 + if (!familyFonts || familyFonts->Length() == 0) { 1.974 + // There are no fonts matching this family, so there is no point 1.975 + // in searching for this family in the FontSort. 1.976 + // 1.977 + // Perhaps the original pattern should be retained for 1.978 + // FcFontRenderPrepare. However, the only a useful config 1.979 + // substitution test against missing families that i can imagine 1.980 + // would only be interested in the preferred family 1.981 + // (qual="first"), so always keep the first family and use the 1.982 + // same pattern for Sort and RenderPrepare. 1.983 + if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) { 1.984 + --v; 1.985 + } 1.986 + continue; 1.987 + } 1.988 + 1.989 + // Aliases seem to often end up occurring more than once, but 1.990 + // duplicate families can't be removed from the sort pattern without 1.991 + // knowing whether duplicates have the same binding. 1.992 + gfxFontconfigUtils::DepFcStrEntry *entry = 1.993 + existingFamilies.PutEntry(family); 1.994 + if (entry) { 1.995 + if (entry->mKey) // old entry 1.996 + continue; 1.997 + 1.998 + entry->mKey = family; // initialize new entry 1.999 + } 1.1000 + 1.1001 + for (uint32_t f = 0; f < familyFonts->Length(); ++f) { 1.1002 + FcPattern *font = familyFonts->ElementAt(f); 1.1003 + 1.1004 + // Fix up the family name of user-font patterns, as the same 1.1005 + // font entry may be used (via the UserFontCache) for multiple 1.1006 + // CSS family names 1.1007 + if (isUserFont) { 1.1008 + font = FcPatternDuplicate(font); 1.1009 + FcPatternDel(font, FC_FAMILY); 1.1010 + FcPatternAddString(font, FC_FAMILY, family); 1.1011 + } 1.1012 + 1.1013 + // User fonts are already filtered by slant (but not size) in 1.1014 + // mUserFontSet->FindFontEntry(). 1.1015 + if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) 1.1016 + continue; 1.1017 + 1.1018 + for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { 1.1019 + const LangSupportEntry& entry = requiredLangs[r]; 1.1020 + FcLangResult support = 1.1021 + gfxFontconfigUtils::GetLangSupport(font, entry.mLang); 1.1022 + if (support <= entry.mBestSupport) { // lower is better 1.1023 + requiredLangs.RemoveElementAt(r); 1.1024 + --r; 1.1025 + } 1.1026 + } 1.1027 + 1.1028 + // FcFontSetDestroy will remove a reference but FcFontSetAdd 1.1029 + // does _not_ take a reference! 1.1030 + if (FcFontSetAdd(fontSet, font)) { 1.1031 + // We don't add a reference here for user fonts, because we're 1.1032 + // using a local clone of the pattern (see above) in order to 1.1033 + // override the family name 1.1034 + if (!isUserFont) { 1.1035 + FcPatternReference(font); 1.1036 + } 1.1037 + } 1.1038 + } 1.1039 + } 1.1040 + 1.1041 + FcPattern *truncateMarker = nullptr; 1.1042 + for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { 1.1043 + const nsTArray< nsCountedRef<FcPattern> >& langFonts = 1.1044 + utils->GetFontsForLang(requiredLangs[r].mLang); 1.1045 + 1.1046 + bool haveLangFont = false; 1.1047 + for (uint32_t f = 0; f < langFonts.Length(); ++f) { 1.1048 + FcPattern *font = langFonts[f]; 1.1049 + if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) 1.1050 + continue; 1.1051 + 1.1052 + haveLangFont = true; 1.1053 + if (FcFontSetAdd(fontSet, font)) { 1.1054 + FcPatternReference(font); 1.1055 + } 1.1056 + } 1.1057 + 1.1058 + if (!haveLangFont && langFonts.Length() > 0) { 1.1059 + // There is a font that supports this language but it didn't pass 1.1060 + // the slant and size criteria. Weak default font families should 1.1061 + // not be considered until the language has been satisfied. 1.1062 + // 1.1063 + // Insert a font that supports the language so that it will mark 1.1064 + // the position of fonts from weak families in the sorted set and 1.1065 + // they can be removed. The language and weak families will be 1.1066 + // considered in the fallback fonts, which use fontconfig's 1.1067 + // algorithm. 1.1068 + // 1.1069 + // Of the fonts that don't meet slant and size criteria, strong 1.1070 + // default font families should be considered before (other) fonts 1.1071 + // for this language, so this marker font will be removed (as well 1.1072 + // as the fonts from weak families), and strong families will be 1.1073 + // reconsidered in the fallback fonts. 1.1074 + FcPattern *font = langFonts[0]; 1.1075 + if (FcFontSetAdd(fontSet, font)) { 1.1076 + FcPatternReference(font); 1.1077 + truncateMarker = font; 1.1078 + } 1.1079 + break; 1.1080 + } 1.1081 + } 1.1082 + 1.1083 + FcFontSet *sets[1] = { fontSet }; 1.1084 + FcResult result; 1.1085 +#ifdef SOLARIS 1.1086 + // Get around a crash of FcFontSetSort when FcConfig is nullptr 1.1087 + // Solaris's FcFontSetSort needs an FcConfig (bug 474758) 1.1088 + fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern, 1.1089 + FcFalse, nullptr, &result)); 1.1090 +#else 1.1091 + fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern, 1.1092 + FcFalse, nullptr, &result)); 1.1093 +#endif 1.1094 + 1.1095 + if (truncateMarker != nullptr && fontSet) { 1.1096 + nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate()); 1.1097 + 1.1098 + for (int f = 0; f < fontSet->nfont; ++f) { 1.1099 + FcPattern *font = fontSet->fonts[f]; 1.1100 + if (font == truncateMarker) 1.1101 + break; 1.1102 + 1.1103 + if (FcFontSetAdd(truncatedSet, font)) { 1.1104 + FcPatternReference(font); 1.1105 + } 1.1106 + } 1.1107 + 1.1108 + fontSet.steal(truncatedSet); 1.1109 + } 1.1110 + 1.1111 + return fontSet.out(); 1.1112 +} 1.1113 + 1.1114 +nsReturnRef<FcFontSet> 1.1115 +gfxFcFontSet::SortFallbackFonts() 1.1116 +{ 1.1117 + // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet, 1.1118 + // but would take much longer due to comparing all the character sets. 1.1119 + // 1.1120 + // The references to fonts in this FcFontSet are almost free 1.1121 + // as they are pointers into mmaped cache files. 1.1122 + // 1.1123 + // GetFontPatternAt() will trim lazily if and as needed, which will also 1.1124 + // remove duplicates of preferred fonts. 1.1125 + FcResult result; 1.1126 + return nsReturnRef<FcFontSet>(FcFontSort(nullptr, mSortPattern, 1.1127 + FcFalse, nullptr, &result)); 1.1128 +} 1.1129 + 1.1130 +// GetFontAt relies on this setting up all patterns up to |i|. 1.1131 +FcPattern * 1.1132 +gfxFcFontSet::GetFontPatternAt(uint32_t i) 1.1133 +{ 1.1134 + while (i >= mFonts.Length()) { 1.1135 + while (!mFcFontSet) { 1.1136 + if (mHaveFallbackFonts) 1.1137 + return nullptr; 1.1138 + 1.1139 + mFcFontSet = SortFallbackFonts(); 1.1140 + mHaveFallbackFonts = true; 1.1141 + mFcFontsTrimmed = 0; 1.1142 + // Loop to test that mFcFontSet is non-nullptr. 1.1143 + } 1.1144 + 1.1145 + while (mFcFontsTrimmed < mFcFontSet->nfont) { 1.1146 + FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed]; 1.1147 + ++mFcFontsTrimmed; 1.1148 + 1.1149 + if (mFonts.Length() != 0) { 1.1150 + // See if the next font provides support for any extra 1.1151 + // characters. Most often the next font is not going to 1.1152 + // support more characters so check for a SubSet first before 1.1153 + // allocating a new CharSet with Union. 1.1154 + FcCharSet *supportedChars = mCharSet; 1.1155 + if (!supportedChars) { 1.1156 + FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern, 1.1157 + FC_CHARSET, 0, &supportedChars); 1.1158 + } 1.1159 + 1.1160 + if (supportedChars) { 1.1161 + FcCharSet *newChars = nullptr; 1.1162 + FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars); 1.1163 + if (newChars) { 1.1164 + if (FcCharSetIsSubset(newChars, supportedChars)) 1.1165 + continue; 1.1166 + 1.1167 + mCharSet.own(FcCharSetUnion(supportedChars, newChars)); 1.1168 + } else if (!mCharSet) { 1.1169 + mCharSet.own(FcCharSetCopy(supportedChars)); 1.1170 + } 1.1171 + } 1.1172 + } 1.1173 + 1.1174 + mFonts.AppendElement(font); 1.1175 + if (mFonts.Length() >= i) 1.1176 + break; 1.1177 + } 1.1178 + 1.1179 + if (mFcFontsTrimmed == mFcFontSet->nfont) { 1.1180 + // finished with this font set 1.1181 + mFcFontSet.reset(); 1.1182 + } 1.1183 + } 1.1184 + 1.1185 + return mFonts[i].mPattern; 1.1186 +} 1.1187 + 1.1188 +#ifdef MOZ_WIDGET_GTK 1.1189 +static void ApplyGdkScreenFontOptions(FcPattern *aPattern); 1.1190 +#endif 1.1191 + 1.1192 +// Apply user settings and defaults to pattern in preparation for matching. 1.1193 +static void 1.1194 +PrepareSortPattern(FcPattern *aPattern, double aFallbackSize, 1.1195 + double aSizeAdjustFactor, bool aIsPrinterFont) 1.1196 +{ 1.1197 + FcConfigSubstitute(nullptr, aPattern, FcMatchPattern); 1.1198 + 1.1199 + // This gets cairo_font_options_t for the Screen. We should have 1.1200 + // different font options for printing (no hinting) but we are not told 1.1201 + // what we are measuring for. 1.1202 + // 1.1203 + // If cairo adds support for lcd_filter, gdk will not provide the default 1.1204 + // setting for that option. We could get the default setting by creating 1.1205 + // an xlib surface once, recording its font_options, and then merging the 1.1206 + // gdk options. 1.1207 + // 1.1208 + // Using an xlib surface would also be an option to get Screen font 1.1209 + // options for non-GTK X11 toolkits, but less efficient than using GDK to 1.1210 + // pick up dynamic changes. 1.1211 + if(aIsPrinterFont) { 1.1212 + cairo_font_options_t *options = cairo_font_options_create(); 1.1213 + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); 1.1214 + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); 1.1215 + cairo_ft_font_options_substitute(options, aPattern); 1.1216 + cairo_font_options_destroy(options); 1.1217 + FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue); 1.1218 + } else { 1.1219 +#ifdef MOZ_GFX_OPTIMIZE_MOBILE 1.1220 + cairo_font_options_t *options = cairo_font_options_create(); 1.1221 + cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); 1.1222 + cairo_ft_font_options_substitute(options, aPattern); 1.1223 + cairo_font_options_destroy(options); 1.1224 +#endif 1.1225 +#ifdef MOZ_WIDGET_GTK 1.1226 + ApplyGdkScreenFontOptions(aPattern); 1.1227 +#endif 1.1228 + } 1.1229 + 1.1230 + // Protect against any fontconfig settings that may have incorrectly 1.1231 + // modified the pixelsize, and consider aSizeAdjustFactor. 1.1232 + double size = aFallbackSize; 1.1233 + if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch 1.1234 + || aSizeAdjustFactor != 1.0) { 1.1235 + FcPatternDel(aPattern, FC_PIXEL_SIZE); 1.1236 + FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor); 1.1237 + } 1.1238 + 1.1239 + FcDefaultSubstitute(aPattern); 1.1240 +} 1.1241 + 1.1242 +/** 1.1243 + ** gfxPangoFontGroup 1.1244 + **/ 1.1245 + 1.1246 +struct FamilyCallbackData { 1.1247 + FamilyCallbackData(nsTArray<nsString> *aFcFamilyList, 1.1248 + gfxUserFontSet *aUserFontSet) 1.1249 + : mFcFamilyList(aFcFamilyList), mUserFontSet(aUserFontSet) 1.1250 + { 1.1251 + } 1.1252 + nsTArray<nsString> *mFcFamilyList; 1.1253 + const gfxUserFontSet *mUserFontSet; 1.1254 +}; 1.1255 + 1.1256 +static int 1.1257 +FFRECountHyphens (const nsAString &aFFREName) 1.1258 +{ 1.1259 + int h = 0; 1.1260 + int32_t hyphen = 0; 1.1261 + while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) { 1.1262 + ++h; 1.1263 + ++hyphen; 1.1264 + } 1.1265 + return h; 1.1266 +} 1.1267 + 1.1268 +static bool 1.1269 +FamilyCallback (const nsAString& fontName, const nsACString& genericName, 1.1270 + bool aUseFontSet, void *closure) 1.1271 +{ 1.1272 + FamilyCallbackData *data = static_cast<FamilyCallbackData*>(closure); 1.1273 + nsTArray<nsString> *list = data->mFcFamilyList; 1.1274 + 1.1275 + // We ignore prefs that have three hypens since they are X style prefs. 1.1276 + if (genericName.Length() && FFRECountHyphens(fontName) >= 3) 1.1277 + return true; 1.1278 + 1.1279 + if (!list->Contains(fontName)) { 1.1280 + // The family properties of FcPatterns for @font-face fonts have a 1.1281 + // namespace to identify them among system fonts. (see 1.1282 + // FONT_FACE_FAMILY_PREFIX.) 1.1283 + // 1.1284 + // Earlier versions of this code allowed the CSS family name to match 1.1285 + // either the @font-face family or the system font family, so both 1.1286 + // were added here. This was in accordance with earlier versions of 1.1287 + // the W3C specifications regarding @font-face. 1.1288 + // 1.1289 + // The current (2011-02-27) draft of CSS3 Fonts says 1.1290 + // 1.1291 + // (Section 4.2: Font family: the font-family descriptor): 1.1292 + // "If the font family name is the same as a font family available in 1.1293 + // a given user's environment, it effectively hides the underlying 1.1294 + // font for documents that use the stylesheet." 1.1295 + // 1.1296 + // (Section 5: Font matching algorithm) 1.1297 + // "... the user agent attempts to find the family name among fonts 1.1298 + // defined via @font-face rules and then among available system fonts, 1.1299 + // .... If a font family defined via @font-face rules contains only 1.1300 + // invalid font data, it should be considered as if a font was present 1.1301 + // but contained an empty character map; matching a platform font with 1.1302 + // the same name must not occur in this case." 1.1303 + // 1.1304 + // Therefore, for names present in the user font set, this code no 1.1305 + // longer includes the family name for matching against system fonts. 1.1306 + // 1.1307 + const gfxUserFontSet *userFontSet = data->mUserFontSet; 1.1308 + if (aUseFontSet && genericName.Length() == 0 && 1.1309 + userFontSet && userFontSet->HasFamily(fontName)) { 1.1310 + nsAutoString userFontName = 1.1311 + NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName; 1.1312 + list->AppendElement(userFontName); 1.1313 + } else { 1.1314 + list->AppendElement(fontName); 1.1315 + } 1.1316 + } 1.1317 + 1.1318 + return true; 1.1319 +} 1.1320 + 1.1321 +gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families, 1.1322 + const gfxFontStyle *aStyle, 1.1323 + gfxUserFontSet *aUserFontSet) 1.1324 + : gfxFontGroup(families, aStyle, aUserFontSet), 1.1325 + mPangoLanguage(GuessPangoLanguage(aStyle->language)) 1.1326 +{ 1.1327 + // This language is passed to the font for shaping. 1.1328 + // Shaping doesn't know about lang groups so make it a real language. 1.1329 + if (mPangoLanguage) { 1.1330 + mStyle.language = do_GetAtom(pango_language_to_string(mPangoLanguage)); 1.1331 + } 1.1332 + 1.1333 + // dummy entry, will be replaced when actually needed 1.1334 + mFonts.AppendElement(FamilyFace()); 1.1335 +} 1.1336 + 1.1337 +gfxPangoFontGroup::~gfxPangoFontGroup() 1.1338 +{ 1.1339 +} 1.1340 + 1.1341 +gfxFontGroup * 1.1342 +gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) 1.1343 +{ 1.1344 + return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet); 1.1345 +} 1.1346 + 1.1347 +// An array of family names suitable for fontconfig 1.1348 +void 1.1349 +gfxPangoFontGroup::GetFcFamilies(nsTArray<nsString> *aFcFamilyList, 1.1350 + nsIAtom *aLanguage) 1.1351 +{ 1.1352 + FamilyCallbackData data(aFcFamilyList, mUserFontSet); 1.1353 + // Leave non-existing fonts in the list so that fontconfig can get the 1.1354 + // best match. 1.1355 + ForEachFontInternal(mFamilies, aLanguage, true, false, true, 1.1356 + FamilyCallback, &data); 1.1357 +} 1.1358 + 1.1359 +gfxFcFont * 1.1360 +gfxPangoFontGroup::GetBaseFont() 1.1361 +{ 1.1362 + if (mFonts[0].Font() == nullptr) { 1.1363 + gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle()); 1.1364 + mFonts[0] = FamilyFace(nullptr, font); 1.1365 + } 1.1366 + 1.1367 + return static_cast<gfxFcFont*>(mFonts[0].Font()); 1.1368 +} 1.1369 + 1.1370 +gfxFont * 1.1371 +gfxPangoFontGroup::GetFontAt(int32_t i) 1.1372 +{ 1.1373 + // If it turns out to be hard for all clients that cache font 1.1374 + // groups to call UpdateFontList at appropriate times, we could 1.1375 + // instead consider just calling UpdateFontList from someplace 1.1376 + // more central (such as here). 1.1377 + NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), 1.1378 + "Whoever was caching this font group should have " 1.1379 + "called UpdateFontList on it"); 1.1380 + 1.1381 + NS_PRECONDITION(i == 0, "Only have one font"); 1.1382 + 1.1383 + return GetBaseFont(); 1.1384 +} 1.1385 + 1.1386 +void 1.1387 +gfxPangoFontGroup::UpdateFontList() 1.1388 +{ 1.1389 + uint64_t newGeneration = GetGeneration(); 1.1390 + if (newGeneration == mCurrGeneration) 1.1391 + return; 1.1392 + 1.1393 + mFonts[0] = FamilyFace(); 1.1394 + mFontSets.Clear(); 1.1395 + mCachedEllipsisTextRun = nullptr; 1.1396 + mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; 1.1397 + mCurrGeneration = newGeneration; 1.1398 + mSkipDrawing = false; 1.1399 +} 1.1400 + 1.1401 +already_AddRefed<gfxFcFontSet> 1.1402 +gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, 1.1403 + nsAutoRef<FcPattern> *aMatchPattern) 1.1404 +{ 1.1405 + const char *lang = pango_language_to_string(aLang); 1.1406 + 1.1407 + nsRefPtr <nsIAtom> langGroup; 1.1408 + if (aLang != mPangoLanguage) { 1.1409 + // Set up langGroup for Mozilla's font prefs. 1.1410 + langGroup = do_GetAtom(lang); 1.1411 + } 1.1412 + 1.1413 + nsAutoTArray<nsString, 20> fcFamilyList; 1.1414 + GetFcFamilies(&fcFamilyList, 1.1415 + langGroup ? langGroup.get() : mStyle.language.get()); 1.1416 + 1.1417 + // To consider: A fontset cache here could be helpful. 1.1418 + 1.1419 + // Get a pattern suitable for matching. 1.1420 + nsAutoRef<FcPattern> pattern 1.1421 + (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang)); 1.1422 + 1.1423 + PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont); 1.1424 + 1.1425 + nsRefPtr<gfxFcFontSet> fontset = 1.1426 + new gfxFcFontSet(pattern, mUserFontSet); 1.1427 + 1.1428 + mSkipDrawing = fontset->WaitingForUserFont(); 1.1429 + 1.1430 + if (aMatchPattern) 1.1431 + aMatchPattern->steal(pattern); 1.1432 + 1.1433 + return fontset.forget(); 1.1434 +} 1.1435 + 1.1436 +gfxPangoFontGroup:: 1.1437 +FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang, 1.1438 + gfxFcFontSet *aFontSet) 1.1439 + : mLang(aLang), mFontSet(aFontSet) 1.1440 +{ 1.1441 +} 1.1442 + 1.1443 +gfxFcFontSet * 1.1444 +gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang) 1.1445 +{ 1.1446 + GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0] 1.1447 + 1.1448 + if (!aLang) 1.1449 + return mFontSets[0].mFontSet; 1.1450 + 1.1451 + for (uint32_t i = 0; i < mFontSets.Length(); ++i) { 1.1452 + if (mFontSets[i].mLang == aLang) 1.1453 + return mFontSets[i].mFontSet; 1.1454 + } 1.1455 + 1.1456 + nsRefPtr<gfxFcFontSet> fontSet = 1.1457 + MakeFontSet(aLang, mSizeAdjustFactor); 1.1458 + mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet)); 1.1459 + 1.1460 + return fontSet; 1.1461 +} 1.1462 + 1.1463 +already_AddRefed<gfxFont> 1.1464 +gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, 1.1465 + int32_t aRunScript, 1.1466 + gfxFont *aPrevMatchedFont, 1.1467 + uint8_t *aMatchType) 1.1468 +{ 1.1469 + if (aPrevMatchedFont) { 1.1470 + // Don't switch fonts for control characters, regardless of 1.1471 + // whether they are present in the current font, as they won't 1.1472 + // actually be rendered (see bug 716229) 1.1473 + uint8_t category = GetGeneralCategory(aCh); 1.1474 + if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) { 1.1475 + return nsRefPtr<gfxFont>(aPrevMatchedFont).forget(); 1.1476 + } 1.1477 + 1.1478 + // if this character is a join-control or the previous is a join-causer, 1.1479 + // use the same font as the previous range if we can 1.1480 + if (gfxFontUtils::IsJoinControl(aCh) || 1.1481 + gfxFontUtils::IsJoinCauser(aPrevCh)) { 1.1482 + if (aPrevMatchedFont->HasCharacter(aCh)) { 1.1483 + return nsRefPtr<gfxFont>(aPrevMatchedFont).forget(); 1.1484 + } 1.1485 + } 1.1486 + } 1.1487 + 1.1488 + // if this character is a variation selector, 1.1489 + // use the previous font regardless of whether it supports VS or not. 1.1490 + // otherwise the text run will be divided. 1.1491 + if (gfxFontUtils::IsVarSelector(aCh)) { 1.1492 + if (aPrevMatchedFont) { 1.1493 + return nsRefPtr<gfxFont>(aPrevMatchedFont).forget(); 1.1494 + } 1.1495 + // VS alone. it's meaningless to search different fonts 1.1496 + return nullptr; 1.1497 + } 1.1498 + 1.1499 + // The real fonts that fontconfig provides for generic/fallback families 1.1500 + // depend on the language used, so a different FontSet is used for each 1.1501 + // language (except for the variation below). 1.1502 + // 1.1503 + // With most fontconfig configurations any real family names prior to a 1.1504 + // fontconfig generic with corresponding fonts installed will still lead 1.1505 + // to the same leading fonts in each FontSet. 1.1506 + // 1.1507 + // There is an inefficiency here therefore because the same base FontSet 1.1508 + // could often be used if these real families support the character. 1.1509 + // However, with fontconfig aliases, it is difficult to distinguish 1.1510 + // where exactly alias fonts end and generic/fallback fonts begin. 1.1511 + // 1.1512 + // The variation from pure language-based matching used here is that the 1.1513 + // same primary/base font is always used irrespective of the language. 1.1514 + // This provides that SCRIPT_COMMON characters are consistently rendered 1.1515 + // with the same font (bug 339513 and bug 416725). This is particularly 1.1516 + // important with the word cache as script can't be reliably determined 1.1517 + // from surrounding words. It also often avoids the unnecessary extra 1.1518 + // FontSet efficiency mentioned above. 1.1519 + // 1.1520 + // However, in two situations, the base font is not checked before the 1.1521 + // language-specific FontSet. 1.1522 + // 1.1523 + // 1. When we don't have a language to make a good choice for 1.1524 + // the base font. 1.1525 + // 1.1526 + // 2. For system fonts, use the default Pango behavior to give 1.1527 + // consistency with other apps. This is relevant when un-localized 1.1528 + // builds are run in non-Latin locales. This special-case probably 1.1529 + // wouldn't be necessary but for bug 91190. 1.1530 + 1.1531 + gfxFcFontSet *fontSet = GetBaseFontSet(); 1.1532 + uint32_t nextFont = 0; 1.1533 + FcPattern *basePattern = nullptr; 1.1534 + if (!mStyle.systemFont && mPangoLanguage) { 1.1535 + basePattern = fontSet->GetFontPatternAt(0); 1.1536 + if (HasChar(basePattern, aCh)) { 1.1537 + *aMatchType = gfxTextRange::kFontGroup; 1.1538 + return nsRefPtr<gfxFont>(GetBaseFont()).forget(); 1.1539 + } 1.1540 + 1.1541 + nextFont = 1; 1.1542 + } 1.1543 + 1.1544 + // Pango, GLib, and Thebes (but not harfbuzz!) all happen to use the same 1.1545 + // script codes, so we can just cast the value here. 1.1546 + const PangoScript script = static_cast<PangoScript>(aRunScript); 1.1547 + // Might be nice to call pango_language_includes_script only once for the 1.1548 + // run rather than for each character. 1.1549 + PangoLanguage *scriptLang; 1.1550 + if ((!basePattern || 1.1551 + !pango_language_includes_script(mPangoLanguage, script)) && 1.1552 + (scriptLang = pango_script_get_sample_language(script))) { 1.1553 + fontSet = GetFontSet(scriptLang); 1.1554 + nextFont = 0; 1.1555 + } 1.1556 + 1.1557 + for (uint32_t i = nextFont; 1.1558 + FcPattern *pattern = fontSet->GetFontPatternAt(i); 1.1559 + ++i) { 1.1560 + if (pattern == basePattern) { 1.1561 + continue; // already checked basePattern 1.1562 + } 1.1563 + 1.1564 + if (HasChar(pattern, aCh)) { 1.1565 + *aMatchType = gfxTextRange::kFontGroup; 1.1566 + return nsRefPtr<gfxFont>(fontSet->GetFontAt(i, GetStyle())).forget(); 1.1567 + } 1.1568 + } 1.1569 + 1.1570 + return nullptr; 1.1571 +} 1.1572 + 1.1573 +// Sanity-check: spot-check a few constants to confirm that Thebes and 1.1574 +// Pango script codes really do match 1.1575 +#define CHECK_SCRIPT_CODE(script) \ 1.1576 + PR_STATIC_ASSERT(int32_t(MOZ_SCRIPT_##script) == \ 1.1577 + int32_t(PANGO_SCRIPT_##script)) 1.1578 + 1.1579 +CHECK_SCRIPT_CODE(COMMON); 1.1580 +CHECK_SCRIPT_CODE(INHERITED); 1.1581 +CHECK_SCRIPT_CODE(ARABIC); 1.1582 +CHECK_SCRIPT_CODE(LATIN); 1.1583 +CHECK_SCRIPT_CODE(UNKNOWN); 1.1584 +CHECK_SCRIPT_CODE(NKO); 1.1585 + 1.1586 +/** 1.1587 + ** gfxFcFont 1.1588 + **/ 1.1589 + 1.1590 +cairo_user_data_key_t gfxFcFont::sGfxFontKey; 1.1591 + 1.1592 +gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont, 1.1593 + gfxFcFontEntry *aFontEntry, 1.1594 + const gfxFontStyle *aFontStyle) 1.1595 + : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle) 1.1596 +{ 1.1597 + cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr); 1.1598 +} 1.1599 + 1.1600 +gfxFcFont::~gfxFcFont() 1.1601 +{ 1.1602 + cairo_scaled_font_set_user_data(mScaledFont, 1.1603 + &sGfxFontKey, 1.1604 + nullptr, 1.1605 + nullptr); 1.1606 +} 1.1607 + 1.1608 +bool 1.1609 +gfxFcFont::ShapeText(gfxContext *aContext, 1.1610 + const char16_t *aText, 1.1611 + uint32_t aOffset, 1.1612 + uint32_t aLength, 1.1613 + int32_t aScript, 1.1614 + gfxShapedText *aShapedText, 1.1615 + bool aPreferPlatformShaping) 1.1616 +{ 1.1617 + bool ok = false; 1.1618 + 1.1619 + if (FontCanSupportGraphite()) { 1.1620 + if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) { 1.1621 + if (!mGraphiteShaper) { 1.1622 + mGraphiteShaper = new gfxGraphiteShaper(this); 1.1623 + } 1.1624 + ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength, 1.1625 + aScript, aShapedText); 1.1626 + } 1.1627 + } 1.1628 + 1.1629 + if (!ok) { 1.1630 + if (!mHarfBuzzShaper) { 1.1631 + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); 1.1632 + } 1.1633 + ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, 1.1634 + aScript, aShapedText); 1.1635 + } 1.1636 + 1.1637 + NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text"); 1.1638 + 1.1639 + PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); 1.1640 + 1.1641 + return ok; 1.1642 +} 1.1643 + 1.1644 +/* static */ void 1.1645 +gfxPangoFontGroup::Shutdown() 1.1646 +{ 1.1647 + // Resetting gFTLibrary in case this is wanted again after a 1.1648 + // cairo_debug_reset_static_data. 1.1649 + gFTLibrary = nullptr; 1.1650 +} 1.1651 + 1.1652 +/* static */ gfxFontEntry * 1.1653 +gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry, 1.1654 + const nsAString& aFullname) 1.1655 +{ 1.1656 + gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); 1.1657 + if (!utils) 1.1658 + return nullptr; 1.1659 + 1.1660 + // The font face name from @font-face { src: local() } is not well 1.1661 + // defined. 1.1662 + // 1.1663 + // On MS Windows, this name gets compared with 1.1664 + // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the 1.1665 + // full font name from the name table. For CFF OpenType fonts this is the 1.1666 + // same as the PostScript name, but for TrueType fonts it is usually 1.1667 + // different. 1.1668 + // 1.1669 + // On Mac, the font face name is compared with the PostScript name, even 1.1670 + // for TrueType fonts. 1.1671 + // 1.1672 + // Fontconfig only records the full font names, so the behavior here 1.1673 + // follows that on MS Windows. However, to provide the possibility 1.1674 + // of aliases to compensate for variations, the font face name is passed 1.1675 + // through FcConfigSubstitute. 1.1676 + 1.1677 + nsAutoRef<FcPattern> pattern(FcPatternCreate()); 1.1678 + if (!pattern) 1.1679 + return nullptr; 1.1680 + 1.1681 + NS_ConvertUTF16toUTF8 fullname(aFullname); 1.1682 + FcPatternAddString(pattern, FC_FULLNAME, 1.1683 + gfxFontconfigUtils::ToFcChar8(fullname)); 1.1684 + FcConfigSubstitute(nullptr, pattern, FcMatchPattern); 1.1685 + 1.1686 + FcChar8 *name; 1.1687 + for (int v = 0; 1.1688 + FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch; 1.1689 + ++v) { 1.1690 + const nsTArray< nsCountedRef<FcPattern> >& fonts = 1.1691 + utils->GetFontsForFullname(name); 1.1692 + 1.1693 + if (fonts.Length() != 0) 1.1694 + return new gfxLocalFcFontEntry(aProxyEntry, fonts); 1.1695 + } 1.1696 + 1.1697 + return nullptr; 1.1698 +} 1.1699 + 1.1700 +/* static */ FT_Library 1.1701 +gfxPangoFontGroup::GetFTLibrary() 1.1702 +{ 1.1703 + if (!gFTLibrary) { 1.1704 + // Use cairo's FT_Library so that cairo takes care of shutdown of the 1.1705 + // FT_Library after it has destroyed its font_faces, and FT_Done_Face 1.1706 + // has been called on each FT_Face, at least until this bug is fixed: 1.1707 + // https://bugs.freedesktop.org/show_bug.cgi?id=18857 1.1708 + // 1.1709 + // Cairo's FT_Library can be obtained from any cairo_scaled_font. The 1.1710 + // font properties requested here are chosen to get an FT_Face that is 1.1711 + // likely to be also used elsewhere. 1.1712 + gfxFontStyle style; 1.1713 + nsRefPtr<gfxPangoFontGroup> fontGroup = 1.1714 + new gfxPangoFontGroup(NS_LITERAL_STRING("sans-serif"), 1.1715 + &style, nullptr); 1.1716 + 1.1717 + gfxFcFont *font = fontGroup->GetBaseFont(); 1.1718 + if (!font) 1.1719 + return nullptr; 1.1720 + 1.1721 + gfxFT2LockedFace face(font); 1.1722 + if (!face.get()) 1.1723 + return nullptr; 1.1724 + 1.1725 + gFTLibrary = face.get()->glyph->library; 1.1726 + } 1.1727 + 1.1728 + return gFTLibrary; 1.1729 +} 1.1730 + 1.1731 +/* static */ gfxFontEntry * 1.1732 +gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry, 1.1733 + const uint8_t *aFontData, uint32_t aLength) 1.1734 +{ 1.1735 + // Ownership of aFontData is passed in here, and transferred to the 1.1736 + // new fontEntry, which will release it when no longer needed. 1.1737 + 1.1738 + // Using face_index = 0 for the first face in the font, as we have no 1.1739 + // other information. FT_New_Memory_Face checks for a nullptr FT_Library. 1.1740 + FT_Face face; 1.1741 + FT_Error error = 1.1742 + FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face); 1.1743 + if (error != 0) { 1.1744 + NS_Free((void*)aFontData); 1.1745 + return nullptr; 1.1746 + } 1.1747 + 1.1748 + return new gfxDownloadedFcFontEntry(aProxyEntry, aFontData, face); 1.1749 +} 1.1750 + 1.1751 + 1.1752 +static double 1.1753 +GetPixelSize(FcPattern *aPattern) 1.1754 +{ 1.1755 + double size; 1.1756 + if (FcPatternGetDouble(aPattern, 1.1757 + FC_PIXEL_SIZE, 0, &size) == FcResultMatch) 1.1758 + return size; 1.1759 + 1.1760 + NS_NOTREACHED("No size on pattern"); 1.1761 + return 0.0; 1.1762 +} 1.1763 + 1.1764 +/** 1.1765 + * The following gfxFcFonts are accessed from the cairo_scaled_font or created 1.1766 + * from the FcPattern, not from the gfxFontCache hash table. The gfxFontCache 1.1767 + * hash table is keyed by desired family and style, whereas here we only know 1.1768 + * actual family and style. There may be more than one of these fonts with 1.1769 + * the same family and style, but different PangoFont and actual font face. 1.1770 + * 1.1771 + * The point of this is to record the exact font face for gfxTextRun glyph 1.1772 + * indices. The style of this font does not necessarily represent the exact 1.1773 + * gfxFontStyle used to build the text run. Notably, the language is not 1.1774 + * recorded. 1.1775 + */ 1.1776 + 1.1777 +/* static */ 1.1778 +already_AddRefed<gfxFcFont> 1.1779 +gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, 1.1780 + const gfxFontStyle *aFontStyle) 1.1781 +{ 1.1782 + nsAutoRef<FcPattern> renderPattern 1.1783 + (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern)); 1.1784 + cairo_font_face_t *face = 1.1785 + cairo_ft_font_face_create_for_pattern(renderPattern); 1.1786 + 1.1787 + // Reuse an existing font entry if available. 1.1788 + nsRefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face); 1.1789 + if (!fe) { 1.1790 + gfxDownloadedFcFontEntry *downloadedFontEntry = 1.1791 + GetDownloadedFontEntry(aFontPattern); 1.1792 + if (downloadedFontEntry) { 1.1793 + // Web font 1.1794 + fe = downloadedFontEntry; 1.1795 + if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) { 1.1796 + // cairo_font_face_t is using the web font data. 1.1797 + // Hold a reference to the font entry to keep the font face 1.1798 + // data. 1.1799 + if (!downloadedFontEntry->SetCairoFace(face)) { 1.1800 + // OOM. Let cairo pick a fallback font 1.1801 + cairo_font_face_destroy(face); 1.1802 + face = cairo_ft_font_face_create_for_pattern(aRequestedPattern); 1.1803 + fe = gfxFcFontEntry::LookupFontEntry(face); 1.1804 + } 1.1805 + } 1.1806 + } 1.1807 + if (!fe) { 1.1808 + // Get a unique name for the font face from the file and id. 1.1809 + nsAutoString name; 1.1810 + FcChar8 *fc_file; 1.1811 + if (FcPatternGetString(renderPattern, 1.1812 + FC_FILE, 0, &fc_file) == FcResultMatch) { 1.1813 + int index; 1.1814 + if (FcPatternGetInteger(renderPattern, 1.1815 + FC_INDEX, 0, &index) != FcResultMatch) { 1.1816 + // cairo defaults to 0. 1.1817 + index = 0; 1.1818 + } 1.1819 + 1.1820 + AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name); 1.1821 + if (index != 0) { 1.1822 + name.AppendLiteral("/"); 1.1823 + name.AppendInt(index); 1.1824 + } 1.1825 + } 1.1826 + 1.1827 + fe = new gfxSystemFcFontEntry(face, aFontPattern, name); 1.1828 + } 1.1829 + } 1.1830 + 1.1831 + gfxFontStyle style(*aFontStyle); 1.1832 + style.size = GetPixelSize(renderPattern); 1.1833 + style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern); 1.1834 + style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern); 1.1835 + 1.1836 + nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(fe, &style); 1.1837 + if (!font) { 1.1838 + // Note that a file/index pair (or FT_Face) and the gfxFontStyle are 1.1839 + // not necessarily enough to provide a key that will describe a unique 1.1840 + // font. cairoFont contains information from renderPattern, which is a 1.1841 + // fully resolved pattern from FcFontRenderPrepare. 1.1842 + // FcFontRenderPrepare takes the requested pattern and the face 1.1843 + // pattern as input and can modify elements of the resulting pattern 1.1844 + // that affect rendering but are not included in the gfxFontStyle. 1.1845 + cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face); 1.1846 + font = new gfxFcFont(cairoFont, fe, &style); 1.1847 + gfxFontCache::GetCache()->AddNew(font); 1.1848 + cairo_scaled_font_destroy(cairoFont); 1.1849 + } 1.1850 + 1.1851 + cairo_font_face_destroy(face); 1.1852 + 1.1853 + nsRefPtr<gfxFcFont> retval(static_cast<gfxFcFont*>(font.get())); 1.1854 + return retval.forget(); 1.1855 +} 1.1856 + 1.1857 +gfxFcFontSet * 1.1858 +gfxPangoFontGroup::GetBaseFontSet() 1.1859 +{ 1.1860 + if (mFontSets.Length() > 0) 1.1861 + return mFontSets[0].mFontSet; 1.1862 + 1.1863 + mSizeAdjustFactor = 1.0; // will be adjusted below if necessary 1.1864 + nsAutoRef<FcPattern> pattern; 1.1865 + nsRefPtr<gfxFcFontSet> fontSet = 1.1866 + MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern); 1.1867 + 1.1868 + double size = GetPixelSize(pattern); 1.1869 + if (size != 0.0 && mStyle.sizeAdjust != 0.0) { 1.1870 + gfxFcFont *font = fontSet->GetFontAt(0, GetStyle()); 1.1871 + if (font) { 1.1872 + const gfxFont::Metrics& metrics = font->GetMetrics(); 1.1873 + 1.1874 + // The factor of 0.1 ensures that xHeight is sane so fonts don't 1.1875 + // become huge. Strictly ">" ensures that xHeight and emHeight are 1.1876 + // not both zero. 1.1877 + if (metrics.xHeight > 0.1 * metrics.emHeight) { 1.1878 + mSizeAdjustFactor = 1.1879 + mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight; 1.1880 + 1.1881 + size *= mSizeAdjustFactor; 1.1882 + FcPatternDel(pattern, FC_PIXEL_SIZE); 1.1883 + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size); 1.1884 + 1.1885 + fontSet = new gfxFcFontSet(pattern, mUserFontSet); 1.1886 + } 1.1887 + } 1.1888 + } 1.1889 + 1.1890 + PangoLanguage *pangoLang = mPangoLanguage; 1.1891 + FcChar8 *fcLang; 1.1892 + if (!pangoLang && 1.1893 + FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) { 1.1894 + pangoLang = 1.1895 + pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang)); 1.1896 + } 1.1897 + 1.1898 + mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet)); 1.1899 + 1.1900 + return fontSet; 1.1901 +} 1.1902 + 1.1903 +/** 1.1904 + ** gfxTextRun 1.1905 + * 1.1906 + * A serious problem: 1.1907 + * 1.1908 + * -- We draw with a font that's hinted for the CTM, but we measure with a font 1.1909 + * hinted to the identity matrix, so our "bounding metrics" may not be accurate. 1.1910 + * 1.1911 + **/ 1.1912 + 1.1913 +// This will fetch an existing scaled_font if one exists. 1.1914 +static cairo_scaled_font_t * 1.1915 +CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace) 1.1916 +{ 1.1917 + double size = GetPixelSize(aPattern); 1.1918 + 1.1919 + cairo_matrix_t fontMatrix; 1.1920 + FcMatrix *fcMatrix; 1.1921 + if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch) 1.1922 + cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0); 1.1923 + else 1.1924 + cairo_matrix_init_identity(&fontMatrix); 1.1925 + cairo_matrix_scale(&fontMatrix, size, size); 1.1926 + 1.1927 + FcBool printing; 1.1928 + if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) { 1.1929 + printing = FcFalse; 1.1930 + } 1.1931 + 1.1932 + // The cairo_scaled_font is created with a unit ctm so that metrics and 1.1933 + // positions are in user space, but this means that hinting effects will 1.1934 + // not be estimated accurately for non-unit transformations. 1.1935 + cairo_matrix_t identityMatrix; 1.1936 + cairo_matrix_init_identity(&identityMatrix); 1.1937 + 1.1938 + // Font options are set explicitly here to improve cairo's caching 1.1939 + // behavior and to record the relevant parts of the pattern for 1.1940 + // SetupCairoFont (so that the pattern can be released). 1.1941 + // 1.1942 + // Most font_options have already been set as defaults on the FcPattern 1.1943 + // with cairo_ft_font_options_substitute(), then user and system 1.1944 + // fontconfig configurations were applied. The resulting font_options 1.1945 + // have been recorded on the face during 1.1946 + // cairo_ft_font_face_create_for_pattern(). 1.1947 + // 1.1948 + // None of the settings here cause this scaled_font to behave any 1.1949 + // differently from how it would behave if it were created from the same 1.1950 + // face with default font_options. 1.1951 + // 1.1952 + // We set options explicitly so that the same scaled_font will be found in 1.1953 + // the cairo_scaled_font_map when cairo loads glyphs from a context with 1.1954 + // the same font_face, font_matrix, ctm, and surface font_options. 1.1955 + // 1.1956 + // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the 1.1957 + // font_options on the cairo_ft_font_face, and doesn't consider default 1.1958 + // option values to not match any explicit values. 1.1959 + // 1.1960 + // Even after cairo_set_scaled_font is used to set font_options for the 1.1961 + // cairo context, when cairo looks for a scaled_font for the context, it 1.1962 + // will look for a font with some option values from the target surface if 1.1963 + // any values are left default on the context font_options. If this 1.1964 + // scaled_font is created with default font_options, cairo will not find 1.1965 + // it. 1.1966 + cairo_font_options_t *fontOptions = cairo_font_options_create(); 1.1967 + 1.1968 + // The one option not recorded in the pattern is hint_metrics, which will 1.1969 + // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON. 1.1970 + // We should be considering the font_options of the surface on which this 1.1971 + // font will be used, but currently we don't have different gfxFonts for 1.1972 + // different surface font_options, so we'll create a font suitable for the 1.1973 + // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON. 1.1974 +#ifdef MOZ_GFX_OPTIMIZE_MOBILE 1.1975 + cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF); 1.1976 +#else 1.1977 + if (printing) { 1.1978 + cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF); 1.1979 + } else { 1.1980 + cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON); 1.1981 + } 1.1982 +#endif 1.1983 + 1.1984 + // The remaining options have been recorded on the pattern and the face. 1.1985 + // _cairo_ft_options_merge has some logic to decide which options from the 1.1986 + // scaled_font or from the cairo_ft_font_face take priority in the way the 1.1987 + // font behaves. 1.1988 + // 1.1989 + // In the majority of cases, _cairo_ft_options_merge uses the options from 1.1990 + // the cairo_ft_font_face, so sometimes it is not so important which 1.1991 + // values are set here so long as they are not defaults, but we'll set 1.1992 + // them to the exact values that we expect from the font, to be consistent 1.1993 + // and to protect against changes in cairo. 1.1994 + // 1.1995 + // In some cases, _cairo_ft_options_merge uses some options from the 1.1996 + // scaled_font's font_options rather than options on the 1.1997 + // cairo_ft_font_face (from fontconfig). 1.1998 + // https://bugs.freedesktop.org/show_bug.cgi?id=11838 1.1999 + // 1.2000 + // Surface font options were set on the pattern in 1.2001 + // cairo_ft_font_options_substitute. If fontconfig has changed the 1.2002 + // hint_style then that is what the user (or distribution) wants, so we 1.2003 + // use the setting from the FcPattern. 1.2004 + // 1.2005 + // Fallback values here mirror treatment of defaults in cairo-ft-font.c. 1.2006 + FcBool hinting = FcFalse; 1.2007 +#ifndef MOZ_GFX_OPTIMIZE_MOBILE 1.2008 + if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) { 1.2009 + hinting = FcTrue; 1.2010 + } 1.2011 +#endif 1.2012 + cairo_hint_style_t hint_style; 1.2013 + if (printing || !hinting) { 1.2014 + hint_style = CAIRO_HINT_STYLE_NONE; 1.2015 + } else { 1.2016 +#ifdef FC_HINT_STYLE // FC_HINT_STYLE is available from fontconfig 2.2.91. 1.2017 + int fc_hintstyle; 1.2018 + if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 1.2019 + 0, &fc_hintstyle ) != FcResultMatch) { 1.2020 + fc_hintstyle = FC_HINT_FULL; 1.2021 + } 1.2022 + switch (fc_hintstyle) { 1.2023 + case FC_HINT_NONE: 1.2024 + hint_style = CAIRO_HINT_STYLE_NONE; 1.2025 + break; 1.2026 + case FC_HINT_SLIGHT: 1.2027 + hint_style = CAIRO_HINT_STYLE_SLIGHT; 1.2028 + break; 1.2029 + case FC_HINT_MEDIUM: 1.2030 + default: // This fallback mirrors _get_pattern_ft_options in cairo. 1.2031 + hint_style = CAIRO_HINT_STYLE_MEDIUM; 1.2032 + break; 1.2033 + case FC_HINT_FULL: 1.2034 + hint_style = CAIRO_HINT_STYLE_FULL; 1.2035 + break; 1.2036 + } 1.2037 +#else // no FC_HINT_STYLE 1.2038 + hint_style = CAIRO_HINT_STYLE_FULL; 1.2039 +#endif 1.2040 + } 1.2041 + cairo_font_options_set_hint_style(fontOptions, hint_style); 1.2042 + 1.2043 + int rgba; 1.2044 + if (FcPatternGetInteger(aPattern, 1.2045 + FC_RGBA, 0, &rgba) != FcResultMatch) { 1.2046 + rgba = FC_RGBA_UNKNOWN; 1.2047 + } 1.2048 + cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; 1.2049 + switch (rgba) { 1.2050 + case FC_RGBA_UNKNOWN: 1.2051 + case FC_RGBA_NONE: 1.2052 + default: 1.2053 + // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing 1.2054 + // is disabled through cairo_antialias_t. 1.2055 + rgba = FC_RGBA_NONE; 1.2056 + // subpixel_order won't be used by the font as we won't use 1.2057 + // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for 1.2058 + // caching reasons described above. Fall through: 1.2059 + case FC_RGBA_RGB: 1.2060 + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; 1.2061 + break; 1.2062 + case FC_RGBA_BGR: 1.2063 + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; 1.2064 + break; 1.2065 + case FC_RGBA_VRGB: 1.2066 + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; 1.2067 + break; 1.2068 + case FC_RGBA_VBGR: 1.2069 + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; 1.2070 + break; 1.2071 + } 1.2072 + cairo_font_options_set_subpixel_order(fontOptions, subpixel_order); 1.2073 + 1.2074 + FcBool fc_antialias; 1.2075 + if (FcPatternGetBool(aPattern, 1.2076 + FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) { 1.2077 + fc_antialias = FcTrue; 1.2078 + } 1.2079 + cairo_antialias_t antialias; 1.2080 + if (!fc_antialias) { 1.2081 + antialias = CAIRO_ANTIALIAS_NONE; 1.2082 + } else if (rgba == FC_RGBA_NONE) { 1.2083 + antialias = CAIRO_ANTIALIAS_GRAY; 1.2084 + } else { 1.2085 + antialias = CAIRO_ANTIALIAS_SUBPIXEL; 1.2086 + } 1.2087 + cairo_font_options_set_antialias(fontOptions, antialias); 1.2088 + 1.2089 + cairo_scaled_font_t *scaledFont = 1.2090 + cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix, 1.2091 + fontOptions); 1.2092 + 1.2093 + cairo_font_options_destroy(fontOptions); 1.2094 + 1.2095 + NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS, 1.2096 + "Failed to create scaled font"); 1.2097 + return scaledFont; 1.2098 +} 1.2099 + 1.2100 +/* static */ 1.2101 +PangoLanguage * 1.2102 +GuessPangoLanguage(nsIAtom *aLanguage) 1.2103 +{ 1.2104 + if (!aLanguage) 1.2105 + return nullptr; 1.2106 + 1.2107 + // Pango and fontconfig won't understand mozilla's internal langGroups, so 1.2108 + // find a real language. 1.2109 + nsAutoCString lang; 1.2110 + gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang); 1.2111 + if (lang.IsEmpty()) 1.2112 + return nullptr; 1.2113 + 1.2114 + return pango_language_from_string(lang.get()); 1.2115 +} 1.2116 + 1.2117 +#ifdef MOZ_WIDGET_GTK 1.2118 +/*************************************************************************** 1.2119 + * 1.2120 + * This function must be last in the file because it uses the system cairo 1.2121 + * library. Above this point the cairo library used is the tree cairo if 1.2122 + * MOZ_TREE_CAIRO. 1.2123 + */ 1.2124 + 1.2125 +#if MOZ_TREE_CAIRO 1.2126 +// Tree cairo symbols have different names. Disable their activation through 1.2127 +// preprocessor macros. 1.2128 +#undef cairo_ft_font_options_substitute 1.2129 + 1.2130 +// The system cairo functions are not declared because the include paths cause 1.2131 +// the gdk headers to pick up the tree cairo.h. 1.2132 +extern "C" { 1.2133 +NS_VISIBILITY_DEFAULT void 1.2134 +cairo_ft_font_options_substitute (const cairo_font_options_t *options, 1.2135 + FcPattern *pattern); 1.2136 +} 1.2137 +#endif 1.2138 + 1.2139 +static void 1.2140 +ApplyGdkScreenFontOptions(FcPattern *aPattern) 1.2141 +{ 1.2142 + const cairo_font_options_t *options = 1.2143 + gdk_screen_get_font_options(gdk_screen_get_default()); 1.2144 + 1.2145 + cairo_ft_font_options_substitute(options, aPattern); 1.2146 +} 1.2147 + 1.2148 +#endif // MOZ_WIDGET_GTK2 1.2149 + 1.2150 +#ifdef USE_SKIA 1.2151 +mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> 1.2152 +gfxFcFont::GetGlyphRenderingOptions() 1.2153 +{ 1.2154 + cairo_scaled_font_t *scaled_font = CairoScaledFont(); 1.2155 + cairo_font_options_t *options = cairo_font_options_create(); 1.2156 + cairo_scaled_font_get_font_options(scaled_font, options); 1.2157 + cairo_hint_style_t hint_style = cairo_font_options_get_hint_style(options); 1.2158 + cairo_font_options_destroy(options); 1.2159 + 1.2160 + mozilla::gfx::FontHinting hinting; 1.2161 + 1.2162 + switch (hint_style) { 1.2163 + case CAIRO_HINT_STYLE_NONE: 1.2164 + hinting = mozilla::gfx::FontHinting::NONE; 1.2165 + break; 1.2166 + case CAIRO_HINT_STYLE_SLIGHT: 1.2167 + hinting = mozilla::gfx::FontHinting::LIGHT; 1.2168 + break; 1.2169 + case CAIRO_HINT_STYLE_FULL: 1.2170 + hinting = mozilla::gfx::FontHinting::FULL; 1.2171 + break; 1.2172 + default: 1.2173 + hinting = mozilla::gfx::FontHinting::NORMAL; 1.2174 + break; 1.2175 + } 1.2176 + 1.2177 + // We don't want to force the use of the autohinter over the font's built in hints 1.2178 + return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false); 1.2179 +} 1.2180 +#endif 1.2181 +