diff --git a/gfx/thebes/public/gfxPangoFonts.h b/gfx/thebes/public/gfxPangoFonts.h index 03342a4c876..2cced879dcd 100644 --- a/gfx/thebes/public/gfxPangoFonts.h +++ b/gfx/thebes/public/gfxPangoFonts.h @@ -82,6 +82,9 @@ public: static void Shutdown(); + // Used for @font-face { src: local(); } + static gfxFontEntry *NewFontEntry(const gfxProxyFontEntry &aProxyEntry, + const nsAString &aFullname); // Used for @font-face { src: url(); } static gfxFontEntry *NewFontEntry(const gfxProxyFontEntry &aProxyEntry, nsISupports *aLoader, diff --git a/gfx/thebes/public/gfxPlatform.h b/gfx/thebes/public/gfxPlatform.h index ddcd215a666..addcee63263 100644 --- a/gfx/thebes/public/gfxPlatform.h +++ b/gfx/thebes/public/gfxPlatform.h @@ -198,7 +198,9 @@ public: * Ownership of the returned gfxFontEntry is passed to the caller, * who must either AddRef() or delete. */ - virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName) { return nsnull; } + virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName) + { return nsnull; } /** * Activate a platform font. (Needed to support @font-face src url().) diff --git a/gfx/thebes/public/gfxPlatformGtk.h b/gfx/thebes/public/gfxPlatformGtk.h index 02257f12645..08227f91177 100644 --- a/gfx/thebes/public/gfxPlatformGtk.h +++ b/gfx/thebes/public/gfxPlatformGtk.h @@ -89,6 +89,13 @@ public: gfxUserFontSet *aUserFontSet); #ifdef MOZ_PANGO + /** + * Look up a local platform font using the full font face name (needed to + * support @font-face src local() ) + */ + virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName); + /** * Activate a platform font (needed to support @font-face src url() ) * diff --git a/gfx/thebes/public/gfxPlatformMac.h b/gfx/thebes/public/gfxPlatformMac.h index 1144d7bc6b2..e09ef09c2ea 100644 --- a/gfx/thebes/public/gfxPlatformMac.h +++ b/gfx/thebes/public/gfxPlatformMac.h @@ -69,7 +69,8 @@ public: const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet); - gfxFontEntry* LookupLocalFont(const nsAString& aFontName); + virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName); virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, nsISupports *aLoader, diff --git a/gfx/thebes/public/gfxWindowsPlatform.h b/gfx/thebes/public/gfxWindowsPlatform.h index 9695cfd2ee8..b1698eb5201 100644 --- a/gfx/thebes/public/gfxWindowsPlatform.h +++ b/gfx/thebes/public/gfxWindowsPlatform.h @@ -81,7 +81,8 @@ public: /** * Look up a local platform font using the full font face name (needed to support @font-face src local() ) */ - virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName); + virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName); /** * Activate a platform font (needed to support @font-face src url() ) diff --git a/gfx/thebes/src/gfxFontconfigUtils.cpp b/gfx/thebes/src/gfxFontconfigUtils.cpp index 25eda88c210..9f0ce14d454 100644 --- a/gfx/thebes/src/gfxFontconfigUtils.cpp +++ b/gfx/thebes/src/gfxFontconfigUtils.cpp @@ -265,6 +265,7 @@ gfxFontconfigUtils::gfxFontconfigUtils() : mLastConfig(NULL) { mFontsByFamily.Init(50); + mFontsByFullname.Init(50); mLangSupportTable.Init(20); UpdateFontListInternal(); } @@ -537,6 +538,7 @@ gfxFontconfigUtils::UpdateFontListInternal(PRBool aForce) FcFontSet *fontSet = FcConfigGetFonts(currentConfig, FcSetSystem); mFontsByFamily.Clear(); + mFontsByFullname.Clear(); mLangSupportTable.Clear(); mAliasForMultiFonts.Clear(); @@ -753,7 +755,7 @@ gfxFontconfigUtils::ResolveFontName(const nsAString& aFontName, PRBool gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName) { - return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName.get())) != nsnull; + return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nsnull; } const nsTArray< nsCountedRef >& @@ -767,6 +769,114 @@ gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName) return entry->GetFonts(); } +// Fontconfig only provides a fullname property for fonts in formats with SFNT +// wrappers. For other font formats (including PCF and PS Type 1), a fullname +// must be generated from the family and style properties. Only the first +// family and style is checked, but that should be OK, as I don't expect +// non-SFNT fonts to have multiple families or styles. +PRBool +gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(FcPattern *aFont, + nsACString *aFullname) +{ + FcChar8 *family; + if (FcPatternGetString(aFont, FC_FAMILY, 0, &family) != FcResultMatch) + return PR_FALSE; + + aFullname->Truncate(); + aFullname->Append(ToCString(family)); + + FcChar8 *style; + if (FcPatternGetString(aFont, FC_STYLE, 0, &style) == FcResultMatch && + strcmp(ToCString(style), "Regular") != 0) { + aFullname->Append(' '); + aFullname->Append(ToCString(style)); + } + + return PR_TRUE; +} + +PRBool +gfxFontconfigUtils::FontsByFullnameEntry::KeyEquals(KeyTypePointer aKey) const +{ + const FcChar8 *key = mKey; + // If mKey is NULL, key comes from the style and family of the first font. + nsCAutoString fullname; + if (!key) { + NS_ASSERTION(mFonts.Length(), "No font in FontsByFullnameEntry!"); + GetFullnameFromFamilyAndStyle(mFonts[0], &fullname); + + key = ToFcChar8(fullname); + } + + return FcStrCmpIgnoreCase(aKey, key) == 0; +} + +void +gfxFontconfigUtils::AddFullnameEntries() +{ + // This FcFontSet is owned by fontconfig + FcFontSet *fontSet = FcConfigGetFonts(NULL, FcSetSystem); + + // Record the existing font families + for (int f = 0; f < fontSet->nfont; ++f) { + FcPattern *font = fontSet->fonts[f]; + + int v = 0; + FcChar8 *fullname; + while (FcPatternGetString(font, + FC_FULLNAME, v, &fullname) == FcResultMatch) { + FontsByFullnameEntry *entry = mFontsByFullname.PutEntry(fullname); + if (entry) { + // entry always has space for one font, so the first AddFont + // will always succeed, and so the entry will always have a + // font from which to obtain the key. + PRBool added = entry->AddFont(font); + // The key may be NULL either if this is the first font, or if + // the first font does not have a fullname property, and so + // the key is obtained from the font. Set the key in both + // cases. The check that AddFont succeeded is required for + // the second case. + if (!entry->mKey && added) { + entry->mKey = fullname; + } + } + + ++v; + } + + // Fontconfig does not provide a fullname property for all fonts. + if (v == 0) { + nsCAutoString name; + if (!GetFullnameFromFamilyAndStyle(font, &name)) + continue; + + FontsByFullnameEntry *entry = + mFontsByFullname.PutEntry(ToFcChar8(name)); + if (entry) { + entry->AddFont(font); + // Either entry->mKey has been set for a previous font or it + // remains NULL to indicate that the key is obtained from the + // first font. + } + } + } +} + +const nsTArray< nsCountedRef >& +gfxFontconfigUtils::GetFontsForFullname(const FcChar8 *aFullname) +{ + if (mFontsByFullname.Count() == 0) { + AddFullnameEntries(); + } + + FontsByFullnameEntry *entry = mFontsByFullname.GetEntry(aFullname); + + if (!entry) + return mEmptyPatternArray; + + return entry->GetFonts(); +} + static FcLangResult CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) { FcLangResult result = FcLangDifferentLang; diff --git a/gfx/thebes/src/gfxFontconfigUtils.h b/gfx/thebes/src/gfxFontconfigUtils.h index 029548fc9a0..664146d698c 100644 --- a/gfx/thebes/src/gfxFontconfigUtils.h +++ b/gfx/thebes/src/gfxFontconfigUtils.h @@ -105,6 +105,9 @@ public: const nsTArray< nsCountedRef >& GetFontsForFamily(const FcChar8 *aFamilyName); + const nsTArray< nsCountedRef >& + GetFontsForFullname(const FcChar8 *aFullname); + // Returns the best support that any font offers for |aLang|. FcLangResult GetBestLangSupport(const FcChar8 *aLang); // Returns the fonts offering this best level of support. @@ -120,6 +123,10 @@ public: { return reinterpret_cast(aCharPtr); } + static const FcChar8 *ToFcChar8(const nsCString& aCString) + { + return ToFcChar8(aCString.get()); + } static const char *ToCString(const FcChar8 *aChar8Ptr) { return reinterpret_cast(aChar8Ptr); @@ -133,6 +140,9 @@ public: // Returns a precise FC_WEIGHT from CSS weight |aBaseWeight|. static int FcWeightForBaseWeight(PRInt8 aBaseWeight); + static PRBool GetFullnameFromFamilyAndStyle(FcPattern *aFont, + nsACString *aFullname); + // This doesn't consider which faces exist, and so initializes the pattern // using a guessed weight, and doesn't consider sizeAdjust. static nsReturnRef @@ -185,7 +195,7 @@ public: class DepFcStrEntry : public FcStrEntryBase { public: // When constructing a new entry in the hashtable, the key is left - // blank. The caller of PutEntry() must fill in mKey when NULL. This + // NULL. The caller of PutEntry() must fill in mKey when NULL. This // provides a mechanism for the caller of PutEntry() to determine // whether the entry has been initialized. DepFcStrEntry(KeyTypePointer aName) @@ -218,7 +228,7 @@ public: : mKey(toCopy.mKey) { } PRBool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey.get())) == 0; + return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; } PRBool IsKeyInitialized() { return !mKey.IsVoid(); } @@ -247,6 +257,41 @@ protected: nsTArray< nsCountedRef > mFonts; }; + // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for + // mFontsByFamily) except for two differences: + // + // * The font does not always contain a single string for the fullname, so + // the key is sometimes a combination of family and style. + // + // * There is usually only one font. + class FontsByFullnameEntry : public DepFcStrEntry { + public: + // When constructing a new entry in the hashtable, the key is left + // NULL. The caller of PutEntry() is must fill in mKey when adding + // the first font if the key is not derived from the family and style. + // If the key is derived from family and style, a font must be added. + FontsByFullnameEntry(KeyTypePointer aName) + : DepFcStrEntry(aName) { } + + FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) + : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } + + PRBool KeyEquals(KeyTypePointer aKey) const; + + PRBool AddFont(FcPattern *aFont) { + return mFonts.AppendElement(aFont) != nsnull; + } + const nsTArray< nsCountedRef >& GetFonts() { + return mFonts; + } + + // Don't memmove the nsAutoTArray. + enum { ALLOW_MEMMOVE = PR_FALSE }; + private: + // There is usually only one font, but sometimes more. + nsAutoTArray,1> mFonts; + }; + class LangSupportEntry : public CopiedFcStrEntry { public: LangSupportEntry(KeyTypePointer aName) @@ -267,10 +312,18 @@ protected: const nsACString& aLangGroup); nsresult UpdateFontListInternal(PRBool aForce = PR_FALSE); + void AddFullnameEntries(); + LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, PRBool aWithFonts); + // mFontsByFamily and mFontsByFullname contain entries only for families + // and fullnames for which there are fonts. nsTHashtable mFontsByFamily; + nsTHashtable mFontsByFullname; + // mLangSupportTable contains an entry for each language that has been + // looked up through GetLangSupportEntry, even when the language is not + // supported. nsTHashtable mLangSupportTable; const nsTArray< nsCountedRef > mEmptyPatternArray; diff --git a/gfx/thebes/src/gfxPangoFonts.cpp b/gfx/thebes/src/gfxPangoFonts.cpp index 41ceb8edcb4..9c99d7a835e 100644 --- a/gfx/thebes/src/gfxPangoFonts.cpp +++ b/gfx/thebes/src/gfxPangoFonts.cpp @@ -148,21 +148,39 @@ ScaleRoundDesignUnits(FT_Short aDesignMetric, FT_Fixed aScale) /** * gfxFcFontEntry: * - * An abstract class for objects in a gfxUserFontSet that can provide an - * FcPattern* handle to a font face. + * 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 +// @font-face rules, but sometimes a one-to-many correspondence between font +// entries and font patterns. +// +// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions +// provided a font-size descriptor to specify the sizes supported by the face, +// but the "Editor's Draft 27 June 2008" +// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a +// descriptor, and Mozilla does not recognize such a descriptor. +// +// Font face names used in src:local() also do not usually specify a size. +// +// PCF format fonts have each size in a different file, and each of these +// files is referenced by its own pattern, but really these are each +// different sizes of one face with one name. +// +// Multiple patterns in an entry also effectively deals with a set of +// PostScript Type 1 font files that all have the same face name but are in +// several files because of the limit on the number of glyphs in a Type 1 font +// file. (e.g. Computer Modern.) + class gfxFcFontEntry : public gfxFontEntry { public: - FcPattern *GetPattern() + const nsTArray< nsCountedRef >& GetPatterns() { - if (!mPattern) { - InitPattern(); - } - return mPattern; + return mPatterns; } protected: @@ -175,76 +193,90 @@ protected: mStretch = aProxyEntry.mStretch; } - // Initializes mPattern. - virtual void InitPattern() = 0; + // 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); - // Helper function to be called from InitPattern() to change the 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(); - - nsCountedRef mPattern; + nsAutoTArray,1> mPatterns; }; void -gfxFcFontEntry::AdjustPatternToCSS() +gfxFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) { int fontWeight = -1; - FcPatternGetInteger(mPattern, FC_WEIGHT, 0, &fontWeight); + FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight); int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight); if (cssWeight != fontWeight) { - FcPatternDel(mPattern, FC_WEIGHT); - FcPatternAddInteger(mPattern, FC_WEIGHT, cssWeight); + FcPatternDel(aPattern, FC_WEIGHT); + FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight); } int fontSlant; - FcResult res = FcPatternGetInteger(mPattern, FC_SLANT, 0, &fontSlant); + FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant); // gfxFontEntry doesn't understand the difference between oblique // and italic. if (res != FcResultMatch || IsItalic() != (fontSlant != FC_SLANT_ROMAN)) { - FcPatternDel(mPattern, FC_SLANT); - FcPatternAddInteger(mPattern, FC_SLANT, + FcPatternDel(aPattern, FC_SLANT); + FcPatternAddInteger(aPattern, FC_SLANT, IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); } // Ensure that there is a fullname property (if there is a family // property) so that fontconfig rules can identify the real name of the // font, because the family property will be replaced. - FcChar8 *fullname; - FcChar8 *fontFamily; - if (FcPatternGetString(mPattern, - FC_FULLNAME, 0, &fullname) == FcResultNoMatch && - FcPatternGetString(mPattern, - FC_FAMILY, 0, &fontFamily) == FcResultMatch) { - // Construct fullname from family and style - nsCAutoString fullname(gfxFontconfigUtils::ToCString(fontFamily)); - FcChar8 *fontStyle; - if (FcPatternGetString(mPattern, - FC_STYLE, 0, &fontStyle) == FcResultMatch) { - const char *style = gfxFontconfigUtils::ToCString(fontStyle); - if (strcmp(style, "Regular") != 0) { - fullname.Append(' '); - fullname.Append(style); - } + FcChar8 *unused; + if (FcPatternGetString(aPattern, + FC_FULLNAME, 0, &unused) == FcResultNoMatch) { + nsCAutoString fullname; + if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern, + &fullname)) { + FcPatternAddString(aPattern, FC_FULLNAME, + gfxFontconfigUtils::ToFcChar8(fullname)); } - - FcPatternAddString(mPattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname.get())); } nsCAutoString family; family.Append(FONT_FACE_FAMILY_PREFIX); AppendUTF16toUTF8(Name(), family); - FcPatternDel(mPattern, FC_FAMILY); - FcPatternDel(mPattern, FC_FAMILYLANG); - FcPatternAddString(mPattern, FC_FAMILY, - gfxFontconfigUtils::ToFcChar8(family.get())); + FcPatternDel(aPattern, FC_FAMILY); + FcPatternDel(aPattern, FC_FAMILYLANG); + FcPatternAddString(aPattern, FC_FAMILY, + gfxFontconfigUtils::ToFcChar8(family)); } +/** + * gfxLocalFcFontEntry: + * + * An implementation of gfxFcFontEntry for local fonts from src:local(). + */ + +class gfxLocalFcFontEntry : public gfxFcFontEntry { +public: + gfxLocalFcFontEntry(const gfxProxyFontEntry &aProxyEntry, + const nsTArray< nsCountedRef >& aPatterns) + : gfxFcFontEntry(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 + + AdjustPatternToCSS(pattern); + + mPatterns.AppendElement(); + mPatterns[i].own(pattern); + } + } +}; + /** * gfxDownloadedFcFontEntry: * @@ -259,6 +291,7 @@ public: : gfxFcFontEntry(aProxyEntry), mLoader(aLoader), mFace(aFace) { NS_PRECONDITION(aFace != NULL, "aFace is NULL!"); + InitPattern(); } virtual ~gfxDownloadedFcFontEntry(); @@ -274,7 +307,7 @@ protected: // mLoader holds a reference to memory used by mFace. nsCOMPtr mLoader; FT_Face mFace; - // mPangoCoverage is the charset property of mPattern translated to a + // mPangoCoverage is the charset property of the pattern translated to a // format that Pango understands. A reference is kept here so that it can // be shared by multiple PangoFonts (of different sizes). nsAutoRef mPangoCoverage; @@ -314,11 +347,13 @@ static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern) gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry() { - if (mPattern) { + if (mPatterns.Length() != 0) { // Remove back reference to this font entry and the face in case // anyone holds a reference to the pattern. - DelDownloadedFontEntry(mPattern); - FcPatternDel(mPattern, FC_FT_FACE); + NS_ASSERTION(mPatterns.Length() == 1, + "More than one pattern in gfxDownloadedFcFontEntry!"); + DelDownloadedFontEntry(mPatterns[0]); + FcPatternDel(mPatterns[0], FC_FT_FACE); } FT_Done_Face(mFace); } @@ -344,6 +379,7 @@ void gfxDownloadedFcFontEntry::InitPattern() { static QueryFaceFunction sQueryFacePtr = GetFcFreeTypeQueryFace(); + FcPattern *pattern; // FcFreeTypeQueryFace is the same function used to construct patterns for // system fonts and so is the preferred function to use for this purpose. @@ -361,10 +397,9 @@ gfxDownloadedFcFontEntry::InitPattern() // blank glyphs are elided. Here, however, we pass NULL for "blanks", // effectively assuming that, if the font has a blank glyph, then the // author intends any associated character to be rendered blank. - mPattern.own((*sQueryFacePtr)(mFace, - gfxFontconfigUtils::ToFcChar8(""), 0, - NULL)); - if (!mPattern) + pattern = + (*sQueryFacePtr)(mFace, gfxFontconfigUtils::ToFcChar8(""), 0, NULL); + if (!pattern) // Either OOM, or fontconfig chose to skip this font because it // has "no encoded characters", which I think means "BDF and PCF // fonts which are not in Unicode (or the effectively equivalent @@ -372,8 +407,8 @@ gfxDownloadedFcFontEntry::InitPattern() return; // These properties don't make sense for this face without a file. - FcPatternDel(mPattern, FC_FILE); - FcPatternDel(mPattern, FC_INDEX); + FcPatternDel(pattern, FC_FILE); + FcPatternDel(pattern, FC_INDEX); } else { // Do the minimum necessary to construct a pattern for sorting. @@ -381,12 +416,12 @@ gfxDownloadedFcFontEntry::InitPattern() // FC_CHARSET is vital to determine which characters are supported. nsAutoRef charset(FcFreeTypeCharSet(mFace, NULL)); // If there are no characters then assume we don't know how to read - // this font and leave mPattern NULL. + // this font. if (!charset || FcCharSetCount(charset) == 0) return; - mPattern.own(FcPatternCreate()); - FcPatternAddCharSet(mPattern, FC_CHARSET, charset); + pattern = FcPatternCreate(); + FcPatternAddCharSet(pattern, FC_CHARSET, charset); // FC_PIXEL_SIZE can be important for font selection of fixed-size // fonts. @@ -397,12 +432,12 @@ gfxDownloadedFcFontEntry::InitPattern() #else double size = mFace->available_sizes[i].height; #endif - FcPatternAddDouble (mPattern, FC_PIXEL_SIZE, size); + FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size); } // Not sure whether this is important; // imitating FcFreeTypeQueryFace: - FcPatternAddBool (mPattern, FC_ANTIALIAS, FcFalse); + FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse); } // Setting up the FC_LANGSET property is very difficult with the APIs @@ -416,10 +451,14 @@ gfxDownloadedFcFontEntry::InitPattern() // fonts). } - FcPatternAddFTFace(mPattern, FC_FT_FACE, mFace); - AddDownloadedFontEntry(mPattern, this); + AdjustPatternToCSS(pattern); - AdjustPatternToCSS(); + FcPatternAddFTFace(pattern, FC_FT_FACE, mFace); + AddDownloadedFontEntry(pattern, this); + + // There is never more than one pattern + mPatterns.AppendElement(); + mPatterns[0].own(pattern); } static PangoCoverage *NewPangoCoverage(FcPattern *aFont) @@ -456,8 +495,10 @@ static PangoCoverage *NewPangoCoverage(FcPattern *aFont) PangoCoverage * gfxDownloadedFcFontEntry::GetPangoCoverage() { + NS_ASSERTION(mPatterns.Length() != 0, + "Can't get coverage without a pattern!"); if (!mPangoCoverage) { - mPangoCoverage.own(NewPangoCoverage(mPattern)); + mPangoCoverage.own(NewPangoCoverage(mPatterns[0])); } return mPangoCoverage; } @@ -987,8 +1028,8 @@ private: // Find the FcPattern for an @font-face font suitable for CSS family |aFamily| // and style |aStyle| properties. -static FcPattern * -FindFontPattern(gfxUserFontSet *mUserFontSet, +static const nsTArray< nsCountedRef >* +FindFontPatterns(gfxUserFontSet *mUserFontSet, const nsACString &aFamily, PRUint8 aStyle, PRUint16 aWeight) { // Convert to UTF16 @@ -1016,7 +1057,7 @@ FindFontPattern(gfxUserFontSet *mUserFontSet, if (!fontEntry) return NULL; - return fontEntry->GetPattern(); + return &fontEntry->GetPatterns(); } typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object, @@ -1156,9 +1197,10 @@ gfxFcPangoFontSet::SortPreferredFonts() for (int v = 0; FcPatternGetString(mSortPattern, FC_FAMILY, v, &family) == FcResultMatch; ++v) { - nsAutoTArray,1> userFont; const nsTArray< nsCountedRef > *familyFonts = nsnull; + // Is this an @font-face family? + PRBool isUserFont = PR_FALSE; if (mUserFontSet) { // Have some @font-face definitions @@ -1166,8 +1208,7 @@ gfxFcPangoFontSet::SortPreferredFonts() NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX); if (StringBeginsWith(cFamily, userPrefix)) { - // This is an @font-face family. - familyFonts = &userFont; + isUserFont = PR_TRUE; // Trim off the prefix nsDependentCSubstring cssFamily(cFamily, userPrefix.Length()); @@ -1177,22 +1218,17 @@ gfxFcPangoFontSet::SortPreferredFonts() PRUint16 thebesWeight = gfxFontconfigUtils::GetThebesWeight(mSortPattern); - FcPattern *fontPattern = - FindFontPattern(mUserFontSet, cssFamily, - thebesStyle, thebesWeight); - - if (fontPattern) { - userFont.AppendElement(fontPattern); - } + familyFonts = FindFontPatterns(mUserFontSet, cssFamily, + thebesStyle, thebesWeight); } } - if (!familyFonts) { + if (!isUserFont) { familyFonts = &utils->GetFontsForFamily(family); } - if (familyFonts->Length() == 0) { - // There are no fonts matching this family, so there is not point + if (!familyFonts || familyFonts->Length() == 0) { + // There are no fonts matching this family, so there is no point // in searching for this family in the FontSort. // // Perhaps the original pattern should be retained for @@ -1224,8 +1260,7 @@ gfxFcPangoFontSet::SortPreferredFonts() // User fonts are already filtered by slant (but not size) in // mUserFontSet->FindFontEntry(). - if (familyFonts != &userFont && - !SlantIsAcceptable(font, requestedSlant)) + if (!isUserFont && !SlantIsAcceptable(font, requestedSlant)) continue; if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) continue; @@ -2060,6 +2095,54 @@ gfxPangoFontGroup::Shutdown() NS_IF_RELEASE(gLangService); } +/* static */ gfxFontEntry * +gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry, + const nsAString& aFullname) +{ + gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); + if (!utils) + return nsnull; + + // The font face name from @font-face { src: local() } is not well + // defined. + // + // On MS Windows, this name gets compared with + // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the + // full font name from the name table. For CFF OpenType fonts this is the + // same as the PostScript name, but for TrueType fonts it is usually + // different. + // + // On Mac, the font face name is compared with the PostScript name, even + // for TrueType fonts. + // + // Fontconfig only records the full font names, so the behavior here + // follows that on MS Windows. However, to provide the possibility + // of aliases to compensate for variations, the font face name is passed + // through FcConfigSubstitute. + + nsAutoRef pattern(FcPatternCreate()); + if (!pattern) + return nsnull; + + NS_ConvertUTF16toUTF8 fullname(aFullname); + FcPatternAddString(pattern, FC_FULLNAME, + gfxFontconfigUtils::ToFcChar8(fullname)); + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + + FcChar8 *name; + for (int v = 0; + FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch; + ++v) { + const nsTArray< nsCountedRef >& fonts = + utils->GetFontsForFullname(name); + + if (fonts.Length() != 0) + return new gfxLocalFcFontEntry(aProxyEntry, fonts); + } + + return nsnull; +} + static FT_Library GetFTLibrary() { diff --git a/gfx/thebes/src/gfxPlatformGtk.cpp b/gfx/thebes/src/gfxPlatformGtk.cpp index 88e4de478af..5c585d1f8b5 100644 --- a/gfx/thebes/src/gfxPlatformGtk.cpp +++ b/gfx/thebes/src/gfxPlatformGtk.cpp @@ -284,6 +284,13 @@ gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies, return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet); } +gfxFontEntry* +gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName) +{ + return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName); +} + gfxFontEntry* gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, nsISupports *aLoader, diff --git a/gfx/thebes/src/gfxPlatformMac.cpp b/gfx/thebes/src/gfxPlatformMac.cpp index 1e2f3067223..6adbcd3a610 100644 --- a/gfx/thebes/src/gfxPlatformMac.cpp +++ b/gfx/thebes/src/gfxPlatformMac.cpp @@ -123,7 +123,8 @@ gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies, } gfxFontEntry* -gfxPlatformMac::LookupLocalFont(const nsAString& aFontName) +gfxPlatformMac::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName) { return gfxQuartzFontCache::SharedFontCache()->LookupLocalFont(aFontName); } diff --git a/gfx/thebes/src/gfxUserFontSet.cpp b/gfx/thebes/src/gfxUserFontSet.cpp index d8562ad006e..39d60965ef6 100644 --- a/gfx/thebes/src/gfxUserFontSet.cpp +++ b/gfx/thebes/src/gfxUserFontSet.cpp @@ -289,7 +289,9 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry) // src local ==> lookup and load if (currSrc.mIsLocal) { - gfxFontEntry *fe = gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName); + gfxFontEntry *fe = + gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry, + currSrc.mLocalName); if (fe) { aProxyEntry->mFamily->ReplaceFontEntry(aProxyEntry, fe); IncrementGeneration(); diff --git a/gfx/thebes/src/gfxWindowsPlatform.cpp b/gfx/thebes/src/gfxWindowsPlatform.cpp index 07a9e0bcb98..ca6a9161e78 100644 --- a/gfx/thebes/src/gfxWindowsPlatform.cpp +++ b/gfx/thebes/src/gfxWindowsPlatform.cpp @@ -619,7 +619,8 @@ FindFullName(nsStringHashKey::KeyType aKey, } gfxFontEntry* -gfxWindowsPlatform::LookupLocalFont(const nsAString& aFontName) +gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName) { // walk over list of names FullFontNameSearch data(aFontName);