gfx/thebes/gfxPangoFonts.cpp

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

mercurial