author Jonathan Kew <>
Tue, 12 Apr 2016 07:06:22 +0100
changeset 325830 976db6fcfed77d4ac4626ab8cbb6a25213232711
parent 320982 84aba71492334d548490820649fb8828ba38161e
child 325831 c9962404eb5dfc4c8fed45a1fc964072c1a783e6
permissions -rw-r--r--
Bug 1245811 - part 1 (based on patch by Andrew Comminos) - Replace gfxPlatformFontList::FindFamily with FindAndAddFamilies to allow for the possibility of the implementation returning multiple font families (e.g. when fontconfig has 'prefer' aliases). r=karlt a=ritu

/* -*- 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 */


#include "gfxFont.h"
#include "gfxFontEntry.h"
#include "gfxFT2FontBase.h"
#include "gfxPlatformFontList.h"
#include "mozilla/mozalloc.h"

#include <fontconfig/fontconfig.h>
#include "ft2build.h"
#include FT_FREETYPE_H
#include <cairo.h>
#include <cairo-ft.h>

#include "gfxFontconfigUtils.h" // xxx - only for nsAutoRefTraits<FcPattern>, etc.

template <>
class nsAutoRefTraits<FcObjectSet> : public nsPointerRefTraits<FcObjectSet>
    static void Release(FcObjectSet *ptr) { FcObjectSetDestroy(ptr); }

template <>
class nsAutoRefTraits<FcConfig> : public nsPointerRefTraits<FcConfig>
    static void Release(FcConfig *ptr) { FcConfigDestroy(ptr); }
    static void AddRef(FcConfig *ptr) { FcConfigReference(ptr); }

// Helper classes used for clearning out user font data when cairo font
// face is destroyed. Since multiple faces may use the same data, be
// careful to assure that the data is only cleared out when all uses
// expire. The font entry object contains a refptr to FTUserFontData and
// each cairo font created from that font entry contains a
// FTUserFontDataRef with a refptr to that same FTUserFontData object.

class FTUserFontData {

    explicit FTUserFontData(FT_Face aFace, const uint8_t* aData)
        : mFace(aFace), mFontData(aData)

    const uint8_t *FontData() const { return mFontData; }

        if (mFontData) {

    FT_Face        mFace;
    const uint8_t *mFontData;

class FTUserFontDataRef {
    explicit FTUserFontDataRef(FTUserFontData *aUserFontData)
        : mUserFontData(aUserFontData)

    static void Destroy(void* aData) {
        FTUserFontDataRef* aUserFontDataRef =
        delete aUserFontDataRef;

    RefPtr<FTUserFontData> mUserFontData;

// The names for the font entry and font classes should really
// the common 'Fc' abbreviation but the gfxPangoFontGroup code already
// defines versions of these, so use the verbose name for now.

class gfxFontconfigFontEntry : public gfxFontEntry {
    // used for system fonts with explicit patterns
    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                    FcPattern* aFontPattern);

    // used for data fonts where the fontentry takes ownership
    // of the font data and the FT_Face
    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                    uint16_t aWeight,
                                    int16_t aStretch,
                                    uint8_t aStyle,
                                    const uint8_t *aData,
                                    FT_Face aFace);

    // used for @font-face local system fonts with explicit patterns
    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                    FcPattern* aFontPattern,
                                    uint16_t aWeight,
                                    int16_t aStretch,
                                    uint8_t aStyle);

    FcPattern* GetPattern() { return mFontPattern; }

    bool SupportsLangGroup(nsIAtom *aLangGroup) const override;

    nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
    bool TestCharacterMap(uint32_t aCh) override;

    hb_blob_t* GetFontTable(uint32_t aTableTag) override;

    void ForgetHBFace() override;
    void ReleaseGrFace(gr_face* aFace) override;

    virtual ~gfxFontconfigFontEntry();

    gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                bool aNeedsBold) override;

    // helper method for creating cairo font from pattern
    CreateScaledFont(FcPattern* aRenderPattern,
                     const gfxFontStyle *aStyle,
                     bool aNeedsBold);

    // override to pull data from FTFace
    virtual nsresult
    CopyFontTable(uint32_t aTableTag,
                  nsTArray<uint8_t>& aBuffer) override;

    // if HB or GR faces are gone, close down the FT_Face
    void MaybeReleaseFTFace();

    double GetAspect();

    // pattern for a single face of a family
    nsCountedRef<FcPattern> mFontPattern;

    // user font data, when needed
    RefPtr<FTUserFontData> mUserFontData;

    // FTFace - initialized when needed
    FT_Face   mFTFace;
    bool      mFTFaceInitialized;
    double    mAspect;

    // data font
    const uint8_t* mFontData;

class gfxFontconfigFontFamily : public gfxFontFamily {
    explicit gfxFontconfigFontFamily(const nsAString& aName) :
        gfxFontFamily(aName) { }

    void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) override;

    // Families are constructed initially with just references to patterns.
    // When necessary, these are enumerated within FindStyleVariations.
    void AddFontPattern(FcPattern* aFontPattern);

    virtual ~gfxFontconfigFontFamily() { }

    nsTArray<nsCountedRef<FcPattern> > mFontPatterns;

class gfxFontconfigFont : public gfxFT2FontBase {
    gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
                      gfxFontEntry *aFontEntry,
                      const gfxFontStyle *aFontStyle,
                      bool aNeedsBold);

#ifdef USE_SKIA
    virtual already_AddRefed<mozilla::gfx::GlyphRenderingOptions>
    GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) override;

    virtual ~gfxFontconfigFont();

class nsILanguageAtomService;

class gfxFcPlatformFontList : public gfxPlatformFontList {

    static gfxFcPlatformFontList* PlatformFontList() {
        return static_cast<gfxFcPlatformFontList*>(sPlatformFontList);

    // initialize font lists
    nsresult InitFontList() override;

    void GetFontList(nsIAtom *aLangGroup,
                     const nsACString& aGenericFamily,
                     nsTArray<nsString>& aListOfFonts) override;

    GetDefaultFont(const gfxFontStyle* aStyle) override;

    LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
                    int16_t aStretch, uint8_t aStyle) override;

    MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
                     int16_t aStretch,
                     uint8_t aStyle,
                     const uint8_t* aFontData,
                     uint32_t aLength) override;

    bool FindAndAddFamilies(const nsAString& aFamily,
                            nsTArray<gfxFontFamily*>* aOutput,
                            gfxFontStyle* aStyle = nullptr,
                            gfxFloat aDevToCssSize = 1.0) override;

    bool GetStandardFamilyName(const nsAString& aFontName,
                               nsAString& aFamilyName) override;

    FcConfig* GetLastConfig() const { return mLastConfig; }

    // override to use fontconfig lookup for generics
    void AddGenericFonts(mozilla::FontFamilyType aGenericType,
                         nsIAtom* aLanguage,
                         nsTArray<gfxFontFamily*>& aFamilyList) override;

    void ClearLangGroupPrefFonts() override;

    // clear out cached generic-lang ==> family-list mappings
    void ClearGenericMappings() {

    static FT_Library GetFTLibrary();

    virtual ~gfxFcPlatformFontList();

    // add all the font families found in a font set
    void AddFontSetFamilies(FcFontSet* aFontSet);

    // figure out which families fontconfig maps a generic to
    // (aGeneric assumed already lowercase)
    PrefFontList* FindGenericFamilies(const nsAString& aGeneric,
                                      nsIAtom* aLanguage);

    // are all pref font settings set to use fontconfig generics?
    bool PrefFontListsUseOnlyGenerics();

    static void CheckFontUpdates(nsITimer *aTimer, void *aThis);

    void ActivateBundledFonts();
    nsCString mBundledFontsPath;
    bool mBundledFontsInitialized;

    // to avoid enumerating all fonts, maintain a mapping of local font
    // names to family
                    FcPattern*> mLocalNames;

    // caching generic/lang ==> font family list
                    PrefFontList*> mGenericMappings;

    // caching family lookups as found by FindFamily after resolving substitutions
    nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mFcSubstituteCache;

    nsCOMPtr<nsITimer> mCheckFontUpdatesTimer;
    nsCountedRef<FcConfig> mLastConfig;

    // By default, font prefs under Linux are set to simply lookup
    // via fontconfig the appropriate font for serif/sans-serif/monospace.
    // Rather than check each time a font pref is used, check them all at startup
    // and set a boolean to flag the case that non-default user font prefs exist
    // Note: langGroup == x-math is handled separately
    bool mAlwaysUseFontconfigGenerics;

    static FT_Library sCairoFTLibrary;