diff options
author | Job Bautista <jobbautista9@protonmail.com> | 2023-04-04 21:48:39 +0800 |
---|---|---|
committer | Job Bautista <jobbautista9@protonmail.com> | 2023-04-05 21:22:17 +0800 |
commit | 57ef40f7833c28fc4d6ad6b2903ca9f2f112b7a2 (patch) | |
tree | be0981dde97b73c5a6d93e2ddf2bf7b72ce1e641 /gfx | |
parent | 3122de954751fe8df9a5fb786e5f8089ce778d9b (diff) | |
download | uxp-57ef40f7833c28fc4d6ad6b2903ca9f2f112b7a2.tar.gz |
Issue #2191 - Remove as much old fontconfig support as needed for Harfbuzz 7.1.0 update.
Based on Mozilla bugs 1119128, 1285533, and 1421964.
gfx.font_rendering.fontconfig.fontlist.enabled is no longer available.
gfxFontconfigUtils.h still exists, and will be removed in another commit. Just
need more research on bug 1385029.
Tag #1862
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/thebes/gfxFontconfigFonts.cpp | 2255 | ||||
-rw-r--r-- | gfx/thebes/gfxFontconfigFonts.h | 124 | ||||
-rw-r--r-- | gfx/thebes/gfxFontconfigUtils.cpp | 1100 | ||||
-rw-r--r-- | gfx/thebes/gfxFontconfigUtils.h | 281 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatform.cpp | 17 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformGtk.cpp | 90 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformGtk.h | 6 | ||||
-rw-r--r-- | gfx/thebes/gfxTextRun.cpp | 17 | ||||
-rw-r--r-- | gfx/thebes/gfxTextRun.h | 3 | ||||
-rw-r--r-- | gfx/thebes/gfxUserFontSet.cpp | 26 | ||||
-rw-r--r-- | gfx/thebes/gfxUserFontSet.h | 8 | ||||
-rw-r--r-- | gfx/thebes/moz.build | 3 |
12 files changed, 28 insertions, 3902 deletions
diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp deleted file mode 100644 index 9caecc4c07..0000000000 --- a/gfx/thebes/gfxFontconfigFonts.cpp +++ /dev/null @@ -1,2255 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prlink.h" -#include "gfxTypes.h" - -#include "nsTArray.h" - -#include "gfxContext.h" -#ifdef MOZ_WIDGET_GTK -#include "gfxPlatformGtk.h" -#endif -#include "gfxFontconfigFonts.h" -#include "gfxFT2FontBase.h" -#include "gfxFT2Utils.h" -#include "harfbuzz/hb.h" -#include "harfbuzz/hb-glib.h" -#include "harfbuzz/hb-ot.h" -#include "nsUnicodeProperties.h" -#include "nsUnicodeScriptCodes.h" -#include "gfxFontconfigUtils.h" -#include "gfxUserFontSet.h" -#include "gfxFontConstants.h" -#include "nsGkAtoms.h" -#include "nsILanguageAtomService.h" -#include "nsServiceManagerUtils.h" - -#include <cairo.h> -#include <cairo-ft.h> -#include "mozilla/gfx/HelpersCairo.h" - -#include <fontconfig/fcfreetype.h> -#include <pango/pango.h> - -#include FT_TRUETYPE_TABLES_H - -#ifdef MOZ_WIDGET_GTK -#include <gdk/gdk.h> -#endif - -#include <math.h> - -using namespace mozilla; -using namespace mozilla::unicode; - -#define PRINTING_FC_PROPERTY "gfx.printing" - -static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage); - -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace); - -static FT_Library gFTLibrary; - -// FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97 -// and so fontconfig-2.3.0 (2005). -#ifndef FC_FAMILYLANG -#define FC_FAMILYLANG "familylang" -#endif -#ifndef FC_FULLNAME -#define FC_FULLNAME "fullname" -#endif - -static PRFuncPtr -FindFunctionSymbol(const char *name) -{ - PRLibrary *lib = nullptr; - PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib); - if (lib) { - PR_UnloadLibrary(lib); - } - - return result; -} - -static bool HasChar(FcPattern *aFont, FcChar32 wc) -{ - FcCharSet *charset = nullptr; - FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset); - - return charset && FcCharSetHasChar(charset, wc); -} - -/** - * gfxFcFontEntry: - * - * An abstract base class of for gfxFontEntry implementations used by - * gfxFcFont and gfxUserFontSet. - */ - -class gfxFcFontEntry : public gfxFontEntry { -public: - // For all FontEntrys attached to gfxFcFonts, there will be only one - // pattern in this array. This is always a font pattern, not a fully - // resolved pattern. gfxFcFont only uses this to construct a PangoFont. - // - // FontEntrys for src:local() fonts in gfxUserFontSet may return more than - // one pattern. (See comment in gfxUserFcFontEntry.) - const nsTArray< nsCountedRef<FcPattern> >& GetPatterns() - { - return mPatterns; - } - - static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace) - { - return static_cast<gfxFcFontEntry*> - (cairo_font_face_get_user_data(aFace, &sFontEntryKey)); - } - - // override the gfxFontEntry impl to read the name from fontconfig - // instead of trying to get the 'name' table, as we don't implement - // GetFontTable() here - virtual nsString RealFaceName(); - - // This is needed to make gfxFontEntry::HasCharacter(aCh) work. - virtual bool TestCharacterMap(uint32_t aCh) - { - for (uint32_t i = 0; i < mPatterns.Length(); ++i) { - if (HasChar(mPatterns[i], aCh)) { - return true; - } - } - return false; - } - -protected: - explicit gfxFcFontEntry(const nsAString& aName) - : gfxFontEntry(aName) - { - } - - // One pattern is the common case and some subclasses rely on successful - // addition of the first element to the array. - AutoTArray<nsCountedRef<FcPattern>,1> mPatterns; - - static cairo_user_data_key_t sFontEntryKey; -}; - -cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey; - -nsString -gfxFcFontEntry::RealFaceName() -{ - FcChar8 *name; - if (!mPatterns.IsEmpty()) { - if (FcPatternGetString(mPatterns[0], - FC_FULLNAME, 0, &name) == FcResultMatch) { - return NS_ConvertUTF8toUTF16((const char*)name); - } - if (FcPatternGetString(mPatterns[0], - FC_FAMILY, 0, &name) == FcResultMatch) { - NS_ConvertUTF8toUTF16 result((const char*)name); - if (FcPatternGetString(mPatterns[0], - FC_STYLE, 0, &name) == FcResultMatch) { - result.Append(' '); - AppendUTF8toUTF16((const char*)name, result); - } - return result; - } - } - // fall back to gfxFontEntry implementation (only works for sfnt fonts) - return gfxFontEntry::RealFaceName(); -} - -/** - * gfxSystemFcFontEntry: - * - * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts, - * including those from regular family-name based font selection as well as - * those from src:local(). - * - * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. - */ - -class gfxSystemFcFontEntry : public gfxFcFontEntry { -public: - // For memory efficiency, aFontPattern should be a font pattern, - // not a fully resolved pattern. - gfxSystemFcFontEntry(cairo_font_face_t *aFontFace, - FcPattern *aFontPattern, - const nsAString& aName) - : gfxFcFontEntry(aName), mFontFace(aFontFace), - mFTFace(nullptr), mFTFaceInitialized(false) - { - cairo_font_face_reference(mFontFace); - cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr); - - // mPatterns is an AutoTArray with 1 space always available, so the - // AppendElement always succeeds. - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0] = aFontPattern; - - FcChar8 *name; - if (FcPatternGetString(aFontPattern, - FC_FAMILY, 0, &name) == FcResultMatch) { - mFamilyName = NS_ConvertUTF8toUTF16((const char*)name); - } - } - - ~gfxSystemFcFontEntry() - { - cairo_font_face_set_user_data(mFontFace, - &sFontEntryKey, - nullptr, - nullptr); - cairo_font_face_destroy(mFontFace); - } - - virtual void ForgetHBFace() override; - virtual void ReleaseGrFace(gr_face* aFace) override; - -protected: - virtual nsresult - CopyFontTable(uint32_t aTableTag, nsTArray<uint8_t>& aBuffer) override; - - void MaybeReleaseFTFace(); - -private: - cairo_font_face_t *mFontFace; - FT_Face mFTFace; - bool mFTFaceInitialized; -}; - -nsresult -gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag, - nsTArray<uint8_t>& aBuffer) -{ - if (!mFTFaceInitialized) { - mFTFaceInitialized = true; - FcChar8 *filename; - if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) { - return NS_ERROR_FAILURE; - } - int index; - if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) { - index = 0; // default to 0 if not found in pattern - } - if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(), - (const char*)filename, index, &mFTFace) != 0) { - return NS_ERROR_FAILURE; - } - } - - if (!mFTFace) { - return NS_ERROR_NOT_AVAILABLE; - } - - FT_ULong length = 0; - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) { - return NS_ERROR_NOT_AVAILABLE; - } - if (!aBuffer.SetLength(length, fallible)) { - return NS_ERROR_OUT_OF_MEMORY; - } - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) { - aBuffer.Clear(); - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -void -gfxSystemFcFontEntry::MaybeReleaseFTFace() -{ - // don't release if either HB or Gr face still exists - if (mHBFace || mGrFace) { - return; - } - if (mFTFace) { - FT_Done_Face(mFTFace); - mFTFace = nullptr; - } - mFTFaceInitialized = false; -} - -void -gfxSystemFcFontEntry::ForgetHBFace() -{ - gfxFontEntry::ForgetHBFace(); - MaybeReleaseFTFace(); -} - -void -gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace) -{ - gfxFontEntry::ReleaseGrFace(aFace); - MaybeReleaseFTFace(); -} - -// A namespace for @font-face family names in FcPatterns so that fontconfig -// aliases do not pick up families from @font-face rules and so that -// fontconfig rules can distinguish between web fonts and platform fonts. -// http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html -#define FONT_FACE_FAMILY_PREFIX "@font-face:" - -/** - * gfxUserFcFontEntry: - * - * An abstract class for objects in a gfxUserFontSet that can provide - * FcPattern* handles to fonts. - * - * Separate implementations of this class support local fonts from src:local() - * and web fonts from src:url(). - */ - -// There is a one-to-one correspondence between gfxUserFcFontEntry objects and -// @font-face rules, but sometimes a one-to-many correspondence between font -// entries and font patterns. -// -// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions -// provided a font-size descriptor to specify the sizes supported by the face, -// but the "Editor's Draft 27 June 2008" -// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a -// descriptor, and Mozilla does not recognize such a descriptor. -// -// Font face names used in src:local() also do not usually specify a size. -// -// PCF format fonts have each size in a different file, and each of these -// files is referenced by its own pattern, but really these are each -// different sizes of one face with one name. -// -// Multiple patterns in an entry also effectively deals with a set of -// PostScript Type 1 font files that all have the same face name but are in -// several files because of the limit on the number of glyphs in a Type 1 font -// file. (e.g. Computer Modern.) - -class gfxUserFcFontEntry : public gfxFcFontEntry { -protected: - explicit gfxUserFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) - : gfxFcFontEntry(aFontName) - { - mStyle = aStyle; - mWeight = aWeight; - mStretch = aStretch; - } - - // Helper function to change a pattern so that it matches the CSS style - // descriptors and so gets properly sorted in font selection. This also - // avoids synthetic style effects being added by the renderer when the - // style of the font itself does not match the descriptor provided by the - // author. - void AdjustPatternToCSS(FcPattern *aPattern); -}; - -void -gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) -{ - int fontWeight = -1; - FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight); - int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100); - if (cssWeight != fontWeight) { - FcPatternDel(aPattern, FC_WEIGHT); - FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight); - } - - int fontSlant; - FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant); - // gfxFontEntry doesn't understand the difference between oblique - // and italic. - if (res != FcResultMatch || - IsItalic() != (fontSlant != FC_SLANT_ROMAN)) { - FcPatternDel(aPattern, FC_SLANT); - FcPatternAddInteger(aPattern, FC_SLANT, - IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); - } - - int fontWidth = -1; - FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth); - int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch); - if (cssWidth != fontWidth) { - FcPatternDel(aPattern, FC_WIDTH); - FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth); - } - - // Ensure that there is a fullname property (if there is a family - // property) so that fontconfig rules can identify the real name of the - // font, because the family property will be replaced. - FcChar8 *unused; - if (FcPatternGetString(aPattern, - FC_FULLNAME, 0, &unused) == FcResultNoMatch) { - nsAutoCString fullname; - if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern, - &fullname)) { - FcPatternAddString(aPattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - } - } - - nsAutoCString family; - family.Append(FONT_FACE_FAMILY_PREFIX); - AppendUTF16toUTF8(Name(), family); - - FcPatternDel(aPattern, FC_FAMILY); - FcPatternDel(aPattern, FC_FAMILYLANG); - FcPatternAddString(aPattern, FC_FAMILY, - gfxFontconfigUtils::ToFcChar8(family)); -} - -/** - * gfxLocalFcFontEntry: - * - * An implementation of gfxUserFcFontEntry for local fonts from src:local(). - * - * This class is used only in gfxUserFontSet and for providing FcPattern* - * handles to system fonts for font selection. gfxFcFonts created from these - * patterns will use gfxSystemFcFontEntrys, which may be shared with - * gfxFcFonts from regular family-name based font selection. - */ - -class gfxLocalFcFontEntry : public gfxUserFcFontEntry { -public: - gfxLocalFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const nsTArray< nsCountedRef<FcPattern> >& aPatterns) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle) - { - if (!mPatterns.SetCapacity(aPatterns.Length(), fallible)) - return; // OOM - - for (uint32_t i = 0; i < aPatterns.Length(); ++i) { - FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i)); - if (!pattern) - return; // OOM - - AdjustPatternToCSS(pattern); - - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[i].own(pattern); - } - mIsLocalUserFont = true; - } -}; - -/** - * gfxDownloadedFcFontEntry: - * - * An implementation of gfxFcFontEntry for web fonts from src:url(). - * - * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t - * keeps a reference to the FontEntry to keep the font data alive. - */ - -class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry { -public: - // This takes ownership of the face and its underlying data - gfxDownloadedFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t *aData, FT_Face aFace) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle), - mFontData(aData), mFace(aFace) - { - NS_PRECONDITION(aFace != nullptr, "aFace is NULL!"); - mIsDataUserFont = true; - InitPattern(); - } - - virtual ~gfxDownloadedFcFontEntry(); - - // Returns true on success - bool SetCairoFace(cairo_font_face_t *aFace); - - virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override; - -protected: - void InitPattern(); - - // mFontData holds the data used to instantiate the FT_Face; - // this has to persist until we are finished with the face, - // then be released with free(). - const uint8_t* mFontData; - - FT_Face mFace; -}; - -// A property for recording gfxDownloadedFcFontEntrys on FcPatterns. -static const char *kFontEntryFcProp = "-moz-font-entry"; - -static FcBool AddDownloadedFontEntry(FcPattern *aPattern, - gfxDownloadedFcFontEntry *aFontEntry) -{ - FcValue value; - value.type = FcTypeFTFace; // void* field of union - value.u.f = aFontEntry; - - return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse); -} - -static FcBool DelDownloadedFontEntry(FcPattern *aPattern) -{ - return FcPatternDel(aPattern, kFontEntryFcProp); -} - -static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern) -{ - FcValue value; - if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch) - return nullptr; - - if (value.type != FcTypeFTFace) { - NS_NOTREACHED("Wrong type for -moz-font-entry font property"); - return nullptr; - } - - return static_cast<gfxDownloadedFcFontEntry*>(value.u.f); -} - -gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry() -{ - if (mPatterns.Length() != 0) { - // Remove back reference to this font entry and the face in case - // anyone holds a reference to the pattern. - NS_ASSERTION(mPatterns.Length() == 1, - "More than one pattern in gfxDownloadedFcFontEntry!"); - DelDownloadedFontEntry(mPatterns[0]); - FcPatternDel(mPatterns[0], FC_FT_FACE); - } - FT_Done_Face(mFace); - free((void*)mFontData); -} - -typedef FcPattern* (*QueryFaceFunction)(const FT_Face face, - const FcChar8 *file, int id, - FcBlanks *blanks); - -void -gfxDownloadedFcFontEntry::InitPattern() -{ - static QueryFaceFunction sQueryFacePtr = - reinterpret_cast<QueryFaceFunction> - (FindFunctionSymbol("FcFreeTypeQueryFace")); - FcPattern *pattern; - - // FcFreeTypeQueryFace is the same function used to construct patterns for - // system fonts and so is the preferred function to use for this purpose. - // This will set up the langset property, which helps with sorting, and - // the foundry, fullname, and fontversion properties, which properly - // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is - // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has - // fontconfig-2.4.1.) - if (sQueryFacePtr) { - // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at - // least). The dummy file passed here is removed below. - // - // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr) - // is passed as the "blanks" argument, which provides that unexpectedly - // blank glyphs are elided. Here, however, we pass nullptr for - // "blanks", effectively assuming that, if the font has a blank glyph, - // then the author intends any associated character to be rendered - // blank. - pattern = - (*sQueryFacePtr)(mFace, - gfxFontconfigUtils::ToFcChar8(""), - 0, - nullptr); - if (!pattern) - // Either OOM, or fontconfig chose to skip this font because it - // has "no encoded characters", which I think means "BDF and PCF - // fonts which are not in Unicode (or the effectively equivalent - // ISO Latin-1) encoding". - return; - - // These properties don't make sense for this face without a file. - FcPatternDel(pattern, FC_FILE); - FcPatternDel(pattern, FC_INDEX); - - } else { - // Do the minimum necessary to construct a pattern for sorting. - - // FC_CHARSET is vital to determine which characters are supported. - nsAutoRef<FcCharSet> charset(FcFreeTypeCharSet(mFace, nullptr)); - // If there are no characters then assume we don't know how to read - // this font. - if (!charset || FcCharSetCount(charset) == 0) - return; - - pattern = FcPatternCreate(); - FcPatternAddCharSet(pattern, FC_CHARSET, charset); - - // FC_PIXEL_SIZE can be important for font selection of fixed-size - // fonts. - if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) { - for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) { -#if HAVE_FT_BITMAP_SIZE_Y_PPEM - double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem); -#else - double size = mFace->available_sizes[i].height; -#endif - FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size); - } - - // Not sure whether this is important; - // imitating FcFreeTypeQueryFace: - FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse); - } - - // Setting up the FC_LANGSET property is very difficult with the APIs - // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET - // property seems better than having a property with an empty LangSet. - // With no FC_LANGSET property, fontconfig sort functions will - // consider this face to have the same priority as (otherwise equal) - // faces that have support for the primary requested language, but - // will not consider any language to have been satisfied (and so will - // continue to look for a face with language support in fallback - // fonts). - } - - AdjustPatternToCSS(pattern); - - FcPatternAddFTFace(pattern, FC_FT_FACE, mFace); - AddDownloadedFontEntry(pattern, this); - - // There is never more than one pattern - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0].own(pattern); -} - -static void ReleaseDownloadedFontEntry(void *data) -{ - gfxDownloadedFcFontEntry *downloadedFontEntry = - static_cast<gfxDownloadedFcFontEntry*>(data); - NS_RELEASE(downloadedFontEntry); -} - -bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace) -{ - if (CAIRO_STATUS_SUCCESS != - cairo_font_face_set_user_data(aFace, &sFontEntryKey, this, - ReleaseDownloadedFontEntry)) - return false; - - // Hold a reference to this font entry to keep the font face data. - NS_ADDREF(this); - return true; -} - -hb_blob_t * -gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag) -{ - // The entry already owns the (sanitized) sfnt data in mFontData, - // so we can just return a blob that "wraps" the appropriate chunk of it. - // The blob should not attempt to free its data, as the entire sfnt data - // will be freed when the font entry is deleted. - return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag); -} - -/* - * gfxFcFont - * - * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT - * cairo_scaled_font created from an FcPattern. - */ - -class gfxFcFont : public gfxFontconfigFontBase { -public: - virtual ~gfxFcFont(); - static already_AddRefed<gfxFcFont> - GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle); - - // return a cloned font resized and offset to simulate sub/superscript glyphs - virtual already_AddRefed<gfxFont> - GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) override; - -protected: - virtual already_AddRefed<gfxFont> MakeScaledFont(gfxFontStyle *aFontStyle, - gfxFloat aFontScale); - virtual already_AddRefed<gfxFont> GetSmallCapsFont() override; - -private: - gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); - - // key for locating a gfxFcFont corresponding to a cairo_scaled_font - static cairo_user_data_key_t sGfxFontKey; -}; - -/** - * gfxFcFontSet: - * - * Translation from a desired FcPattern to a sorted set of font references - * (fontconfig cache data) and (when needed) fonts. - */ - -class gfxFcFontSet final { -public: - NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet) - - explicit gfxFcFontSet(FcPattern *aPattern, - gfxUserFontSet *aUserFontSet) - : mSortPattern(aPattern), mUserFontSet(aUserFontSet), - mFcFontsTrimmed(0), - mHaveFallbackFonts(false) - { - bool waitForUserFont; - mFcFontSet = SortPreferredFonts(waitForUserFont); - mWaitingForUserFont = waitForUserFont; - } - - // A reference is held by the FontSet. - // The caller may add a ref to keep the font alive longer than the FontSet. - gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle) - { - if (i >= mFonts.Length() || !mFonts[i].mFont) { - // GetFontPatternAt sets up mFonts - FcPattern *fontPattern = GetFontPatternAt(i); - if (!fontPattern) - return nullptr; - - mFonts[i].mFont = - gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern, - aFontStyle); - } - return mFonts[i].mFont; - } - - FcPattern *GetFontPatternAt(uint32_t i); - - bool WaitingForUserFont() const { - return mWaitingForUserFont; - } - -private: - // Private destructor, to discourage deletion outside of Release(): - ~gfxFcFontSet() - { - } - - nsReturnRef<FcFontSet> SortPreferredFonts(bool& aWaitForUserFont); - nsReturnRef<FcFontSet> SortFallbackFonts(); - - struct FontEntry { - explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {} - nsCountedRef<FcPattern> mPattern; - RefPtr<gfxFcFont> mFont; - }; - - struct LangSupportEntry { - LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) : - mLang(aLang), mBestSupport(aSupport) {} - FcChar8 *mLang; - FcLangResult mBestSupport; - }; - -public: - // public for nsTArray - class LangComparator { - public: - bool Equals(const LangSupportEntry& a, const FcChar8 *b) const - { - return FcStrCmpIgnoreCase(a.mLang, b) == 0; - } - }; - -private: - // The requested pattern - nsCountedRef<FcPattern> mSortPattern; - // Fonts from @font-face rules - RefPtr<gfxUserFontSet> mUserFontSet; - // A (trimmed) list of font patterns and fonts that is built up as - // required. - nsTArray<FontEntry> mFonts; - // Holds a list of font patterns that will be trimmed. This is first set - // to a list of preferred fonts. Then, if/when all the preferred fonts - // have been trimmed and added to mFonts, this is set to a list of - // fallback fonts. - nsAutoRef<FcFontSet> mFcFontSet; - // The set of characters supported by the fonts in mFonts. - nsAutoRef<FcCharSet> mCharSet; - // The index of the next font in mFcFontSet that has not yet been - // considered for mFonts. - int mFcFontsTrimmed; - // True iff fallback fonts are either stored in mFcFontSet or have been - // trimmed and added to mFonts (so that mFcFontSet is nullptr). - bool mHaveFallbackFonts; - // True iff there was a user font set with pending downloads, - // so the set may be updated when downloads complete - bool mWaitingForUserFont; -}; - -// Find the FcPattern for an @font-face font suitable for CSS family |aFamily| -// and style |aStyle| properties. -static const nsTArray< nsCountedRef<FcPattern> >* -FindFontPatterns(gfxUserFontSet *mUserFontSet, - const nsACString &aFamily, uint8_t aStyle, - uint16_t aWeight, int16_t aStretch, - bool& aWaitForUserFont) -{ - // Convert to UTF16 - NS_ConvertUTF8toUTF16 utf16Family(aFamily); - - // needsBold is not used here. Instead synthetic bold is enabled through - // FcFontRenderPrepare when the weight in the requested pattern is - // compared against the weight in the font pattern. - bool needsBold; - - gfxFontStyle style; - style.style = aStyle; - style.weight = aWeight; - style.stretch = aStretch; - - gfxUserFcFontEntry *fontEntry = nullptr; - gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family); - if (family) { - gfxUserFontEntry* userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast<gfxUserFcFontEntry*> - (userFontEntry->GetPlatformFontEntry()); - } - - // Accept synthetic oblique for italic and oblique. - // xxx - this isn't really ideal behavior, for docs that only use a - // single italic face it will also pull down the normal face - // and probably never use it - if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) { - style.style = NS_FONT_STYLE_NORMAL; - userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, - needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast<gfxUserFcFontEntry*> - (userFontEntry->GetPlatformFontEntry()); - } - } - } - - if (!fontEntry) { - return nullptr; - } - - return &fontEntry->GetPatterns(); -} - -typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object, - int id); - -// FcPatternRemove is available in fontconfig-2.3.0 (2005) -static FcBool -moz_FcPatternRemove(FcPattern *p, const char *object, int id) -{ - static FcPatternRemoveFunction sFcPatternRemovePtr = - reinterpret_cast<FcPatternRemoveFunction> - (FindFunctionSymbol("FcPatternRemove")); - - if (!sFcPatternRemovePtr) - return FcFalse; - - return (*sFcPatternRemovePtr)(p, object, id); -} - -// fontconfig prefers a matching family or lang to pixelsize of bitmap -// fonts. CSS suggests a tolerance of 20% on pixelsize. -static bool -SizeIsAcceptable(FcPattern *aFont, double aRequestedSize) -{ - double size; - int v = 0; - while (FcPatternGetDouble(aFont, - FC_PIXEL_SIZE, v, &size) == FcResultMatch) { - ++v; - if (5.0 * fabs(size - aRequestedSize) < aRequestedSize) - return true; - } - - // No size means scalable - return v == 0; -} - -// Sorting only the preferred fonts first usually saves having to sort through -// every font on the system. -nsReturnRef<FcFontSet> -gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont) -{ - aWaitForUserFont = false; - - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nsReturnRef<FcFontSet>(); - - // The list of families in mSortPattern has values with both weak and - // strong bindings. Values with strong bindings should be preferred. - // Values with weak bindings are default fonts that should be considered - // only when the font provides the best support for a requested language - // or after other fonts have satisfied all the requested languages. - // - // There are no direct fontconfig APIs to get the binding type. The - // binding only takes effect in the sort and match functions. - - // |requiredLangs| is a list of requested languages that have not yet been - // satisfied. gfxFontconfigUtils only sets one FC_LANG property value, - // but FcConfigSubstitute may add more values (e.g. prepending "en" to - // "ja" will use western fonts to render Latin/Arabic numerals in Japanese - // text.) - AutoTArray<LangSupportEntry,10> requiredLangs; - for (int v = 0; ; ++v) { - FcChar8 *lang; - FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang); - if (result != FcResultMatch) { - // No need to check FcPatternGetLangSet() because - // gfxFontconfigUtils sets only a string value for FC_LANG and - // FcConfigSubstitute cannot add LangSets. - NS_ASSERTION(result != FcResultTypeMismatch, - "Expected a string for FC_LANG"); - break; - } - - if (!requiredLangs.Contains(lang, LangComparator())) { - FcLangResult bestLangSupport = utils->GetBestLangSupport(lang); - if (bestLangSupport != FcLangDifferentLang) { - requiredLangs. - AppendElement(LangSupportEntry(lang, bestLangSupport)); - } - } - } - - nsAutoRef<FcFontSet> fontSet(FcFontSetCreate()); - if (!fontSet) - return fontSet.out(); - - // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever - // doesn't happen, Roman will be used. - int requestedSlant = FC_SLANT_ROMAN; - FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant); - double requestedSize = -1.0; - FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize); - - nsTHashtable<gfxFontconfigUtils::DepFcStrEntry> existingFamilies(32); - FcChar8 *family; - for (int v = 0; - FcPatternGetString(mSortPattern, - FC_FAMILY, v, &family) == FcResultMatch; ++v) { - const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nullptr; - - // Is this an @font-face family? - bool isUserFont = false; - if (mUserFontSet) { - // Have some @font-face definitions - - nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family)); - NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX); - - if (StringBeginsWith(cFamily, userPrefix)) { - isUserFont = true; - - // Trim off the prefix - nsDependentCSubstring cssFamily(cFamily, userPrefix.Length()); - - uint8_t thebesStyle = - gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant); - uint16_t thebesWeight = - gfxFontconfigUtils::GetThebesWeight(mSortPattern); - int16_t thebesStretch = - gfxFontconfigUtils::GetThebesStretch(mSortPattern); - - bool waitForUserFont; - familyFonts = FindFontPatterns(mUserFontSet, cssFamily, - thebesStyle, - thebesWeight, thebesStretch, - waitForUserFont); - if (waitForUserFont) { - aWaitForUserFont = true; - } - } - } - - if (!isUserFont) { - familyFonts = &utils->GetFontsForFamily(family); - } - - if (!familyFonts || familyFonts->Length() == 0) { - // There are no fonts matching this family, so there is no point - // in searching for this family in the FontSort. - // - // Perhaps the original pattern should be retained for - // FcFontRenderPrepare. However, the only a useful config - // substitution test against missing families that i can imagine - // would only be interested in the preferred family - // (qual="first"), so always keep the first family and use the - // same pattern for Sort and RenderPrepare. - if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) { - --v; - } - continue; - } - - // Aliases seem to often end up occurring more than once, but - // duplicate families can't be removed from the sort pattern without - // knowing whether duplicates have the same binding. - gfxFontconfigUtils::DepFcStrEntry *familyEntry = - existingFamilies.PutEntry(family); - if (familyEntry) { - if (familyEntry->mKey) // old entry - continue; - - familyEntry->mKey = family; // initialize new entry - } - - for (uint32_t f = 0; f < familyFonts->Length(); ++f) { - FcPattern *font = familyFonts->ElementAt(f); - - // Fix up the family name of user-font patterns, as the same - // font entry may be used (via the UserFontCache) for multiple - // CSS family names - if (isUserFont) { - font = FcPatternDuplicate(font); - FcPatternDel(font, FC_FAMILY); - FcPatternAddString(font, FC_FAMILY, family); - } - - // User fonts are already filtered by slant (but not size) in - // mUserFontSet->FindUserFontEntry(). - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const LangSupportEntry& langEntry = requiredLangs[r]; - FcLangResult support = - gfxFontconfigUtils::GetLangSupport(font, langEntry.mLang); - if (support <= langEntry.mBestSupport) { // lower is better - requiredLangs.RemoveElementAt(r); - --r; - } - } - - // FcFontSetDestroy will remove a reference but FcFontSetAdd - // does _not_ take a reference! - if (FcFontSetAdd(fontSet, font)) { - // We don't add a reference here for user fonts, because we're - // using a local clone of the pattern (see above) in order to - // override the family name - if (!isUserFont) { - FcPatternReference(font); - } - } - } - } - - FcPattern *truncateMarker = nullptr; - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const nsTArray< nsCountedRef<FcPattern> >& langFonts = - utils->GetFontsForLang(requiredLangs[r].mLang); - - bool haveLangFont = false; - for (uint32_t f = 0; f < langFonts.Length(); ++f) { - FcPattern *font = langFonts[f]; - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - haveLangFont = true; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - } - } - - if (!haveLangFont && langFonts.Length() > 0) { - // There is a font that supports this language but it didn't pass - // the slant and size criteria. Weak default font families should - // not be considered until the language has been satisfied. - // - // Insert a font that supports the language so that it will mark - // the position of fonts from weak families in the sorted set and - // they can be removed. The language and weak families will be - // considered in the fallback fonts, which use fontconfig's - // algorithm. - // - // Of the fonts that don't meet slant and size criteria, strong - // default font families should be considered before (other) fonts - // for this language, so this marker font will be removed (as well - // as the fonts from weak families), and strong families will be - // reconsidered in the fallback fonts. - FcPattern *font = langFonts[0]; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - truncateMarker = font; - } - break; - } - } - - FcFontSet *sets[1] = { fontSet }; - FcResult result; - fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern, - FcFalse, nullptr, &result)); - - if (truncateMarker != nullptr && fontSet) { - nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate()); - - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - if (font == truncateMarker) - break; - - if (FcFontSetAdd(truncatedSet, font)) { - FcPatternReference(font); - } - } - - fontSet.steal(truncatedSet); - } - - return fontSet.out(); -} - -nsReturnRef<FcFontSet> -gfxFcFontSet::SortFallbackFonts() -{ - // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet, - // but would take much longer due to comparing all the character sets. - // - // The references to fonts in this FcFontSet are almost free - // as they are pointers into mmaped cache files. - // - // GetFontPatternAt() will trim lazily if and as needed, which will also - // remove duplicates of preferred fonts. - FcResult result; - return nsReturnRef<FcFontSet>(FcFontSort(nullptr, mSortPattern, - FcFalse, nullptr, &result)); -} - -// GetFontAt relies on this setting up all patterns up to |i|. -FcPattern * -gfxFcFontSet::GetFontPatternAt(uint32_t i) -{ - while (i >= mFonts.Length()) { - while (!mFcFontSet) { - if (mHaveFallbackFonts) - return nullptr; - - mFcFontSet = SortFallbackFonts(); - mHaveFallbackFonts = true; - mFcFontsTrimmed = 0; - // Loop to test that mFcFontSet is non-nullptr. - } - - while (mFcFontsTrimmed < mFcFontSet->nfont) { - FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed]; - ++mFcFontsTrimmed; - - if (mFonts.Length() != 0) { - // See if the next font provides support for any extra - // characters. Most often the next font is not going to - // support more characters so check for a SubSet first before - // allocating a new CharSet with Union. - FcCharSet *supportedChars = mCharSet; - if (!supportedChars) { - FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern, - FC_CHARSET, 0, &supportedChars); - } - - if (supportedChars) { - FcCharSet *newChars = nullptr; - FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars); - if (newChars) { - if (FcCharSetIsSubset(newChars, supportedChars)) - continue; - - mCharSet.own(FcCharSetUnion(supportedChars, newChars)); - } else if (!mCharSet) { - mCharSet.own(FcCharSetCopy(supportedChars)); - } - } - } - - mFonts.AppendElement(font); - if (mFonts.Length() >= i) - break; - } - - if (mFcFontsTrimmed == mFcFontSet->nfont) { - // finished with this font set - mFcFontSet.reset(); - } - } - - return mFonts[i].mPattern; -} - -#ifdef MOZ_WIDGET_GTK -static void ApplyGdkScreenFontOptions(FcPattern *aPattern); -#endif - -// Apply user settings and defaults to pattern in preparation for matching. -static void -PrepareSortPattern(FcPattern *aPattern, double aFallbackSize, - double aSizeAdjustFactor, bool aIsPrinterFont) -{ - FcConfigSubstitute(nullptr, aPattern, FcMatchPattern); - - // This gets cairo_font_options_t for the Screen. We should have - // different font options for printing (no hinting) but we are not told - // what we are measuring for. - // - // If cairo adds support for lcd_filter, gdk will not provide the default - // setting for that option. We could get the default setting by creating - // an xlib surface once, recording its font_options, and then merging the - // gdk options. - // - // Using an xlib surface would also be an option to get Screen font - // options for non-GTK X11 toolkits, but less efficient than using GDK to - // pick up dynamic changes. - if(aIsPrinterFont) { - cairo_font_options_t *options = cairo_font_options_create(); - cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); - cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); - cairo_ft_font_options_substitute(options, aPattern); - cairo_font_options_destroy(options); - FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue); - } else { -#ifdef MOZ_WIDGET_GTK - ApplyGdkScreenFontOptions(aPattern); -#endif - } - - // Protect against any fontconfig settings that may have incorrectly - // modified the pixelsize, and consider aSizeAdjustFactor. - double size = aFallbackSize; - if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch - || aSizeAdjustFactor != 1.0) { - FcPatternDel(aPattern, FC_PIXEL_SIZE); - FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor); - } - - FcDefaultSubstitute(aPattern); -} - -/** - ** gfxPangoFontGroup - **/ - -gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize) - : gfxFontGroup(aFontFamilyList, aStyle, nullptr, aUserFontSet, aDevToCssSize), - mPangoLanguage(GuessPangoLanguage(aStyle->language)) -{ - // This language is passed to the font for shaping. - // Shaping doesn't know about lang groups so make it a real language. - if (mPangoLanguage) { - mStyle.language = NS_Atomize(pango_language_to_string(mPangoLanguage)); - } - - // dummy entry, will be replaced when actually needed - mFonts.AppendElement(FamilyFace()); - mSkipUpdateUserFonts = true; -} - -gfxPangoFontGroup::~gfxPangoFontGroup() -{ -} - -gfxFontGroup * -gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) -{ - return new gfxPangoFontGroup(mFamilyList, aStyle, mUserFontSet, mDevToCssSize); -} - -void -gfxPangoFontGroup::FindGenericFontsPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure) -{ - AutoTArray<nsString, 5> resolvedGenerics; - ResolveGenericFontNamesPFG(aGenericType, aLanguage, resolvedGenerics); - uint32_t g = 0, numGenerics = resolvedGenerics.Length(); - for (g = 0; g < numGenerics; g++) { - FindPlatformFontPFG(resolvedGenerics[g], false, aClosure); - } -} - -/* static */ void -gfxPangoFontGroup::ResolveGenericFontNamesPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray<nsString>& aGenericFamilies) -{ - static const char kGeneric_serif[] = "serif"; - static const char kGeneric_sans_serif[] = "sans-serif"; - static const char kGeneric_monospace[] = "monospace"; - static const char kGeneric_cursive[] = "cursive"; - static const char kGeneric_fantasy[] = "fantasy"; - - // treat -moz-fixed as monospace - if (aGenericType == eFamily_moz_fixed) { - aGenericType = eFamily_monospace; - } - - // type should be standard generic type at this point - NS_ASSERTION(aGenericType >= eFamily_serif && - aGenericType <= eFamily_fantasy, - "standard generic font family type required"); - - // create the lang string - nsIAtom *langGroupAtom = nullptr; - nsAutoCString langGroupString; - if (aLanguage) { - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - if (gLangService) { - nsresult rv; - langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv); - } - } - if (!langGroupAtom) { - langGroupAtom = nsGkAtoms::Unicode; - } - langGroupAtom->ToUTF8String(langGroupString); - - // map generic type to string - const char *generic = nullptr; - switch (aGenericType) { - case eFamily_serif: - generic = kGeneric_serif; - break; - case eFamily_sans_serif: - generic = kGeneric_sans_serif; - break; - case eFamily_monospace: - generic = kGeneric_monospace; - break; - case eFamily_cursive: - generic = kGeneric_cursive; - break; - case eFamily_fantasy: - generic = kGeneric_fantasy; - break; - default: - break; - } - - if (!generic) { - return; - } - - aGenericFamilies.Clear(); - - // load family for "font.name.generic.lang" - nsAutoCString prefFontName("font.name."); - prefFontName.Append(generic); - prefFontName.Append('.'); - prefFontName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontName.get(), - aGenericFamilies); - - // if lang has pref fonts, also load fonts for "font.name-list.generic.lang" - if (!aGenericFamilies.IsEmpty()) { - nsAutoCString prefFontListName("font.name-list."); - prefFontListName.Append(generic); - prefFontListName.Append('.'); - prefFontListName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), - aGenericFamilies); - } - -#if 0 // dump out generic mappings - printf("%s ===> ", prefFontName.get()); - for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) { - if (k > 0) printf(", "); - printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get()); - } - printf("\n"); -#endif -} - -void gfxPangoFontGroup::EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure) -{ - // initialize fonts in the font family list - const nsTArray<FontFamilyName>& fontlist = mFamilyList.GetFontlist(); - - // lookup fonts in the fontlist - uint32_t i, numFonts = fontlist.Length(); - for (i = 0; i < numFonts; i++) { - const FontFamilyName& name = fontlist[i]; - if (name.IsNamed()) { - FindPlatformFontPFG(name.mName, true, aClosure); - } else { - FindGenericFontsPFG(name.mType, aLanguage, aClosure); - } - } - - // if necessary, append default generic onto the end - if (mFamilyList.GetDefaultFontType() != eFamily_none && - !mFamilyList.HasDefaultGeneric()) { - FindGenericFontsPFG(mFamilyList.GetDefaultFontType(), - aLanguage, aClosure); - } -} - -void -gfxPangoFontGroup::FindPlatformFontPFG(const nsAString& fontName, - bool aUseFontSet, - void *aClosure) -{ - nsTArray<nsString> *list = static_cast<nsTArray<nsString>*>(aClosure); - - if (!list->Contains(fontName)) { - // names present in the user fontset are not matched against system fonts - if (aUseFontSet && mUserFontSet && mUserFontSet->HasFamily(fontName)) { - nsAutoString userFontName = - NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName; - list->AppendElement(userFontName); - } else { - list->AppendElement(fontName); - } - } -} - -gfxFcFont * -gfxPangoFontGroup::GetBaseFont() -{ - if (mFonts[0].Font() == nullptr) { - gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle()); - mFonts[0] = FamilyFace(nullptr, font); - } - - return static_cast<gfxFcFont*>(mFonts[0].Font()); -} - -gfxFont* -gfxPangoFontGroup::GetFirstValidFont(uint32_t aCh) -{ - return GetFontAt(0); -} - -gfxFont * -gfxPangoFontGroup::GetFontAt(int32_t i, uint32_t aCh) -{ - // If it turns out to be hard for all clients that cache font - // groups to call UpdateUserFonts at appropriate times, we could - // instead consider just calling UpdateUserFonts from someplace - // more central (such as here). - NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), - "Whoever was caching this font group should have " - "called UpdateUserFonts on it"); - - NS_PRECONDITION(i == 0, "Only have one font"); - - return GetBaseFont(); -} - -void -gfxPangoFontGroup::UpdateUserFonts() -{ - uint64_t newGeneration = GetGeneration(); - if (newGeneration == mCurrGeneration) - return; - - mFonts[0] = FamilyFace(); - mFontSets.Clear(); - ClearCachedData(); - mCurrGeneration = newGeneration; -} - -already_AddRefed<gfxFcFontSet> -gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef<FcPattern> *aMatchPattern) -{ - const char *lang = pango_language_to_string(aLang); - - RefPtr<nsIAtom> langGroup; - if (aLang != mPangoLanguage) { - // Set up langGroup for Mozilla's font prefs. - langGroup = NS_Atomize(lang); - } - - AutoTArray<nsString, 20> fcFamilyList; - EnumerateFontListPFG(langGroup ? langGroup.get() : mStyle.language.get(), - &fcFamilyList); - - // To consider: A fontset cache here could be helpful. - - // Get a pattern suitable for matching. - nsAutoRef<FcPattern> pattern - (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang)); - - PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont); - - RefPtr<gfxFcFontSet> fontset = - new gfxFcFontSet(pattern, mUserFontSet); - - mSkipDrawing = fontset->WaitingForUserFont(); - - if (aMatchPattern) - aMatchPattern->steal(pattern); - - return fontset.forget(); -} - -gfxPangoFontGroup:: -FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang, - gfxFcFontSet *aFontSet) - : mLang(aLang), mFontSet(aFontSet) -{ -} - -gfxFcFontSet * -gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang) -{ - GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0] - - if (!aLang) - return mFontSets[0].mFontSet; - - for (uint32_t i = 0; i < mFontSets.Length(); ++i) { - if (mFontSets[i].mLang == aLang) - return mFontSets[i].mFontSet; - } - - RefPtr<gfxFcFontSet> fontSet = - MakeFontSet(aLang, mSizeAdjustFactor); - mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet)); - - return fontSet; -} - -already_AddRefed<gfxFont> -gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, - uint32_t aNextCh, Script aRunScript, - gfxFont *aPrevMatchedFont, - uint8_t *aMatchType) -{ - if (aPrevMatchedFont) { - // Don't switch fonts for control characters, regardless of - // whether they are present in the current font, as they won't - // actually be rendered (see bug 716229) - uint8_t category = GetGeneralCategory(aCh); - if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) { - return RefPtr<gfxFont>(aPrevMatchedFont).forget(); - } - - // if this character is a join-control or the previous is a join-causer, - // use the same font as the previous range if we can - if (gfxFontUtils::IsJoinControl(aCh) || - gfxFontUtils::IsJoinCauser(aPrevCh)) { - if (aPrevMatchedFont->HasCharacter(aCh)) { - return RefPtr<gfxFont>(aPrevMatchedFont).forget(); - } - } - } - - // if this character is a variation selector, - // use the previous font regardless of whether it supports VS or not. - // otherwise the text run will be divided. - if (gfxFontUtils::IsVarSelector(aCh)) { - if (aPrevMatchedFont) { - return RefPtr<gfxFont>(aPrevMatchedFont).forget(); - } - // VS alone. it's meaningless to search different fonts - return nullptr; - } - - // The real fonts that fontconfig provides for generic/fallback families - // depend on the language used, so a different FontSet is used for each - // language (except for the variation below). - // - // With most fontconfig configurations any real family names prior to a - // fontconfig generic with corresponding fonts installed will still lead - // to the same leading fonts in each FontSet. - // - // There is an inefficiency here therefore because the same base FontSet - // could often be used if these real families support the character. - // However, with fontconfig aliases, it is difficult to distinguish - // where exactly alias fonts end and generic/fallback fonts begin. - // - // The variation from pure language-based matching used here is that the - // same primary/base font is always used irrespective of the language. - // This provides that SCRIPT_COMMON characters are consistently rendered - // with the same font (bug 339513 and bug 416725). This is particularly - // important with the word cache as script can't be reliably determined - // from surrounding words. It also often avoids the unnecessary extra - // FontSet efficiency mentioned above. - // - // However, in two situations, the base font is not checked before the - // language-specific FontSet. - // - // 1. When we don't have a language to make a good choice for - // the base font. - // - // 2. For system fonts, use the default Pango behavior to give - // consistency with other apps. This is relevant when un-localized - // builds are run in non-Latin locales. This special-case probably - // wouldn't be necessary but for bug 91190. - - gfxFcFontSet *fontSet = GetBaseFontSet(); - uint32_t nextFont = 0; - FcPattern *basePattern = nullptr; - if (!mStyle.systemFont && mPangoLanguage) { - basePattern = fontSet->GetFontPatternAt(0); - if (HasChar(basePattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr<gfxFont>(GetBaseFont()).forget(); - } - - nextFont = 1; - } - - // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values - // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag. - // Note that PangoScript is defined to be compatible with GUnicodeScript: - // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript - const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript); - const PangoScript script = - (const PangoScript)hb_glib_script_from_script(hb_script_from_iso15924_tag(scriptTag)); - - // Might be nice to call pango_language_includes_script only once for the - // run rather than for each character. - PangoLanguage *scriptLang; - if ((!basePattern || - !pango_language_includes_script(mPangoLanguage, script)) && - (scriptLang = pango_script_get_sample_language(script))) { - fontSet = GetFontSet(scriptLang); - nextFont = 0; - } - - for (uint32_t i = nextFont; - FcPattern *pattern = fontSet->GetFontPatternAt(i); - ++i) { - if (pattern == basePattern) { - continue; // already checked basePattern - } - - if (HasChar(pattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr<gfxFont>(fontSet->GetFontAt(i, GetStyle())).forget(); - } - } - - return nullptr; -} - -/** - ** gfxFcFont - **/ - -cairo_user_data_key_t gfxFcFont::sGfxFontKey; - -gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFontconfigFontBase(aCairoFont, aPattern, aFontEntry, aFontStyle) -{ - cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr); -} - -gfxFcFont::~gfxFcFont() -{ - cairo_scaled_font_set_user_data(mScaledFont, - &sGfxFontKey, - nullptr, - nullptr); -} - -already_AddRefed<gfxFont> -gfxFcFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) -{ - gfxFontStyle style(*GetStyle()); - style.AdjustForSubSuperscript(aAppUnitsPerDevPixel); - return MakeScaledFont(&style, style.size / GetStyle()->size); -} - -already_AddRefed<gfxFont> -gfxFcFont::MakeScaledFont(gfxFontStyle *aFontStyle, gfxFloat aScaleFactor) -{ - gfxFcFontEntry* fe = static_cast<gfxFcFontEntry*>(GetFontEntry()); - RefPtr<gfxFont> font = - gfxFontCache::GetCache()->Lookup(fe, aFontStyle, nullptr); - if (font) { - return font.forget(); - } - - cairo_matrix_t fontMatrix; - cairo_scaled_font_get_font_matrix(mScaledFont, &fontMatrix); - cairo_matrix_scale(&fontMatrix, aScaleFactor, aScaleFactor); - - cairo_matrix_t ctm; - cairo_scaled_font_get_ctm(mScaledFont, &ctm); - - cairo_font_options_t *options = cairo_font_options_create(); - cairo_scaled_font_get_font_options(mScaledFont, options); - - cairo_scaled_font_t *newFont = - cairo_scaled_font_create(cairo_scaled_font_get_font_face(mScaledFont), - &fontMatrix, &ctm, options); - cairo_font_options_destroy(options); - - font = new gfxFcFont(newFont, GetPattern(), fe, aFontStyle); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(newFont); - - return font.forget(); -} - -already_AddRefed<gfxFont> -gfxFcFont::GetSmallCapsFont() -{ - gfxFontStyle style(*GetStyle()); - style.size *= SMALL_CAPS_SCALE_FACTOR; - style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL; - return MakeScaledFont(&style, SMALL_CAPS_SCALE_FACTOR); -} - -/* static */ void -gfxPangoFontGroup::Shutdown() -{ - // Resetting gFTLibrary in case this is wanted again after a - // cairo_debug_reset_static_data. - gFTLibrary = nullptr; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) -{ - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nullptr; - - // The font face name from @font-face { src: local() } is not well - // defined. - // - // On MS Windows, this name gets compared with - // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the - // full font name from the name table. For CFF OpenType fonts this is the - // same as the PostScript name, but for TrueType fonts it is usually - // different. - // - // On Mac, the font face name is compared with the PostScript name, even - // for TrueType fonts. - // - // Fontconfig only records the full font names, so the behavior here - // follows that on MS Windows. However, to provide the possibility - // of aliases to compensate for variations, the font face name is passed - // through FcConfigSubstitute. - - nsAutoRef<FcPattern> pattern(FcPatternCreate()); - if (!pattern) - return nullptr; - - NS_ConvertUTF16toUTF8 fullname(aFontName); - FcPatternAddString(pattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - - FcChar8 *name; - for (int v = 0; - FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch; - ++v) { - const nsTArray< nsCountedRef<FcPattern> >& fonts = - utils->GetFontsForFullname(name); - - if (fonts.Length() != 0) - return new gfxLocalFcFontEntry(aFontName, - aWeight, - aStretch, - aStyle, - fonts); - } - - return nullptr; -} - -/* static */ FT_Library -gfxPangoFontGroup::GetFTLibrary() -{ - if (!gFTLibrary) { - // Use cairo's FT_Library so that cairo takes care of shutdown of the - // FT_Library after it has destroyed its font_faces, and FT_Done_Face - // has been called on each FT_Face, at least until this bug is fixed: - // https://bugs.freedesktop.org/show_bug.cgi?id=18857 - // - // Cairo's FT_Library can be obtained from any cairo_scaled_font. The - // font properties requested here are chosen to get an FT_Face that is - // likely to be also used elsewhere. - gfxFontStyle style; - RefPtr<gfxPangoFontGroup> fontGroup = - new gfxPangoFontGroup(FontFamilyList(eFamily_sans_serif), - &style, nullptr, 1.0); - - gfxFcFont *font = fontGroup->GetBaseFont(); - if (!font) - return nullptr; - - gfxFT2LockedFace face(font); - if (!face.get()) - return nullptr; - - gFTLibrary = face.get()->glyph->library; - } - - return gFTLibrary; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength) -{ - // Ownership of aFontData is passed in here, and transferred to the - // new fontEntry, which will release it when no longer needed. - - // Using face_index = 0 for the first face in the font, as we have no - // other information. FT_New_Memory_Face checks for a nullptr FT_Library. - FT_Face face; - FT_Error error = - FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face); - if (error != 0) { - free((void*)aFontData); - return nullptr; - } - - return new gfxDownloadedFcFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, face); -} - - -static double -GetPixelSize(FcPattern *aPattern) -{ - double size; - if (FcPatternGetDouble(aPattern, - FC_PIXEL_SIZE, 0, &size) == FcResultMatch) - return size; - - NS_NOTREACHED("No size on pattern"); - return 0.0; -} - -/** - * The following gfxFcFonts are accessed from the cairo_scaled_font or created - * from the FcPattern, not from the gfxFontCache hash table. The gfxFontCache - * hash table is keyed by desired family and style, whereas here we only know - * actual family and style. There may be more than one of these fonts with - * the same family and style, but different PangoFont and actual font face. - * - * The point of this is to record the exact font face for gfxTextRun glyph - * indices. The style of this font does not necessarily represent the exact - * gfxFontStyle used to build the text run. Notably, the language is not - * recorded. - */ - -/* static */ -already_AddRefed<gfxFcFont> -gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle) -{ - nsAutoRef<FcPattern> renderPattern - (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern)); - - // If synthetic bold/italic is not allowed by the style, adjust the - // resulting pattern to match the actual properties of the font. - if (!aFontStyle->allowSyntheticWeight) { - int weight; - if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, - &weight) == FcResultMatch) { - FcPatternDel(renderPattern, FC_WEIGHT); - FcPatternAddInteger(renderPattern, FC_WEIGHT, weight); - } - } - if (!aFontStyle->allowSyntheticStyle) { - int slant; - if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, - &slant) == FcResultMatch) { - FcPatternDel(renderPattern, FC_SLANT); - FcPatternAddInteger(renderPattern, FC_SLANT, slant); - } - } - - cairo_font_face_t *face = - cairo_ft_font_face_create_for_pattern(renderPattern); - - // Reuse an existing font entry if available. - RefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face); - if (!fe) { - gfxDownloadedFcFontEntry *downloadedFontEntry = - GetDownloadedFontEntry(aFontPattern); - if (downloadedFontEntry) { - // Web font - fe = downloadedFontEntry; - if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) { - // cairo_font_face_t is using the web font data. - // Hold a reference to the font entry to keep the font face - // data. - if (!downloadedFontEntry->SetCairoFace(face)) { - // OOM. Let cairo pick a fallback font - cairo_font_face_destroy(face); - face = cairo_ft_font_face_create_for_pattern(aRequestedPattern); - fe = gfxFcFontEntry::LookupFontEntry(face); - } - } - } - if (!fe) { - // Get a unique name for the font face from the file and id. - nsAutoString name; - FcChar8 *fc_file; - if (FcPatternGetString(renderPattern, - FC_FILE, 0, &fc_file) == FcResultMatch) { - int index; - if (FcPatternGetInteger(renderPattern, - FC_INDEX, 0, &index) != FcResultMatch) { - // cairo defaults to 0. - index = 0; - } - - AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name); - if (index != 0) { - name.Append('/'); - name.AppendInt(index); - } - } - - fe = new gfxSystemFcFontEntry(face, aFontPattern, name); - } - } - - gfxFontStyle style(*aFontStyle); - style.size = GetPixelSize(renderPattern); - style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern); - style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern); - - RefPtr<gfxFont> font = - gfxFontCache::GetCache()->Lookup(fe, &style, nullptr); - if (!font) { - // Note that a file/index pair (or FT_Face) and the gfxFontStyle are - // not necessarily enough to provide a key that will describe a unique - // font. cairoFont contains information from renderPattern, which is a - // fully resolved pattern from FcFontRenderPrepare. - // FcFontRenderPrepare takes the requested pattern and the face - // pattern as input and can modify elements of the resulting pattern - // that affect rendering but are not included in the gfxFontStyle. - cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face); - font = new gfxFcFont(cairoFont, renderPattern, fe, &style); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(cairoFont); - } - - cairo_font_face_destroy(face); - - RefPtr<gfxFcFont> retval(static_cast<gfxFcFont*>(font.get())); - return retval.forget(); -} - -gfxFcFontSet * -gfxPangoFontGroup::GetBaseFontSet() -{ - if (mFontSets.Length() > 0) - return mFontSets[0].mFontSet; - - mSizeAdjustFactor = 1.0; // will be adjusted below if necessary - nsAutoRef<FcPattern> pattern; - RefPtr<gfxFcFontSet> fontSet = - MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern); - - double size = GetPixelSize(pattern); - if (size != 0.0 && mStyle.sizeAdjust > 0.0) { - gfxFcFont *font = fontSet->GetFontAt(0, GetStyle()); - if (font) { - const gfxFont::Metrics& metrics = - font->GetMetrics(gfxFont::eHorizontal); // XXX vertical? - - // The factor of 0.1 ensures that xHeight is sane so fonts don't - // become huge. Strictly ">" ensures that xHeight and emHeight are - // not both zero. - if (metrics.xHeight > 0.1 * metrics.emHeight) { - mSizeAdjustFactor = - mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight; - - size *= mSizeAdjustFactor; - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size); - - fontSet = new gfxFcFontSet(pattern, mUserFontSet); - } - } - } - - PangoLanguage *pangoLang = mPangoLanguage; - FcChar8 *fcLang; - if (!pangoLang && - FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) { - pangoLang = - pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang)); - } - - mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet)); - - return fontSet; -} - -/** - ** gfxTextRun - * - * A serious problem: - * - * -- We draw with a font that's hinted for the CTM, but we measure with a font - * hinted to the identity matrix, so our "bounding metrics" may not be accurate. - * - **/ - -// This will fetch an existing scaled_font if one exists. -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace) -{ - double size = GetPixelSize(aPattern); - - cairo_matrix_t fontMatrix; - FcMatrix *fcMatrix; - if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch) - cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0); - else - cairo_matrix_init_identity(&fontMatrix); - cairo_matrix_scale(&fontMatrix, size, size); - - FcBool printing; - if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) { - printing = FcFalse; - } - - // The cairo_scaled_font is created with a unit ctm so that metrics and - // positions are in user space, but this means that hinting effects will - // not be estimated accurately for non-unit transformations. - cairo_matrix_t identityMatrix; - cairo_matrix_init_identity(&identityMatrix); - - // Font options are set explicitly here to improve cairo's caching - // behavior and to record the relevant parts of the pattern for - // SetupCairoFont (so that the pattern can be released). - // - // Most font_options have already been set as defaults on the FcPattern - // with cairo_ft_font_options_substitute(), then user and system - // fontconfig configurations were applied. The resulting font_options - // have been recorded on the face during - // cairo_ft_font_face_create_for_pattern(). - // - // None of the settings here cause this scaled_font to behave any - // differently from how it would behave if it were created from the same - // face with default font_options. - // - // We set options explicitly so that the same scaled_font will be found in - // the cairo_scaled_font_map when cairo loads glyphs from a context with - // the same font_face, font_matrix, ctm, and surface font_options. - // - // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the - // font_options on the cairo_ft_font_face, and doesn't consider default - // option values to not match any explicit values. - // - // Even after cairo_set_scaled_font is used to set font_options for the - // cairo context, when cairo looks for a scaled_font for the context, it - // will look for a font with some option values from the target surface if - // any values are left default on the context font_options. If this - // scaled_font is created with default font_options, cairo will not find - // it. - cairo_font_options_t *fontOptions = cairo_font_options_create(); - - // The one option not recorded in the pattern is hint_metrics, which will - // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON. - // We should be considering the font_options of the surface on which this - // font will be used, but currently we don't have different gfxFonts for - // different surface font_options, so we'll create a font suitable for the - // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON. - if (printing) { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF); - } else { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON); - } - - // The remaining options have been recorded on the pattern and the face. - // _cairo_ft_options_merge has some logic to decide which options from the - // scaled_font or from the cairo_ft_font_face take priority in the way the - // font behaves. - // - // In the majority of cases, _cairo_ft_options_merge uses the options from - // the cairo_ft_font_face, so sometimes it is not so important which - // values are set here so long as they are not defaults, but we'll set - // them to the exact values that we expect from the font, to be consistent - // and to protect against changes in cairo. - // - // In some cases, _cairo_ft_options_merge uses some options from the - // scaled_font's font_options rather than options on the - // cairo_ft_font_face (from fontconfig). - // https://bugs.freedesktop.org/show_bug.cgi?id=11838 - // - // Surface font options were set on the pattern in - // cairo_ft_font_options_substitute. If fontconfig has changed the - // hint_style then that is what the user (or distribution) wants, so we - // use the setting from the FcPattern. - // - // Fallback values here mirror treatment of defaults in cairo-ft-font.c. - FcBool hinting = FcFalse; - if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) { - hinting = FcTrue; - } - - cairo_hint_style_t hint_style; - if (printing || !hinting) { - hint_style = CAIRO_HINT_STYLE_NONE; - } else { -#ifdef FC_HINT_STYLE // FC_HINT_STYLE is available from fontconfig 2.2.91. - int fc_hintstyle; - if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, - 0, &fc_hintstyle ) != FcResultMatch) { - fc_hintstyle = FC_HINT_FULL; - } - switch (fc_hintstyle) { - case FC_HINT_NONE: - hint_style = CAIRO_HINT_STYLE_NONE; - break; - case FC_HINT_SLIGHT: - hint_style = CAIRO_HINT_STYLE_SLIGHT; - break; - case FC_HINT_MEDIUM: - default: // This fallback mirrors _get_pattern_ft_options in cairo. - hint_style = CAIRO_HINT_STYLE_MEDIUM; - break; - case FC_HINT_FULL: - hint_style = CAIRO_HINT_STYLE_FULL; - break; - } -#else // no FC_HINT_STYLE - hint_style = CAIRO_HINT_STYLE_FULL; -#endif - } - cairo_font_options_set_hint_style(fontOptions, hint_style); - - int rgba; - if (FcPatternGetInteger(aPattern, - FC_RGBA, 0, &rgba) != FcResultMatch) { - rgba = FC_RGBA_UNKNOWN; - } - cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; - switch (rgba) { - case FC_RGBA_UNKNOWN: - case FC_RGBA_NONE: - default: - // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing - // is disabled through cairo_antialias_t. - rgba = FC_RGBA_NONE; - // subpixel_order won't be used by the font as we won't use - // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for - // caching reasons described above. Fall through: - MOZ_FALLTHROUGH; - case FC_RGBA_RGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; - break; - case FC_RGBA_BGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; - break; - case FC_RGBA_VRGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; - break; - case FC_RGBA_VBGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; - break; - } - cairo_font_options_set_subpixel_order(fontOptions, subpixel_order); - - FcBool fc_antialias; - if (FcPatternGetBool(aPattern, - FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) { - fc_antialias = FcTrue; - } - cairo_antialias_t antialias; - if (!fc_antialias) { - antialias = CAIRO_ANTIALIAS_NONE; - } else if (rgba == FC_RGBA_NONE) { - antialias = CAIRO_ANTIALIAS_GRAY; - } else { - antialias = CAIRO_ANTIALIAS_SUBPIXEL; - } - cairo_font_options_set_antialias(fontOptions, antialias); - - cairo_scaled_font_t *scaledFont = - cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix, - fontOptions); - - cairo_font_options_destroy(fontOptions); - - NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS, - "Failed to create scaled font"); - return scaledFont; -} - -/* static */ -PangoLanguage * -GuessPangoLanguage(nsIAtom *aLanguage) -{ - if (!aLanguage) - return nullptr; - - // Pango and fontconfig won't understand mozilla's internal langGroups, so - // find a real language. - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang); - if (lang.IsEmpty()) - return nullptr; - - return pango_language_from_string(lang.get()); -} - -#ifdef MOZ_WIDGET_GTK -/*************************************************************************** - * - * This function must be last in the file because it uses the system cairo - * library. Above this point the cairo library used is the tree cairo if - * MOZ_TREE_CAIRO. - */ - -#if MOZ_TREE_CAIRO -// Tree cairo symbols have different names. Disable their activation through -// preprocessor macros. -#undef cairo_ft_font_options_substitute - -// The system cairo functions are not declared because the include paths cause -// the gdk headers to pick up the tree cairo.h. -extern "C" { -NS_VISIBILITY_DEFAULT void -cairo_ft_font_options_substitute (const cairo_font_options_t *options, - FcPattern *pattern); -} -#endif - -static void -ApplyGdkScreenFontOptions(FcPattern *aPattern) -{ - const cairo_font_options_t *options = - gdk_screen_get_font_options(gdk_screen_get_default()); - - cairo_ft_font_options_substitute(options, aPattern); -} - -#endif // MOZ_WIDGET_GTK - diff --git a/gfx/thebes/gfxFontconfigFonts.h b/gfx/thebes/gfxFontconfigFonts.h deleted file mode 100644 index cea9d0dbfa..0000000000 --- a/gfx/thebes/gfxFontconfigFonts.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_FONTCONFIG_FONTS_H -#define GFX_FONTCONFIG_FONTS_H - -#include "cairo.h" -#include "gfxTypes.h" -#include "gfxTextRun.h" - -#include "nsAutoRef.h" -#include "nsTArray.h" - -#include <pango/pango.h> - -class gfxFcFontSet; -class gfxFcFont; -typedef struct _FcPattern FcPattern; -typedef struct FT_FaceRec_* FT_Face; -typedef struct FT_LibraryRec_ *FT_Library; - -class gfxPangoFontGroup : public gfxFontGroup { -public: - gfxPangoFontGroup(const mozilla::FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize); - virtual ~gfxPangoFontGroup(); - - virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); - - virtual gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); - - virtual void UpdateUserFonts(); - - virtual already_AddRefed<gfxFont> - FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, - Script aRunScript, gfxFont *aPrevMatchedFont, - uint8_t *aMatchType); - - static void Shutdown(); - - // Used for @font-face { src: local(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle); - // Used for @font-face { src: url(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength); - -private: - - virtual gfxFont *GetFontAt(int32_t i, uint32_t aCh = 0x20); - - // @param aLang [in] language to use for pref fonts and system default font - // selection, or nullptr for the language guessed from the - // gfxFontStyle. - // The FontGroup holds a reference to this set. - gfxFcFontSet *GetFontSet(PangoLanguage *aLang = nullptr); - - class FontSetByLangEntry { - public: - FontSetByLangEntry(PangoLanguage *aLang, gfxFcFontSet *aFontSet); - PangoLanguage *mLang; - RefPtr<gfxFcFontSet> mFontSet; - }; - // There is only one of entry in this array unless characters from scripts - // of other languages are measured. - AutoTArray<FontSetByLangEntry,1> mFontSets; - - gfxFloat mSizeAdjustFactor; - PangoLanguage *mPangoLanguage; - - // @param aLang [in] language to use for pref fonts and system font - // resolution, or nullptr to guess a language from the gfxFontStyle. - // @param aMatchPattern [out] if non-nullptr, will return the pattern used. - already_AddRefed<gfxFcFontSet> - MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef<FcPattern> *aMatchPattern = nullptr); - - gfxFcFontSet *GetBaseFontSet(); - gfxFcFont *GetBaseFont(); - - gfxFloat GetSizeAdjustFactor() - { - if (mFontSets.Length() == 0) - GetBaseFontSet(); - return mSizeAdjustFactor; - } - - // old helper methods from gfxFontGroup, moved here so that those methods - // can be revamped without affecting the legacy code here - - // iterate over the fontlist, lookup names and expand generics - void EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure); - - // expand a generic to a list of specific names based on prefs - void FindGenericFontsPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure); - - // lookup and add a font with a given name (i.e. *not* a generic!) - void FindPlatformFontPFG(const nsAString& aName, - bool aUseFontSet, - void *aClosure); - - static void - ResolveGenericFontNamesPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray<nsString>& aGenericFamilies); - - - friend class gfxSystemFcFontEntry; - static FT_Library GetFTLibrary(); -}; - -#endif /* GFX_FONTCONFIG_FONTS_H */ diff --git a/gfx/thebes/gfxFontconfigUtils.cpp b/gfx/thebes/gfxFontconfigUtils.cpp deleted file mode 100644 index 5bf606c13e..0000000000 --- a/gfx/thebes/gfxFontconfigUtils.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ArrayUtils.h" - -#include "gfxFontconfigUtils.h" -#include "gfxFont.h" -#include "nsGkAtoms.h" - -#include <locale.h> -#include <fontconfig/fontconfig.h> - -#include "nsServiceManagerUtils.h" -#include "nsILanguageAtomService.h" -#include "nsTArray.h" -#include "mozilla/Preferences.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsAppDirectoryServiceDefs.h" - -#include "nsIAtom.h" -#include "nsCRT.h" -#include "gfxFontConstants.h" -#include "mozilla/gfx/2D.h" - -using namespace mozilla; - -/* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nullptr; -static nsILanguageAtomService* gLangService = nullptr; - -/* static */ void -gfxFontconfigUtils::Shutdown() { - if (sUtils) { - delete sUtils; - sUtils = nullptr; - } - NS_IF_RELEASE(gLangService); -} - -/* static */ uint8_t -gfxFontconfigUtils::FcSlantToThebesStyle(int aFcSlant) -{ - switch (aFcSlant) { - case FC_SLANT_ITALIC: - return NS_FONT_STYLE_ITALIC; - case FC_SLANT_OBLIQUE: - return NS_FONT_STYLE_OBLIQUE; - default: - return NS_FONT_STYLE_NORMAL; - } -} - -/* static */ uint8_t -gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern) -{ - int slant; - if (FcPatternGetInteger(aPattern, FC_SLANT, 0, &slant) != FcResultMatch) { - return NS_FONT_STYLE_NORMAL; - } - - return FcSlantToThebesStyle(slant); -} - -/* static */ int -gfxFontconfigUtils::GetFcSlant(const gfxFontStyle& aFontStyle) -{ - if (aFontStyle.style == NS_FONT_STYLE_ITALIC) - return FC_SLANT_ITALIC; - if (aFontStyle.style == NS_FONT_STYLE_OBLIQUE) - return FC_SLANT_OBLIQUE; - - return FC_SLANT_ROMAN; -} - -// OS/2 weight classes were introduced in fontconfig-2.1.93 (2003). -#ifndef FC_WEIGHT_THIN -#define FC_WEIGHT_THIN 0 // 2.1.93 -#define FC_WEIGHT_EXTRALIGHT 40 // 2.1.93 -#define FC_WEIGHT_REGULAR 80 // 2.1.93 -#define FC_WEIGHT_EXTRABOLD 205 // 2.1.93 -#endif -// book was introduced in fontconfig-2.2.90 (and so fontconfig-2.3.0 in 2005) -#ifndef FC_WEIGHT_BOOK -#define FC_WEIGHT_BOOK 75 -#endif -// extra black was introduced in fontconfig-2.4.91 (2007) -#ifndef FC_WEIGHT_EXTRABLACK -#define FC_WEIGHT_EXTRABLACK 215 -#endif - -/* static */ uint16_t -gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern) -{ - int weight; - if (FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) - return NS_FONT_WEIGHT_NORMAL; - - if (weight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) - return 100; - if (weight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) - return 200; - if (weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) - return 300; - if (weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) - // This includes FC_WEIGHT_BOOK - return 400; - if (weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) - return 500; - if (weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) - return 600; - if (weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) - return 700; - if (weight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) - return 800; - if (weight <= FC_WEIGHT_BLACK) - return 900; - - // including FC_WEIGHT_EXTRABLACK - return 901; -} - -/* static */ int -gfxFontconfigUtils::FcWeightForBaseWeight(int8_t aBaseWeight) -{ - NS_PRECONDITION(aBaseWeight >= 0 && aBaseWeight <= 10, - "base weight out of range"); - - switch (aBaseWeight) { - case 2: - return FC_WEIGHT_EXTRALIGHT; - case 3: - return FC_WEIGHT_LIGHT; - case 4: - return FC_WEIGHT_REGULAR; - case 5: - return FC_WEIGHT_MEDIUM; - case 6: - return FC_WEIGHT_DEMIBOLD; - case 7: - return FC_WEIGHT_BOLD; - case 8: - return FC_WEIGHT_EXTRABOLD; - case 9: - return FC_WEIGHT_BLACK; - } - - // extremes - return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK; -} - -/* static */ int16_t -gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern) -{ - int width; - if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) { - return NS_FONT_STRETCH_NORMAL; - } - - if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) { - return NS_FONT_STRETCH_ULTRA_CONDENSED; - } - if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) { - return NS_FONT_STRETCH_EXTRA_CONDENSED; - } - if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) { - return NS_FONT_STRETCH_CONDENSED; - } - if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) { - return NS_FONT_STRETCH_SEMI_CONDENSED; - } - if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) { - return NS_FONT_STRETCH_NORMAL; - } - if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) { - return NS_FONT_STRETCH_SEMI_EXPANDED; - } - if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXPANDED; - } - if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXTRA_EXPANDED; - } - return NS_FONT_STRETCH_ULTRA_EXPANDED; -} - -/* static */ int -gfxFontconfigUtils::FcWidthForThebesStretch(int16_t aStretch) -{ - switch (aStretch) { - default: // this will catch "normal" (0) as well as out-of-range values - return FC_WIDTH_NORMAL; - case NS_FONT_STRETCH_ULTRA_CONDENSED: - return FC_WIDTH_ULTRACONDENSED; - case NS_FONT_STRETCH_EXTRA_CONDENSED: - return FC_WIDTH_EXTRACONDENSED; - case NS_FONT_STRETCH_CONDENSED: - return FC_WIDTH_CONDENSED; - case NS_FONT_STRETCH_SEMI_CONDENSED: - return FC_WIDTH_SEMICONDENSED; - case NS_FONT_STRETCH_SEMI_EXPANDED: - return FC_WIDTH_SEMIEXPANDED; - case NS_FONT_STRETCH_EXPANDED: - return FC_WIDTH_EXPANDED; - case NS_FONT_STRETCH_EXTRA_EXPANDED: - return FC_WIDTH_EXTRAEXPANDED; - case NS_FONT_STRETCH_ULTRA_EXPANDED: - return FC_WIDTH_ULTRAEXPANDED; - } -} - -// This makes a guess at an FC_WEIGHT corresponding to a base weight and -// offset (without any knowledge of which weights are available). - -/* static */ int -GuessFcWeight(const gfxFontStyle& aFontStyle) -{ - /* - * weights come in two parts crammed into one - * integer -- the "base" weight is weight / 100, - * the rest of the value is the "offset" from that - * weight -- the number of steps to move to adjust - * the weight in the list of supported font weights, - * this value can be negative or positive. - */ - int8_t weight = aFontStyle.ComputeWeight(); - - // ComputeWeight trimmed the range of weights for us - NS_ASSERTION(weight >= 0 && weight <= 10, - "base weight out of range"); - - return gfxFontconfigUtils::FcWeightForBaseWeight(weight); -} - -static void -AddString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcPatternAddString(aPattern, object, - gfxFontconfigUtils::ToFcChar8(aString)); -} - -static void -AddWeakString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcValue value; - value.type = FcTypeString; - value.u.s = gfxFontconfigUtils::ToFcChar8(aString); - - FcPatternAddWeak(aPattern, object, value, FcTrue); -} - -static void -AddLangGroup(FcPattern *aPattern, nsIAtom *aLangGroup) -{ - // Translate from mozilla's internal mapping into fontconfig's - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang); - - if (!lang.IsEmpty()) { - AddString(aPattern, FC_LANG, lang.get()); - } -} - -nsReturnRef<FcPattern> -gfxFontconfigUtils::NewPattern(const nsTArray<nsString>& aFamilies, - const gfxFontStyle& aFontStyle, - const char *aLang) -{ - static const char* sFontconfigGenerics[] = - { "sans-serif", "serif", "monospace", "fantasy", "cursive" }; - - nsAutoRef<FcPattern> pattern(FcPatternCreate()); - if (!pattern) - return nsReturnRef<FcPattern>(); - - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size); - FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle)); - FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle)); - FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch)); - - if (aLang) { - AddString(pattern, FC_LANG, aLang); - } - - bool useWeakBinding = false; - for (uint32_t i = 0; i < aFamilies.Length(); ++i) { - NS_ConvertUTF16toUTF8 family(aFamilies[i]); - if (!useWeakBinding) { - AddString(pattern, FC_FAMILY, family.get()); - - // fontconfig generic families are typically implemented with weak - // aliases (so that the preferred font depends on language). - // However, this would give them lower priority than subsequent - // non-generic families in the list. To ensure that subsequent - // families do not have a higher priority, they are given weak - // bindings. - for (uint32_t g = 0; - g < ArrayLength(sFontconfigGenerics); - ++g) { - if (0 == FcStrCmpIgnoreCase(ToFcChar8(sFontconfigGenerics[g]), - ToFcChar8(family.get()))) { - useWeakBinding = true; - break; - } - } - } else { - AddWeakString(pattern, FC_FAMILY, family.get()); - } - } - - return pattern.out(); -} - -gfxFontconfigUtils::gfxFontconfigUtils() - : mFontsByFamily(32) - , mFontsByFullname(32) - , mLangSupportTable(32) - , mLastConfig(nullptr) -#ifdef MOZ_BUNDLED_FONTS - , mBundledFontsInitialized(false) -#endif -{ - UpdateFontListInternal(); -} - -nsresult -gfxFontconfigUtils::GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray<nsString>& aListOfFonts) -{ - aListOfFonts.Clear(); - - nsTArray<nsCString> fonts; - nsresult rv = GetFontListInternal(fonts, aLangGroup); - if (NS_FAILED(rv)) - return rv; - - for (uint32_t i = 0; i < fonts.Length(); ++i) { - aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(fonts[i])); - } - - aListOfFonts.Sort(); - - int32_t serif = 0, sansSerif = 0, monospace = 0; - - // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and - // "monospace", slightly different from CSS's 5. - if (aGenericFamily.IsEmpty()) - serif = sansSerif = monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("serif")) - serif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif")) - sansSerif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("monospace")) - monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") || - aGenericFamily.LowerCaseEqualsLiteral("fantasy")) - serif = sansSerif = 1; - else - NS_NOTREACHED("unexpected CSS generic font family"); - - // The first in the list becomes the default in - // FontBuilder.readFontSelection() if the preference-selected font is not - // available, so put system configured defaults first. - if (monospace) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace")); - if (sansSerif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif")); - if (serif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif")); - - return NS_OK; -} - -struct MozLangGroupData { - nsIAtom* const& mozLangGroup; - const char *defaultLang; -}; - -const MozLangGroupData MozLangGroups[] = { - { nsGkAtoms::x_western, "en" }, - { nsGkAtoms::x_cyrillic, "ru" }, - { nsGkAtoms::x_devanagari, "hi" }, - { nsGkAtoms::x_tamil, "ta" }, - { nsGkAtoms::x_armn, "hy" }, - { nsGkAtoms::x_beng, "bn" }, - { nsGkAtoms::x_cans, "iu" }, - { nsGkAtoms::x_ethi, "am" }, - { nsGkAtoms::x_geor, "ka" }, - { nsGkAtoms::x_gujr, "gu" }, - { nsGkAtoms::x_guru, "pa" }, - { nsGkAtoms::x_khmr, "km" }, - { nsGkAtoms::x_knda, "kn" }, - { nsGkAtoms::x_mlym, "ml" }, - { nsGkAtoms::x_orya, "or" }, - { nsGkAtoms::x_sinh, "si" }, - { nsGkAtoms::x_telu, "te" }, - { nsGkAtoms::x_tibt, "bo" }, - { nsGkAtoms::Unicode, 0 }, -}; - -static bool -TryLangForGroup(const nsACString& aOSLang, nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. - // aOSLang is in the form "language[_territory][.codeset][@modifier]". - // fontconfig takes languages in the form "language-territory". - // nsILanguageAtomService takes languages in the form language-subtag, - // where subtag may be a territory. fontconfig and nsILanguageAtomService - // handle case-conversion for us. - const char *pos, *end; - aOSLang.BeginReading(pos); - aOSLang.EndReading(end); - aFcLang->Truncate(); - while (pos < end) { - switch (*pos) { - case '.': - case '@': - end = pos; - break; - case '_': - aFcLang->Append('-'); - break; - default: - aFcLang->Append(*pos); - } - ++pos; - } - - nsIAtom *atom = - gLangService->LookupLanguage(*aFcLang); - - return atom == aLangGroup; -} - -/* static */ void -gfxFontconfigUtils::GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - NS_PRECONDITION(aFcLang != nullptr, "aFcLang must not be NULL"); - - const MozLangGroupData *langGroup = nullptr; - - for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) { - if (aLangGroup == MozLangGroups[i].mozLangGroup) { - langGroup = &MozLangGroups[i]; - break; - } - } - - if (!langGroup) { - // Not a special mozilla language group. - // Use aLangGroup as a language code. - aLangGroup->ToUTF8String(*aFcLang); - return; - } - - // Check the environment for the users preferred language that corresponds - // to this langGroup. - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - - if (gLangService) { - const char *languages = getenv("LANGUAGE"); - if (languages) { - const char separator = ':'; - - for (const char *pos = languages; true; ++pos) { - if (*pos == '\0' || *pos == separator) { - if (languages < pos && - TryLangForGroup(Substring(languages, pos), - aLangGroup, aFcLang)) - return; - - if (*pos == '\0') - break; - - languages = pos + 1; - } - } - } - const char *ctype = setlocale(LC_CTYPE, nullptr); - if (ctype && - TryLangForGroup(nsDependentCString(ctype), aLangGroup, aFcLang)) - return; - } - - if (langGroup->defaultLang) { - aFcLang->Assign(langGroup->defaultLang); - } else { - aFcLang->Truncate(); - } -} - -nsresult -gfxFontconfigUtils::GetFontListInternal(nsTArray<nsCString>& aListOfFonts, - nsIAtom *aLangGroup) -{ - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *fs = nullptr; - nsresult rv = NS_ERROR_FAILURE; - - aListOfFonts.Clear(); - - pat = FcPatternCreate(); - if (!pat) - goto end; - - os = FcObjectSetBuild(FC_FAMILY, nullptr); - if (!os) - goto end; - - // take the pattern and add the lang group to it - if (aLangGroup) { - AddLangGroup(pat, aLangGroup); - } - - fs = FcFontList(nullptr, pat, os); - if (!fs) - goto end; - - for (int i = 0; i < fs->nfont; i++) { - char *family; - - if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &family) != FcResultMatch) - { - continue; - } - - // Remove duplicates... - nsAutoCString strFamily(family); - if (aListOfFonts.Contains(strFamily)) - continue; - - aListOfFonts.AppendElement(strFamily); - } - - rv = NS_OK; - - end: - if (NS_FAILED(rv)) - aListOfFonts.Clear(); - - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (fs) - FcFontSetDestroy(fs); - - return rv; -} - -nsresult -gfxFontconfigUtils::UpdateFontList() -{ - return UpdateFontListInternal(true); -} - -nsresult -gfxFontconfigUtils::UpdateFontListInternal(bool aForce) -{ - if (!aForce) { - // This checks periodically according to fontconfig's configured - // <rescan> interval. - FcInitBringUptoDate(); - } else if (!FcConfigUptoDate(nullptr)) { // check now with aForce - mLastConfig = nullptr; - FcInitReinitialize(); - } - - // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config - // before destroying the old config, so the only way that we'd miss an - // update is if fontconfig did more than one update and the memory for the - // most recent config happened to be at the same location as the original - // config. - FcConfig *currentConfig = FcConfigGetCurrent(); - if (currentConfig == mLastConfig) - return NS_OK; - -#ifdef MOZ_BUNDLED_FONTS - ActivateBundledFonts(); -#endif - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(currentConfig, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(currentConfig, FcSetApplication) -#endif - }; - - mFontsByFamily.Clear(); - mFontsByFullname.Clear(); - mLangSupportTable.Clear(); - - // Record the existing font families - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { // the application set might not exist - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcChar8 *family; - for (int v = 0; - FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch; - ++v) { - FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family); - if (entry) { - bool added = entry->AddFont(font); - - if (!entry->mKey) { - // The reference to the font pattern keeps the pointer - // to string for the key valid. If adding the font - // failed then the entry must be removed. - if (added) { - entry->mKey = family; - } else { - mFontsByFamily.RemoveEntry(entry); - } - } - } - } - } - } - - mLastConfig = currentConfig; - return NS_OK; -} - -nsresult -gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) -{ - aFamilyName.Truncate(); - - // The fontconfig has generic family names in the font list. - if (aFontName.EqualsLiteral("serif") || - aFontName.EqualsLiteral("sans-serif") || - aFontName.EqualsLiteral("monospace")) { - aFamilyName.Assign(aFontName); - return NS_OK; - } - - nsresult rv = UpdateFontListInternal(); - if (NS_FAILED(rv)) - return rv; - - NS_ConvertUTF16toUTF8 fontname(aFontName); - - // return empty string if no such family exists - if (!IsExistingFamily(fontname)) - return NS_OK; - - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *givenFS = nullptr; - nsTArray<nsCString> candidates; - FcFontSet *candidateFS = nullptr; - rv = NS_ERROR_FAILURE; - - pat = FcPatternCreate(); - if (!pat) - goto end; - - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)fontname.get()); - - os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, nullptr); - if (!os) - goto end; - - givenFS = FcFontList(nullptr, pat, os); - if (!givenFS) - goto end; - - // The first value associated with a FC_FAMILY property is the family - // returned by GetFontList(), so use this value if appropriate. - - // See if there is a font face with first family equal to the given family. - for (int i = 0; i < givenFS->nfont; ++i) { - char *firstFamily; - if (FcPatternGetString(givenFS->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &firstFamily) != FcResultMatch) - continue; - - nsDependentCString first(firstFamily); - if (!candidates.Contains(first)) { - candidates.AppendElement(first); - - if (fontname.Equals(first)) { - aFamilyName.Assign(aFontName); - rv = NS_OK; - goto end; - } - } - } - - // See if any of the first family names represent the same set of font - // faces as the given family. - for (uint32_t j = 0; j < candidates.Length(); ++j) { - FcPatternDel(pat, FC_FAMILY); - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)candidates[j].get()); - - candidateFS = FcFontList(nullptr, pat, os); - if (!candidateFS) - goto end; - - if (candidateFS->nfont != givenFS->nfont) - continue; - - bool equal = true; - for (int i = 0; i < givenFS->nfont; ++i) { - if (!FcPatternEqual(candidateFS->fonts[i], givenFS->fonts[i])) { - equal = false; - break; - } - } - if (equal) { - AppendUTF8toUTF16(candidates[j], aFamilyName); - rv = NS_OK; - goto end; - } - } - - // No match found; return empty string. - rv = NS_OK; - - end: - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (givenFS) - FcFontSetDestroy(givenFS); - if (candidateFS) - FcFontSetDestroy(candidateFS); - - return rv; -} - -bool -gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName) -{ - return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nullptr; -} - -const nsTArray< nsCountedRef<FcPattern> >& -gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName) -{ - FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -// Fontconfig only provides a fullname property for fonts in formats with SFNT -// wrappers. For other font formats (including PCF and PS Type 1), a fullname -// must be generated from the family and style properties. Only the first -// family and style is checked, but that should be OK, as I don't expect -// non-SFNT fonts to have multiple families or styles. -bool -gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname) -{ - FcChar8 *family; - if (FcPatternGetString(aFont, FC_FAMILY, 0, &family) != FcResultMatch) - return false; - - aFullname->Truncate(); - aFullname->Append(ToCString(family)); - - FcChar8 *style; - if (FcPatternGetString(aFont, FC_STYLE, 0, &style) == FcResultMatch && - strcmp(ToCString(style), "Regular") != 0) { - aFullname->Append(' '); - aFullname->Append(ToCString(style)); - } - - return true; -} - -bool -gfxFontconfigUtils::FontsByFullnameEntry::KeyEquals(KeyTypePointer aKey) const -{ - const FcChar8 *key = mKey; - // If mKey is nullptr, key comes from the style and family of the first - // font. - nsAutoCString fullname; - if (!key) { - NS_ASSERTION(mFonts.Length(), "No font in FontsByFullnameEntry!"); - GetFullnameFromFamilyAndStyle(mFonts[0], &fullname); - - key = ToFcChar8(fullname); - } - - return FcStrCmpIgnoreCase(aKey, key) == 0; -} - -void -gfxFontconfigUtils::AddFullnameEntries() -{ - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - // Record the existing font families - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - int v = 0; - FcChar8 *fullname; - while (FcPatternGetString(font, - FC_FULLNAME, v, &fullname) == FcResultMatch) { - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(fullname); - if (entry) { - // entry always has space for one font, so the first - // AddFont will always succeed, and so the entry will - // always have a font from which to obtain the key. - bool added = entry->AddFont(font); - // The key may be nullptr either if this is the first - // font, or if the first font does not have a fullname - // property, and so the key is obtained from the font. - // Set the key in both cases. The check that AddFont - // succeeded is required for the second case. - if (!entry->mKey && added) { - entry->mKey = fullname; - } - } - - ++v; - } - - // Fontconfig does not provide a fullname property for all fonts. - if (v == 0) { - nsAutoCString name; - if (!GetFullnameFromFamilyAndStyle(font, &name)) - continue; - - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(ToFcChar8(name)); - if (entry) { - entry->AddFont(font); - // Either entry->mKey has been set for a previous font or it - // remains nullptr to indicate that the key is obtained from - // the first font. - } - } - } - } -} - -const nsTArray< nsCountedRef<FcPattern> >& -gfxFontconfigUtils::GetFontsForFullname(const FcChar8 *aFullname) -{ - if (mFontsByFullname.Count() == 0) { - AddFullnameEntries(); - } - - FontsByFullnameEntry *entry = mFontsByFullname.GetEntry(aFullname); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -static FcLangResult -CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) { - FcLangResult result = FcLangDifferentLang; - for (uint32_t i = 0; ; ++i) { - FcChar8 a = FcToLower(aLangA[i]); - FcChar8 b = FcToLower(aLangB[i]); - - if (a != b) { - if ((a == '\0' && b == '-') || (a == '-' && b == '\0')) - return FcLangDifferentCountry; - - return result; - } - if (a == '\0') - return FcLangEqual; - - if (a == '-') { - result = FcLangDifferentCountry; - } - } -} - -/* static */ -FcLangResult -gfxFontconfigUtils::GetLangSupport(FcPattern *aFont, const FcChar8 *aLang) -{ - // When fontconfig builds a pattern for a system font, it will set a - // single LangSet property value for the font. That value may be removed - // and additional string values may be added through FcConfigSubsitute - // with FcMatchScan. Values that are neither LangSet nor string are - // considered errors in fontconfig sort and match functions. - // - // If no string nor LangSet value is found, then either the font is a - // system font and the LangSet has been removed through FcConfigSubsitute, - // or the font is a web font and its language support is unknown. - // Returning FcLangDifferentLang for these fonts ensures that this font - // will not be assumed to satisfy the language, and so language will be - // prioritized in sorting fallback fonts. - FcValue value; - FcLangResult best = FcLangDifferentLang; - for (int v = 0; - FcPatternGet(aFont, FC_LANG, v, &value) == FcResultMatch; - ++v) { - - FcLangResult support; - switch (value.type) { - case FcTypeLangSet: - support = FcLangSetHasLang(value.u.l, aLang); - break; - case FcTypeString: - support = CompareLangString(value.u.s, aLang); - break; - default: - // error. continue to see if there is a useful value. - continue; - } - - if (support < best) { // lower is better - if (support == FcLangEqual) - return support; - best = support; - } - } - - return best; -} - -gfxFontconfigUtils::LangSupportEntry * -gfxFontconfigUtils::GetLangSupportEntry(const FcChar8 *aLang, bool aWithFonts) -{ - // Currently any unrecognized languages from documents will be converted - // to x-unicode by nsILanguageAtomService, so there is a limit on the - // langugages that will be added here. Reconsider when/if document - // languages are passed to this routine. - - LangSupportEntry *entry = mLangSupportTable.PutEntry(aLang); - if (!entry) - return nullptr; - - FcLangResult best = FcLangDifferentLang; - - if (!entry->IsKeyInitialized()) { - entry->InitKey(aLang); - } else { - // mSupport is already initialized. - if (!aWithFonts) - return entry; - - best = entry->mSupport; - // If there is support for this language, an empty font list indicates - // that the list hasn't been initialized yet. - if (best == FcLangDifferentLang || entry->mFonts.Length() > 0) - return entry; - } - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - AutoTArray<FcPattern*,100> fonts; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcLangResult support = GetLangSupport(font, aLang); - - if (support < best) { // lower is better - best = support; - if (aWithFonts) { - fonts.Clear(); - } else if (best == FcLangEqual) { - break; - } - } - - // The font list in the LangSupportEntry is expected to be used - // only when no default fonts support the language. There would - // be a large number of fonts in entries for languages using Latin - // script but these do not need to be created because default - // fonts already support these languages. - if (aWithFonts && support != FcLangDifferentLang && - support == best) { - fonts.AppendElement(font); - } - } - } - - entry->mSupport = best; - if (aWithFonts) { - if (fonts.Length() != 0) { - entry->mFonts.AppendElements(fonts.Elements(), fonts.Length()); - } else if (best != FcLangDifferentLang) { - // Previously there was a font that supported this language at the - // level of entry->mSupport, but it has now disappeared. At least - // entry->mSupport needs to be recalculated, but this is an - // indication that the set of installed fonts has changed, so - // update all caches. - mLastConfig = nullptr; // invalidates caches - UpdateFontListInternal(true); - return GetLangSupportEntry(aLang, aWithFonts); - } - } - - return entry; -} - -FcLangResult -gfxFontconfigUtils::GetBestLangSupport(const FcChar8 *aLang) -{ - UpdateFontListInternal(); - - LangSupportEntry *entry = GetLangSupportEntry(aLang, false); - if (!entry) - return FcLangEqual; - - return entry->mSupport; -} - -const nsTArray< nsCountedRef<FcPattern> >& -gfxFontconfigUtils::GetFontsForLang(const FcChar8 *aLang) -{ - LangSupportEntry *entry = GetLangSupportEntry(aLang, true); - if (!entry) - return mEmptyPatternArray; - - return entry->mFonts; -} - -#ifdef MOZ_BUNDLED_FONTS - -void -gfxFontconfigUtils::ActivateBundledFonts() -{ - if (!mBundledFontsInitialized) { - mBundledFontsInitialized = true; - nsCOMPtr<nsIFile> localDir; - nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)); - if (NS_FAILED(rv)) { - return; - } - if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) { - return; - } - bool isDir; - if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) { - return; - } - if (NS_FAILED(localDir->GetNativePath(mBundledFontsPath))) { - return; - } - } - if (!mBundledFontsPath.IsEmpty()) { - FcConfigAppFontAddDir(nullptr, (const FcChar8*)mBundledFontsPath.get()); - } -} - -#endif - -gfxFontconfigFontBase::gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, - FcPattern *aPattern, - gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) - , mPattern(aPattern) -{ -} - diff --git a/gfx/thebes/gfxFontconfigUtils.h b/gfx/thebes/gfxFontconfigUtils.h index eee69e4816..3f502c1243 100644 --- a/gfx/thebes/gfxFontconfigUtils.h +++ b/gfx/thebes/gfxFontconfigUtils.h @@ -8,11 +8,7 @@ #include "gfxPlatform.h" -#include "mozilla/MathAlgorithms.h" #include "nsAutoRef.h" -#include "nsTArray.h" -#include "nsTHashtable.h" -#include "nsISupportsImpl.h" #include "gfxFT2FontBase.h" #include <fontconfig/fontconfig.h> @@ -40,285 +36,14 @@ public: static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } }; -class gfxIgnoreCaseCStringComparator -{ - public: - bool Equals(const nsACString& a, const nsACString& b) const - { - return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); - } - - bool LessThan(const nsACString& a, const nsACString& b) const - { - return a < b; - } -}; - -class gfxFontconfigUtils { -public: - gfxFontconfigUtils(); - - static gfxFontconfigUtils* GetFontconfigUtils() { - if (!sUtils) - sUtils = new gfxFontconfigUtils(); - return sUtils; - } - - static void Shutdown(); - - nsresult GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray<nsString>& aListOfFonts); - - nsresult UpdateFontList(); - - nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); - - const nsTArray< nsCountedRef<FcPattern> >& - GetFontsForFamily(const FcChar8 *aFamilyName); - - const nsTArray< nsCountedRef<FcPattern> >& - GetFontsForFullname(const FcChar8 *aFullname); - - // Returns the best support that any font offers for |aLang|. - FcLangResult GetBestLangSupport(const FcChar8 *aLang); - // Returns the fonts offering this best level of support. - const nsTArray< nsCountedRef<FcPattern> >& - GetFontsForLang(const FcChar8 *aLang); - - // Retuns the language support for a fontconfig font pattern - static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); - - // Conversions between FcChar8*, which is unsigned char*, - // and (signed) char*, that check the type of the argument. - static const FcChar8 *ToFcChar8(const char *aCharPtr) - { - return reinterpret_cast<const FcChar8*>(aCharPtr); - } - static const FcChar8 *ToFcChar8(const nsCString& aCString) - { - return ToFcChar8(aCString.get()); - } - static const char *ToCString(const FcChar8 *aChar8Ptr) - { - return reinterpret_cast<const char*>(aChar8Ptr); - } - - static uint8_t FcSlantToThebesStyle(int aFcSlant); - static uint8_t GetThebesStyle(FcPattern *aPattern); // slant - static uint16_t GetThebesWeight(FcPattern *aPattern); - static int16_t GetThebesStretch(FcPattern *aPattern); - - static int GetFcSlant(const gfxFontStyle& aFontStyle); - // Returns a precise FC_WEIGHT from |aBaseWeight|, - // which is a CSS absolute weight / 100. - static int FcWeightForBaseWeight(int8_t aBaseWeight); - - static int FcWidthForThebesStretch(int16_t aStretch); - - static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname); - - // This doesn't consider which faces exist, and so initializes the pattern - // using a guessed weight, and doesn't consider sizeAdjust. - static nsReturnRef<FcPattern> - NewPattern(const nsTArray<nsString>& aFamilies, - const gfxFontStyle& aFontStyle, const char *aLang); - - /** - * @param aLangGroup [in] a Mozilla langGroup. - * @param aFcLang [out] returns a language suitable for fontconfig - * matching |aLangGroup| or an empty string if no match is found. - */ - static void GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang); - -protected: - // Base class for hash table entries with case-insensitive FcChar8 - // string keys. - class FcStrEntryBase : public PLDHashEntryHdr { - public: - typedef const FcChar8 *KeyType; - typedef const FcChar8 *KeyTypePointer; - - static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } - // Case-insensitive hash. - // - // fontconfig always ignores case of ASCII characters in family - // names and languages, but treatment of whitespace in families is - // not consistent. FcFontSort and FcFontMatch ignore whitespace - // except for whitespace in the first character, while FcFontList - // and config subsitution tests require whitespace to match - // exactly. CSS 2.1 implies that whitespace is important in the - // font-family property. FcStrCmpIgnoreCase considers whitespace - // important. - static PLDHashNumber HashKey(const FcChar8 *aKey) { - uint32_t hash = 0; - for (const FcChar8 *c = aKey; *c != '\0'; ++c) { - hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); - } - return hash; - } - enum { ALLOW_MEMMOVE = true }; - }; - -public: - // Hash entry with a dependent const FcChar8* pointer to an external - // string for a key (and no data). The user must ensure that the string - // associated with the pointer is not destroyed. This entry type is - // useful for family name keys as the family name string is held in the - // font pattern. - class DepFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() must fill in mKey when nullptr. - // This provides a mechanism for the caller of PutEntry() to determine - // whether the entry has been initialized. - explicit DepFcStrEntry(KeyTypePointer aName) - : mKey(nullptr) { } - - DepFcStrEntry(const DepFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, mKey) == 0; - } - - const FcChar8 *mKey; - }; - - // Hash entry that uses a copy of an FcChar8 string to store the key. - // This entry type is useful for language keys, as languages are usually - // not stored as strings in font patterns. - class CopiedFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is void. - // The caller of PutEntry() must call InitKey() when IsKeyInitialized() - // returns false. This provides a mechanism for the caller of - // PutEntry() to determine whether the entry has been initialized. - explicit CopiedFcStrEntry(KeyTypePointer aName) { - mKey.SetIsVoid(true); - } - - CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; - } - - bool IsKeyInitialized() { return !mKey.IsVoid(); } - void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } - - private: - nsCString mKey; - }; - -protected: - class FontsByFcStrEntry : public DepFcStrEntry { - public: - explicit FontsByFcStrEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { - return mFonts; - } - private: - nsTArray< nsCountedRef<FcPattern> > mFonts; - }; - - // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for - // mFontsByFamily) except for two differences: - // - // * The font does not always contain a single string for the fullname, so - // the key is sometimes a combination of family and style. - // - // * There is usually only one font. - class FontsByFullnameEntry : public DepFcStrEntry { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() is must fill in mKey when adding - // the first font if the key is not derived from the family and style. - // If the key is derived from family and style, a font must be added. - explicit FontsByFullnameEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool KeyEquals(KeyTypePointer aKey) const; - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef<FcPattern> >& GetFonts() { - return mFonts; - } - - // Don't memmove the AutoTArray. - enum { ALLOW_MEMMOVE = false }; - private: - // There is usually only one font, but sometimes more. - AutoTArray<nsCountedRef<FcPattern>,1> mFonts; - }; - - class LangSupportEntry : public CopiedFcStrEntry { - public: - explicit LangSupportEntry(KeyTypePointer aName) - : CopiedFcStrEntry(aName) { } - - LangSupportEntry(const LangSupportEntry& toCopy) - : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } - - FcLangResult mSupport; - nsTArray< nsCountedRef<FcPattern> > mFonts; - }; - - static gfxFontconfigUtils* sUtils; - - bool IsExistingFamily(const nsCString& aFamilyName); - - nsresult GetFontListInternal(nsTArray<nsCString>& aListOfFonts, - nsIAtom *aLangGroup); - nsresult UpdateFontListInternal(bool aForce = false); - - void AddFullnameEntries(); - - LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, - bool aWithFonts); - - // mFontsByFamily and mFontsByFullname contain entries only for families - // and fullnames for which there are fonts. - nsTHashtable<FontsByFcStrEntry> mFontsByFamily; - nsTHashtable<FontsByFullnameEntry> mFontsByFullname; - // mLangSupportTable contains an entry for each language that has been - // looked up through GetLangSupportEntry, even when the language is not - // supported. - nsTHashtable<LangSupportEntry> mLangSupportTable; - const nsTArray< nsCountedRef<FcPattern> > mEmptyPatternArray; - - FcConfig *mLastConfig; - -#ifdef MOZ_BUNDLED_FONTS - void ActivateBundledFonts(); - - nsCString mBundledFontsPath; - bool mBundledFontsInitialized; -#endif -}; - class gfxFontconfigFontBase : public gfxFT2FontBase { public: gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, FcPattern *aPattern, gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); + const gfxFontStyle *aFontStyle) + : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) + , mPattern(aPattern) { } virtual FontType GetType() const override { return FONT_TYPE_FONTCONFIG; } virtual FcPattern *GetPattern() const { return mPattern; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 7ec9139c0a..0fc596e828 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -83,10 +83,6 @@ #include "GLContextProvider.h" #include "mozilla/gfx/Logging.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef USE_SKIA # ifdef __GNUC__ # pragma GCC diagnostic push @@ -616,16 +612,9 @@ gfxPlatform::Init() nsresult rv; - bool usePlatformFontList = true; -#if defined(MOZ_WIDGET_GTK) - usePlatformFontList = gfxPlatformGtk::UseFcFontList(); -#endif - - if (usePlatformFontList) { - rv = gfxPlatformFontList::Init(); - if (NS_FAILED(rv)) { - NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList"); - } + rv = gfxPlatformFontList::Init(); + if (NS_FAILED(rv)) { + NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList"); } gPlatform->mScreenReferenceSurface = diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 73d1741922..d8bafac918 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -14,13 +14,13 @@ #include "gfx2DGlue.h" #include "gfxFcPlatformFontList.h" #include "gfxFontconfigUtils.h" -#include "gfxFontconfigFonts.h" #include "gfxConfig.h" #include "gfxContext.h" #include "gfxUserFontSet.h" #include "gfxUtils.h" #include "gfxFT2FontBase.h" #include "gfxPrefs.h" +#include "gfxTextRun.h" #include "VsyncSource.h" #include "mozilla/Atomics.h" #include "mozilla/Monitor.h" @@ -67,23 +67,14 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::unicode; -gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr; - #if (MOZ_WIDGET_GTK == 2) static cairo_user_data_key_t cairo_gdk_drawable_key; #endif -bool gfxPlatformGtk::sUseFcFontList = false; - gfxPlatformGtk::gfxPlatformGtk() { gtk_init(nullptr, nullptr); - sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled"); - if (!sUseFcFontList && !sFontconfigUtils) { - sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); - } - mMaxGenericSubstitutions = UNINITIALIZED_VALUE; #ifdef MOZ_X11 @@ -117,12 +108,6 @@ gfxPlatformGtk::gfxPlatformGtk() gfxPlatformGtk::~gfxPlatformGtk() { - if (!sUseFcFontList) { - gfxFontconfigUtils::Shutdown(); - sFontconfigUtils = nullptr; - gfxPangoFontGroup::Shutdown(); - } - #ifdef MOZ_X11 if (mCompositorDisplay) { XCloseDisplay(mCompositorDisplay); @@ -197,27 +182,17 @@ gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); - return NS_OK; - } - - return sFontconfigUtils->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); + gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, + aGenericFamily, + aListOfFonts); + return NS_OK; } nsresult gfxPlatformGtk::UpdateFontList() { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->UpdateFontList(); - return NS_OK; - } - - return sFontconfigUtils->UpdateFontList(); + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); + return NS_OK; } // xxx - this is ubuntu centric, need to go through other distros and flesh @@ -280,13 +255,9 @@ gfxPlatformGtk::CreatePlatformFontList() nsresult gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()-> - GetStandardFamilyName(aFontName, aFamilyName); - return NS_OK; - } - - return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName); + gfxPlatformFontList::PlatformFontList()-> + GetStandardFamilyName(aFontName, aFamilyName); + return NS_OK; } gfxFontGroup * @@ -296,13 +267,8 @@ gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList, gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) { - if (sUseFcFontList) { - return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, - aUserFontSet, aDevToCssSize); - } - - return new gfxPangoFontGroup(aFontFamilyList, aStyle, - aUserFontSet, aDevToCssSize); + return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, + aUserFontSet, aDevToCssSize); } gfxFontEntry* @@ -311,14 +277,9 @@ gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName, int16_t aStretch, uint8_t aStyle) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->LookupLocalFont(aFontName, aWeight, aStretch, - aStyle); - } - - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->LookupLocalFont(aFontName, aWeight, aStretch, + aStyle); } gfxFontEntry* @@ -329,16 +290,9 @@ gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName, const uint8_t* aFontData, uint32_t aLength) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->MakePlatformFont(aFontName, aWeight, aStretch, - aStyle, aFontData, aLength); - } - - // passing ownership of the font data to the new font entry - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, aLength); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->MakePlatformFont(aFontName, aWeight, aStretch, + aStyle, aFontData, aLength); } bool @@ -429,11 +383,9 @@ void gfxPlatformGtk::FontsPrefsChanged(const char *aPref) } mMaxGenericSubstitutions = UNINITIALIZED_VALUE; - if (sUseFcFontList) { - gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); - pfl->ClearGenericMappings(); - FlushFontAndWordCaches(); - } + gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); + pfl->ClearGenericMappings(); + FlushFontAndWordCaches(); } uint32_t gfxPlatformGtk::MaxGenericSubstitions() diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 22ed4b08fd..cfaca45074 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -111,8 +111,6 @@ public: } #endif - static bool UseFcFontList() { return sUseFcFontList; } - bool UseImageOffscreenSurfaces(); virtual gfxImageFormat GetOffscreenFormat() override; @@ -154,10 +152,6 @@ private: #ifdef MOZ_X11 Display* mCompositorDisplay; #endif - - // xxx - this will be removed once the new fontconfig platform font list - // replaces gfxPangoFontGroup - static bool sUseFcFontList; }; #endif /* GFX_PLATFORM_GTK_H */ diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 438f6f61ae..100af6da7b 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -26,10 +26,6 @@ #include "mozilla/gfx/Logging.h" // for gfxCriticalError #include "mozilla/UniquePtr.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef XP_WIN #include "gfxWindowsPlatform.h" #endif @@ -1599,7 +1595,6 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, , mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)) , mLastPrefFirstFont(false) , mSkipDrawing(false) - , mSkipUpdateUserFonts(false) { // We don't use SetUserFontSet() here, as we want to unconditionally call // BuildFontList() rather than only do UpdateUserFonts() if it changed. @@ -1616,14 +1611,6 @@ gfxFontGroup::BuildFontList() { bool enumerateFonts = true; -#if defined(MOZ_WIDGET_GTK) - // xxx - eliminate this once gfxPangoFontGroup is no longer needed - enumerateFonts = gfxPlatformGtk::UseFcFontList(); -#endif - if (!enumerateFonts) { - return; - } - // initialize fonts in the font family list AutoTArray<gfxFontFamily*,10> fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); @@ -2338,7 +2325,7 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, "don't call InitScriptRun with aborted shaping state"); // confirm the load state of userfonts in the list - if (!mSkipUpdateUserFonts && mUserFontSet && + if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) { UpdateUserFonts(); } @@ -3076,8 +3063,6 @@ gfxFontGroup::GetRebuildGeneration() return mUserFontSet->GetRebuildGeneration(); } -// note: gfxPangoFontGroup overrides UpdateUserFonts, such that -// BuildFontList is never used void gfxFontGroup::UpdateUserFonts() { diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 2ef835f189..8189861756 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -1108,9 +1108,6 @@ protected: // download to complete (or fallback // timer to fire) - // xxx - gfxPangoFontGroup skips UpdateUserFonts - bool mSkipUpdateUserFonts; - /** * Textrun creation short-cuts for special cases where we don't need to * call a font shaper to generate glyphs. diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 585bd14d02..4b487552cc 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -926,32 +926,6 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName, } } -gfxUserFontEntry* -gfxUserFontSet::FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont) -{ - aWaitForUserFont = false; - gfxFontEntry* fe = aFamily->FindFontForStyle(aFontStyle, aNeedsBold); - NS_ASSERTION(!fe || fe->mIsUserFontContainer, - "should only have userfont entries in userfont families"); - if (!fe) { - return nullptr; - } - - gfxUserFontEntry* userFontEntry = static_cast<gfxUserFontEntry*>(fe); - - // start the load if it hasn't been loaded - userFontEntry->Load(); - if (userFontEntry->GetPlatformFontEntry()) { - return userFontEntry; - } - - aWaitForUserFont = userFontEntry->WaitForUserFont(); - return nullptr; -} - void gfxUserFontSet::IncrementGeneration(bool aIsRebuild) { diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 896c6951e9..3a13573ac2 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -248,14 +248,6 @@ public: // Look up names in a fontlist and return true if any are in the set bool ContainsUserFontSetFonts(const mozilla::FontFamilyList& aFontList) const; - // Lookup a font entry for a given style, returns null if not loaded. - // aFamily must be a family returned by our LookupFamily method. - // (only used by gfxPangoFontGroup for now) - gfxUserFontEntry* FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont); - // check whether the given source is allowed to be loaded; // returns the Principal (for use in the key when caching the loaded font), // and whether the load should bypass the cache (force-reload). diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 2d4dc41a40..036df875cf 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -76,7 +76,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': ] elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: EXPORTS += [ - 'gfxFontconfigFonts.h', 'gfxFT2FontBase.h', 'gfxGdkNativeRenderer.h', 'gfxPlatformGtk.h', @@ -87,8 +86,6 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: ] SOURCES += [ 'gfxFcPlatformFontList.cpp', - 'gfxFontconfigFonts.cpp', - 'gfxFontconfigUtils.cpp', 'gfxFT2FontBase.cpp', 'gfxFT2Utils.cpp', 'gfxGdkNativeRenderer.cpp', |