LCOV - code coverage report
Current view: directory - gfx/thebes - gfxPangoFonts.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1122 4 0.4 %
Date: 2012-06-02 Functions: 122 1 0.8 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Foundation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Vladimir Vukicevic <vladimir@mozilla.com>
      23                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      24                 :  *   Behdad Esfahbod <behdad@gnome.org>
      25                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      26                 :  *   Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
      27                 :  *
      28                 :  * based on nsFontMetricsPango.cpp by
      29                 :  *   Christopher Blizzard <blizzard@mozilla.org>
      30                 :  *
      31                 :  * Alternatively, the contents of this file may be used under the terms of
      32                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      33                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      34                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      35                 :  * of those above. If you wish to allow use of your version of this file only
      36                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      37                 :  * use your version of this file under the terms of the MPL, indicate your
      38                 :  * decision by deleting the provisions above and replace them with the notice
      39                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      40                 :  * the provisions above, a recipient may use your version of this file under
      41                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      42                 :  *
      43                 :  * ***** END LICENSE BLOCK ***** */
      44                 : 
      45                 : #include "mozilla/Util.h"
      46                 : 
      47                 : #define PANGO_ENABLE_BACKEND
      48                 : #define PANGO_ENABLE_ENGINE
      49                 : 
      50                 : #include "prtypes.h"
      51                 : #include "prlink.h"
      52                 : #include "gfxTypes.h"
      53                 : 
      54                 : #include "nsTArray.h"
      55                 : 
      56                 : #include "gfxContext.h"
      57                 : #ifdef MOZ_WIDGET_GTK2
      58                 : #include "gfxPlatformGtk.h"
      59                 : #endif
      60                 : #ifdef MOZ_WIDGET_QT
      61                 : #include "gfxQtPlatform.h"
      62                 : #endif
      63                 : #include "gfxPangoFonts.h"
      64                 : #include "gfxFT2FontBase.h"
      65                 : #include "gfxFT2Utils.h"
      66                 : #include "harfbuzz/hb-unicode.h"
      67                 : #include "harfbuzz/hb-ot-tag.h"
      68                 : #include "gfxHarfBuzzShaper.h"
      69                 : #ifdef MOZ_GRAPHITE
      70                 : #include "gfxGraphiteShaper.h"
      71                 : #endif
      72                 : #include "nsUnicodeProperties.h"
      73                 : #include "nsUnicodeScriptCodes.h"
      74                 : #include "gfxFontconfigUtils.h"
      75                 : #include "gfxUserFontSet.h"
      76                 : #include "gfxAtoms.h"
      77                 : 
      78                 : #include <cairo.h>
      79                 : #include <cairo-ft.h>
      80                 : 
      81                 : #include <fontconfig/fcfreetype.h>
      82                 : #include <pango/pango.h>
      83                 : #include <pango/pangocairo.h>
      84                 : #include <pango/pango-modules.h>
      85                 : #include <pango/pangofc-fontmap.h>
      86                 : 
      87                 : #ifdef MOZ_WIDGET_GTK2
      88                 : #include <gdk/gdk.h>
      89                 : #endif
      90                 : 
      91                 : #include <math.h>
      92                 : 
      93                 : using namespace mozilla;
      94                 : using namespace mozilla::unicode;
      95                 : 
      96                 : #define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE)
      97                 : 
      98                 : #ifndef PANGO_VERSION_CHECK
      99                 : #define PANGO_VERSION_CHECK(x,y,z) 0
     100                 : #endif
     101                 : #ifndef PANGO_GLYPH_UNKNOWN_FLAG
     102                 : #define PANGO_GLYPH_UNKNOWN_FLAG ((PangoGlyph)0x10000000)
     103                 : #endif
     104                 : #ifndef PANGO_GLYPH_EMPTY
     105                 : #define PANGO_GLYPH_EMPTY           ((PangoGlyph)0)
     106                 : #endif
     107                 : // For g a PangoGlyph,
     108                 : #define IS_MISSING_GLYPH(g) ((g) & PANGO_GLYPH_UNKNOWN_FLAG)
     109                 : #define IS_EMPTY_GLYPH(g) ((g) == PANGO_GLYPH_EMPTY)
     110                 : 
     111                 : #define PRINTING_FC_PROPERTY "gfx.printing"
     112                 : 
     113                 : struct gfxPangoFcFont;
     114                 : 
     115                 : // Same as pango_units_from_double from Pango 1.16 (but not in older versions)
     116               0 : int moz_pango_units_from_double(double d) {
     117               0 :     return NS_lround(d * FLOAT_PANGO_SCALE);
     118                 : }
     119                 : 
     120                 : static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage);
     121                 : 
     122                 : static cairo_scaled_font_t *
     123                 : CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace);
     124                 : static void SetMissingGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8,
     125                 :                              PRUint32 aUTF8Length, PRUint32 *aUTF16Offset,
     126                 :                              gfxFont *aFont);
     127                 : 
     128                 : static PangoFontMap *gPangoFontMap;
     129                 : static PangoFontMap *GetPangoFontMap();
     130                 : static bool gUseFontMapProperty;
     131                 : 
     132                 : static FT_Library gFTLibrary;
     133                 : 
     134                 : template <class T>
     135               0 : class gfxGObjectRefTraits : public nsPointerRefTraits<T> {
     136                 : public:
     137               0 :     static void Release(T *aPtr) { g_object_unref(aPtr); }
     138                 :     static void AddRef(T *aPtr) { g_object_ref(aPtr); }
     139                 : };
     140                 : 
     141                 : template <>
     142               0 : class nsAutoRefTraits<PangoFont> : public gfxGObjectRefTraits<PangoFont> { };
     143                 : 
     144                 : template <>
     145                 : class nsAutoRefTraits<PangoCoverage>
     146               0 :     : public nsPointerRefTraits<PangoCoverage> {
     147                 : public:
     148               0 :     static void Release(PangoCoverage *aPtr) { pango_coverage_unref(aPtr); }
     149                 :     static void AddRef(PangoCoverage *aPtr) { pango_coverage_ref(aPtr); }
     150                 : };
     151                 : 
     152                 : 
     153                 : // FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97
     154                 : // and so fontconfig-2.3.0 (2005).
     155                 : #ifndef FC_FAMILYLANG
     156                 : #define FC_FAMILYLANG "familylang"
     157                 : #endif
     158                 : #ifndef FC_FULLNAME
     159                 : #define FC_FULLNAME "fullname"
     160                 : #endif
     161                 : 
     162                 : static PRFuncPtr
     163               0 : FindFunctionSymbol(const char *name)
     164                 : {
     165               0 :     PRLibrary *lib = nsnull;
     166               0 :     PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib);
     167               0 :     if (lib) {
     168               0 :         PR_UnloadLibrary(lib);
     169                 :     }
     170                 : 
     171               0 :     return result;
     172                 : }
     173                 : 
     174               0 : static bool HasChar(FcPattern *aFont, FcChar32 wc)
     175                 : {
     176               0 :     FcCharSet *charset = NULL;
     177               0 :     FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
     178                 : 
     179               0 :     return charset && FcCharSetHasChar(charset, wc);
     180                 : }
     181                 : 
     182                 : /**
     183                 :  * gfxFcFontEntry:
     184                 :  *
     185                 :  * An abstract base class of for gfxFontEntry implementations used by
     186                 :  * gfxFcFont and gfxUserFontSet.
     187                 :  */
     188                 : 
     189               0 : class gfxFcFontEntry : public gfxFontEntry {
     190                 : public:
     191                 :     // For all FontEntrys attached to gfxFcFonts, there will be only one
     192                 :     // pattern in this array.  This is always a font pattern, not a fully
     193                 :     // resolved pattern.  gfxFcFont only uses this to construct a PangoFont.
     194                 :     //
     195                 :     // FontEntrys for src:local() fonts in gfxUserFontSet may return more than
     196                 :     // one pattern.  (See comment in gfxUserFcFontEntry.)
     197               0 :     const nsTArray< nsCountedRef<FcPattern> >& GetPatterns()
     198                 :     {
     199               0 :         return mPatterns;
     200                 :     }
     201                 : 
     202                 :     bool ShouldUseHarfBuzz(PRInt32 aRunScript);
     203               0 :     void SkipHarfBuzz() { mSkipHarfBuzz = true; }
     204                 : 
     205               0 :     static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace)
     206                 :     {
     207                 :         return static_cast<gfxFcFontEntry*>
     208               0 :             (cairo_font_face_get_user_data(aFace, &sFontEntryKey));
     209                 :     }
     210                 : 
     211                 :     // override the default impl in gfxFontEntry because we don't organize
     212                 :     // gfxFcFontEntries in families; just read the name from fontconfig
     213                 :     virtual nsString FamilyName() const;
     214                 : 
     215                 :     // override the gfxFontEntry impl to read the name from fontconfig
     216                 :     // instead of trying to get the 'name' table, as we don't implement
     217                 :     // GetFontTable() here
     218                 :     virtual nsString RealFaceName();
     219                 : 
     220                 :     // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
     221               0 :     virtual bool TestCharacterMap(PRUint32 aCh)
     222                 :     {
     223               0 :         for (PRUint32 i = 0; i < mPatterns.Length(); ++i) {
     224               0 :             if (HasChar(mPatterns[i], aCh)) {
     225               0 :                 return true;
     226                 :             }
     227                 :         }
     228               0 :         return false;
     229                 :     }
     230                 : 
     231                 : protected:
     232               0 :     gfxFcFontEntry(const nsAString& aName)
     233                 :         : gfxFontEntry(aName),
     234               0 :           mSkipHarfBuzz(false), mSkipGraphiteCheck(false)
     235                 :     {
     236               0 :     }
     237                 : 
     238                 : #ifdef MOZ_GRAPHITE
     239                 :     virtual void CheckForGraphiteTables();
     240                 : #endif
     241                 : 
     242                 :     // One pattern is the common case and some subclasses rely on successful
     243                 :     // addition of the first element to the array.
     244                 :     nsAutoTArray<nsCountedRef<FcPattern>,1> mPatterns;
     245                 :     bool mSkipHarfBuzz;
     246                 :     bool mSkipGraphiteCheck;
     247                 : 
     248                 :     static cairo_user_data_key_t sFontEntryKey;
     249                 : };
     250                 : 
     251                 : cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
     252                 : 
     253                 : nsString
     254               0 : gfxFcFontEntry::FamilyName() const
     255                 : {
     256               0 :     if (mIsUserFont) {
     257                 :         // for user fonts, we want the name of the family
     258                 :         // as specified in the user font set
     259               0 :         return gfxFontEntry::FamilyName();
     260                 :     }
     261                 :     FcChar8 *familyname;
     262               0 :     if (!mPatterns.IsEmpty() &&
     263               0 :         FcPatternGetString(mPatterns[0],
     264               0 :                            FC_FAMILY, 0, &familyname) == FcResultMatch) {
     265               0 :         return NS_ConvertUTF8toUTF16((const char*)familyname);
     266                 :     }
     267               0 :     return gfxFontEntry::FamilyName();
     268                 : }
     269                 : 
     270                 : nsString
     271               0 : gfxFcFontEntry::RealFaceName()
     272                 : {
     273                 :     FcChar8 *name;
     274               0 :     if (!mPatterns.IsEmpty()) {
     275               0 :         if (FcPatternGetString(mPatterns[0],
     276               0 :                                FC_FULLNAME, 0, &name) == FcResultMatch) {
     277               0 :             return NS_ConvertUTF8toUTF16((const char*)name);
     278                 :         }
     279               0 :         if (FcPatternGetString(mPatterns[0],
     280               0 :                                FC_FAMILY, 0, &name) == FcResultMatch) {
     281               0 :             NS_ConvertUTF8toUTF16 result((const char*)name);
     282               0 :             if (FcPatternGetString(mPatterns[0],
     283               0 :                                    FC_STYLE, 0, &name) == FcResultMatch) {
     284               0 :                 result.AppendLiteral(" ");
     285               0 :                 AppendUTF8toUTF16((const char*)name, result);
     286                 :             }
     287               0 :             return result;
     288                 :         }
     289                 :     }
     290               0 :     return gfxFontEntry::RealFaceName();
     291                 : }
     292                 : 
     293                 : #ifdef MOZ_GRAPHITE
     294                 : void
     295               0 : gfxFcFontEntry::CheckForGraphiteTables()
     296                 : {
     297                 :     FcChar8 *capability;
     298                 :     mHasGraphiteTables =
     299               0 :         !mPatterns.IsEmpty() &&
     300               0 :         FcPatternGetString(mPatterns[0],
     301               0 :                            FC_CAPABILITY, 0, &capability) == FcResultMatch &&
     302               0 :         FcStrStr(capability, gfxFontconfigUtils::ToFcChar8("ttable:Silf"));
     303               0 : }
     304                 : #endif
     305                 : 
     306                 : bool
     307               0 : gfxFcFontEntry::ShouldUseHarfBuzz(PRInt32 aRunScript) {
     308               0 :     if (mSkipHarfBuzz ||
     309               0 :         !gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript))
     310                 :     {
     311               0 :         return false;
     312                 :     }
     313                 : 
     314               0 :     if (mSkipGraphiteCheck) {
     315               0 :         return true;
     316                 :     }
     317                 : 
     318                 :     // Check whether to fall back to Pango for Graphite shaping.
     319                 :     // pango-graphite checks for ttable:Silf.
     320                 :     FcChar8 *capability;
     321                 :     // FontEntries used at shaping have only one pattern.
     322               0 :     if (mPatterns.IsEmpty() ||
     323               0 :         FcPatternGetString(mPatterns[0],
     324               0 :                            FC_CAPABILITY, 0, &capability) == FcResultNoMatch ||
     325               0 :         !FcStrStr(capability, gfxFontconfigUtils::ToFcChar8("ttable:Silf")))
     326                 :     {
     327               0 :         mSkipGraphiteCheck = true;
     328               0 :         return true;
     329                 :     }
     330                 : 
     331                 :     // Mimicing gfxHarfBuzzShaper::ShapeWord
     332                 :     hb_script_t script = (aRunScript <= MOZ_SCRIPT_INHERITED) ?
     333                 :         HB_SCRIPT_LATIN :
     334               0 :         hb_script_t(GetScriptTagForCode(aRunScript));
     335                 : 
     336                 :     // Prefer HarfBuzz if the font also has support for OpenType shaping of
     337                 :     // this script.
     338               0 :     const FcChar8 otCapTemplate[] = "otlayout:XXXX";
     339                 :     FcChar8 otCap[NS_ARRAY_LENGTH(otCapTemplate)];
     340               0 :     memcpy(otCap, otCapTemplate, ArrayLength(otCapTemplate));
     341                 :     // Subtract 5, for 4 characters and NUL. 
     342               0 :     const PRUint32 scriptOffset = ArrayLength(otCapTemplate) - 5;
     343                 : 
     344                 :     hb_tag_t tags[2];
     345               0 :     hb_ot_tags_from_script(script, &tags[0], &tags[1]);
     346               0 :     for (int i = 0; i < 2; ++i) {
     347               0 :         hb_tag_t scriptTag = tags[i];
     348               0 :         if (scriptTag == HB_TAG('D','F','L','T')) { // e.g. HB_SCRIPT_UNKNOWN
     349               0 :             continue;
     350                 :         }
     351                 : 
     352                 :         // FcChar8 is unsigned so truncates appropriately.
     353               0 :         otCap[scriptOffset + 0] = scriptTag >> 24;
     354               0 :         otCap[scriptOffset + 1] = scriptTag >> 16;
     355               0 :         otCap[scriptOffset + 2] = scriptTag >> 8;
     356               0 :         otCap[scriptOffset + 3] = scriptTag;
     357               0 :         if (FcStrStr(capability, otCap)) {
     358               0 :             return true;
     359                 :         }
     360                 :     }
     361                 : 
     362               0 :     return false; // use Pango for Graphite
     363                 : }
     364                 : 
     365                 : /**
     366                 :  * gfxSystemFcFontEntry:
     367                 :  *
     368                 :  * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts,
     369                 :  * including those from regular family-name based font selection as well as
     370                 :  * those from src:local().
     371                 :  *
     372                 :  * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. 
     373                 :  */
     374                 : 
     375                 : class gfxSystemFcFontEntry : public gfxFcFontEntry {
     376                 : public:
     377                 :     // For memory efficiency, aFontPattern should be a font pattern,
     378                 :     // not a fully resolved pattern.
     379               0 :     gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
     380                 :                          FcPattern *aFontPattern,
     381                 :                          const nsAString& aName)
     382               0 :         : gfxFcFontEntry(aName), mFontFace(aFontFace)
     383                 :     {
     384               0 :         cairo_font_face_reference(mFontFace);
     385               0 :         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, NULL);
     386               0 :         mPatterns.AppendElement();
     387                 :         // mPatterns is an nsAutoTArray with 1 space always available, so the
     388                 :         // AppendElement always succeeds.
     389               0 :         mPatterns[0] = aFontPattern;
     390               0 :     }
     391                 : 
     392               0 :     ~gfxSystemFcFontEntry()
     393               0 :     {
     394               0 :         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, NULL, NULL);
     395               0 :         cairo_font_face_destroy(mFontFace);
     396               0 :     }
     397                 : private:
     398                 :     cairo_font_face_t *mFontFace;
     399                 : };
     400                 : 
     401                 : // A namespace for @font-face family names in FcPatterns so that fontconfig
     402                 : // aliases do not pick up families from @font-face rules and so that
     403                 : // fontconfig rules can distinguish between web fonts and platform fonts.
     404                 : // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
     405                 : #define FONT_FACE_FAMILY_PREFIX "@font-face:"
     406                 : 
     407                 : /**
     408                 :  * gfxUserFcFontEntry:
     409                 :  *
     410                 :  * An abstract class for objects in a gfxUserFontSet that can provide
     411                 :  * FcPattern* handles to fonts.
     412                 :  *
     413                 :  * Separate implementations of this class support local fonts from src:local()
     414                 :  * and web fonts from src:url().
     415                 :  */
     416                 : 
     417                 : // There is a one-to-one correspondence between gfxUserFcFontEntry objects and
     418                 : // @font-face rules, but sometimes a one-to-many correspondence between font
     419                 : // entries and font patterns.
     420                 : //
     421                 : // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions
     422                 : // provided a font-size descriptor to specify the sizes supported by the face,
     423                 : // but the "Editor's Draft 27 June 2008"
     424                 : // http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a
     425                 : // descriptor, and Mozilla does not recognize such a descriptor.
     426                 : //
     427                 : // Font face names used in src:local() also do not usually specify a size.
     428                 : //
     429                 : // PCF format fonts have each size in a different file, and each of these
     430                 : // files is referenced by its own pattern, but really these are each
     431                 : // different sizes of one face with one name.
     432                 : //
     433                 : // Multiple patterns in an entry also effectively deals with a set of
     434                 : // PostScript Type 1 font files that all have the same face name but are in
     435                 : // several files because of the limit on the number of glyphs in a Type 1 font
     436                 : // file.  (e.g. Computer Modern.)
     437                 : 
     438               0 : class gfxUserFcFontEntry : public gfxFcFontEntry {
     439                 : protected:
     440               0 :     gfxUserFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
     441                 :         // store the family name
     442               0 :         : gfxFcFontEntry(aProxyEntry.mFamily->Name())
     443                 :     {
     444               0 :         mItalic = aProxyEntry.mItalic;
     445               0 :         mWeight = aProxyEntry.mWeight;
     446               0 :         mStretch = aProxyEntry.mStretch;
     447               0 :         mIsUserFont = true;
     448               0 :     }
     449                 : 
     450                 :     // Helper function to change a pattern so that it matches the CSS style
     451                 :     // descriptors and so gets properly sorted in font selection.  This also
     452                 :     // avoids synthetic style effects being added by the renderer when the
     453                 :     // style of the font itself does not match the descriptor provided by the
     454                 :     // author.
     455                 :     void AdjustPatternToCSS(FcPattern *aPattern);
     456                 : };
     457                 : 
     458                 : void
     459               0 : gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
     460                 : {
     461               0 :     int fontWeight = -1;
     462               0 :     FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight);
     463               0 :     int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100);
     464               0 :     if (cssWeight != fontWeight) {
     465               0 :         FcPatternDel(aPattern, FC_WEIGHT);
     466               0 :         FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight);
     467                 :     }
     468                 : 
     469                 :     int fontSlant;
     470               0 :     FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant);
     471                 :     // gfxFontEntry doesn't understand the difference between oblique
     472                 :     // and italic.
     473               0 :     if (res != FcResultMatch ||
     474               0 :         IsItalic() != (fontSlant != FC_SLANT_ROMAN)) {
     475               0 :         FcPatternDel(aPattern, FC_SLANT);
     476                 :         FcPatternAddInteger(aPattern, FC_SLANT,
     477               0 :                             IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN);
     478                 :     }
     479                 : 
     480               0 :     int fontWidth = -1;
     481               0 :     FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth);
     482               0 :     int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch);
     483               0 :     if (cssWidth != fontWidth) {
     484               0 :         FcPatternDel(aPattern, FC_WIDTH);
     485               0 :         FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth);
     486                 :     }
     487                 : 
     488                 :     // Ensure that there is a fullname property (if there is a family
     489                 :     // property) so that fontconfig rules can identify the real name of the
     490                 :     // font, because the family property will be replaced.
     491                 :     FcChar8 *unused;
     492               0 :     if (FcPatternGetString(aPattern,
     493               0 :                            FC_FULLNAME, 0, &unused) == FcResultNoMatch) {
     494               0 :         nsCAutoString fullname;
     495               0 :         if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern,
     496                 :                                                               &fullname)) {
     497                 :             FcPatternAddString(aPattern, FC_FULLNAME,
     498               0 :                                gfxFontconfigUtils::ToFcChar8(fullname));
     499                 :         }
     500                 :     }
     501                 : 
     502               0 :     nsCAutoString family;
     503               0 :     family.Append(FONT_FACE_FAMILY_PREFIX);
     504               0 :     AppendUTF16toUTF8(Name(), family);
     505                 : 
     506               0 :     FcPatternDel(aPattern, FC_FAMILY);
     507               0 :     FcPatternDel(aPattern, FC_FAMILYLANG);
     508                 :     FcPatternAddString(aPattern, FC_FAMILY,
     509               0 :                        gfxFontconfigUtils::ToFcChar8(family));
     510               0 : }
     511                 : 
     512                 : /**
     513                 :  * gfxLocalFcFontEntry:
     514                 :  *
     515                 :  * An implementation of gfxUserFcFontEntry for local fonts from src:local().
     516                 :  *
     517                 :  * This class is used only in gfxUserFontSet and for providing FcPattern*
     518                 :  * handles to system fonts for font selection.  gfxFcFonts created from these
     519                 :  * patterns will use gfxSystemFcFontEntrys, which may be shared with
     520                 :  * gfxFcFonts from regular family-name based font selection.
     521                 :  */
     522                 : 
     523               0 : class gfxLocalFcFontEntry : public gfxUserFcFontEntry {
     524                 : public:
     525               0 :     gfxLocalFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
     526                 :                         const nsTArray< nsCountedRef<FcPattern> >& aPatterns)
     527               0 :         : gfxUserFcFontEntry(aProxyEntry)
     528                 :     {
     529               0 :         if (!mPatterns.SetCapacity(aPatterns.Length()))
     530               0 :             return; // OOM
     531                 : 
     532               0 :         for (PRUint32 i = 0; i < aPatterns.Length(); ++i) {
     533               0 :             FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i));
     534               0 :             if (!pattern)
     535               0 :                 return; // OOM
     536                 : 
     537               0 :             AdjustPatternToCSS(pattern);
     538                 : 
     539               0 :             mPatterns.AppendElement();
     540               0 :             mPatterns[i].own(pattern);
     541                 :         }
     542               0 :         mIsLocalUserFont = true;
     543                 :     }
     544                 : };
     545                 : 
     546                 : /**
     547                 :  * gfxDownloadedFcFontEntry:
     548                 :  *
     549                 :  * An implementation of gfxFcFontEntry for web fonts from src:url().
     550                 :  * 
     551                 :  * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t
     552                 :  * keeps a reference to the FontEntry to keep the font data alive.
     553                 :  */
     554                 : 
     555                 : class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry {
     556                 : public:
     557                 :     // This takes ownership of the face and its underlying data
     558               0 :     gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
     559                 :                              const PRUint8 *aData, FT_Face aFace)
     560               0 :         : gfxUserFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
     561                 :     {
     562               0 :         NS_PRECONDITION(aFace != NULL, "aFace is NULL!");
     563               0 :         InitPattern();
     564               0 :     }
     565                 : 
     566                 :     virtual ~gfxDownloadedFcFontEntry();
     567                 : 
     568                 :     // Returns true on success
     569                 :     bool SetCairoFace(cairo_font_face_t *aFace);
     570                 : 
     571                 :     // Returns a PangoCoverage owned by the FontEntry.  The caller must add a
     572                 :     // reference if it wishes to keep the PangoCoverage longer than the
     573                 :     // lifetime of the FontEntry.
     574                 :     PangoCoverage *GetPangoCoverage();
     575                 : 
     576                 : protected:
     577                 :     void InitPattern();
     578                 : 
     579                 :     // mFontData holds the data used to instantiate the FT_Face;
     580                 :     // this has to persist until we are finished with the face,
     581                 :     // then be released with NS_Free().
     582                 :     const PRUint8* mFontData;
     583                 : 
     584                 :     FT_Face mFace;
     585                 : 
     586                 :     // mPangoCoverage is the charset property of the pattern translated to a
     587                 :     // format that Pango understands.  A reference is kept here so that it can
     588                 :     // be shared by multiple PangoFonts (of different sizes).
     589                 :     nsAutoRef<PangoCoverage> mPangoCoverage;
     590                 : };
     591                 : 
     592                 : // A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
     593                 : static const char *kFontEntryFcProp = "-moz-font-entry";
     594                 : 
     595               0 : static FcBool AddDownloadedFontEntry(FcPattern *aPattern,
     596                 :                                      gfxDownloadedFcFontEntry *aFontEntry)
     597                 : {
     598                 :     FcValue value;
     599               0 :     value.type = FcTypeFTFace; // void* field of union
     600               0 :     value.u.f = aFontEntry;
     601                 : 
     602               0 :     return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse);
     603                 : }
     604                 : 
     605               0 : static FcBool DelDownloadedFontEntry(FcPattern *aPattern)
     606                 : {
     607               0 :     return FcPatternDel(aPattern, kFontEntryFcProp);
     608                 : }
     609                 : 
     610               0 : static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern)
     611                 : {
     612                 :     FcValue value;
     613               0 :     if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch)
     614               0 :         return nsnull;
     615                 : 
     616               0 :     if (value.type != FcTypeFTFace) {
     617               0 :         NS_NOTREACHED("Wrong type for -moz-font-entry font property");
     618               0 :         return nsnull;
     619                 :     }
     620                 : 
     621               0 :     return static_cast<gfxDownloadedFcFontEntry*>(value.u.f);
     622                 : }
     623                 : 
     624               0 : gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
     625                 : {
     626               0 :     if (mPatterns.Length() != 0) {
     627                 :         // Remove back reference to this font entry and the face in case
     628                 :         // anyone holds a reference to the pattern.
     629               0 :         NS_ASSERTION(mPatterns.Length() == 1,
     630                 :                      "More than one pattern in gfxDownloadedFcFontEntry!");
     631               0 :         DelDownloadedFontEntry(mPatterns[0]);
     632               0 :         FcPatternDel(mPatterns[0], FC_FT_FACE);
     633                 :     }
     634               0 :     FT_Done_Face(mFace);
     635               0 :     NS_Free((void*)mFontData);
     636               0 : }
     637                 : 
     638                 : typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
     639                 :                                         const FcChar8 *file, int id,
     640                 :                                         FcBlanks *blanks);
     641                 : 
     642                 : void
     643               0 : gfxDownloadedFcFontEntry::InitPattern()
     644                 : {
     645                 :     static QueryFaceFunction sQueryFacePtr =
     646                 :         reinterpret_cast<QueryFaceFunction>
     647               0 :         (FindFunctionSymbol("FcFreeTypeQueryFace"));
     648                 :     FcPattern *pattern;
     649                 : 
     650                 :     // FcFreeTypeQueryFace is the same function used to construct patterns for
     651                 :     // system fonts and so is the preferred function to use for this purpose.
     652                 :     // This will set up the langset property, which helps with sorting, and
     653                 :     // the foundry, fullname, and fontversion properties, which properly
     654                 :     // identify the font to fontconfig rules.  However, FcFreeTypeQueryFace is
     655                 :     // available only from fontconfig-2.4.2 (December 2006).  (CentOS 5.0 has
     656                 :     // fontconfig-2.4.1.)
     657               0 :     if (sQueryFacePtr) {
     658                 :         // The "file" argument cannot be NULL (in fontconfig-2.6.0 at least).
     659                 :         // The dummy file passed here is removed below.
     660                 :         //
     661                 :         // When fontconfig scans the system fonts, FcConfigGetBlanks(NULL) is
     662                 :         // passed as the "blanks" argument, which provides that unexpectedly
     663                 :         // blank glyphs are elided.  Here, however, we pass NULL for "blanks",
     664                 :         // effectively assuming that, if the font has a blank glyph, then the
     665                 :         // author intends any associated character to be rendered blank.
     666                 :         pattern =
     667               0 :             (*sQueryFacePtr)(mFace, gfxFontconfigUtils::ToFcChar8(""), 0, NULL);
     668               0 :         if (!pattern)
     669                 :             // Either OOM, or fontconfig chose to skip this font because it
     670                 :             // has "no encoded characters", which I think means "BDF and PCF
     671                 :             // fonts which are not in Unicode (or the effectively equivalent
     672                 :             // ISO Latin-1) encoding".
     673               0 :             return;
     674                 : 
     675                 :         // These properties don't make sense for this face without a file.
     676               0 :         FcPatternDel(pattern, FC_FILE);
     677               0 :         FcPatternDel(pattern, FC_INDEX);
     678                 : 
     679                 :     } else {
     680                 :         // Do the minimum necessary to construct a pattern for sorting.
     681                 : 
     682                 :         // FC_CHARSET is vital to determine which characters are supported.
     683               0 :         nsAutoRef<FcCharSet> charset(FcFreeTypeCharSet(mFace, NULL));
     684                 :         // If there are no characters then assume we don't know how to read
     685                 :         // this font.
     686               0 :         if (!charset || FcCharSetCount(charset) == 0)
     687                 :             return;
     688                 : 
     689               0 :         pattern = FcPatternCreate();
     690               0 :         FcPatternAddCharSet(pattern, FC_CHARSET, charset);
     691                 : 
     692                 :         // FC_PIXEL_SIZE can be important for font selection of fixed-size
     693                 :         // fonts.
     694               0 :         if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) {
     695               0 :             for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) {
     696                 : #if HAVE_FT_BITMAP_SIZE_Y_PPEM
     697               0 :                 double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem);
     698                 : #else
     699                 :                 double size = mFace->available_sizes[i].height;
     700                 : #endif
     701               0 :                 FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
     702                 :             }
     703                 : 
     704                 :             // Not sure whether this is important;
     705                 :             // imitating FcFreeTypeQueryFace:
     706               0 :             FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse);
     707                 :         }
     708                 : 
     709                 :         // Setting up the FC_LANGSET property is very difficult with the APIs
     710                 :         // available prior to FcFreeTypeQueryFace.  Having no FC_LANGSET
     711                 :         // property seems better than having a property with an empty LangSet.
     712                 :         // With no FC_LANGSET property, fontconfig sort functions will
     713                 :         // consider this face to have the same priority as (otherwise equal)
     714                 :         // faces that have support for the primary requested language, but
     715                 :         // will not consider any language to have been satisfied (and so will
     716                 :         // continue to look for a face with language support in fallback
     717                 :         // fonts).
     718                 :     }
     719                 : 
     720               0 :     AdjustPatternToCSS(pattern);
     721                 : 
     722               0 :     FcPatternAddFTFace(pattern, FC_FT_FACE, mFace);
     723               0 :     AddDownloadedFontEntry(pattern, this);
     724                 : 
     725                 :     // There is never more than one pattern
     726               0 :     mPatterns.AppendElement();
     727               0 :     mPatterns[0].own(pattern);
     728                 : }
     729                 : 
     730               0 : static void ReleaseDownloadedFontEntry(void *data)
     731                 : {
     732                 :     gfxDownloadedFcFontEntry *downloadedFontEntry =
     733               0 :         static_cast<gfxDownloadedFcFontEntry*>(data);
     734               0 :     NS_RELEASE(downloadedFontEntry);
     735               0 : }
     736                 : 
     737               0 : bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace)
     738                 : {
     739               0 :     if (CAIRO_STATUS_SUCCESS !=
     740                 :         cairo_font_face_set_user_data(aFace, &sFontEntryKey, this,
     741               0 :                                       ReleaseDownloadedFontEntry))
     742               0 :         return false;
     743                 : 
     744                 :     // Hold a reference to this font entry to keep the font face data.
     745               0 :     NS_ADDREF(this);
     746               0 :     return true;
     747                 : }
     748                 : 
     749               0 : static PangoCoverage *NewPangoCoverage(FcPattern *aFont)
     750                 : {
     751                 :     // This uses g_slice_alloc which will abort on OOM rather than return NULL.
     752               0 :     PangoCoverage *coverage = pango_coverage_new();
     753                 : 
     754                 :     FcCharSet *charset;
     755               0 :     if (FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset) != FcResultMatch)
     756               0 :         return coverage; // empty
     757                 : 
     758                 :     FcChar32 base;
     759                 :     FcChar32 map[FC_CHARSET_MAP_SIZE];
     760                 :     FcChar32 next;
     761               0 :     for (base = FcCharSetFirstPage(charset, map, &next);
     762                 :          base != FC_CHARSET_DONE;
     763               0 :          base = FcCharSetNextPage(charset, map, &next)) {
     764               0 :         for (PRUint32 i = 0; i < FC_CHARSET_MAP_SIZE; ++i) {
     765               0 :             PRUint32 offset = 0;
     766               0 :             FcChar32 bitmap = map[i];
     767               0 :             for (; bitmap; bitmap >>= 1) {
     768               0 :                 if (bitmap & 1) {
     769                 :                     pango_coverage_set(coverage, base + offset,
     770               0 :                                        PANGO_COVERAGE_EXACT);
     771                 :                 }
     772               0 :                 ++offset;
     773                 :             }
     774               0 :             base += 32;
     775                 :         }
     776                 :     }
     777               0 :     return coverage;
     778                 : }
     779                 : 
     780                 : PangoCoverage *
     781               0 : gfxDownloadedFcFontEntry::GetPangoCoverage()
     782                 : {
     783               0 :     NS_ASSERTION(mPatterns.Length() != 0,
     784                 :                  "Can't get coverage without a pattern!");
     785               0 :     if (!mPangoCoverage) {
     786               0 :         mPangoCoverage.own(NewPangoCoverage(mPatterns[0]));
     787                 :     }
     788               0 :     return mPangoCoverage;
     789                 : }
     790                 : 
     791                 : /*
     792                 :  * gfxFcFont
     793                 :  *
     794                 :  * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
     795                 :  * cairo_scaled_font created from an FcPattern.
     796                 :  */
     797                 : 
     798                 : class gfxFcFont : public gfxFT2FontBase {
     799                 : public:
     800                 :     virtual ~gfxFcFont();
     801                 :     static already_AddRefed<gfxFcFont>
     802                 :     GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
     803                 :                   const gfxFontStyle *aFontStyle);
     804                 : 
     805                 :     // The PangoFont returned is owned by the gfxFcFont
     806               0 :     PangoFont *GetPangoFont() {
     807               0 :         if (!mPangoFont) {
     808               0 :             MakePangoFont();
     809                 :         }
     810               0 :         return mPangoFont;
     811                 :     }
     812                 : 
     813                 : protected:
     814                 :     virtual bool ShapeWord(gfxContext *aContext,
     815                 :                            gfxShapedWord *aShapedWord,
     816                 :                            const PRUnichar *aString,
     817                 :                            bool aPreferPlatformShaping);
     818                 : 
     819                 :     bool InitGlyphRunWithPango(gfxShapedWord *aTextRun,
     820                 :                                const PRUnichar *aString);
     821                 : 
     822                 : private:
     823                 :     gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
     824                 :               const gfxFontStyle *aFontStyle);
     825                 : 
     826                 :     void MakePangoFont();
     827                 : 
     828                 :     PangoFont *mPangoFont;
     829                 : 
     830                 :     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
     831                 :     static cairo_user_data_key_t sGfxFontKey;
     832                 : };
     833                 : 
     834                 : /**
     835                 :  * gfxPangoFcFont:
     836                 :  *
     837                 :  * An implementation of PangoFcFont that wraps a gfxFont so that it can be
     838                 :  * passed to PangoRenderFc shapers.
     839                 :  *
     840                 :  * Many of these will be created for pango_itemize, but most will only be
     841                 :  * tested for coverage of individual characters (and sometimes not even that).
     842                 :  * Therefore the gfxFont is only constructed if and when needed.
     843                 :  */
     844                 : 
     845                 : #define GFX_TYPE_PANGO_FC_FONT              (gfx_pango_fc_font_get_type())
     846                 : #define GFX_PANGO_FC_FONT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFont))
     847                 : #define GFX_IS_PANGO_FC_FONT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FC_FONT))
     848                 : 
     849                 : /* static */
     850                 : GType gfx_pango_fc_font_get_type (void);
     851                 : 
     852                 : #define GFX_PANGO_FC_FONT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
     853                 : #define GFX_IS_PANGO_FC_FONT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FC_FONT))
     854                 : #define GFX_PANGO_FC_FONT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
     855                 : 
     856                 : // This struct is POD so that it can be used as a GObject.
     857                 : struct gfxPangoFcFont {
     858                 :     PangoFcFont parent_instance;
     859                 : 
     860                 :     PangoCoverage *mCoverage;
     861                 :     gfxFcFont *mGfxFont;
     862                 : 
     863                 :     // The caller promises to ensure that |aGfxFont| remains valid until the
     864                 :     // new gfxPangoFcFont is destroyed.  See PangoFontToggleNotify.
     865                 :     //
     866                 :     // The gfxPangoFcFont holds a reference to |aFontPattern|.
     867                 :     // Providing one of fontconfig's font patterns uses much less memory than
     868                 :     // using a fully resolved pattern, because fontconfig's font patterns are
     869                 :     // shared and will exist anyway.
     870                 :     static nsReturnRef<PangoFont>
     871                 :     NewFont(gfxFcFont *aGfxFont, FcPattern *aFontPattern);
     872                 : 
     873               0 :     gfxFcFont *GfxFont() { return mGfxFont; }
     874                 : 
     875               0 :     cairo_scaled_font_t *CairoFont()
     876                 :     {
     877               0 :         return GfxFont()->CairoScaledFont();
     878                 :     }
     879                 : 
     880                 : private:
     881                 :     void SetFontMap();
     882                 : };
     883                 : 
     884                 : struct gfxPangoFcFontClass {
     885                 :     PangoFcFontClass parent_class;
     886                 : };
     887                 : 
     888               0 : G_DEFINE_TYPE (gfxPangoFcFont, gfx_pango_fc_font, PANGO_TYPE_FC_FONT)
     889                 : 
     890                 : /* static */ nsReturnRef<PangoFont>
     891               0 : gfxPangoFcFont::NewFont(gfxFcFont *aGfxFont, FcPattern *aFontPattern)
     892                 : {
     893                 :     // The font pattern is needed for pango_fc_font_finalize.
     894                 :     gfxPangoFcFont *font = static_cast<gfxPangoFcFont*>
     895               0 :         (g_object_new(GFX_TYPE_PANGO_FC_FONT, "pattern", aFontPattern, NULL));
     896                 : 
     897               0 :     font->mGfxFont = aGfxFont;
     898               0 :     font->SetFontMap();
     899                 : 
     900               0 :     PangoFcFont *fc_font = &font->parent_instance;
     901               0 :     cairo_scaled_font_t *scaled_font = aGfxFont->CairoScaledFont();
     902                 :     // Normally the is_hinted field of PangoFcFont is set based on the
     903                 :     // FC_HINTING property on the pattern at construction, but this property
     904                 :     // is not on an unresolved aFontPattern.  is_hinted is used by
     905                 :     // pango_fc_font_kern_glyphs, which is sometimes used by
     906                 :     // pango_ot_buffer_output.
     907               0 :     cairo_font_options_t *options = cairo_font_options_create();
     908               0 :     cairo_scaled_font_get_font_options(scaled_font, options);
     909               0 :     cairo_hint_style_t hint_style = cairo_font_options_get_hint_style(options);
     910               0 :     cairo_font_options_destroy(options);
     911               0 :     fc_font->is_hinted = hint_style != CAIRO_HINT_STYLE_NONE;
     912                 : 
     913                 :     // is_transformed does not appear to be used anywhere but looks
     914                 :     // like it should be set.
     915                 :     cairo_matrix_t matrix;
     916               0 :     cairo_scaled_font_get_font_matrix(scaled_font, &matrix);
     917                 :     fc_font->is_transformed = (matrix.xy != 0.0 || matrix.yx != 0.0 ||
     918               0 :                                matrix.xx != matrix.yy);
     919                 : 
     920               0 :     return nsReturnRef<PangoFont>(PANGO_FONT(font));
     921                 : }
     922                 : 
     923                 : void
     924               0 : gfxPangoFcFont::SetFontMap()
     925                 : {
     926                 :     // PangoFcFont::get_coverage wants a PangoFcFontMap.  (PangoFcFontMap
     927                 :     // would usually set this after calling PangoFcFontMap::create_font()
     928                 :     // or new_font().)
     929               0 :     PangoFontMap *fontmap = GetPangoFontMap();
     930                 :     // In Pango-1.24.4, we can use the "fontmap" property; by setting the
     931                 :     // property, the PangoFcFont base class manages the pointer (as a weak
     932                 :     // reference).
     933               0 :     PangoFcFont *fc_font = &parent_instance;
     934               0 :     if (gUseFontMapProperty) {
     935               0 :         g_object_set(this, "fontmap", fontmap, NULL);
     936                 :     } else {
     937                 :         // In Pango versions up to 1.20.5, the parent class will decrement
     938                 :         // the reference count of the fontmap during shutdown() or
     939                 :         // finalize() of the font.  In Pango versions from 1.22.0 this no
     940                 :         // longer happens, so we'll end up leaking the (singleton)
     941                 :         // fontmap.
     942               0 :         fc_font->fontmap = fontmap;
     943               0 :         g_object_ref(fc_font->fontmap);
     944                 :     }
     945               0 : }
     946                 : 
     947                 : static void
     948               0 : gfx_pango_fc_font_init(gfxPangoFcFont *font)
     949                 : {
     950               0 : }
     951                 : 
     952                 : static void
     953               0 : gfx_pango_fc_font_finalize(GObject *object)
     954                 : {
     955               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(object);
     956                 : 
     957               0 :     if (self->mCoverage)
     958               0 :         pango_coverage_unref(self->mCoverage);
     959                 : 
     960               0 :     G_OBJECT_CLASS(gfx_pango_fc_font_parent_class)->finalize(object);
     961               0 : }
     962                 : 
     963                 : static PangoCoverage *
     964               0 : gfx_pango_fc_font_get_coverage(PangoFont *font, PangoLanguage *lang)
     965                 : {
     966               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
     967                 : 
     968                 :     // The coverage is requested often enough that it is worth holding a
     969                 :     // reference on the font.
     970               0 :     if (!self->mCoverage) {
     971               0 :         FcPattern *pattern = self->parent_instance.font_pattern;
     972                 :         gfxDownloadedFcFontEntry *downloadedFontEntry =
     973               0 :             GetDownloadedFontEntry(pattern);
     974                 :         // The parent class implementation requires the font pattern to have
     975                 :         // a file and caches results against that filename.  This is not
     976                 :         // suitable for web fonts.
     977               0 :         if (!downloadedFontEntry) {
     978                 :             self->mCoverage =
     979               0 :                 PANGO_FONT_CLASS(gfx_pango_fc_font_parent_class)->
     980               0 :                 get_coverage(font, lang);
     981                 :         } else {
     982                 :             self->mCoverage =
     983               0 :                 pango_coverage_ref(downloadedFontEntry->GetPangoCoverage());
     984                 :         }
     985                 :     }
     986                 : 
     987               0 :     return pango_coverage_ref(self->mCoverage);
     988                 : }
     989                 : 
     990                 : static PRInt32
     991               0 : GetDPI()
     992                 : {
     993                 : #if defined(MOZ_WIDGET_GTK2)
     994               0 :     return gfxPlatformGtk::GetDPI();
     995                 : #elif defined(MOZ_WIDGET_QT)
     996                 :     return gfxQtPlatform::GetDPI();
     997                 : #else
     998                 :     return 96;
     999                 : #endif
    1000                 : }
    1001                 : 
    1002                 : static PangoFontDescription *
    1003               0 : gfx_pango_fc_font_describe(PangoFont *font)
    1004                 : {
    1005               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1006               0 :     PangoFcFont *fcFont = &self->parent_instance;
    1007                 :     PangoFontDescription *result =
    1008               0 :         pango_font_description_copy(fcFont->description);
    1009                 : 
    1010               0 :     gfxFcFont *gfxFont = self->GfxFont();
    1011               0 :     if (gfxFont) {
    1012               0 :         double pixelsize = gfxFont->GetStyle()->size;
    1013               0 :         double dpi = GetDPI();
    1014               0 :         gint size = moz_pango_units_from_double(pixelsize * dpi / 72.0);
    1015               0 :         pango_font_description_set_size(result, size);
    1016                 :     }
    1017               0 :     return result;
    1018                 : }
    1019                 : 
    1020                 : static PangoFontDescription *
    1021               0 : gfx_pango_fc_font_describe_absolute(PangoFont *font)
    1022                 : {
    1023               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1024               0 :     PangoFcFont *fcFont = &self->parent_instance;
    1025                 :     PangoFontDescription *result =
    1026               0 :         pango_font_description_copy(fcFont->description);
    1027                 : 
    1028               0 :     gfxFcFont *gfxFont = self->GfxFont();
    1029               0 :     if (gfxFont) {
    1030               0 :         double size = gfxFont->GetStyle()->size * PANGO_SCALE;
    1031               0 :         pango_font_description_set_absolute_size(result, size);
    1032                 :     }
    1033               0 :     return result;
    1034                 : }
    1035                 : 
    1036                 : static void
    1037               0 : gfx_pango_fc_font_get_glyph_extents(PangoFont *font, PangoGlyph glyph,
    1038                 :                                     PangoRectangle *ink_rect,
    1039                 :                                     PangoRectangle *logical_rect)
    1040                 : {
    1041               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1042               0 :     gfxFcFont *gfxFont = self->GfxFont();
    1043                 : 
    1044               0 :     if (IS_MISSING_GLYPH(glyph)) {
    1045               0 :         const gfxFont::Metrics& metrics = gfxFont->GetMetrics();
    1046                 : 
    1047                 :         PangoRectangle rect;
    1048               0 :         rect.x = 0;
    1049               0 :         rect.y = moz_pango_units_from_double(-metrics.maxAscent);
    1050               0 :         rect.width = moz_pango_units_from_double(metrics.aveCharWidth);
    1051               0 :         rect.height = moz_pango_units_from_double(metrics.maxHeight);
    1052               0 :         if (ink_rect) {
    1053               0 :             *ink_rect = rect;
    1054                 :         }
    1055               0 :         if (logical_rect) {
    1056               0 :             *logical_rect = rect;
    1057                 :         }
    1058               0 :         return;
    1059                 :     }
    1060                 : 
    1061               0 :     if (logical_rect) {
    1062                 :         // logical_rect.width is possibly used by pango_ot_buffer_output (used
    1063                 :         // by many shapers) and used by fallback_engine_shape (possibly used
    1064                 :         // by pango_shape and pango_itemize when no glyphs are found).  I
    1065                 :         // doubt the other fields will be used but we won't have any way to
    1066                 :         // detecting if they are so we'd better set them.
    1067               0 :         const gfxFont::Metrics& metrics = gfxFont->GetMetrics();
    1068               0 :         logical_rect->y = moz_pango_units_from_double(-metrics.maxAscent);
    1069               0 :         logical_rect->height = moz_pango_units_from_double(metrics.maxHeight);
    1070                 :     }
    1071                 : 
    1072                 :     cairo_text_extents_t extents;
    1073               0 :     if (IS_EMPTY_GLYPH(glyph)) {
    1074               0 :         new (&extents) cairo_text_extents_t(); // zero
    1075                 :     } else {
    1076               0 :         gfxFont->GetGlyphExtents(glyph, &extents);
    1077                 :     }
    1078                 : 
    1079               0 :     if (ink_rect) {
    1080               0 :         ink_rect->x = moz_pango_units_from_double(extents.x_bearing);
    1081               0 :         ink_rect->y = moz_pango_units_from_double(extents.y_bearing);
    1082               0 :         ink_rect->width = moz_pango_units_from_double(extents.width);
    1083               0 :         ink_rect->height = moz_pango_units_from_double(extents.height);
    1084                 :     }
    1085               0 :     if (logical_rect) {
    1086               0 :         logical_rect->x = 0;
    1087               0 :         logical_rect->width = moz_pango_units_from_double(extents.x_advance);
    1088                 :     }
    1089                 : }
    1090                 : 
    1091                 : static PangoFontMetrics *
    1092               0 : gfx_pango_fc_font_get_metrics(PangoFont *font, PangoLanguage *language)
    1093                 : {
    1094               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1095                 : 
    1096                 :     // This uses g_slice_alloc which will abort on OOM rather than return NULL.
    1097               0 :     PangoFontMetrics *result = pango_font_metrics_new();
    1098                 : 
    1099               0 :     gfxFcFont *gfxFont = self->GfxFont();
    1100               0 :     if (gfxFont) {
    1101               0 :         const gfxFont::Metrics& metrics = gfxFont->GetMetrics();
    1102                 : 
    1103               0 :         result->ascent = moz_pango_units_from_double(metrics.maxAscent);
    1104               0 :         result->descent = moz_pango_units_from_double(metrics.maxDescent);
    1105                 :         result->approximate_char_width =
    1106               0 :             moz_pango_units_from_double(metrics.aveCharWidth);
    1107                 :         result->approximate_digit_width =
    1108               0 :             moz_pango_units_from_double(metrics.zeroOrAveCharWidth);
    1109                 :         result->underline_position =
    1110               0 :             moz_pango_units_from_double(metrics.underlineOffset);
    1111                 :         result->underline_thickness =
    1112               0 :             moz_pango_units_from_double(metrics.underlineSize);
    1113                 :         result->strikethrough_position =
    1114               0 :             moz_pango_units_from_double(metrics.strikeoutOffset);
    1115                 :         result->strikethrough_thickness =
    1116               0 :             moz_pango_units_from_double(metrics.strikeoutSize);
    1117                 :     }
    1118               0 :     return result;
    1119                 : }
    1120                 : 
    1121                 : static FT_Face
    1122               0 : gfx_pango_fc_font_lock_face(PangoFcFont *font)
    1123                 : {
    1124               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1125               0 :     return cairo_ft_scaled_font_lock_face(self->CairoFont());
    1126                 : }
    1127                 : 
    1128                 : static void
    1129               0 : gfx_pango_fc_font_unlock_face(PangoFcFont *font)
    1130                 : {
    1131               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1132               0 :     cairo_ft_scaled_font_unlock_face(self->CairoFont());
    1133               0 : }
    1134                 : 
    1135                 : static guint
    1136               0 : gfx_pango_fc_font_get_glyph(PangoFcFont *font, gunichar wc)
    1137                 : {
    1138               0 :     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
    1139               0 :     gfxFcFont *gfxFont = self->GfxFont();
    1140               0 :     return gfxFont->GetGlyph(wc);
    1141                 : }
    1142                 : 
    1143                 : typedef int (*PangoVersionFunction)();
    1144                 : 
    1145                 : static void
    1146               0 : gfx_pango_fc_font_class_init (gfxPangoFcFontClass *klass)
    1147                 : {
    1148               0 :     GObjectClass *object_class = G_OBJECT_CLASS (klass);
    1149               0 :     PangoFontClass *font_class = PANGO_FONT_CLASS (klass);
    1150               0 :     PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (klass);
    1151                 : 
    1152               0 :     object_class->finalize = gfx_pango_fc_font_finalize;
    1153                 : 
    1154               0 :     font_class->get_coverage = gfx_pango_fc_font_get_coverage;
    1155                 :     // describe is called on errors in pango_shape.
    1156               0 :     font_class->describe = gfx_pango_fc_font_describe;
    1157               0 :     font_class->get_glyph_extents = gfx_pango_fc_font_get_glyph_extents;
    1158                 :     // get_metrics and describe_absolute are not likely to be used but
    1159                 :     //   implemented because the class makes them available.
    1160               0 :     font_class->get_metrics = gfx_pango_fc_font_get_metrics;
    1161               0 :     font_class->describe_absolute = gfx_pango_fc_font_describe_absolute;
    1162                 :     // font_class->find_shaper,get_font_map are inherited from PangoFcFontClass
    1163                 : 
    1164                 :     // fc_font_class->has_char is inherited
    1165               0 :     fc_font_class->lock_face = gfx_pango_fc_font_lock_face;
    1166               0 :     fc_font_class->unlock_face = gfx_pango_fc_font_unlock_face;
    1167               0 :     fc_font_class->get_glyph = gfx_pango_fc_font_get_glyph;
    1168                 : 
    1169                 :     // The "fontmap" property on PangoFcFont was introduced for Pango-1.24.0
    1170                 :     // but versions prior to Pango-1.24.4 leaked weak pointers for every font,
    1171                 :     // which would causes crashes when shutting down the FontMap.  For the
    1172                 :     // early Pango-1.24.x versions we're better off setting the fontmap member
    1173                 :     // ourselves, which will not create weak pointers to leak, and instead
    1174                 :     // we'll leak the FontMap on shutdown.  pango_version() and
    1175                 :     // PANGO_VERSION_ENCODE require Pango-1.16.
    1176                 :     PangoVersionFunction pango_version =
    1177                 :         reinterpret_cast<PangoVersionFunction>
    1178               0 :         (FindFunctionSymbol("pango_version"));
    1179               0 :     gUseFontMapProperty = pango_version && (*pango_version)() >= 12404;
    1180               0 : }
    1181                 : 
    1182                 : /**
    1183                 :  * gfxFcFontSet:
    1184                 :  *
    1185                 :  * Translation from a desired FcPattern to a sorted set of font references
    1186                 :  * (fontconfig cache data) and (when needed) fonts.
    1187                 :  */
    1188                 : 
    1189               0 : class gfxFcFontSet {
    1190                 : public:
    1191               0 :     NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet)
    1192                 :     
    1193               0 :     explicit gfxFcFontSet(FcPattern *aPattern,
    1194                 :                                gfxUserFontSet *aUserFontSet)
    1195                 :         : mSortPattern(aPattern), mUserFontSet(aUserFontSet),
    1196                 :           mFcFontsTrimmed(0),
    1197               0 :           mHaveFallbackFonts(false)
    1198                 :     {
    1199                 :         bool waitForUserFont;
    1200               0 :         mFcFontSet = SortPreferredFonts(waitForUserFont);
    1201               0 :         mWaitingForUserFont = waitForUserFont;
    1202               0 :     }
    1203                 : 
    1204                 :     // A reference is held by the FontSet.
    1205                 :     // The caller may add a ref to keep the font alive longer than the FontSet.
    1206               0 :     gfxFcFont *GetFontAt(PRUint32 i, const gfxFontStyle *aFontStyle)
    1207                 :     {
    1208               0 :         if (i >= mFonts.Length() || !mFonts[i].mFont) { 
    1209                 :             // GetFontPatternAt sets up mFonts
    1210               0 :             FcPattern *fontPattern = GetFontPatternAt(i);
    1211               0 :             if (!fontPattern)
    1212               0 :                 return NULL;
    1213                 : 
    1214               0 :             mFonts[i].mFont =
    1215                 :                 gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern,
    1216               0 :                                          aFontStyle);
    1217                 :         }
    1218               0 :         return mFonts[i].mFont;
    1219                 :     }
    1220                 : 
    1221                 :     FcPattern *GetFontPatternAt(PRUint32 i);
    1222                 : 
    1223               0 :     bool WaitingForUserFont() const {
    1224               0 :         return mWaitingForUserFont;
    1225                 :     }
    1226                 : 
    1227                 : private:
    1228                 :     nsReturnRef<FcFontSet> SortPreferredFonts(bool& aWaitForUserFont);
    1229                 :     nsReturnRef<FcFontSet> SortFallbackFonts();
    1230                 : 
    1231               0 :     struct FontEntry {
    1232               0 :         explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {}
    1233                 :         nsCountedRef<FcPattern> mPattern;
    1234                 :         nsRefPtr<gfxFcFont> mFont;
    1235                 :         nsCountedRef<PangoFont> mPangoFont;
    1236                 :     };
    1237                 : 
    1238               0 :     struct LangSupportEntry {
    1239               0 :         LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) :
    1240               0 :             mLang(aLang), mBestSupport(aSupport) {}
    1241                 :         FcChar8 *mLang;
    1242                 :         FcLangResult mBestSupport;
    1243                 :     };
    1244                 : 
    1245                 : public:
    1246                 :     // public for nsTArray
    1247                 :     class LangComparator {
    1248                 :     public:
    1249               0 :         bool Equals(const LangSupportEntry& a, const FcChar8 *b) const
    1250                 :         {
    1251               0 :             return FcStrCmpIgnoreCase(a.mLang, b) == 0;
    1252                 :         }
    1253                 :     };
    1254                 : 
    1255                 : private:
    1256                 :     // The requested pattern
    1257                 :     nsCountedRef<FcPattern> mSortPattern;
    1258                 :     // Fonts from @font-face rules
    1259                 :     nsRefPtr<gfxUserFontSet> mUserFontSet;
    1260                 :     // A (trimmed) list of font patterns and fonts that is built up as
    1261                 :     // required.
    1262                 :     nsTArray<FontEntry> mFonts;
    1263                 :     // Holds a list of font patterns that will be trimmed.  This is first set
    1264                 :     // to a list of preferred fonts.  Then, if/when all the preferred fonts
    1265                 :     // have been trimmed and added to mFonts, this is set to a list of
    1266                 :     // fallback fonts.
    1267                 :     nsAutoRef<FcFontSet> mFcFontSet;
    1268                 :     // The set of characters supported by the fonts in mFonts.
    1269                 :     nsAutoRef<FcCharSet> mCharSet;
    1270                 :     // The index of the next font in mFcFontSet that has not yet been
    1271                 :     // considered for mFonts.
    1272                 :     int mFcFontsTrimmed;
    1273                 :     // True iff fallback fonts are either stored in mFcFontSet or have been
    1274                 :     // trimmed and added to mFonts (so that mFcFontSet is NULL).
    1275                 :     bool mHaveFallbackFonts;
    1276                 :     // True iff there was a user font set with pending downloads,
    1277                 :     // so the set may be updated when downloads complete
    1278                 :     bool mWaitingForUserFont;
    1279                 : };
    1280                 : 
    1281                 : // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
    1282                 : // and style |aStyle| properties.
    1283                 : static const nsTArray< nsCountedRef<FcPattern> >*
    1284               0 : FindFontPatterns(gfxUserFontSet *mUserFontSet,
    1285                 :                  const nsACString &aFamily, PRUint8 aStyle,
    1286                 :                  PRUint16 aWeight, PRInt16 aStretch,
    1287                 :                  bool& aFoundFamily, bool& aWaitForUserFont)
    1288                 : {
    1289                 :     // Convert to UTF16
    1290               0 :     NS_ConvertUTF8toUTF16 utf16Family(aFamily);
    1291                 : 
    1292                 :     // needsBold is not used here.  Instead synthetic bold is enabled through
    1293                 :     // FcFontRenderPrepare when the weight in the requested pattern is
    1294                 :     // compared against the weight in the font pattern.
    1295                 :     bool needsBold;
    1296                 : 
    1297               0 :     gfxFontStyle style;
    1298               0 :     style.style = aStyle;
    1299               0 :     style.weight = aWeight;
    1300               0 :     style.stretch = aStretch;
    1301                 : 
    1302                 :     gfxUserFcFontEntry *fontEntry = static_cast<gfxUserFcFontEntry*>
    1303                 :         (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily,
    1304               0 :                                      needsBold, aWaitForUserFont));
    1305                 : 
    1306                 :     // Accept synthetic oblique for italic and oblique.
    1307               0 :     if (!fontEntry && aStyle != FONT_STYLE_NORMAL) {
    1308               0 :         style.style = FONT_STYLE_NORMAL;
    1309                 :         fontEntry = static_cast<gfxUserFcFontEntry*>
    1310                 :             (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily,
    1311               0 :                                          needsBold, aWaitForUserFont));
    1312                 :     }
    1313                 : 
    1314               0 :     if (!fontEntry)
    1315               0 :         return NULL;
    1316                 : 
    1317               0 :     return &fontEntry->GetPatterns();
    1318                 : }
    1319                 : 
    1320                 : typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object,
    1321                 :                                           int id);
    1322                 : 
    1323                 : // FcPatternRemove is available in fontconfig-2.3.0 (2005)
    1324                 : static FcBool
    1325               0 : moz_FcPatternRemove(FcPattern *p, const char *object, int id)
    1326                 : {
    1327                 :     static FcPatternRemoveFunction sFcPatternRemovePtr =
    1328                 :         reinterpret_cast<FcPatternRemoveFunction>
    1329               0 :         (FindFunctionSymbol("FcPatternRemove"));
    1330                 : 
    1331               0 :     if (!sFcPatternRemovePtr)
    1332               0 :         return FcFalse;
    1333                 : 
    1334               0 :     return (*sFcPatternRemovePtr)(p, object, id);
    1335                 : }
    1336                 : 
    1337                 : // fontconfig always prefers a matching family to a matching slant, but CSS
    1338                 : // mostly prioritizes slant.  The logic here is from CSS 2.1.
    1339                 : static bool
    1340               0 : SlantIsAcceptable(FcPattern *aFont, int aRequestedSlant)
    1341                 : {
    1342                 :     // CSS accepts (possibly synthetic) oblique for italic.
    1343               0 :     if (aRequestedSlant == FC_SLANT_ITALIC)
    1344               0 :         return true;
    1345                 : 
    1346                 :     int slant;
    1347               0 :     FcResult result = FcPatternGetInteger(aFont, FC_SLANT, 0, &slant);
    1348                 :     // Not having a value would be strange.
    1349                 :     // fontconfig sort and match functions would consider no value a match.
    1350               0 :     if (result != FcResultMatch)
    1351               0 :         return true;
    1352                 : 
    1353               0 :     switch (aRequestedSlant) {
    1354                 :         case FC_SLANT_ROMAN:
    1355                 :             // CSS requires an exact match
    1356               0 :             return slant == aRequestedSlant;
    1357                 :         case FC_SLANT_OBLIQUE:
    1358                 :             // Accept synthetic oblique from Roman,
    1359                 :             // but CSS doesn't accept italic.
    1360               0 :             return slant != FC_SLANT_ITALIC;
    1361                 :     }
    1362                 : 
    1363               0 :     return true;
    1364                 : }
    1365                 : 
    1366                 : // fontconfig prefers a matching family or lang to pixelsize of bitmap
    1367                 : // fonts.  CSS suggests a tolerance of 20% on pixelsize.
    1368                 : static bool
    1369               0 : SizeIsAcceptable(FcPattern *aFont, double aRequestedSize)
    1370                 : {
    1371                 :     double size;
    1372               0 :     int v = 0;
    1373               0 :     while (FcPatternGetDouble(aFont,
    1374               0 :                               FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
    1375               0 :         ++v;
    1376               0 :         if (5.0 * fabs(size - aRequestedSize) < aRequestedSize)
    1377               0 :             return true;
    1378                 :     }
    1379                 : 
    1380                 :     // No size means scalable
    1381               0 :     return v == 0;
    1382                 : }
    1383                 : 
    1384                 : // Sorting only the preferred fonts first usually saves having to sort through
    1385                 : // every font on the system.
    1386                 : nsReturnRef<FcFontSet>
    1387               0 : gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
    1388                 : {
    1389               0 :     aWaitForUserFont = false;
    1390                 : 
    1391               0 :     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
    1392               0 :     if (!utils)
    1393               0 :         return nsReturnRef<FcFontSet>();
    1394                 : 
    1395                 :     // The list of families in mSortPattern has values with both weak and
    1396                 :     // strong bindings.  Values with strong bindings should be preferred.
    1397                 :     // Values with weak bindings are default fonts that should be considered
    1398                 :     // only when the font provides the best support for a requested language
    1399                 :     // or after other fonts have satisfied all the requested languages.
    1400                 :     //
    1401                 :     // There are no direct fontconfig APIs to get the binding type.  The
    1402                 :     // binding only takes effect in the sort and match functions.
    1403                 : 
    1404                 :     // |requiredLangs| is a list of requested languages that have not yet been
    1405                 :     // satisfied.  gfxFontconfigUtils only sets one FC_LANG property value,
    1406                 :     // but FcConfigSubstitute may add more values (e.g. prepending "en" to
    1407                 :     // "ja" will use western fonts to render Latin/Arabic numerals in Japanese
    1408                 :     // text.)
    1409               0 :     nsAutoTArray<LangSupportEntry,10> requiredLangs;
    1410               0 :     for (int v = 0; ; ++v) {
    1411                 :         FcChar8 *lang;
    1412               0 :         FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang);
    1413               0 :         if (result != FcResultMatch) {
    1414                 :             // No need to check FcPatternGetLangSet() because
    1415                 :             // gfxFontconfigUtils sets only a string value for FC_LANG and
    1416                 :             // FcConfigSubstitute cannot add LangSets.
    1417               0 :             NS_ASSERTION(result != FcResultTypeMismatch,
    1418                 :                          "Expected a string for FC_LANG");
    1419                 :             break;
    1420                 :         }
    1421                 : 
    1422               0 :         if (!requiredLangs.Contains(lang, LangComparator())) {
    1423               0 :             FcLangResult bestLangSupport = utils->GetBestLangSupport(lang);
    1424               0 :             if (bestLangSupport != FcLangDifferentLang) {
    1425                 :                 requiredLangs.
    1426               0 :                     AppendElement(LangSupportEntry(lang, bestLangSupport));
    1427                 :             }
    1428                 :         }
    1429                 :     }
    1430                 : 
    1431               0 :     nsAutoRef<FcFontSet> fontSet(FcFontSetCreate());
    1432               0 :     if (!fontSet)
    1433               0 :         return fontSet.out();
    1434                 : 
    1435                 :     // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever
    1436                 :     // doesn't happen, Roman will be used.
    1437               0 :     int requestedSlant = FC_SLANT_ROMAN;
    1438               0 :     FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant);
    1439               0 :     double requestedSize = -1.0;
    1440               0 :     FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize);
    1441                 : 
    1442               0 :     nsTHashtable<gfxFontconfigUtils::DepFcStrEntry> existingFamilies;
    1443               0 :     existingFamilies.Init(50);
    1444                 :     FcChar8 *family;
    1445               0 :     for (int v = 0;
    1446                 :          FcPatternGetString(mSortPattern,
    1447               0 :                             FC_FAMILY, v, &family) == FcResultMatch; ++v) {
    1448               0 :         const nsTArray< nsCountedRef<FcPattern> > *familyFonts = nsnull;
    1449                 : 
    1450                 :         // Is this an @font-face family?
    1451               0 :         bool isUserFont = false;
    1452               0 :         if (mUserFontSet) {
    1453                 :             // Have some @font-face definitions
    1454                 : 
    1455               0 :             nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family));
    1456               0 :             NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX);
    1457                 : 
    1458               0 :             if (StringBeginsWith(cFamily, userPrefix)) {
    1459               0 :                 isUserFont = true;
    1460                 : 
    1461                 :                 // Trim off the prefix
    1462               0 :                 nsDependentCSubstring cssFamily(cFamily, userPrefix.Length());
    1463                 : 
    1464                 :                 PRUint8 thebesStyle =
    1465               0 :                     gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant);
    1466                 :                 PRUint16 thebesWeight =
    1467               0 :                     gfxFontconfigUtils::GetThebesWeight(mSortPattern);
    1468                 :                 PRInt16 thebesStretch =
    1469               0 :                     gfxFontconfigUtils::GetThebesStretch(mSortPattern);
    1470                 : 
    1471                 :                 bool foundFamily, waitForUserFont;
    1472                 :                 familyFonts = FindFontPatterns(mUserFontSet, cssFamily,
    1473                 :                                                thebesStyle,
    1474                 :                                                thebesWeight, thebesStretch,
    1475               0 :                                                foundFamily, waitForUserFont);
    1476               0 :                 if (waitForUserFont) {
    1477               0 :                     aWaitForUserFont = true;
    1478                 :                 }
    1479               0 :                 NS_ASSERTION(foundFamily,
    1480                 :                              "expected to find a user font, but it's missing!");
    1481                 :             }
    1482                 :         }
    1483                 : 
    1484               0 :         if (!isUserFont) {
    1485               0 :             familyFonts = &utils->GetFontsForFamily(family);
    1486                 :         }
    1487                 : 
    1488               0 :         if (!familyFonts || familyFonts->Length() == 0) {
    1489                 :             // There are no fonts matching this family, so there is no point
    1490                 :             // in searching for this family in the FontSort.
    1491                 :             //
    1492                 :             // Perhaps the original pattern should be retained for
    1493                 :             // FcFontRenderPrepare.  However, the only a useful config
    1494                 :             // substitution test against missing families that i can imagine
    1495                 :             // would only be interested in the preferred family
    1496                 :             // (qual="first"), so always keep the first family and use the
    1497                 :             // same pattern for Sort and RenderPrepare.
    1498               0 :             if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) {
    1499               0 :                 --v;
    1500                 :             }
    1501               0 :             continue;
    1502                 :         }
    1503                 : 
    1504                 :         // Aliases seem to often end up occurring more than once, but
    1505                 :         // duplicate families can't be removed from the sort pattern without
    1506                 :         // knowing whether duplicates have the same binding.
    1507                 :         gfxFontconfigUtils::DepFcStrEntry *entry =
    1508               0 :             existingFamilies.PutEntry(family);
    1509               0 :         if (entry) {
    1510               0 :             if (entry->mKey) // old entry
    1511               0 :                 continue;
    1512                 : 
    1513               0 :             entry->mKey = family; // initialize new entry
    1514                 :         }
    1515                 : 
    1516               0 :         for (PRUint32 f = 0; f < familyFonts->Length(); ++f) {
    1517               0 :             FcPattern *font = familyFonts->ElementAt(f);
    1518                 : 
    1519                 :             // User fonts are already filtered by slant (but not size) in
    1520                 :             // mUserFontSet->FindFontEntry().
    1521               0 :             if (!isUserFont && !SlantIsAcceptable(font, requestedSlant))
    1522               0 :                 continue;
    1523               0 :             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
    1524               0 :                 continue;
    1525                 : 
    1526               0 :             for (PRUint32 r = 0; r < requiredLangs.Length(); ++r) {
    1527               0 :                 const LangSupportEntry& entry = requiredLangs[r];
    1528                 :                 FcLangResult support =
    1529               0 :                     gfxFontconfigUtils::GetLangSupport(font, entry.mLang);
    1530               0 :                 if (support <= entry.mBestSupport) { // lower is better
    1531               0 :                     requiredLangs.RemoveElementAt(r);
    1532               0 :                     --r;
    1533                 :                 }
    1534                 :             }
    1535                 : 
    1536                 :             // FcFontSetDestroy will remove a reference but FcFontSetAdd
    1537                 :             // does _not_ take a reference!
    1538               0 :             if (FcFontSetAdd(fontSet, font)) {
    1539               0 :                 FcPatternReference(font);
    1540                 :             }
    1541                 :         }
    1542                 :     }
    1543                 : 
    1544               0 :     FcPattern *truncateMarker = NULL;
    1545               0 :     for (PRUint32 r = 0; r < requiredLangs.Length(); ++r) {
    1546                 :         const nsTArray< nsCountedRef<FcPattern> >& langFonts =
    1547               0 :             utils->GetFontsForLang(requiredLangs[r].mLang);
    1548                 : 
    1549               0 :         bool haveLangFont = false;
    1550               0 :         for (PRUint32 f = 0; f < langFonts.Length(); ++f) {
    1551               0 :             FcPattern *font = langFonts[f];
    1552               0 :             if (!SlantIsAcceptable(font, requestedSlant))
    1553               0 :                 continue;
    1554               0 :             if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize))
    1555               0 :                 continue;
    1556                 : 
    1557               0 :             haveLangFont = true;
    1558               0 :             if (FcFontSetAdd(fontSet, font)) {
    1559               0 :                 FcPatternReference(font);
    1560                 :             }
    1561                 :         }
    1562                 : 
    1563               0 :         if (!haveLangFont && langFonts.Length() > 0) {
    1564                 :             // There is a font that supports this language but it didn't pass
    1565                 :             // the slant and size criteria.  Weak default font families should
    1566                 :             // not be considered until the language has been satisfied.
    1567                 :             //
    1568                 :             // Insert a font that supports the language so that it will mark
    1569                 :             // the position of fonts from weak families in the sorted set and
    1570                 :             // they can be removed.  The language and weak families will be
    1571                 :             // considered in the fallback fonts, which use fontconfig's
    1572                 :             // algorithm.
    1573                 :             //
    1574                 :             // Of the fonts that don't meet slant and size criteria, strong
    1575                 :             // default font families should be considered before (other) fonts
    1576                 :             // for this language, so this marker font will be removed (as well
    1577                 :             // as the fonts from weak families), and strong families will be
    1578                 :             // reconsidered in the fallback fonts.
    1579               0 :             FcPattern *font = langFonts[0];
    1580               0 :             if (FcFontSetAdd(fontSet, font)) {
    1581               0 :                 FcPatternReference(font);
    1582               0 :                 truncateMarker = font;
    1583                 :             }
    1584               0 :             break;
    1585                 :         }
    1586                 :     }
    1587                 : 
    1588               0 :     FcFontSet *sets[1] = { fontSet };
    1589                 :     FcResult result;
    1590                 : #ifdef SOLARIS
    1591                 :     // Get around a crash of FcFontSetSort when FcConfig is NULL
    1592                 :     // Solaris's FcFontSetSort needs an FcConfig (bug 474758)
    1593                 :     fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern,
    1594                 :                               FcFalse, NULL, &result));
    1595                 : #else
    1596                 :     fontSet.own(FcFontSetSort(NULL, sets, 1, mSortPattern,
    1597               0 :                               FcFalse, NULL, &result));
    1598                 : #endif
    1599                 : 
    1600               0 :     if (truncateMarker != NULL && fontSet) {
    1601               0 :         nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate());
    1602                 : 
    1603               0 :         for (int f = 0; f < fontSet->nfont; ++f) {
    1604               0 :             FcPattern *font = fontSet->fonts[f];
    1605               0 :             if (font == truncateMarker)
    1606               0 :                 break;
    1607                 : 
    1608               0 :             if (FcFontSetAdd(truncatedSet, font)) {
    1609               0 :                 FcPatternReference(font);
    1610                 :             }
    1611                 :         }
    1612                 : 
    1613               0 :         fontSet.steal(truncatedSet);
    1614                 :     }
    1615                 : 
    1616               0 :     return fontSet.out();
    1617                 : }
    1618                 : 
    1619                 : nsReturnRef<FcFontSet>
    1620               0 : gfxFcFontSet::SortFallbackFonts()
    1621                 : {
    1622                 :     // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet,
    1623                 :     // but would take much longer due to comparing all the character sets.
    1624                 :     //
    1625                 :     // The references to fonts in this FcFontSet are almost free
    1626                 :     // as they are pointers into mmaped cache files.
    1627                 :     //
    1628                 :     // GetFontPatternAt() will trim lazily if and as needed, which will also
    1629                 :     // remove duplicates of preferred fonts.
    1630                 :     FcResult result;
    1631                 :     return nsReturnRef<FcFontSet>(FcFontSort(NULL, mSortPattern,
    1632               0 :                                              FcFalse, NULL, &result));
    1633                 : }
    1634                 : 
    1635                 : // GetFontAt relies on this setting up all patterns up to |i|.
    1636                 : FcPattern *
    1637               0 : gfxFcFontSet::GetFontPatternAt(PRUint32 i)
    1638                 : {
    1639               0 :     while (i >= mFonts.Length()) {
    1640               0 :         while (!mFcFontSet) {
    1641               0 :             if (mHaveFallbackFonts)
    1642               0 :                 return nsnull;
    1643                 : 
    1644               0 :             mFcFontSet = SortFallbackFonts();
    1645               0 :             mHaveFallbackFonts = true;
    1646               0 :             mFcFontsTrimmed = 0;
    1647                 :             // Loop to test that mFcFontSet is non-NULL.
    1648                 :         }
    1649                 : 
    1650               0 :         while (mFcFontsTrimmed < mFcFontSet->nfont) {
    1651               0 :             FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed];
    1652               0 :             ++mFcFontsTrimmed;
    1653                 : 
    1654               0 :             if (mFonts.Length() != 0) {
    1655                 :                 // See if the next font provides support for any extra
    1656                 :                 // characters.  Most often the next font is not going to
    1657                 :                 // support more characters so check for a SubSet first before
    1658                 :                 // allocating a new CharSet with Union.
    1659               0 :                 FcCharSet *supportedChars = mCharSet;
    1660               0 :                 if (!supportedChars) {
    1661               0 :                     FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern,
    1662               0 :                                         FC_CHARSET, 0, &supportedChars);
    1663                 :                 }
    1664                 : 
    1665               0 :                 if (supportedChars) {
    1666               0 :                     FcCharSet *newChars = NULL;
    1667               0 :                     FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars);
    1668               0 :                     if (newChars) {
    1669               0 :                         if (FcCharSetIsSubset(newChars, supportedChars))
    1670               0 :                             continue;
    1671                 : 
    1672               0 :                         mCharSet.own(FcCharSetUnion(supportedChars, newChars));
    1673               0 :                     } else if (!mCharSet) {
    1674               0 :                         mCharSet.own(FcCharSetCopy(supportedChars));
    1675                 :                     }
    1676                 :                 }
    1677                 :             }
    1678                 : 
    1679               0 :             mFonts.AppendElement(font);
    1680               0 :             if (mFonts.Length() >= i)
    1681               0 :                 break;
    1682                 :         }
    1683                 : 
    1684               0 :         if (mFcFontsTrimmed == mFcFontSet->nfont) {
    1685                 :             // finished with this font set
    1686               0 :             mFcFontSet.reset();
    1687                 :         }
    1688                 :     }
    1689                 : 
    1690               0 :     return mFonts[i].mPattern;
    1691                 : }
    1692                 : 
    1693                 : /**
    1694                 :  * gfxPangoFontMap: An implementation of a PangoFontMap.
    1695                 :  *
    1696                 :  * This is a PangoFcFontMap for gfxPangoFcFont.  It will only ever be used if
    1697                 :  * some day pango_cairo_font_map_get_default() does not return a
    1698                 :  * PangoFcFontMap.
    1699                 :  */
    1700                 : 
    1701                 : #define GFX_TYPE_PANGO_FONT_MAP              (gfx_pango_font_map_get_type())
    1702                 : #define GFX_PANGO_FONT_MAP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMap))
    1703                 : #define GFX_IS_PANGO_FONT_MAP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONT_MAP))
    1704                 : 
    1705                 : GType gfx_pango_font_map_get_type (void);
    1706                 : 
    1707                 : #define GFX_PANGO_FONT_MAP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
    1708                 : #define GFX_IS_PANGO_FONT_MAP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONT_MAP))
    1709                 : #define GFX_PANGO_FONT_MAP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
    1710                 : 
    1711                 : // Do not instantiate this class directly, but use NewFontMap.
    1712                 : // This struct is POD so that it can be used as a GObject.
    1713                 : struct gfxPangoFontMap {
    1714                 :     PangoFcFontMap parent_instance;
    1715                 : 
    1716                 :     static PangoFontMap *
    1717               0 :     NewFontMap()
    1718                 :     {
    1719                 :         gfxPangoFontMap *fontmap = static_cast<gfxPangoFontMap *>
    1720               0 :             (g_object_new(GFX_TYPE_PANGO_FONT_MAP, NULL));
    1721                 : 
    1722               0 :         return PANGO_FONT_MAP(fontmap);
    1723                 :     }
    1724                 : };
    1725                 : 
    1726                 : struct gfxPangoFontMapClass {
    1727                 :     PangoFcFontMapClass parent_class;
    1728                 : };
    1729                 : 
    1730               0 : G_DEFINE_TYPE (gfxPangoFontMap, gfx_pango_font_map, PANGO_TYPE_FC_FONT_MAP)
    1731                 : 
    1732                 : static void
    1733               0 : gfx_pango_font_map_init(gfxPangoFontMap *fontset)
    1734                 : {
    1735               0 : }
    1736                 : 
    1737                 : static PangoFcFont *
    1738               0 : gfx_pango_font_map_new_font(PangoFcFontMap *fontmap,
    1739                 :                             FcPattern *pattern)
    1740                 : {
    1741                 :     // new_font is not likely to be used, but the class makes the method
    1742                 :     // available and shapers have access to the class through the font.  Not
    1743                 :     // bothering to make an effort here because this will only ever be used if
    1744                 :     // pango_cairo_font_map_get_default() does not return a PangoFcFontMap and
    1745                 :     // a shaper tried to create a different font from the one it was provided.
    1746                 :     // Only a basic implementation is provided that simply refuses to
    1747                 :     // create a new font.  PangoFcFontMap allows NULL return values here.
    1748               0 :     return NULL;
    1749                 : }
    1750                 : 
    1751                 : static void
    1752               0 : gfx_pango_font_map_class_init(gfxPangoFontMapClass *klass)
    1753                 : {
    1754                 :     // inherit GObjectClass::finalize from parent as this class adds no data.
    1755                 : 
    1756                 :     // inherit PangoFontMap::load_font (which is not likely to be used)
    1757                 :     //   from PangoFcFontMap
    1758                 :     // inherit PangoFontMap::list_families (which is not likely to be used)
    1759                 :     //   from PangoFcFontMap
    1760                 :     // inherit PangoFontMap::load_fontset (which is not likely to be used)
    1761                 :     //   from PangoFcFontMap
    1762                 :     // inherit PangoFontMap::shape_engine_type from PangoFcFontMap
    1763                 : 
    1764               0 :     PangoFcFontMapClass *fcfontmap_class = PANGO_FC_FONT_MAP_CLASS (klass);
    1765                 :     // default_substitute is not required.
    1766                 :     // The API for create_font changed between Pango 1.22 and 1.24 so new_font
    1767                 :     // is provided instead.
    1768               0 :     fcfontmap_class->new_font = gfx_pango_font_map_new_font;
    1769                 :     // get_resolution is not required.
    1770                 :     // context_key_* virtual functions are only necessary if we want to
    1771                 :     // dynamically respond to changes in the screen cairo_font_options_t.
    1772               0 : }
    1773                 : 
    1774                 : #ifdef MOZ_WIDGET_GTK2
    1775                 : static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
    1776                 : #endif
    1777                 : 
    1778                 : // Apply user settings and defaults to pattern in preparation for matching.
    1779                 : static void
    1780               0 : PrepareSortPattern(FcPattern *aPattern, double aFallbackSize,
    1781                 :                    double aSizeAdjustFactor, bool aIsPrinterFont)
    1782                 : {
    1783               0 :     FcConfigSubstitute(NULL, aPattern, FcMatchPattern);
    1784                 : 
    1785                 :     // This gets cairo_font_options_t for the Screen.  We should have
    1786                 :     // different font options for printing (no hinting) but we are not told
    1787                 :     // what we are measuring for.
    1788                 :     //
    1789                 :     // If cairo adds support for lcd_filter, gdk will not provide the default
    1790                 :     // setting for that option.  We could get the default setting by creating
    1791                 :     // an xlib surface once, recording its font_options, and then merging the
    1792                 :     // gdk options.
    1793                 :     //
    1794                 :     // Using an xlib surface would also be an option to get Screen font
    1795                 :     // options for non-GTK X11 toolkits, but less efficient than using GDK to
    1796                 :     // pick up dynamic changes.
    1797               0 :     if(aIsPrinterFont) {
    1798               0 :        cairo_font_options_t *options = cairo_font_options_create();
    1799               0 :        cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
    1800               0 :        cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
    1801               0 :        cairo_ft_font_options_substitute(options, aPattern);
    1802               0 :        cairo_font_options_destroy(options);
    1803               0 :        FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue);
    1804                 :     } else {
    1805                 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    1806                 :        cairo_font_options_t *options = cairo_font_options_create();
    1807                 :        cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
    1808                 :        cairo_ft_font_options_substitute(options, aPattern);
    1809                 :        cairo_font_options_destroy(options);
    1810                 : #endif
    1811                 : #ifdef MOZ_WIDGET_GTK2
    1812               0 :        ApplyGdkScreenFontOptions(aPattern);
    1813                 : #endif
    1814                 :     }
    1815                 : 
    1816                 :     // Protect against any fontconfig settings that may have incorrectly
    1817                 :     // modified the pixelsize, and consider aSizeAdjustFactor.
    1818               0 :     double size = aFallbackSize;
    1819               0 :     if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch
    1820                 :         || aSizeAdjustFactor != 1.0) {
    1821               0 :         FcPatternDel(aPattern, FC_PIXEL_SIZE);
    1822               0 :         FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor);
    1823                 :     }
    1824                 : 
    1825               0 :     FcDefaultSubstitute(aPattern);
    1826               0 : }
    1827                 : 
    1828                 : /**
    1829                 :  ** gfxPangoFontGroup
    1830                 :  **/
    1831                 : 
    1832                 : struct FamilyCallbackData {
    1833               0 :     FamilyCallbackData(nsTArray<nsString> *aFcFamilyList,
    1834                 :                        gfxUserFontSet *aUserFontSet)
    1835               0 :         : mFcFamilyList(aFcFamilyList), mUserFontSet(aUserFontSet)
    1836                 :     {
    1837               0 :     }
    1838                 :     nsTArray<nsString> *mFcFamilyList;
    1839                 :     const gfxUserFontSet *mUserFontSet;
    1840                 : };
    1841                 : 
    1842                 : static int
    1843               0 : FFRECountHyphens (const nsAString &aFFREName)
    1844                 : {
    1845               0 :     int h = 0;
    1846               0 :     PRInt32 hyphen = 0;
    1847               0 :     while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) {
    1848               0 :         ++h;
    1849               0 :         ++hyphen;
    1850                 :     }
    1851               0 :     return h;
    1852                 : }
    1853                 : 
    1854                 : static bool
    1855               0 : FamilyCallback (const nsAString& fontName, const nsACString& genericName,
    1856                 :                 bool aUseFontSet, void *closure)
    1857                 : {
    1858               0 :     FamilyCallbackData *data = static_cast<FamilyCallbackData*>(closure);
    1859               0 :     nsTArray<nsString> *list = data->mFcFamilyList;
    1860                 : 
    1861                 :     // We ignore prefs that have three hypens since they are X style prefs.
    1862               0 :     if (genericName.Length() && FFRECountHyphens(fontName) >= 3)
    1863               0 :         return true;
    1864                 : 
    1865               0 :     if (!list->Contains(fontName)) {
    1866                 :         // The family properties of FcPatterns for @font-face fonts have a
    1867                 :         // namespace to identify them among system fonts.  (see
    1868                 :         // FONT_FACE_FAMILY_PREFIX.)
    1869                 :         //
    1870                 :         // Earlier versions of this code allowed the CSS family name to match
    1871                 :         // either the @font-face family or the system font family, so both
    1872                 :         // were added here. This was in accordance with earlier versions of
    1873                 :         // the W3C specifications regarding @font-face.
    1874                 :         //
    1875                 :         // The current (2011-02-27) draft of CSS3 Fonts says
    1876                 :         //
    1877                 :         // (Section 4.2: Font family: the font-family descriptor):
    1878                 :         // "If the font family name is the same as a font family available in
    1879                 :         // a given user's environment, it effectively hides the underlying
    1880                 :         // font for documents that use the stylesheet."
    1881                 :         //
    1882                 :         // (Section 5: Font matching algorithm)
    1883                 :         // "... the user agent attempts to find the family name among fonts
    1884                 :         // defined via @font-face rules and then among available system fonts,
    1885                 :         // .... If a font family defined via @font-face rules contains only
    1886                 :         // invalid font data, it should be considered as if a font was present
    1887                 :         // but contained an empty character map; matching a platform font with
    1888                 :         // the same name must not occur in this case."
    1889                 :         //
    1890                 :         // Therefore, for names present in the user font set, this code no
    1891                 :         // longer includes the family name for matching against system fonts.
    1892                 :         //
    1893               0 :         const gfxUserFontSet *userFontSet = data->mUserFontSet;
    1894               0 :         if (aUseFontSet && genericName.Length() == 0 &&
    1895               0 :             userFontSet && userFontSet->HasFamily(fontName)) {
    1896                 :             nsAutoString userFontName =
    1897               0 :                 NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName;
    1898               0 :             list->AppendElement(userFontName);
    1899                 :         } else {
    1900               0 :             list->AppendElement(fontName);
    1901                 :         }
    1902                 :     }
    1903                 : 
    1904               0 :     return true;
    1905                 : }
    1906                 : 
    1907               0 : gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
    1908                 :                                       const gfxFontStyle *aStyle,
    1909                 :                                       gfxUserFontSet *aUserFontSet)
    1910                 :     : gfxFontGroup(families, aStyle, aUserFontSet),
    1911               0 :       mPangoLanguage(GuessPangoLanguage(aStyle->language))
    1912                 : {
    1913                 :     // This language is passed to the font for shaping.
    1914                 :     // Shaping doesn't know about lang groups so make it a real language.
    1915               0 :     if (mPangoLanguage) {
    1916               0 :         mStyle.language = do_GetAtom(pango_language_to_string(mPangoLanguage));
    1917                 :     }
    1918                 : 
    1919               0 :     mFonts.AppendElements(1);
    1920               0 : }
    1921                 : 
    1922               0 : gfxPangoFontGroup::~gfxPangoFontGroup()
    1923                 : {
    1924               0 : }
    1925                 : 
    1926                 : gfxFontGroup *
    1927               0 : gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
    1928                 : {
    1929               0 :     return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet);
    1930                 : }
    1931                 : 
    1932                 : // An array of family names suitable for fontconfig
    1933                 : void
    1934               0 : gfxPangoFontGroup::GetFcFamilies(nsTArray<nsString> *aFcFamilyList,
    1935                 :                                  nsIAtom *aLanguage)
    1936                 : {
    1937               0 :     FamilyCallbackData data(aFcFamilyList, mUserFontSet);
    1938                 :     // Leave non-existing fonts in the list so that fontconfig can get the
    1939                 :     // best match.
    1940                 :     ForEachFontInternal(mFamilies, aLanguage, true, false, true,
    1941               0 :                         FamilyCallback, &data);
    1942               0 : }
    1943                 : 
    1944                 : gfxFcFont *
    1945               0 : gfxPangoFontGroup::GetBaseFont()
    1946                 : {
    1947               0 :     if (!mFonts[0]) {
    1948               0 :         mFonts[0] = GetBaseFontSet()->GetFontAt(0, GetStyle());
    1949                 :     }
    1950                 : 
    1951               0 :     return static_cast<gfxFcFont*>(mFonts[0].get());
    1952                 : }
    1953                 : 
    1954                 : gfxFont *
    1955               0 : gfxPangoFontGroup::GetFontAt(PRInt32 i) {
    1956                 :     // If it turns out to be hard for all clients that cache font
    1957                 :     // groups to call UpdateFontList at appropriate times, we could
    1958                 :     // instead consider just calling UpdateFontList from someplace
    1959                 :     // more central (such as here).
    1960               0 :     NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
    1961                 :                  "Whoever was caching this font group should have "
    1962                 :                  "called UpdateFontList on it");
    1963                 : 
    1964               0 :     NS_PRECONDITION(i == 0, "Only have one font");
    1965                 : 
    1966               0 :     return GetBaseFont();
    1967                 : }
    1968                 : 
    1969                 : void
    1970               0 : gfxPangoFontGroup::UpdateFontList()
    1971                 : {
    1972               0 :     if (!mUserFontSet)
    1973               0 :         return;
    1974                 : 
    1975               0 :     PRUint64 newGeneration = mUserFontSet->GetGeneration();
    1976               0 :     if (newGeneration == mCurrGeneration)
    1977               0 :         return;
    1978                 : 
    1979               0 :     mFonts[0] = NULL;
    1980               0 :     mFontSets.Clear();
    1981               0 :     mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
    1982               0 :     mCurrGeneration = newGeneration;
    1983               0 :     mSkipDrawing = false;
    1984                 : }
    1985                 : 
    1986                 : already_AddRefed<gfxFcFontSet>
    1987               0 : gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
    1988                 :                                nsAutoRef<FcPattern> *aMatchPattern)
    1989                 : {
    1990               0 :     const char *lang = pango_language_to_string(aLang);
    1991                 : 
    1992               0 :     nsRefPtr <nsIAtom> langGroup;
    1993               0 :     if (aLang != mPangoLanguage) {
    1994                 :         // Set up langGroup for Mozilla's font prefs.
    1995               0 :         langGroup = do_GetAtom(lang);
    1996                 :     }
    1997                 : 
    1998               0 :     nsAutoTArray<nsString, 20> fcFamilyList;
    1999                 :     GetFcFamilies(&fcFamilyList,
    2000               0 :                   langGroup ? langGroup.get() : mStyle.language.get());
    2001                 : 
    2002                 :     // To consider: A fontset cache here could be helpful.
    2003                 : 
    2004                 :     // Get a pattern suitable for matching.
    2005                 :     nsAutoRef<FcPattern> pattern
    2006               0 :         (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang));
    2007                 : 
    2008               0 :     PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont);
    2009                 : 
    2010                 :     nsRefPtr<gfxFcFontSet> fontset =
    2011               0 :         new gfxFcFontSet(pattern, mUserFontSet);
    2012                 : 
    2013               0 :     mSkipDrawing = fontset->WaitingForUserFont();
    2014                 : 
    2015               0 :     if (aMatchPattern)
    2016               0 :         aMatchPattern->steal(pattern);
    2017                 : 
    2018               0 :     return fontset.forget();
    2019                 : }
    2020                 : 
    2021               0 : gfxPangoFontGroup::
    2022                 : FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang,
    2023                 :                                        gfxFcFontSet *aFontSet)
    2024               0 :     : mLang(aLang), mFontSet(aFontSet)
    2025                 : {
    2026               0 : }
    2027                 : 
    2028                 : gfxFcFontSet *
    2029               0 : gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang)
    2030                 : {
    2031               0 :     GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0]
    2032                 : 
    2033               0 :     if (!aLang)
    2034               0 :         return mFontSets[0].mFontSet;
    2035                 : 
    2036               0 :     for (PRUint32 i = 0; i < mFontSets.Length(); ++i) {
    2037               0 :         if (mFontSets[i].mLang == aLang)
    2038               0 :             return mFontSets[i].mFontSet;
    2039                 :     }
    2040                 : 
    2041                 :     nsRefPtr<gfxFcFontSet> fontSet =
    2042               0 :         MakeFontSet(aLang, mSizeAdjustFactor);
    2043               0 :     mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet));
    2044                 : 
    2045               0 :     return fontSet;
    2046                 : }
    2047                 : 
    2048                 : already_AddRefed<gfxFont>
    2049               0 : gfxPangoFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
    2050                 :                                    PRInt32 aRunScript,
    2051                 :                                    gfxFont *aPrevMatchedFont,
    2052                 :                                    PRUint8 *aMatchType)
    2053                 : {
    2054               0 :     if (aPrevMatchedFont) {
    2055                 :         // Don't switch fonts for control characters, regardless of
    2056                 :         // whether they are present in the current font, as they won't
    2057                 :         // actually be rendered (see bug 716229)
    2058               0 :         PRUint8 category = GetGeneralCategory(aCh);
    2059               0 :         if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) {
    2060               0 :             return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
    2061                 :         }
    2062                 : 
    2063                 :         // if this character is a join-control or the previous is a join-causer,
    2064                 :         // use the same font as the previous range if we can
    2065               0 :         if (gfxFontUtils::IsJoinControl(aCh) ||
    2066               0 :             gfxFontUtils::IsJoinCauser(aPrevCh)) {
    2067               0 :             if (aPrevMatchedFont->HasCharacter(aCh)) {
    2068               0 :                 return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
    2069                 :             }
    2070                 :         }
    2071                 :     }
    2072                 : 
    2073                 :     // if this character is a variation selector,
    2074                 :     // use the previous font regardless of whether it supports VS or not.
    2075                 :     // otherwise the text run will be divided.
    2076               0 :     if (gfxFontUtils::IsVarSelector(aCh)) {
    2077               0 :         if (aPrevMatchedFont) {
    2078               0 :             return nsRefPtr<gfxFont>(aPrevMatchedFont).forget();
    2079                 :         }
    2080                 :         // VS alone. it's meaningless to search different fonts
    2081               0 :         return nsnull;
    2082                 :     }
    2083                 : 
    2084                 :     // The real fonts that fontconfig provides for generic/fallback families
    2085                 :     // depend on the language used, so a different FontSet is used for each
    2086                 :     // language (except for the variation below).
    2087                 :     //
    2088                 :     //   With most fontconfig configurations any real family names prior to a
    2089                 :     //   fontconfig generic with corresponding fonts installed will still lead
    2090                 :     //   to the same leading fonts in each FontSet.
    2091                 :     //
    2092                 :     //   There is an inefficiency here therefore because the same base FontSet
    2093                 :     //   could often be used if these real families support the character.
    2094                 :     //   However, with fontconfig aliases, it is difficult to distinguish
    2095                 :     //   where exactly alias fonts end and generic/fallback fonts begin.
    2096                 :     //
    2097                 :     // The variation from pure language-based matching used here is that the
    2098                 :     // same primary/base font is always used irrespective of the language.
    2099                 :     // This provides that SCRIPT_COMMON characters are consistently rendered
    2100                 :     // with the same font (bug 339513 and bug 416725).  This is particularly
    2101                 :     // important with the word cache as script can't be reliably determined
    2102                 :     // from surrounding words.  It also often avoids the unnecessary extra
    2103                 :     // FontSet efficiency mentioned above.
    2104                 :     //
    2105                 :     // However, in two situations, the base font is not checked before the
    2106                 :     // language-specific FontSet.
    2107                 :     //
    2108                 :     //   1. When we don't have a language to make a good choice for
    2109                 :     //      the base font.
    2110                 :     //
    2111                 :     //   2. For system fonts, use the default Pango behavior to give
    2112                 :     //      consistency with other apps.  This is relevant when un-localized
    2113                 :     //      builds are run in non-Latin locales.  This special-case probably
    2114                 :     //      wouldn't be necessary but for bug 91190.
    2115                 : 
    2116               0 :     gfxFcFontSet *fontSet = GetBaseFontSet();
    2117               0 :     PRUint32 nextFont = 0;
    2118               0 :     FcPattern *basePattern = NULL;
    2119               0 :     if (!mStyle.systemFont && mPangoLanguage) {
    2120               0 :         basePattern = fontSet->GetFontPatternAt(0);
    2121               0 :         if (HasChar(basePattern, aCh)) {
    2122               0 :             *aMatchType = gfxTextRange::kFontGroup;
    2123               0 :             return nsRefPtr<gfxFont>(GetBaseFont()).forget();
    2124                 :         }
    2125                 : 
    2126               0 :         nextFont = 1;
    2127                 :     }
    2128                 : 
    2129                 :     // Pango, GLib, and Thebes (but not harfbuzz!) all happen to use the same
    2130                 :     // script codes, so we can just cast the value here.
    2131               0 :     const PangoScript script = static_cast<PangoScript>(aRunScript);
    2132                 :     // Might be nice to call pango_language_includes_script only once for the
    2133                 :     // run rather than for each character.
    2134                 :     PangoLanguage *scriptLang;
    2135               0 :     if ((!basePattern ||
    2136               0 :          !pango_language_includes_script(mPangoLanguage, script)) &&
    2137                 :         (scriptLang = pango_script_get_sample_language(script))) {
    2138               0 :         fontSet = GetFontSet(scriptLang);
    2139               0 :         nextFont = 0;
    2140                 :     }
    2141                 : 
    2142               0 :     for (PRUint32 i = nextFont;
    2143               0 :          FcPattern *pattern = fontSet->GetFontPatternAt(i);
    2144                 :          ++i) {
    2145               0 :         if (pattern == basePattern) {
    2146               0 :             continue; // already checked basePattern
    2147                 :         }
    2148                 : 
    2149               0 :         if (HasChar(pattern, aCh)) {
    2150               0 :             *aMatchType = gfxTextRange::kFontGroup;
    2151               0 :             return nsRefPtr<gfxFont>(fontSet->GetFontAt(i, GetStyle())).forget();
    2152                 :         }
    2153                 :     }
    2154                 : 
    2155               0 :     return nsnull;
    2156                 : }
    2157                 : 
    2158                 : // Sanity-check: spot-check a few constants to confirm that Thebes and
    2159                 : // Pango script codes really do match
    2160                 : PR_STATIC_ASSERT(MOZ_SCRIPT_COMMON    == PANGO_SCRIPT_COMMON);
    2161                 : PR_STATIC_ASSERT(MOZ_SCRIPT_INHERITED == PANGO_SCRIPT_INHERITED);
    2162                 : PR_STATIC_ASSERT(MOZ_SCRIPT_ARABIC    == PANGO_SCRIPT_ARABIC);
    2163                 : PR_STATIC_ASSERT(MOZ_SCRIPT_LATIN     == PANGO_SCRIPT_LATIN);
    2164                 : PR_STATIC_ASSERT(MOZ_SCRIPT_UNKNOWN   == PANGO_SCRIPT_UNKNOWN);
    2165                 : PR_STATIC_ASSERT(MOZ_SCRIPT_NKO       == PANGO_SCRIPT_NKO);
    2166                 : 
    2167                 : /**
    2168                 :  ** gfxFcFont
    2169                 :  **/
    2170                 : 
    2171                 : cairo_user_data_key_t gfxFcFont::sGfxFontKey;
    2172                 : 
    2173               0 : gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
    2174                 :                      gfxFcFontEntry *aFontEntry,
    2175                 :                      const gfxFontStyle *aFontStyle)
    2176                 :     : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle),
    2177               0 :       mPangoFont()
    2178                 : {
    2179               0 :     cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, NULL);
    2180               0 : }
    2181                 : 
    2182                 : // The gfxFcFont keeps (only) a toggle_ref on mPangoFont.
    2183                 : // While mPangoFont has other references, a reference to the
    2184                 : // gfxFcFont is held.  While mPangoFont has no other references, the reference
    2185                 : // to the gfxFcFont is removed.
    2186                 : static void
    2187               0 : PangoFontToggleNotify(gpointer data, GObject* object, gboolean is_last_ref)
    2188                 : {
    2189               0 :     gfxFcFont *font = static_cast<gfxFcFont*>(data);
    2190               0 :     if (is_last_ref) { // gfxFcFont has last ref to PangoFont
    2191               0 :         NS_RELEASE(font);
    2192                 :     } else {
    2193               0 :         NS_ADDREF(font);
    2194                 :     }
    2195               0 : }
    2196                 : 
    2197                 : void
    2198               0 : gfxFcFont::MakePangoFont()
    2199                 : {
    2200                 :     // Switch from a normal reference to a toggle_ref.
    2201               0 :     gfxFcFontEntry *fe = static_cast<gfxFcFontEntry*>(mFontEntry.get());
    2202                 :     nsAutoRef<PangoFont> pangoFont
    2203               0 :         (gfxPangoFcFont::NewFont(this, fe->GetPatterns()[0]));
    2204               0 :     mPangoFont = pangoFont;
    2205               0 :     g_object_add_toggle_ref(G_OBJECT(mPangoFont), PangoFontToggleNotify, this);
    2206                 :     // This self-reference gets removed when the normal reference to the
    2207                 :     // PangoFont is removed as the nsAutoRef goes out of scope.
    2208               0 :     NS_ADDREF(this);
    2209               0 : }
    2210                 : 
    2211               0 : gfxFcFont::~gfxFcFont()
    2212                 : {
    2213               0 :     cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, NULL, NULL);
    2214               0 :     if (mPangoFont) {
    2215               0 :         g_object_remove_toggle_ref(G_OBJECT(mPangoFont),
    2216               0 :                                    PangoFontToggleNotify, this);
    2217                 :     }
    2218               0 : }
    2219                 : 
    2220                 : bool
    2221               0 : gfxFcFont::ShapeWord(gfxContext *aContext,
    2222                 :                      gfxShapedWord *aShapedWord,
    2223                 :                      const PRUnichar *aString,
    2224                 :                      bool aPreferPlatformShaping)
    2225                 : {
    2226               0 :     gfxFcFontEntry *fontEntry = static_cast<gfxFcFontEntry*>(GetFontEntry());
    2227                 : 
    2228                 : #ifdef MOZ_GRAPHITE
    2229               0 :     if (FontCanSupportGraphite()) {
    2230               0 :         if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
    2231               0 :             if (!mGraphiteShaper) {
    2232               0 :                 mGraphiteShaper = new gfxGraphiteShaper(this);
    2233                 :             }
    2234               0 :             if (mGraphiteShaper->ShapeWord(aContext, aShapedWord, aString)) {
    2235               0 :                 return true;
    2236                 :             }
    2237                 :         }
    2238                 :     }
    2239                 : #endif
    2240                 : 
    2241               0 :     if (fontEntry->ShouldUseHarfBuzz(aShapedWord->Script())) {
    2242               0 :         if (!mHarfBuzzShaper) {
    2243               0 :             gfxFT2LockedFace face(this);
    2244               0 :             mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
    2245                 :             // Used by gfxHarfBuzzShaper, currently only for kerning
    2246               0 :             mFUnitsConvFactor = face.XScale();
    2247                 :         }
    2248               0 :         if (mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aString)) {
    2249               0 :             return true;
    2250                 :         }
    2251                 : 
    2252                 :         // Wrong font type for HarfBuzz
    2253               0 :         fontEntry->SkipHarfBuzz();
    2254               0 :         mHarfBuzzShaper = nsnull;
    2255                 :     }
    2256                 : 
    2257               0 :     bool ok = InitGlyphRunWithPango(aShapedWord, aString);
    2258                 : 
    2259               0 :     NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
    2260               0 :     return ok;
    2261                 : }
    2262                 : 
    2263                 : /* static */ void
    2264               3 : gfxPangoFontGroup::Shutdown()
    2265                 : {
    2266               3 :     if (gPangoFontMap) {
    2267               0 :         g_object_unref(gPangoFontMap);
    2268               0 :         gPangoFontMap = NULL;
    2269                 :     }
    2270                 : 
    2271                 :     // Resetting gFTLibrary in case this is wanted again after a
    2272                 :     // cairo_debug_reset_static_data.
    2273               3 :     gFTLibrary = NULL;
    2274               3 : }
    2275                 : 
    2276                 : /* static */ gfxFontEntry *
    2277               0 : gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
    2278                 :                                 const nsAString& aFullname)
    2279                 : {
    2280               0 :     gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
    2281               0 :     if (!utils)
    2282               0 :         return nsnull;
    2283                 : 
    2284                 :     // The font face name from @font-face { src: local() } is not well
    2285                 :     // defined.
    2286                 :     //
    2287                 :     // On MS Windows, this name gets compared with
    2288                 :     // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the
    2289                 :     // full font name from the name table.  For CFF OpenType fonts this is the
    2290                 :     // same as the PostScript name, but for TrueType fonts it is usually
    2291                 :     // different.
    2292                 :     //
    2293                 :     // On Mac, the font face name is compared with the PostScript name, even
    2294                 :     // for TrueType fonts.
    2295                 :     //
    2296                 :     // Fontconfig only records the full font names, so the behavior here
    2297                 :     // follows that on MS Windows.  However, to provide the possibility
    2298                 :     // of aliases to compensate for variations, the font face name is passed
    2299                 :     // through FcConfigSubstitute.
    2300                 : 
    2301               0 :     nsAutoRef<FcPattern> pattern(FcPatternCreate());
    2302               0 :     if (!pattern)
    2303               0 :         return nsnull;
    2304                 : 
    2305               0 :     NS_ConvertUTF16toUTF8 fullname(aFullname);
    2306                 :     FcPatternAddString(pattern, FC_FULLNAME,
    2307               0 :                        gfxFontconfigUtils::ToFcChar8(fullname));
    2308               0 :     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
    2309                 : 
    2310                 :     FcChar8 *name;
    2311               0 :     for (int v = 0;
    2312               0 :          FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch;
    2313                 :          ++v) {
    2314                 :         const nsTArray< nsCountedRef<FcPattern> >& fonts =
    2315               0 :             utils->GetFontsForFullname(name);
    2316                 : 
    2317               0 :         if (fonts.Length() != 0)
    2318               0 :             return new gfxLocalFcFontEntry(aProxyEntry, fonts);
    2319                 :     }
    2320                 : 
    2321               0 :     return nsnull;
    2322                 : }
    2323                 : 
    2324                 : /* static */ FT_Library
    2325               0 : gfxPangoFontGroup::GetFTLibrary()
    2326                 : {
    2327               0 :     if (!gFTLibrary) {
    2328                 :         // Use cairo's FT_Library so that cairo takes care of shutdown of the
    2329                 :         // FT_Library after it has destroyed its font_faces, and FT_Done_Face
    2330                 :         // has been called on each FT_Face, at least until this bug is fixed:
    2331                 :         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
    2332                 :         //
    2333                 :         // Cairo's FT_Library can be obtained from any cairo_scaled_font.  The
    2334                 :         // font properties requested here are chosen to get an FT_Face that is
    2335                 :         // likely to be also used elsewhere.
    2336               0 :         gfxFontStyle style;
    2337                 :         nsRefPtr<gfxPangoFontGroup> fontGroup =
    2338               0 :             new gfxPangoFontGroup(NS_LITERAL_STRING("sans-serif"),
    2339               0 :                                   &style, nsnull);
    2340                 : 
    2341               0 :         gfxFcFont *font = fontGroup->GetBaseFont();
    2342               0 :         if (!font)
    2343               0 :             return NULL;
    2344                 : 
    2345               0 :         gfxFT2LockedFace face(font);
    2346               0 :         if (!face.get())
    2347               0 :             return NULL;
    2348                 : 
    2349               0 :         gFTLibrary = face.get()->glyph->library;
    2350                 :     }
    2351                 : 
    2352               0 :     return gFTLibrary;
    2353                 : }
    2354                 : 
    2355                 : /* static */ gfxFontEntry *
    2356               0 : gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
    2357                 :                                 const PRUint8 *aFontData, PRUint32 aLength)
    2358                 : {
    2359                 :     // Ownership of aFontData is passed in here, and transferred to the
    2360                 :     // new fontEntry, which will release it when no longer needed.
    2361                 : 
    2362                 :     // Using face_index = 0 for the first face in the font, as we have no
    2363                 :     // other information.  FT_New_Memory_Face checks for a NULL FT_Library.
    2364                 :     FT_Face face;
    2365                 :     FT_Error error =
    2366               0 :         FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face);
    2367               0 :     if (error != 0) {
    2368               0 :         NS_Free((void*)aFontData);
    2369               0 :         return nsnull;
    2370                 :     }
    2371                 : 
    2372               0 :     return new gfxDownloadedFcFontEntry(aProxyEntry, aFontData, face);
    2373                 : }
    2374                 : 
    2375                 : 
    2376                 : static double
    2377               0 : GetPixelSize(FcPattern *aPattern)
    2378                 : {
    2379                 :     double size;
    2380               0 :     if (FcPatternGetDouble(aPattern,
    2381               0 :                            FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
    2382               0 :         return size;
    2383                 : 
    2384               0 :     NS_NOTREACHED("No size on pattern");
    2385               0 :     return 0.0;
    2386                 : }
    2387                 : 
    2388                 : /**
    2389                 :  * The following gfxFcFonts are accessed from the cairo_scaled_font or created
    2390                 :  * from the FcPattern, not from the gfxFontCache hash table.  The gfxFontCache
    2391                 :  * hash table is keyed by desired family and style, whereas here we only know
    2392                 :  * actual family and style.  There may be more than one of these fonts with
    2393                 :  * the same family and style, but different PangoFont and actual font face.
    2394                 :  * 
    2395                 :  * The point of this is to record the exact font face for gfxTextRun glyph
    2396                 :  * indices.  The style of this font does not necessarily represent the exact
    2397                 :  * gfxFontStyle used to build the text run.  Notably, the language is not
    2398                 :  * recorded.
    2399                 :  */
    2400                 : 
    2401                 : /* static */
    2402                 : already_AddRefed<gfxFcFont>
    2403               0 : gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
    2404                 :                          const gfxFontStyle *aFontStyle)
    2405                 : {
    2406                 :     nsAutoRef<FcPattern> renderPattern
    2407               0 :         (FcFontRenderPrepare(NULL, aRequestedPattern, aFontPattern));
    2408                 :     cairo_font_face_t *face =
    2409               0 :         cairo_ft_font_face_create_for_pattern(renderPattern);
    2410                 : 
    2411                 :     // Reuse an existing font entry if available.
    2412               0 :     nsRefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face);
    2413               0 :     if (!fe) {
    2414                 :         gfxDownloadedFcFontEntry *downloadedFontEntry =
    2415               0 :             GetDownloadedFontEntry(aFontPattern);
    2416               0 :         if (downloadedFontEntry) {
    2417                 :             // Web font
    2418               0 :             fe = downloadedFontEntry;
    2419               0 :             if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) {
    2420                 :                 // cairo_font_face_t is using the web font data.
    2421                 :                 // Hold a reference to the font entry to keep the font face
    2422                 :                 // data.
    2423               0 :                 if (!downloadedFontEntry->SetCairoFace(face)) {
    2424                 :                     // OOM.  Let cairo pick a fallback font
    2425               0 :                     cairo_font_face_destroy(face);
    2426               0 :                     face = cairo_ft_font_face_create_for_pattern(aRequestedPattern);
    2427               0 :                     fe = gfxFcFontEntry::LookupFontEntry(face);
    2428                 :                 }
    2429                 :             }
    2430                 :         }
    2431               0 :         if (!fe) {
    2432                 :             // Get a unique name for the font face from the file and id.
    2433               0 :             nsAutoString name;
    2434                 :             FcChar8 *fc_file;
    2435               0 :             if (FcPatternGetString(renderPattern,
    2436               0 :                                    FC_FILE, 0, &fc_file) == FcResultMatch) {
    2437                 :                 int index;
    2438               0 :                 if (FcPatternGetInteger(renderPattern,
    2439               0 :                                         FC_INDEX, 0, &index) != FcResultMatch) {
    2440                 :                     // cairo defaults to 0.
    2441               0 :                     index = 0;
    2442                 :                 }
    2443                 : 
    2444               0 :                 AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name);
    2445               0 :                 if (index != 0) {
    2446               0 :                     name.AppendLiteral("/");
    2447               0 :                     name.AppendInt(index);
    2448                 :                 }
    2449                 :             }
    2450                 : 
    2451               0 :             fe = new gfxSystemFcFontEntry(face, aFontPattern, name);
    2452                 :         }
    2453                 :     }
    2454                 : 
    2455               0 :     gfxFontStyle style(*aFontStyle);
    2456               0 :     style.size = GetPixelSize(renderPattern);
    2457               0 :     style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern);
    2458               0 :     style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern);
    2459                 : 
    2460               0 :     nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(fe, &style);
    2461               0 :     if (!font) {
    2462                 :         // Note that a file/index pair (or FT_Face) and the gfxFontStyle are
    2463                 :         // not necessarily enough to provide a key that will describe a unique
    2464                 :         // font.  cairoFont contains information from renderPattern, which is a
    2465                 :         // fully resolved pattern from FcFontRenderPrepare.
    2466                 :         // FcFontRenderPrepare takes the requested pattern and the face
    2467                 :         // pattern as input and can modify elements of the resulting pattern
    2468                 :         // that affect rendering but are not included in the gfxFontStyle.
    2469               0 :         cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face);
    2470               0 :         font = new gfxFcFont(cairoFont, fe, &style);
    2471               0 :         gfxFontCache::GetCache()->AddNew(font);
    2472               0 :         cairo_scaled_font_destroy(cairoFont);
    2473                 :     }
    2474                 : 
    2475               0 :     cairo_font_face_destroy(face);
    2476                 : 
    2477               0 :     nsRefPtr<gfxFcFont> retval(static_cast<gfxFcFont*>(font.get()));
    2478               0 :     return retval.forget();
    2479                 : }
    2480                 : 
    2481                 : static PangoFontMap *
    2482               0 : GetPangoFontMap()
    2483                 : {
    2484               0 :     if (!gPangoFontMap) {
    2485                 :         // This is the same FontMap used by GDK, so that the same
    2486                 :         // PangoCoverage cache is shared.
    2487               0 :         gPangoFontMap = pango_cairo_font_map_get_default();
    2488                 : 
    2489               0 :         if (PANGO_IS_FC_FONT_MAP(gPangoFontMap)) {
    2490               0 :             g_object_ref(gPangoFontMap);
    2491                 :         } else {
    2492                 :             // Future proofing: We need a PangoFcFontMap for gfxPangoFcFont.
    2493                 :             // pango_cairo_font_map_get_default() is expected to return a
    2494                 :             // PangoFcFontMap on Linux systems, but, just in case this ever
    2495                 :             // changes, we provide our own basic implementation.
    2496               0 :             gPangoFontMap = gfxPangoFontMap::NewFontMap();
    2497                 :         }
    2498                 :     }
    2499               0 :     return gPangoFontMap;
    2500                 : }
    2501                 : 
    2502                 : gfxFcFontSet *
    2503               0 : gfxPangoFontGroup::GetBaseFontSet()
    2504                 : {
    2505               0 :     if (mFontSets.Length() > 0)
    2506               0 :         return mFontSets[0].mFontSet;
    2507                 : 
    2508               0 :     mSizeAdjustFactor = 1.0; // will be adjusted below if necessary
    2509               0 :     nsAutoRef<FcPattern> pattern;
    2510                 :     nsRefPtr<gfxFcFontSet> fontSet =
    2511               0 :         MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern);
    2512                 : 
    2513               0 :     double size = GetPixelSize(pattern);
    2514               0 :     if (size != 0.0 && mStyle.sizeAdjust != 0.0) {
    2515               0 :         gfxFcFont *font = fontSet->GetFontAt(0, GetStyle());
    2516               0 :         if (font) {
    2517               0 :             const gfxFont::Metrics& metrics = font->GetMetrics();
    2518                 : 
    2519                 :             // The factor of 0.1 ensures that xHeight is sane so fonts don't
    2520                 :             // become huge.  Strictly ">" ensures that xHeight and emHeight are
    2521                 :             // not both zero.
    2522               0 :             if (metrics.xHeight > 0.1 * metrics.emHeight) {
    2523                 :                 mSizeAdjustFactor =
    2524               0 :                     mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight;
    2525                 : 
    2526               0 :                 size *= mSizeAdjustFactor;
    2527               0 :                 FcPatternDel(pattern, FC_PIXEL_SIZE);
    2528               0 :                 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
    2529                 : 
    2530               0 :                 fontSet = new gfxFcFontSet(pattern, mUserFontSet);
    2531                 :             }
    2532                 :         }
    2533                 :     }
    2534                 : 
    2535               0 :     PangoLanguage *pangoLang = mPangoLanguage;
    2536                 :     FcChar8 *fcLang;
    2537               0 :     if (!pangoLang &&
    2538               0 :         FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) {
    2539                 :         pangoLang =
    2540               0 :             pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang));
    2541                 :     }
    2542                 : 
    2543               0 :     mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet));
    2544                 : 
    2545               0 :     return fontSet;
    2546                 : }
    2547                 : 
    2548                 : /**
    2549                 :  ** gfxTextRun
    2550                 :  * 
    2551                 :  * A serious problem:
    2552                 :  *
    2553                 :  * -- We draw with a font that's hinted for the CTM, but we measure with a font
    2554                 :  * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
    2555                 :  * 
    2556                 :  **/
    2557                 : 
    2558                 : // This will fetch an existing scaled_font if one exists.
    2559                 : static cairo_scaled_font_t *
    2560               0 : CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace)
    2561                 : {
    2562               0 :     double size = GetPixelSize(aPattern);
    2563                 :         
    2564                 :     cairo_matrix_t fontMatrix;
    2565                 :     FcMatrix *fcMatrix;
    2566               0 :     if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch)
    2567               0 :         cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0);
    2568                 :     else
    2569               0 :         cairo_matrix_init_identity(&fontMatrix);
    2570               0 :     cairo_matrix_scale(&fontMatrix, size, size);
    2571                 : 
    2572                 :     FcBool printing;
    2573               0 :     if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) {
    2574               0 :         printing = FcFalse;
    2575                 :     }
    2576                 : 
    2577                 :     // The cairo_scaled_font is created with a unit ctm so that metrics and
    2578                 :     // positions are in user space, but this means that hinting effects will
    2579                 :     // not be estimated accurately for non-unit transformations.
    2580                 :     cairo_matrix_t identityMatrix;
    2581               0 :     cairo_matrix_init_identity(&identityMatrix);
    2582                 : 
    2583                 :     // Font options are set explicitly here to improve cairo's caching
    2584                 :     // behavior and to record the relevant parts of the pattern for
    2585                 :     // SetupCairoFont (so that the pattern can be released).
    2586                 :     //
    2587                 :     // Most font_options have already been set as defaults on the FcPattern
    2588                 :     // with cairo_ft_font_options_substitute(), then user and system
    2589                 :     // fontconfig configurations were applied.  The resulting font_options
    2590                 :     // have been recorded on the face during
    2591                 :     // cairo_ft_font_face_create_for_pattern().
    2592                 :     //
    2593                 :     // None of the settings here cause this scaled_font to behave any
    2594                 :     // differently from how it would behave if it were created from the same
    2595                 :     // face with default font_options.
    2596                 :     //
    2597                 :     // We set options explicitly so that the same scaled_font will be found in
    2598                 :     // the cairo_scaled_font_map when cairo loads glyphs from a context with
    2599                 :     // the same font_face, font_matrix, ctm, and surface font_options.
    2600                 :     //
    2601                 :     // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
    2602                 :     // font_options on the cairo_ft_font_face, and doesn't consider default
    2603                 :     // option values to not match any explicit values.
    2604                 :     //
    2605                 :     // Even after cairo_set_scaled_font is used to set font_options for the
    2606                 :     // cairo context, when cairo looks for a scaled_font for the context, it
    2607                 :     // will look for a font with some option values from the target surface if
    2608                 :     // any values are left default on the context font_options.  If this
    2609                 :     // scaled_font is created with default font_options, cairo will not find
    2610                 :     // it.
    2611               0 :     cairo_font_options_t *fontOptions = cairo_font_options_create();
    2612                 : 
    2613                 :     // The one option not recorded in the pattern is hint_metrics, which will
    2614                 :     // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
    2615                 :     // We should be considering the font_options of the surface on which this
    2616                 :     // font will be used, but currently we don't have different gfxFonts for
    2617                 :     // different surface font_options, so we'll create a font suitable for the
    2618                 :     // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
    2619                 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    2620                 :     cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
    2621                 : #else
    2622               0 :     if (printing) {
    2623               0 :         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
    2624                 :     } else {
    2625               0 :         cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON);
    2626                 :     }
    2627                 : #endif
    2628                 : 
    2629                 :     // The remaining options have been recorded on the pattern and the face.
    2630                 :     // _cairo_ft_options_merge has some logic to decide which options from the
    2631                 :     // scaled_font or from the cairo_ft_font_face take priority in the way the
    2632                 :     // font behaves.
    2633                 :     //
    2634                 :     // In the majority of cases, _cairo_ft_options_merge uses the options from
    2635                 :     // the cairo_ft_font_face, so sometimes it is not so important which
    2636                 :     // values are set here so long as they are not defaults, but we'll set
    2637                 :     // them to the exact values that we expect from the font, to be consistent
    2638                 :     // and to protect against changes in cairo.
    2639                 :     //
    2640                 :     // In some cases, _cairo_ft_options_merge uses some options from the
    2641                 :     // scaled_font's font_options rather than options on the
    2642                 :     // cairo_ft_font_face (from fontconfig).
    2643                 :     // https://bugs.freedesktop.org/show_bug.cgi?id=11838
    2644                 :     //
    2645                 :     // Surface font options were set on the pattern in
    2646                 :     // cairo_ft_font_options_substitute.  If fontconfig has changed the
    2647                 :     // hint_style then that is what the user (or distribution) wants, so we
    2648                 :     // use the setting from the FcPattern.
    2649                 :     //
    2650                 :     // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
    2651               0 :     FcBool hinting = FcFalse;
    2652                 : #ifndef MOZ_GFX_OPTIMIZE_MOBILE
    2653               0 :     if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
    2654               0 :         hinting = FcTrue;
    2655                 :     }
    2656                 : #endif
    2657                 :     cairo_hint_style_t hint_style;
    2658               0 :     if (printing || !hinting) {
    2659               0 :         hint_style = CAIRO_HINT_STYLE_NONE;
    2660                 :     } else {
    2661                 : #ifdef FC_HINT_STYLE  // FC_HINT_STYLE is available from fontconfig 2.2.91.
    2662                 :         int fc_hintstyle;
    2663               0 :         if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
    2664               0 :                                 0, &fc_hintstyle        ) != FcResultMatch) {
    2665               0 :             fc_hintstyle = FC_HINT_FULL;
    2666                 :         }
    2667               0 :         switch (fc_hintstyle) {
    2668                 :             case FC_HINT_NONE:
    2669               0 :                 hint_style = CAIRO_HINT_STYLE_NONE;
    2670               0 :                 break;
    2671                 :             case FC_HINT_SLIGHT:
    2672               0 :                 hint_style = CAIRO_HINT_STYLE_SLIGHT;
    2673               0 :                 break;
    2674                 :             case FC_HINT_MEDIUM:
    2675                 :             default: // This fallback mirrors _get_pattern_ft_options in cairo.
    2676               0 :                 hint_style = CAIRO_HINT_STYLE_MEDIUM;
    2677               0 :                 break;
    2678                 :             case FC_HINT_FULL:
    2679               0 :                 hint_style = CAIRO_HINT_STYLE_FULL;
    2680               0 :                 break;
    2681                 :         }
    2682                 : #else // no FC_HINT_STYLE
    2683                 :         hint_style = CAIRO_HINT_STYLE_FULL;
    2684                 : #endif
    2685                 :     }
    2686               0 :     cairo_font_options_set_hint_style(fontOptions, hint_style);
    2687                 : 
    2688                 :     int rgba;
    2689               0 :     if (FcPatternGetInteger(aPattern,
    2690               0 :                             FC_RGBA, 0, &rgba) != FcResultMatch) {
    2691               0 :         rgba = FC_RGBA_UNKNOWN;
    2692                 :     }
    2693               0 :     cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
    2694               0 :     switch (rgba) {
    2695                 :         case FC_RGBA_UNKNOWN:
    2696                 :         case FC_RGBA_NONE:
    2697                 :         default:
    2698                 :             // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
    2699                 :             // is disabled through cairo_antialias_t.
    2700               0 :             rgba = FC_RGBA_NONE;
    2701                 :             // subpixel_order won't be used by the font as we won't use
    2702                 :             // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
    2703                 :             // caching reasons described above.  Fall through:
    2704                 :         case FC_RGBA_RGB:
    2705               0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
    2706               0 :             break;
    2707                 :         case FC_RGBA_BGR:
    2708               0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
    2709               0 :             break;
    2710                 :         case FC_RGBA_VRGB:
    2711               0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
    2712               0 :             break;
    2713                 :         case FC_RGBA_VBGR:
    2714               0 :             subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
    2715               0 :             break;
    2716                 :     }
    2717               0 :     cairo_font_options_set_subpixel_order(fontOptions, subpixel_order);
    2718                 : 
    2719                 :     FcBool fc_antialias;
    2720               0 :     if (FcPatternGetBool(aPattern,
    2721               0 :                          FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
    2722               0 :         fc_antialias = FcTrue;
    2723                 :     }
    2724                 :     cairo_antialias_t antialias;
    2725               0 :     if (!fc_antialias) {
    2726               0 :         antialias = CAIRO_ANTIALIAS_NONE;
    2727               0 :     } else if (rgba == FC_RGBA_NONE) {
    2728               0 :         antialias = CAIRO_ANTIALIAS_GRAY;
    2729                 :     } else {
    2730               0 :         antialias = CAIRO_ANTIALIAS_SUBPIXEL;
    2731                 :     }
    2732               0 :     cairo_font_options_set_antialias(fontOptions, antialias);
    2733                 : 
    2734                 :     cairo_scaled_font_t *scaledFont =
    2735                 :         cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix,
    2736               0 :                                  fontOptions);
    2737                 : 
    2738               0 :     cairo_font_options_destroy(fontOptions);
    2739                 : 
    2740               0 :     NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
    2741                 :                  "Failed to create scaled font");
    2742               0 :     return scaledFont;
    2743                 : }
    2744                 : 
    2745                 : static PRInt32
    2746               0 : ConvertPangoToAppUnits(PRInt32 aCoordinate, PRUint32 aAppUnitsPerDevUnit)
    2747                 : {
    2748               0 :     PRInt64 v = (PRInt64(aCoordinate)*aAppUnitsPerDevUnit + PANGO_SCALE/2)/PANGO_SCALE;
    2749               0 :     return PRInt32(v);
    2750                 : }
    2751                 : 
    2752                 : /**
    2753                 :  * Given a run of Pango glyphs that should be treated as a single
    2754                 :  * cluster/ligature, store them in the textrun at the appropriate character
    2755                 :  * and set the other characters involved to be ligature/cluster continuations
    2756                 :  * as appropriate.
    2757                 :  */ 
    2758                 : static nsresult
    2759               0 : SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, PRUint32 aGlyphCount,
    2760                 :                            gfxShapedWord *aShapedWord,
    2761                 :                            const gchar *aUTF8, PRUint32 aUTF8Length,
    2762                 :                            PRUint32 *aUTF16Offset,
    2763                 :                            PangoGlyphUnit aOverrideSpaceWidth)
    2764                 : {
    2765               0 :     PRUint32 utf16Offset = *aUTF16Offset;
    2766               0 :     PRUint32 wordLength = aShapedWord->Length();
    2767               0 :     const PRUint32 appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
    2768                 : 
    2769                 :     // Override the width of a space, but only for spaces that aren't
    2770                 :     // clustered with something else (like a freestanding diacritical mark)
    2771               0 :     PangoGlyphUnit width = aGlyphs[0].geometry.width;
    2772               0 :     if (aOverrideSpaceWidth && aUTF8[0] == ' ' &&
    2773                 :         (utf16Offset + 1 == wordLength ||
    2774               0 :          aShapedWord->IsClusterStart(utf16Offset))) {
    2775               0 :         width = aOverrideSpaceWidth;
    2776                 :     }
    2777               0 :     PRInt32 advance = ConvertPangoToAppUnits(width, appUnitsPerDevUnit);
    2778                 : 
    2779               0 :     gfxShapedWord::CompressedGlyph g;
    2780               0 :     bool atClusterStart = aShapedWord->IsClusterStart(utf16Offset);
    2781                 :     // See if we fit in the compressed area.
    2782               0 :     if (aGlyphCount == 1 && advance >= 0 && atClusterStart &&
    2783                 :         aGlyphs[0].geometry.x_offset == 0 &&
    2784                 :         aGlyphs[0].geometry.y_offset == 0 &&
    2785               0 :         !IS_EMPTY_GLYPH(aGlyphs[0].glyph) &&
    2786               0 :         gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
    2787               0 :         gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(aGlyphs[0].glyph)) {
    2788                 :         aShapedWord->SetSimpleGlyph(utf16Offset,
    2789               0 :                                     g.SetSimpleGlyph(advance, aGlyphs[0].glyph));
    2790                 :     } else {
    2791               0 :         nsAutoTArray<gfxShapedWord::DetailedGlyph,10> detailedGlyphs;
    2792               0 :         if (!detailedGlyphs.AppendElements(aGlyphCount))
    2793               0 :             return NS_ERROR_OUT_OF_MEMORY;
    2794                 : 
    2795               0 :         PRInt32 direction = aShapedWord->IsRightToLeft() ? -1 : 1;
    2796               0 :         PRUint32 pangoIndex = direction > 0 ? 0 : aGlyphCount - 1;
    2797               0 :         PRUint32 detailedIndex = 0;
    2798               0 :         for (PRUint32 i = 0; i < aGlyphCount; ++i) {
    2799               0 :             const PangoGlyphInfo &glyph = aGlyphs[pangoIndex];
    2800               0 :             pangoIndex += direction;
    2801                 :             // The zero width characters return empty glyph ID at
    2802                 :             // shaping; we should skip these.
    2803               0 :             if (IS_EMPTY_GLYPH(glyph.glyph))
    2804               0 :                 continue;
    2805                 : 
    2806               0 :             gfxShapedWord::DetailedGlyph *details = &detailedGlyphs[detailedIndex];
    2807               0 :             ++detailedIndex;
    2808                 : 
    2809               0 :             details->mGlyphID = glyph.glyph;
    2810               0 :             NS_ASSERTION(details->mGlyphID == glyph.glyph,
    2811                 :                          "Seriously weird glyph ID detected!");
    2812                 :             details->mAdvance =
    2813                 :                 ConvertPangoToAppUnits(glyph.geometry.width,
    2814               0 :                                        appUnitsPerDevUnit);
    2815                 :             details->mXOffset =
    2816               0 :                 float(glyph.geometry.x_offset)*appUnitsPerDevUnit/PANGO_SCALE;
    2817                 :             details->mYOffset =
    2818               0 :                 float(glyph.geometry.y_offset)*appUnitsPerDevUnit/PANGO_SCALE;
    2819                 :         }
    2820               0 :         g.SetComplex(atClusterStart, true, detailedIndex);
    2821               0 :         aShapedWord->SetGlyphs(utf16Offset, g, detailedGlyphs.Elements());
    2822                 :     }
    2823                 : 
    2824                 :     // Check for ligatures and set *aUTF16Offset.
    2825               0 :     const gchar *p = aUTF8;
    2826               0 :     const gchar *end = aUTF8 + aUTF8Length;
    2827               0 :     while (1) {
    2828                 :         // Skip the CompressedGlyph that we have added, but check if the
    2829                 :         // character was supposed to be ignored. If it's supposed to be ignored,
    2830                 :         // overwrite the textrun entry with an invisible missing-glyph.
    2831               0 :         gunichar ch = g_utf8_get_char(p);
    2832               0 :         NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
    2833               0 :         if (ch >= 0x10000) {
    2834                 :             // Skip surrogate
    2835               0 :             ++utf16Offset;
    2836                 :         }
    2837               0 :         NS_ASSERTION(!gfxFontGroup::IsInvalidChar(PRUnichar(ch)),
    2838                 :                      "Invalid character detected");
    2839               0 :         ++utf16Offset;
    2840                 : 
    2841                 :         // We produced this UTF8 so we don't need to worry about malformed stuff
    2842               0 :         p = g_utf8_next_char(p);
    2843               0 :         if (p >= end)
    2844                 :             break;
    2845                 : 
    2846               0 :         if (utf16Offset >= wordLength) {
    2847               0 :             NS_ERROR("Someone has added too many glyphs!");
    2848               0 :             return NS_ERROR_FAILURE;
    2849                 :         }
    2850                 : 
    2851               0 :         g.SetComplex(aShapedWord->IsClusterStart(utf16Offset), false, 0);
    2852               0 :         aShapedWord->SetGlyphs(utf16Offset, g, nsnull);
    2853                 :     }
    2854               0 :     *aUTF16Offset = utf16Offset;
    2855               0 :     return NS_OK;
    2856                 : }
    2857                 : 
    2858                 : static nsresult
    2859               0 : SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, PRUint32 aUTF8Length,
    2860                 :           PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
    2861                 :           PangoGlyphUnit aOverrideSpaceWidth,
    2862                 :           gfxFont *aFont)
    2863                 : {
    2864               0 :     gint numGlyphs = aGlyphs->num_glyphs;
    2865               0 :     PangoGlyphInfo *glyphs = aGlyphs->glyphs;
    2866               0 :     const gint *logClusters = aGlyphs->log_clusters;
    2867                 :     // We cannot make any assumptions about the order of glyph clusters
    2868                 :     // provided by pango_shape (see 375864), so we work through the UTF8 text
    2869                 :     // and process the glyph clusters in logical order.
    2870                 : 
    2871                 :     // logGlyphs is like an inverse of logClusters.  For each UTF8 byte:
    2872                 :     //   >= 0 indicates that the byte is first in a cluster and
    2873                 :     //        gives the position of the starting glyph for the cluster.
    2874                 :     //     -1 indicates that the byte does not start a cluster.
    2875               0 :     nsAutoTArray<gint,2000> logGlyphs;
    2876               0 :     if (!logGlyphs.AppendElements(aUTF8Length + 1))
    2877               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2878               0 :     PRUint32 utf8Index = 0;
    2879               0 :     for(; utf8Index < aUTF8Length; ++utf8Index)
    2880               0 :         logGlyphs[utf8Index] = -1;
    2881               0 :     logGlyphs[aUTF8Length] = numGlyphs;
    2882                 : 
    2883               0 :     gint lastCluster = -1; // != utf8Index
    2884               0 :     for (gint glyphIndex = 0; glyphIndex < numGlyphs; ++glyphIndex) {
    2885               0 :         gint thisCluster = logClusters[glyphIndex];
    2886               0 :         if (thisCluster != lastCluster) {
    2887               0 :             lastCluster = thisCluster;
    2888               0 :             NS_ASSERTION(0 <= thisCluster && thisCluster < gint(aUTF8Length),
    2889                 :                          "garbage from pango_shape - this is bad");
    2890               0 :             logGlyphs[thisCluster] = glyphIndex;
    2891                 :         }
    2892                 :     }
    2893                 : 
    2894               0 :     PRUint32 utf16Offset = *aUTF16Offset;
    2895               0 :     PRUint32 wordLength = aShapedWord->Length();
    2896               0 :     utf8Index = 0;
    2897                 :     // The next glyph cluster in logical order. 
    2898               0 :     gint nextGlyphClusterStart = logGlyphs[utf8Index];
    2899               0 :     NS_ASSERTION(nextGlyphClusterStart >= 0, "No glyphs! - NUL in string?");
    2900               0 :     while (utf8Index < aUTF8Length) {
    2901               0 :         if (utf16Offset >= wordLength) {
    2902               0 :           NS_ERROR("Someone has added too many glyphs!");
    2903               0 :           return NS_ERROR_FAILURE;
    2904                 :         }
    2905               0 :         gint glyphClusterStart = nextGlyphClusterStart;
    2906                 :         // Find the utf8 text associated with this glyph cluster.
    2907               0 :         PRUint32 clusterUTF8Start = utf8Index;
    2908                 :         // Check whether we are consistent with pango_break data.
    2909               0 :         NS_WARN_IF_FALSE(aShapedWord->IsClusterStart(utf16Offset),
    2910                 :                          "Glyph cluster not aligned on character cluster.");
    2911               0 :         do {
    2912               0 :             ++utf8Index;
    2913               0 :             nextGlyphClusterStart = logGlyphs[utf8Index];
    2914                 :         } while (nextGlyphClusterStart < 0);
    2915               0 :         const gchar *clusterUTF8 = &aUTF8[clusterUTF8Start];
    2916               0 :         PRUint32 clusterUTF8Length = utf8Index - clusterUTF8Start;
    2917                 : 
    2918               0 :         bool haveMissingGlyph = false;
    2919               0 :         gint glyphIndex = glyphClusterStart;
    2920                 : 
    2921                 :         // It's now unncecessary to do NUL handling here.
    2922               0 :         do {
    2923               0 :             if (IS_MISSING_GLYPH(glyphs[glyphIndex].glyph)) {
    2924                 :                 // Does pango ever provide more than one glyph in the
    2925                 :                 // cluster if there is a missing glyph?
    2926                 :                 // behdad: yes
    2927               0 :                 haveMissingGlyph = true;
    2928                 :             }
    2929               0 :             glyphIndex++;
    2930                 :         } while (glyphIndex < numGlyphs && 
    2931               0 :                  logClusters[glyphIndex] == gint(clusterUTF8Start));
    2932                 : 
    2933                 :         nsresult rv;
    2934               0 :         if (haveMissingGlyph) {
    2935                 :             SetMissingGlyphs(aShapedWord, clusterUTF8, clusterUTF8Length,
    2936               0 :                              &utf16Offset, aFont);
    2937                 :         } else {
    2938                 :             rv = SetGlyphsForCharacterGroup(&glyphs[glyphClusterStart],
    2939                 :                                             glyphIndex - glyphClusterStart,
    2940                 :                                             aShapedWord,
    2941                 :                                             clusterUTF8, clusterUTF8Length,
    2942               0 :                                             &utf16Offset, aOverrideSpaceWidth);
    2943               0 :             NS_ENSURE_SUCCESS(rv,rv);
    2944                 :         }
    2945                 :     }
    2946               0 :     *aUTF16Offset = utf16Offset;
    2947               0 :     return NS_OK;
    2948                 : }
    2949                 : 
    2950                 : static void
    2951               0 : SetMissingGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8,
    2952                 :                  PRUint32 aUTF8Length, PRUint32 *aUTF16Offset,
    2953                 :                  gfxFont *aFont)
    2954                 : {
    2955               0 :     PRUint32 utf16Offset = *aUTF16Offset;
    2956               0 :     PRUint32 wordLength = aShapedWord->Length();
    2957               0 :     for (PRUint32 index = 0; index < aUTF8Length;) {
    2958               0 :         if (utf16Offset >= wordLength) {
    2959               0 :             NS_ERROR("Someone has added too many glyphs!");
    2960               0 :             break;
    2961                 :         }
    2962               0 :         gunichar ch = g_utf8_get_char(aUTF8 + index);
    2963               0 :         aShapedWord->SetMissingGlyph(utf16Offset, ch, aFont);
    2964                 : 
    2965               0 :         ++utf16Offset;
    2966               0 :         NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
    2967               0 :         if (ch >= 0x10000)
    2968               0 :             ++utf16Offset;
    2969                 :         // We produced this UTF8 so we don't need to worry about malformed stuff
    2970               0 :         index = g_utf8_next_char(aUTF8 + index) - aUTF8;
    2971                 :     }
    2972                 : 
    2973               0 :     *aUTF16Offset = utf16Offset;
    2974               0 : }
    2975                 : 
    2976                 : static void
    2977               0 : InitGlyphRunWithPangoAnalysis(gfxShapedWord *aShapedWord,
    2978                 :                               const gchar *aUTF8, PRUint32 aUTF8Length,
    2979                 :                               PangoAnalysis *aAnalysis,
    2980                 :                               PangoGlyphUnit aOverrideSpaceWidth,
    2981                 :                               gfxFont *aFont)
    2982                 : {
    2983               0 :     PRUint32 utf16Offset = 0;
    2984               0 :     PangoGlyphString *glyphString = pango_glyph_string_new();
    2985                 : 
    2986               0 :     const gchar *p = aUTF8;
    2987               0 :     const gchar *end = p + aUTF8Length;
    2988               0 :     while (p < end) {
    2989               0 :         if (*p == 0) {
    2990               0 :             aShapedWord->SetMissingGlyph(utf16Offset, 0, aFont);
    2991               0 :             ++p;
    2992               0 :             ++utf16Offset;
    2993               0 :             continue;
    2994                 :         }
    2995                 : 
    2996                 :         // It's necessary to loop over pango_shape as it treats
    2997                 :         // NULs as string terminators
    2998               0 :         const gchar *text = p;
    2999               0 :         do {
    3000               0 :             ++p;
    3001                 :         } while(p < end && *p != 0);
    3002               0 :         gint len = p - text;
    3003                 : 
    3004               0 :         pango_shape(text, len, aAnalysis, glyphString);
    3005                 :         SetGlyphs(aShapedWord, text, len, &utf16Offset, glyphString,
    3006               0 :                   aOverrideSpaceWidth, aFont);
    3007                 :     }
    3008                 : 
    3009               0 :     pango_glyph_string_free(glyphString);
    3010               0 : }
    3011                 : 
    3012                 : // PangoAnalysis is part of Pango's ABI but over time extra fields have been
    3013                 : // inserted into padding.  This union is used so that the code here can be
    3014                 : // compiled against older Pango versions but run against newer versions.
    3015                 : typedef union {
    3016                 :     PangoAnalysis pango;
    3017                 :     // This struct matches PangoAnalysis from Pango version
    3018                 :     // 1.16.5 to 1.28.1 (at least).
    3019                 :     struct {
    3020                 :         PangoEngineShape *shape_engine;
    3021                 :         PangoEngineLang  *lang_engine;
    3022                 :         PangoFont *font;
    3023                 :         guint8 level;
    3024                 :         guint8 gravity; /* PangoGravity */
    3025                 :         guint8 flags;
    3026                 :         guint8 script; /* PangoScript */
    3027                 :         PangoLanguage *language;
    3028                 :         GSList *extra_attrs;
    3029                 :     } local;
    3030                 : } PangoAnalysisUnion;
    3031                 : 
    3032                 : bool
    3033               0 : gfxFcFont::InitGlyphRunWithPango(gfxShapedWord *aShapedWord,
    3034                 :                                  const PRUnichar *aString)
    3035                 : {
    3036               0 :     const PangoScript script = static_cast<PangoScript>(aShapedWord->Script());
    3037               0 :     NS_ConvertUTF16toUTF8 utf8(aString, aShapedWord->Length());
    3038                 : 
    3039               0 :     PangoFont *font = GetPangoFont();
    3040                 : 
    3041               0 :     hb_language_t languageOverride = NULL;
    3042               0 :     if (GetStyle()->languageOverride) {
    3043                 :         languageOverride =
    3044               0 :             hb_ot_tag_to_language(GetStyle()->languageOverride);
    3045               0 :     } else if (GetFontEntry()->mLanguageOverride) {
    3046                 :         languageOverride =
    3047               0 :             hb_ot_tag_to_language(GetFontEntry()->mLanguageOverride);
    3048                 :     }
    3049                 : 
    3050                 :     PangoLanguage *language;
    3051               0 :     if (languageOverride) {
    3052                 :         language =
    3053               0 :             pango_language_from_string(hb_language_to_string(languageOverride));
    3054                 :     } else {
    3055                 : #if 0 // FIXME ??
    3056                 :         language = fontGroup->GetPangoLanguage();
    3057                 : #endif
    3058                 :         // FIXME: should probably cache this in the gfxFcFont
    3059               0 :         language = GuessPangoLanguage(GetStyle()->language);
    3060                 : 
    3061                 :         // The language that we have here is often not as good an indicator for
    3062                 :         // the run as the script.  This is not so important for the PangoMaps
    3063                 :         // here as all the default Pango shape and lang engines are selected
    3064                 :         // by script only (not language) anyway, but may be important in the
    3065                 :         // PangoAnalysis as the shaper sometimes accesses language-specific
    3066                 :         // tables.
    3067                 :         PangoLanguage *scriptLang;
    3068               0 :         if ((!language ||
    3069               0 :              !pango_language_includes_script(language, script)) &&
    3070                 :             (scriptLang = pango_script_get_sample_language(script))) {
    3071               0 :             language = scriptLang;
    3072                 :         }
    3073                 :     }
    3074                 : 
    3075                 :     static GQuark engineLangId =
    3076               0 :         g_quark_from_static_string(PANGO_ENGINE_TYPE_LANG);
    3077                 :     static GQuark renderNoneId =
    3078               0 :         g_quark_from_static_string(PANGO_RENDER_TYPE_NONE);
    3079               0 :     PangoMap *langMap = pango_find_map(language, engineLangId, renderNoneId);
    3080                 : 
    3081                 :     static GQuark engineShapeId =
    3082               0 :         g_quark_from_static_string(PANGO_ENGINE_TYPE_SHAPE);
    3083                 :     static GQuark renderFcId =
    3084               0 :         g_quark_from_static_string(PANGO_RENDER_TYPE_FC);
    3085               0 :     PangoMap *shapeMap = pango_find_map(language, engineShapeId, renderFcId);
    3086               0 :     if (!shapeMap) {
    3087               0 :         return false;
    3088                 :     }
    3089                 : 
    3090                 :     // The preferred shape engine for language and script
    3091                 :     PangoEngineShape *shapeEngine =
    3092               0 :         PANGO_ENGINE_SHAPE(pango_map_get_engine(shapeMap, script));
    3093               0 :     if (!shapeEngine) {
    3094               0 :         return false;
    3095                 :     }
    3096                 : 
    3097                 :     PangoEngineShapeClass *shapeClass = static_cast<PangoEngineShapeClass*>
    3098               0 :         (g_type_class_peek(PANGO_TYPE_ENGINE_SHAPE));
    3099                 : 
    3100                 :     // The |covers| method in the PangoEngineShape base class, which is the
    3101                 :     // method used by Pango shapers, merely copies the fontconfig coverage map
    3102                 :     // to a PangoCoverage and checks that the character is supported.  We've
    3103                 :     // already checked for character support, so we can avoid this copy for
    3104                 :     // these shapers.
    3105                 :     //
    3106                 :     // With SIL Graphite shapers, however, |covers| also checks that the font
    3107                 :     // is a Graphite font.  (bug 397860)
    3108               0 :     if (!shapeClass ||
    3109                 :         PANGO_ENGINE_SHAPE_GET_CLASS(shapeEngine)->covers != shapeClass->covers)
    3110                 :     {
    3111                 :         GSList *exact_engines;
    3112                 :         GSList *fallback_engines;
    3113                 :         pango_map_get_engines(shapeMap, script,
    3114               0 :                               &exact_engines, &fallback_engines);
    3115                 : 
    3116               0 :         GSList *engines = g_slist_concat(exact_engines, fallback_engines);
    3117               0 :         for (GSList *link = engines; link; link = link->next) {
    3118               0 :             PangoEngineShape *engine = PANGO_ENGINE_SHAPE(link->data);
    3119                 :             PangoCoverageLevel (*covers)(PangoEngineShape*, PangoFont*,
    3120                 :                                          PangoLanguage*, gunichar) =
    3121               0 :                 PANGO_ENGINE_SHAPE_GET_CLASS(shapeEngine)->covers;
    3122                 : 
    3123               0 :             if ((shapeClass && covers == shapeClass->covers) ||
    3124               0 :                 covers(engine, font, language, ' ') != PANGO_COVERAGE_NONE)
    3125                 :             {
    3126               0 :                 shapeEngine = engine;
    3127               0 :                 break;
    3128                 :             }
    3129                 :         }
    3130               0 :         g_slist_free(engines); // Frees exact and fallback links
    3131                 :     }
    3132                 : 
    3133                 :     PangoAnalysisUnion analysis;
    3134               0 :     memset(&analysis, 0, sizeof(analysis));
    3135                 : 
    3136                 :     // For pango_shape
    3137               0 :     analysis.local.shape_engine = shapeEngine;
    3138                 :     // For pango_break
    3139                 :     analysis.local.lang_engine =
    3140               0 :         PANGO_ENGINE_LANG(pango_map_get_engine(langMap, script));
    3141                 : 
    3142               0 :     analysis.local.font = font;
    3143               0 :     analysis.local.level = aShapedWord->IsRightToLeft() ? 1 : 0;
    3144                 :     // gravity and flags are used in Pango 1.14.10 and newer.
    3145                 :     //
    3146                 :     // PANGO_GRAVITY_SOUTH is what we want for upright horizontal text.  The
    3147                 :     // constant is not available when compiling with older Pango versions, but
    3148                 :     // is zero so the zero memset initialization is sufficient.
    3149                 :     //
    3150                 :     // Pango uses non-zero flags for vertical gravities only
    3151                 :     // (up to version 1.28 at least), so using zero is fine for flags too.
    3152                 : #if 0
    3153                 :     analysis.local.gravity = PANGO_GRAVITY_SOUTH;
    3154                 :     analysis.local.flags = 0;
    3155                 : #endif
    3156                 :     // Only used in Pango 1.16.5 and newer.
    3157               0 :     analysis.local.script = script;
    3158                 : 
    3159               0 :     analysis.local.language = language;
    3160                 :     // Non-font attributes.  Not used here.
    3161               0 :     analysis.local.extra_attrs = NULL;
    3162                 : 
    3163                 :     PangoGlyphUnit spaceWidth =
    3164               0 :         moz_pango_units_from_double(GetMetrics().spaceWidth);
    3165                 : 
    3166                 :     InitGlyphRunWithPangoAnalysis(aShapedWord, utf8.get(), utf8.Length(),
    3167               0 :                                   &analysis.pango, spaceWidth, this);
    3168               0 :     return true;
    3169                 : }
    3170                 : 
    3171                 : /* static */
    3172                 : PangoLanguage *
    3173               0 : GuessPangoLanguage(nsIAtom *aLanguage)
    3174                 : {
    3175               0 :     if (!aLanguage)
    3176               0 :         return NULL;
    3177                 : 
    3178                 :     // Pango and fontconfig won't understand mozilla's internal langGroups, so
    3179                 :     // find a real language.
    3180               0 :     nsCAutoString lang;
    3181               0 :     gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang);
    3182               0 :     if (lang.IsEmpty())
    3183               0 :         return NULL;
    3184                 : 
    3185               0 :     return pango_language_from_string(lang.get());
    3186                 : }
    3187                 : 
    3188                 : #ifdef MOZ_WIDGET_GTK2
    3189                 : /***************************************************************************
    3190                 :  *
    3191                 :  * This function must be last in the file because it uses the system cairo
    3192                 :  * library.  Above this point the cairo library used is the tree cairo if
    3193                 :  * MOZ_TREE_CAIRO.
    3194                 :  */
    3195                 : 
    3196                 : #if MOZ_TREE_CAIRO
    3197                 : // Tree cairo symbols have different names.  Disable their activation through
    3198                 : // preprocessor macros.
    3199                 : #undef cairo_ft_font_options_substitute
    3200                 : 
    3201                 : // The system cairo functions are not declared because the include paths cause
    3202                 : // the gdk headers to pick up the tree cairo.h.
    3203                 : extern "C" {
    3204                 : NS_VISIBILITY_DEFAULT void
    3205                 : cairo_ft_font_options_substitute (const cairo_font_options_t *options,
    3206                 :                                   FcPattern                  *pattern);
    3207                 : }
    3208                 : #endif
    3209                 : 
    3210                 : static void
    3211               0 : ApplyGdkScreenFontOptions(FcPattern *aPattern)
    3212                 : {
    3213                 :     const cairo_font_options_t *options =
    3214               0 :         gdk_screen_get_font_options(gdk_screen_get_default());
    3215                 : 
    3216               0 :     cairo_ft_font_options_substitute(options, aPattern);
    3217               0 : }
    3218                 : 
    3219                 : #endif // MOZ_WIDGET_GTK2

Generated by: LCOV version 1.7