Bug 705594. Fixup of intra-family fallback code. r=jfkthame
authorJohn Daggett <jdaggett@mozilla.com>
Fri, 09 Mar 2012 11:05:33 +0900
changeset 88601 f4b0642049b9fd74e088b34ed30d99aab143b371
parent 88600 b4554dac242ac87f8d7022da6d4823644c394c72
child 88602 b2570817c14a3077a5e576489d2c0765e6376480
push id22208
push usermak77@bonardo.net
push dateFri, 09 Mar 2012 12:34:50 +0000
treeherdermozilla-central@ead9016b4102 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs705594
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 705594. Fixup of intra-family fallback code. r=jfkthame
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxUserFontSet.cpp
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -685,16 +685,45 @@ gfxFontFamily::FindWeightsForStyle(gfxFo
 
 
 void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     // just return the primary name; subclasses should override
     aLocalizedName = mName;
 }
 
+// metric for how close a given font matches a style
+static PRInt32
+CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
+{
+    PRInt32 rank = 0;
+    if (aStyle) {
+         // italics
+         bool wantItalic =
+             ((aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
+         if (aFontEntry->IsItalic() == wantItalic) {
+             rank += 10;
+         }
+
+        // measure of closeness of weight to the desired value
+        rank += 9 - abs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
+    } else {
+        // if no font to match, prefer non-bold, non-italic fonts
+        if (!aFontEntry->IsItalic()) {
+            rank += 3;
+        }
+        if (!aFontEntry->IsBold()) {
+            rank += 2;
+        }
+    }
+
+    return rank;
+}
+
+#define RANK_MATCHED_CMAP   20
 
 void
 gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
 {
     if (mCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
         // none of the faces in the family support the required char,
         // so bail out immediately
         return;
@@ -705,17 +734,17 @@ gfxFontFamily::FindFontForChar(GlobalFon
     gfxFontEntry *fe = FindFontForStyle(
                   (aMatchData->mStyle == nsnull) ? *aMatchData->mStyle : normal,
                   needsBold);
 
     if (fe && !fe->SkipDuringSystemFallback()) {
         PRInt32 rank = 0;
 
         if (fe->TestCharacterMap(aMatchData->mCh)) {
-            rank += 20;
+            rank += RANK_MATCHED_CMAP;
             aMatchData->mCount++;
 #ifdef PR_LOGGING
             PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
 
             if (NS_UNLIKELY(log)) {
                 PRUint32 charRange = gfxFontUtils::CharRangeBit(aMatchData->mCh);
                 PRUint32 unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
                 PRUint32 script = GetScriptCode(aMatchData->mCh);
@@ -731,51 +760,50 @@ gfxFontFamily::FindFontForChar(GlobalFon
 
         aMatchData->mCmapsTested++;
         if (rank == 0) {
             return;
         }
 
          // omitting from original windows code -- family name, lang group, pitch
          // not available in current FontEntry implementation
-
-        if (aMatchData->mStyle) {
-            const gfxFontStyle *style = aMatchData->mStyle;
-
-             // italics
-             bool wantItalic =
-                 ((style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
-             if (fe->IsItalic() == wantItalic) {
-                 rank += 10;
-             }
-
-            // measure of closeness of weight to the desired value
-            rank += 9 - abs(fe->Weight() / 100 - style->ComputeWeight());
-        } else {
-            // if no font to match, prefer non-bold, non-italic fonts
-            if (!fe->IsItalic()) {
-                rank += 3;
-            }
-            if (!fe->IsBold()) {
-                rank += 2;
-            }
-        }
+        rank += CalcStyleMatch(fe, aMatchData->mStyle);
 
         // xxx - add whether AAT font with morphing info for specific lang groups
 
         if (rank > aMatchData->mMatchRank
             || (rank == aMatchData->mMatchRank &&
                 Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
         {
             aMatchData->mBestMatch = fe;
             aMatchData->mMatchRank = rank;
         }
     }
 }
 
+void
+gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
+{
+    PRUint32 i, numFonts = mAvailableFonts.Length();
+    for (i = 0; i < numFonts; i++) {
+        gfxFontEntry *fe = mAvailableFonts[i];
+        if (fe && fe->TestCharacterMap(aMatchData->mCh)) {
+            PRInt32 rank = RANK_MATCHED_CMAP;
+            rank += CalcStyleMatch(fe, aMatchData->mStyle);
+            if (rank > aMatchData->mMatchRank
+                || (rank == aMatchData->mMatchRank &&
+                    Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
+            {
+                aMatchData->mBestMatch = fe;
+                aMatchData->mMatchRank = rank;
+            }
+        }
+    }
+}
+
 // returns true if other names were found, false otherwise
 bool
 gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
                                            FallibleTArray<PRUint8>& aNameTable,
                                            bool useFullName)
 {
     const PRUint8 *nameData = aNameTable.Elements();
     PRUint32 dataLength = aNameTable.Length();
@@ -3350,37 +3378,32 @@ gfxFontGroup::FindFontForChar(PRUint32 a
     // 1. check fonts in the font group
     for (PRUint32 i = 0; i < FontListLength(); i++) {
         nsRefPtr<gfxFont> font = GetFontAt(i);
         if (font->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
 
-#if 0 // code currently assumes FindFontForChar iterates over all faces
-// fix by overriding useCmaps?
-
         // check other faces of the family
         gfxFontFamily *family = font->GetFontEntry()->Family();
         if (family && family->TestCharacterMap(aCh)) {
-            FontSearch matchData(aCh, font);
-            family->FindFontForChar(&matchData);
+            GlobalFontMatch matchData(aCh, aRunScript, &mStyle);
+            family->SearchAllFontsForChar(&matchData);
             gfxFontEntry *fe = matchData.mBestMatch;
             if (fe) {
                 bool needsBold =
                     font->GetStyle()->weight >= 600 && !fe->IsBold();
                 selectedFont =
                     fe->FindOrMakeFont(font->GetStyle(), needsBold);
                 if (selectedFont) {
                     return selectedFont.forget();
                 }
             }
         }
-#endif
-
     }
 
     // if character is in Private Use Area, don't do matching against pref or system fonts
     if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
         return nsnull;
 
     // 2. search pref fonts
     if ((selectedFont = WhichPrefFontSupportsChar(aCh))) {
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -564,16 +564,19 @@ public:
     // needed, false otherwise
     gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
                                    bool& aNeedsSyntheticBold);
 
     // checks for a matching font within the family
     // used as part of the font fallback process
     void FindFontForChar(GlobalFontMatch *aMatchData);
 
+    // checks all fonts for a matching font within the family
+    void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
+
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
 
     // set when other family names have been read in
     void SetOtherFamilyNamesInitialized() {
         mOtherFamilyNamesInitialized = true;
     }
 
@@ -585,33 +588,33 @@ public:
     // find faces belonging to this family (platform implementations override this;
     // should be made pure virtual once all subclasses have been updated)
     virtual void FindStyleVariations() { }
 
     // search for a specific face using the Postscript name
     gfxFontEntry* FindFont(const nsAString& aPostscriptName);
 
     // read in cmaps for all the faces
-    void ReadCMAP() {
+    void ReadAllCMAPs() {
         PRUint32 i, numFonts = mAvailableFonts.Length();
         for (i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (!fe) {
                 continue;
             }
             fe->ReadCMAP();
             mCharacterMap.Union(fe->mCharacterMap);
         }
         mCharacterMap.Compact();
         mCharacterMapInitialized = true;
     }
 
     bool TestCharacterMap(PRUint32 aCh) {
         if (!mCharacterMapInitialized) {
-            ReadCMAP();
+            ReadAllCMAPs();
         }
         return mCharacterMap.test(aCh);
     }
 
     void ResetCharacterMap() {
         mCharacterMap.reset();
         mCharacterMapInitialized = false;
     }
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -681,17 +681,17 @@ gfxPlatformFontList::RunLoader()
             // failed to load any faces for this family, so discard it
             nsAutoString key;
             GenerateFontListKey(familyEntry->Name(), key);
             mFontFamilies.Remove(key);
             continue;
         }
 
         // load the cmaps
-        familyEntry->ReadCMAP();
+        familyEntry->ReadAllCMAPs();
 
         // read in face names
         familyEntry->ReadFaceNames(this, mNeedFullnamePostscriptNames);
 
         // check whether the family can be considered "simple" for style matching
         familyEntry->CheckForSimpleFamily();
     }
 
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -397,43 +397,44 @@ StoreUserFontData(gfxFontEntry* aFontEnt
     userFontData->mFormat = src.mFormatFlags;
     userFontData->mRealName = aOriginalName;
     if (aMetadata) {
         userFontData->mMetadata.SwapElements(*aMetadata);
         userFontData->mMetaOrigLen = aMetaOrigLen;
     }
 }
 
+struct WOFFHeader {
+    AutoSwap_PRUint32 signature;
+    AutoSwap_PRUint32 flavor;
+    AutoSwap_PRUint32 length;
+    AutoSwap_PRUint16 numTables;
+    AutoSwap_PRUint16 reserved;
+    AutoSwap_PRUint32 totalSfntSize;
+    AutoSwap_PRUint16 majorVersion;
+    AutoSwap_PRUint16 minorVersion;
+    AutoSwap_PRUint32 metaOffset;
+    AutoSwap_PRUint32 metaCompLen;
+    AutoSwap_PRUint32 metaOrigLen;
+    AutoSwap_PRUint32 privOffset;
+    AutoSwap_PRUint32 privLen;
+};
+
 void
 gfxUserFontSet::CopyWOFFMetadata(const PRUint8* aFontData,
                                  PRUint32 aLength,
                                  nsTArray<PRUint8>* aMetadata,
                                  PRUint32* aMetaOrigLen)
 {
     // This function may be called with arbitrary, unvalidated "font" data
     // from @font-face, so it needs to be careful to bounds-check, etc.,
     // before trying to read anything.
     // This just saves a copy of the compressed data block; it does NOT check
     // that the block can be successfully decompressed, or that it contains
     // well-formed/valid XML metadata.
-    struct WOFFHeader {
-        AutoSwap_PRUint32 signature;
-        AutoSwap_PRUint32 flavor;
-        AutoSwap_PRUint32 length;
-        AutoSwap_PRUint16 numTables;
-        AutoSwap_PRUint16 reserved;
-        AutoSwap_PRUint32 totalSfntSize;
-        AutoSwap_PRUint16 majorVersion;
-        AutoSwap_PRUint16 minorVersion;
-        AutoSwap_PRUint32 metaOffset;
-        AutoSwap_PRUint32 metaCompLen;
-        AutoSwap_PRUint32 metaOrigLen;
-        AutoSwap_PRUint32 privOffset;
-        AutoSwap_PRUint32 privLen;
-    };
     if (aLength < sizeof(WOFFHeader)) {
         return;
     }
     const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
     PRUint32 metaOffset = woff->metaOffset;
     PRUint32 metaCompLen = woff->metaCompLen;
     if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
         return;