b=600452 move font FcPattern reference from Font to FontEntry r=jfkthame a=blocking
authorKarl Tomlinson <karlt+@karlt.net>
Mon, 22 Nov 2010 11:21:19 +1300
changeset 57979 6b3f7a3a6a7f68d5bb630534f22c002601a0469b
parent 57978 df3db4d3a0c74ac046f6c8589132546cdbd85539
child 57980 4847e1cf6cf4725b9a36da1a94788374b0cab397
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersjfkthame, blocking
bugs600452
milestone2.0b8pre
b=600452 move font FcPattern reference from Font to FontEntry r=jfkthame a=blocking
gfx/thebes/gfxFont.h
gfx/thebes/gfxPangoFonts.cpp
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -322,17 +322,17 @@ public:
     gfxUserFontData* mUserFontData;
 
     nsTArray<gfxFontFeature> *mFeatureSettings;
     PRUint32         mLanguageOverride;
 
 protected:
     friend class gfxPlatformFontList;
     friend class gfxMacPlatformFontList;
-    friend class gfxFcFontEntry;
+    friend class gfxUserFcFontEntry;
     friend class gfxFontFamily;
     friend class gfxSingleFaceMacFontFamily;
 
     gfxFontEntry() :
         mItalic(PR_FALSE), mFixedPitch(PR_FALSE),
         mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
         mIsBadUnderlineFont(PR_FALSE),
         mIsUserFont(PR_FALSE),
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -154,35 +154,80 @@ FindFunctionSymbol(const char *name)
     PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib);
     if (lib) {
         PR_UnloadLibrary(lib);
     }
 
     return result;
 }
 
-static cairo_user_data_key_t sFontEntryKey;
+/**
+ * gfxFcFontEntry:
+ *
+ * An abstract base class of for gfxFontEntry implementations used by
+ * gfxFcFont and gfxUserFontSet.
+ */
+
+class gfxFcFontEntry : public gfxFontEntry {
+public:
+    // For all FontEntrys attached to gfxFcFonts, there will be only one
+    // pattern in this array.  This is always a font pattern, not a fully
+    // resolved pattern.  gfxFcFont only uses this to construct a PangoFont.
+    //
+    // FontEntrys for src:local() fonts in gfxUserFontSet may return more than
+    // one pattern.  (See comment in gfxUserFcFontEntry.)
+    const nsTArray< nsCountedRef<FcPattern> >& GetPatterns()
+    {
+        return mPatterns;
+    }
+
+    static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace)
+    {
+        return static_cast<gfxFcFontEntry*>
+            (cairo_font_face_get_user_data(aFace, &sFontEntryKey));
+    }
+
+protected:
+    gfxFcFontEntry(const nsAString& aName)
+        : gfxFontEntry(aName) { }
+
+    // One pattern is the common case and some subclasses rely on successful
+    // addition of the first element to the array.
+    nsAutoTArray<nsCountedRef<FcPattern>,1> mPatterns;
+
+    static cairo_user_data_key_t sFontEntryKey;
+};
+
+cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
 
 /**
  * gfxSystemFcFontEntry:
  *
- * An implementation of gfxFontEntry used by gfxFcFonts for system fonts,
+ * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts,
  * including those from regular family-name based font selection as well as
  * those from src:local().
  *
  * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. 
  */
 
-class gfxSystemFcFontEntry : public gfxFontEntry {
+class gfxSystemFcFontEntry : public gfxFcFontEntry {
 public:
-    gfxSystemFcFontEntry(cairo_font_face_t *aFontFace, const nsAString& aName)
-        : gfxFontEntry(aName), mFontFace(aFontFace)
+    // For memory efficiency, aFontPattern should be a font pattern,
+    // not a fully resolved pattern.
+    gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
+                         FcPattern *aFontPattern,
+                         const nsAString& aName)
+        : gfxFcFontEntry(aName), mFontFace(aFontFace)
     {
         cairo_font_face_reference(mFontFace);
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, NULL);
+        mPatterns.AppendElement();
+        // mPatterns is an nsAutoTArray with 1 space always available, so the
+        // AppendElement always succeeds.
+        mPatterns[0] = aFontPattern;
     }
 
     ~gfxSystemFcFontEntry()
     {
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, NULL, NULL);
         cairo_font_face_destroy(mFontFace);
     }
 private:
@@ -191,26 +236,26 @@ private:
 
 // A namespace for @font-face family names in FcPatterns so that fontconfig
 // aliases do not pick up families from @font-face rules and so that
 // fontconfig rules can distinguish between web fonts and platform fonts.
 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
 
 /**
- * gfxFcFontEntry:
+ * gfxUserFcFontEntry:
  *
  * An abstract class for objects in a gfxUserFontSet that can provide
  * FcPattern* handles to fonts.
  *
  * Separate implementations of this class support local fonts from src:local()
  * and web fonts from src:url().
  */
 
-// There is a one-to-one correspondence between gfxFcFontEntry objects and
+// There is a one-to-one correspondence between gfxUserFcFontEntry objects and
 // @font-face rules, but sometimes a one-to-many correspondence between font
 // entries and font patterns.
 //
 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions
 // provided a font-size descriptor to specify the sizes supported by the face,
 // but the "Editor's Draft 27 June 2008"
 // http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a
 // descriptor, and Mozilla does not recognize such a descriptor.
@@ -221,46 +266,38 @@ private:
 // files is referenced by its own pattern, but really these are each
 // different sizes of one face with one name.
 //
 // Multiple patterns in an entry also effectively deals with a set of
 // PostScript Type 1 font files that all have the same face name but are in
 // several files because of the limit on the number of glyphs in a Type 1 font
 // file.  (e.g. Computer Modern.)
 
-class gfxFcFontEntry : public gfxFontEntry {
-public:
-    const nsTArray< nsCountedRef<FcPattern> >& GetPatterns()
-    {
-        return mPatterns;
-    }
-
+class gfxUserFcFontEntry : public gfxFcFontEntry {
 protected:
-    gfxFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
+    gfxUserFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
         // store the family name
-        : gfxFontEntry(aProxyEntry.mFamily->Name())
+        : gfxFcFontEntry(aProxyEntry.mFamily->Name())
     {
         mItalic = aProxyEntry.mItalic;
         mWeight = aProxyEntry.mWeight;
         mStretch = aProxyEntry.mStretch;
         mIsUserFont = PR_TRUE;
     }
 
     // Helper function to change a pattern so that it matches the CSS style
     // descriptors and so gets properly sorted in font selection.  This also
     // avoids synthetic style effects being added by the renderer when the
     // style of the font itself does not match the descriptor provided by the
     // author.
     void AdjustPatternToCSS(FcPattern *aPattern);
-
-    nsAutoTArray<nsCountedRef<FcPattern>,1> mPatterns;
 };
 
 void
-gfxFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
+gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
 {
     int fontWeight = -1;
     FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight);
     int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100);
     if (cssWeight != fontWeight) {
         FcPatternDel(aPattern, FC_WEIGHT);
         FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight);
     }
@@ -298,29 +335,29 @@ gfxFcFontEntry::AdjustPatternToCSS(FcPat
     FcPatternDel(aPattern, FC_FAMILYLANG);
     FcPatternAddString(aPattern, FC_FAMILY,
                        gfxFontconfigUtils::ToFcChar8(family));
 }
 
 /**
  * gfxLocalFcFontEntry:
  *
- * An implementation of gfxFcFontEntry for local fonts from src:local().
+ * An implementation of gfxUserFcFontEntry for local fonts from src:local().
  *
  * This class is used only in gfxUserFontSet and for providing FcPattern*
  * handles to system fonts for font selection.  gfxFcFonts created from these
  * patterns will use gfxSystemFcFontEntrys, which may be shared with
  * gfxFcFonts from regular family-name based font selection.
  */
 
-class gfxLocalFcFontEntry : public gfxFcFontEntry {
+class gfxLocalFcFontEntry : public gfxUserFcFontEntry {
 public:
     gfxLocalFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
                         const nsTArray< nsCountedRef<FcPattern> >& aPatterns)
-        : gfxFcFontEntry(aProxyEntry)
+        : gfxUserFcFontEntry(aProxyEntry)
     {
         if (!mPatterns.SetCapacity(aPatterns.Length()))
             return; // OOM
 
         for (PRUint32 i = 0; i < aPatterns.Length(); ++i) {
             FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i));
             if (!pattern)
                 return; // OOM
@@ -338,36 +375,39 @@ public:
  * gfxDownloadedFcFontEntry:
  *
  * An implementation of gfxFcFontEntry for web fonts from src:url().
  * 
  * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t
  * keeps a reference to the FontEntry to keep the font data alive.
  */
 
-class gfxDownloadedFcFontEntry : public gfxFcFontEntry {
+class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry {
 public:
     // This takes ownership of the face and its underlying data
     gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
                              const PRUint8 *aData, FT_Face aFace)
-        : gfxFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
+        : gfxUserFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
     {
         NS_PRECONDITION(aFace != NULL, "aFace is NULL!");
         InitPattern();
     }
 
     virtual ~gfxDownloadedFcFontEntry();
 
+    // Returns true on success
+    PRBool SetCairoFace(cairo_font_face_t *aFace);
+
     // Returns a PangoCoverage owned by the FontEntry.  The caller must add a
     // reference if it wishes to keep the PangoCoverage longer than the
     // lifetime of the FontEntry.
     PangoCoverage *GetPangoCoverage();
 
 protected:
-    virtual void InitPattern();
+    void InitPattern();
 
     // mFontData holds the data used to instantiate the FT_Face;
     // this has to persist until we are finished with the face,
     // then be released with NS_Free().
     const PRUint8* mFontData;
 
     FT_Face mFace;
 
@@ -510,16 +550,35 @@ gfxDownloadedFcFontEntry::InitPattern()
     FcPatternAddFTFace(pattern, FC_FT_FACE, mFace);
     AddDownloadedFontEntry(pattern, this);
 
     // There is never more than one pattern
     mPatterns.AppendElement();
     mPatterns[0].own(pattern);
 }
 
+static void ReleaseDownloadedFontEntry(void *data)
+{
+    gfxDownloadedFcFontEntry *downloadedFontEntry =
+        static_cast<gfxDownloadedFcFontEntry*>(data);
+    NS_RELEASE(downloadedFontEntry);
+}
+
+PRBool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace)
+{
+    if (CAIRO_STATUS_SUCCESS !=
+        cairo_font_face_set_user_data(aFace, &sFontEntryKey, this,
+                                      ReleaseDownloadedFontEntry))
+        return PR_FALSE;
+
+    // Hold a reference to this font entry to keep the font face data.
+    NS_ADDREF(this);
+    return PR_TRUE;
+}
+
 static PangoCoverage *NewPangoCoverage(FcPattern *aFont)
 {
     // This uses g_slice_alloc which will abort on OOM rather than return NULL.
     PangoCoverage *coverage = pango_coverage_new();
 
     FcCharSet *charset;
     if (FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset) != FcResultMatch)
         return coverage; // empty
@@ -592,24 +651,21 @@ public:
         if (!mPangoFont) {
             MakePangoFont();
         }
         return mPangoFont;
     }
 
 private:
     static already_AddRefed<gfxFcFont> GetOrMakeFont(FcPattern *aPattern);
-    gfxFcFont(cairo_scaled_font_t *aCairoFont, FcPattern *aFontPattern,
-              gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle);
+    gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
+              const gfxFontStyle *aFontStyle);
 
     void MakePangoFont();
 
-    // For memory efficiency, this is a font pattern, not a fully resolved
-    // pattern.  Only needed for constructing mPangoFont.
-    nsCountedRef<FcPattern> mFontPattern;
     PangoFont *mPangoFont;
 
     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
     static cairo_user_data_key_t sGfxFontKey;
 };
 
 /**
  * gfxPangoFcFont:
@@ -1060,23 +1116,23 @@ FindFontPatterns(gfxUserFontSet *mUserFo
     // FcFontRenderPrepare when the weight in the requested pattern is
     // compared against the weight in the font pattern.
     PRBool needsBold;
 
     gfxFontStyle style;
     style.style = aStyle;
     style.weight = aWeight;
 
-    gfxFcFontEntry *fontEntry = static_cast<gfxFcFontEntry*>
+    gfxUserFcFontEntry *fontEntry = static_cast<gfxUserFcFontEntry*>
         (mUserFontSet->FindFontEntry(utf16Family, style, needsBold));
 
     // Accept synthetic oblique for italic and oblique.
     if (!fontEntry && aStyle != FONT_STYLE_NORMAL) {
         style.style = FONT_STYLE_NORMAL;
-        fontEntry = static_cast<gfxFcFontEntry*>
+        fontEntry = static_cast<gfxUserFcFontEntry*>
             (mUserFontSet->FindFontEntry(utf16Family, style, needsBold));
     }
 
     if (!fontEntry)
         return NULL;
 
     return &fontEntry->GetPatterns();
 }
@@ -1901,21 +1957,19 @@ gfxPangoFontGroup::FindFontForChar(PRUin
 
 /**
  ** gfxFcFont
  **/
 
 cairo_user_data_key_t gfxFcFont::sGfxFontKey;
 
 gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
-                     FcPattern *aFontPattern,
-                     gfxFontEntry *aFontEntry,
+                     gfxFcFontEntry *aFontEntry,
                      const gfxFontStyle *aFontStyle)
     : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle),
-      mFontPattern(aFontPattern),
       mPangoFont()
 {
     cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, NULL);
 }
 
 // The gfxFcFont keeps (only) a toggle_ref on mPangoFont.
 // While mPangoFont has other references, a reference to the
 // gfxFcFont is held.  While mPangoFont has no other references, the reference
@@ -1930,17 +1984,19 @@ PangoFontToggleNotify(gpointer data, GOb
         NS_ADDREF(font);
     }
 }
 
 void
 gfxFcFont::MakePangoFont()
 {
     // Switch from a normal reference to a toggle_ref.
-    nsAutoRef<PangoFont> pangoFont(gfxPangoFcFont::NewFont(this, mFontPattern));
+    gfxFcFontEntry *fe = static_cast<gfxFcFontEntry*>(mFontEntry.get());
+    nsAutoRef<PangoFont> pangoFont
+        (gfxPangoFcFont::NewFont(this, fe->GetPatterns()[0]));
     mPangoFont = pangoFont;
     g_object_add_toggle_ref(G_OBJECT(mPangoFont), PangoFontToggleNotify, this);
     // This self-reference gets removed when the normal reference to the
     // PangoFont is removed as the nsAutoRef goes out of scope.
     NS_ADDREF(this);
 }
 
 gfxFcFont::~gfxFcFont()
@@ -2106,23 +2162,16 @@ GetPixelSize(FcPattern *aPattern)
     if (FcPatternGetDouble(aPattern,
                            FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
         return size;
 
     NS_NOTREACHED("No size on pattern");
     return 0.0;
 }
 
-static void ReleaseDownloadedFontEntry(void *data)
-{
-    gfxDownloadedFcFontEntry *downloadedFontEntry =
-        static_cast<gfxDownloadedFcFontEntry*>(data);
-    NS_RELEASE(downloadedFontEntry);
-}
-
 /**
  * The following gfxFcFonts are accessed from the cairo_scaled_font or created
  * from the FcPattern, not from the gfxFontCache hash table.  The gfxFontCache
  * hash table is keyed by desired family and style, whereas here we only know
  * actual family and style.  There may be more than one of these fonts with
  * the same family and style, but different PangoFont and actual font face.
  * 
  * The point of this is to record the exact font face for gfxTextRun glyph
@@ -2136,34 +2185,33 @@ already_AddRefed<gfxFcFont>
 gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern)
 {
     nsAutoRef<FcPattern> renderPattern
         (FcFontRenderPrepare(NULL, aRequestedPattern, aFontPattern));
     cairo_font_face_t *face =
         cairo_ft_font_face_create_for_pattern(renderPattern);
 
     // Reuse an existing font entry if available.
-    nsRefPtr<gfxFontEntry> fe = static_cast<gfxFontEntry*>
-        (cairo_font_face_get_user_data(face, &sFontEntryKey));
+    nsRefPtr<gfxFcFontEntry> fe = gfxFcFontEntry::LookupFontEntry(face);
     if (!fe) {
-        fe = GetDownloadedFontEntry(aFontPattern);
-        if (fe && cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) {
-            // Web font with cairo_font_face_t using the web font data.
-            if (CAIRO_STATUS_SUCCESS ==
-                cairo_font_face_set_user_data(face, &sFontEntryKey, fe,
-                                              ReleaseDownloadedFontEntry)) {
+        gfxDownloadedFcFontEntry *downloadedFontEntry =
+            GetDownloadedFontEntry(aFontPattern);
+        if (downloadedFontEntry) {
+            // Web font
+            fe = downloadedFontEntry;
+            if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) {
+                // cairo_font_face_t is using the web font data.
                 // Hold a reference to the font entry to keep the font face
                 // data.
-                NS_ADDREF(fe);
-            } else {
-                // OOM.  Let cairo pick a fallback font
-                cairo_font_face_destroy(face);
-                face = cairo_ft_font_face_create_for_pattern(aRequestedPattern);
-                fe = static_cast<gfxFontEntry*>
-                    (cairo_font_face_get_user_data(face, &sFontEntryKey));
+                if (!downloadedFontEntry->SetCairoFace(face)) {
+                    // OOM.  Let cairo pick a fallback font
+                    cairo_font_face_destroy(face);
+                    face = cairo_ft_font_face_create_for_pattern(aRequestedPattern);
+                    fe = gfxFcFontEntry::LookupFontEntry(face);
+                }
             }
         }
         if (!fe) {
             // Get a unique name for the font face from the file and id.
             nsAutoString name;
             FcChar8 *fc_file;
             if (FcPatternGetString(renderPattern,
                                    FC_FILE, 0, &fc_file) == FcResultMatch) {
@@ -2176,17 +2224,17 @@ gfxFcFont::GetOrMakeFont(FcPattern *aReq
 
                 AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name);
                 if (index != 0) {
                     name.AppendLiteral("/");
                     name.AppendInt(index);
                 }
             }
 
-            fe = new gfxSystemFcFontEntry(face, name);
+            fe = new gfxSystemFcFontEntry(face, aFontPattern, name);
         }
     }
 
     cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face);
 
     nsRefPtr<gfxFcFont> font = static_cast<gfxFcFont*>
         (cairo_scaled_font_get_user_data(cairoFont, &sGfxFontKey));
 
@@ -2211,17 +2259,17 @@ gfxFcFont::GetOrMakeFont(FcPattern *aReq
 
         // Note that a file/index pair (or FT_Face) and the gfxFontStyle are
         // not necessarily enough to provide a key that will describe a unique
         // font.  cairoFont contains information from renderPattern, which is a
         // fully resolved pattern from FcFontRenderPrepare.
         // FcFontRenderPrepare takes the requested pattern and the face
         // pattern as input and can modify elements of the resulting pattern
         // that affect rendering but are not included in the gfxFontStyle.
-        font = new gfxFcFont(cairoFont, aFontPattern, fe, &fontStyle);
+        font = new gfxFcFont(cairoFont, fe, &fontStyle);
     }
 
     cairo_scaled_font_destroy(cairoFont);
     cairo_font_face_destroy(face);
     return font.forget();
 }
 
 static PangoFontMap *