bug 382542. fix problems with font fallback and font variations. r=vlad/jdaggett
authorpavlov@pavlov.net
Wed, 19 Mar 2008 17:41:19 -0700
changeset 13340 0fca09536e75404bc7009516e9236a14d37be7bf
parent 13339 1f58de9a23b8413c51517202b16c7cbaeb67697d
child 13341 63e3861f185658a626a155891386487b8ae9c838
push idunknown
push userunknown
push dateunknown
reviewersvlad, jdaggett
bugs382542
milestone1.9b5pre
bug 382542. fix problems with font fallback and font variations. r=vlad/jdaggett
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/public/gfxWindowsPlatform.h
gfx/thebes/src/gfxWindowsFonts.cpp
gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -205,17 +205,17 @@ public:
 /**********************************************************************
  *
  * class gfxWindowsFont
  *
  **********************************************************************/
 
 class gfxWindowsFont : public gfxFont {
 public:
-    gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFontStyle);
+    gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFontStyle, FontEntry *aFontEntry);
     virtual ~gfxWindowsFont();
 
     virtual const gfxFont::Metrics& GetMetrics();
 
     HFONT GetHFONT() { return mFont; }
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CairoScaledFont();
     SCRIPT_CACHE *ScriptCache() { return &mScriptCache; }
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -80,16 +80,17 @@ public:
      * this involves looking at the fonts on your machine and seeing which
      * code points they support as well as looking at things like the font
      * family, style, weight, etc.
      */
     FontEntry *FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont);
 
     /* Find a FontFamily/FontEntry object that represents a font on your system given a name */
     FontFamily *FindFontFamily(const nsAString& aName);
+    FontEntry *FindFontEntry(FontFamily *aFontFamily, const gfxFontStyle *aFontStyle);
     FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle);
 
     PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
     void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
 
     typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
 
 private:
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -110,24 +110,22 @@ struct DCFromContext {
 };
 
 /**********************************************************************
  *
  * class gfxWindowsFont
  *
  **********************************************************************/
 
-gfxWindowsFont::gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFontStyle)
+gfxWindowsFont::gfxWindowsFont(const nsAString& aName, const gfxFontStyle *aFontStyle, FontEntry *aFontEntry)
     : gfxFont(aName, aFontStyle),
       mFont(nsnull), mAdjustedSize(0.0), mScriptCache(nsnull),
       mFontFace(nsnull), mScaledFont(nsnull),
-      mMetrics(nsnull)
+      mMetrics(nsnull), mFontEntry(aFontEntry)
 {
-    // XXX we should work to get this passed in rather than having to find it again.
-    mFontEntry = gfxWindowsPlatform::GetPlatform()->FindFontEntry(aName, aFontStyle);
     NS_ASSERTION(mFontEntry, "Unable to find font entry for font.  Something is whack.");
 
     mFont = MakeHFONT(); // create the HFONT, compute metrics, etc
     NS_ASSERTION(mFont, "Failed to make HFONT");
 }
 
 gfxWindowsFont::~gfxWindowsFont()
 {
@@ -414,17 +412,17 @@ gfxWindowsFont::SetupCairoFont(gfxContex
  * In either case, add a ref, append it to the aFonts array, and return it ---
  * except for OOM in which case we do nothing and return null.
  */
 static already_AddRefed<gfxWindowsFont>
 GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
 {
     nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry->GetName(), aStyle);
     if (!font) {
-        font = new gfxWindowsFont(aFontEntry->GetName(), aStyle);
+        font = new gfxWindowsFont(aFontEntry->GetName(), aStyle, aFontEntry);
         if (!font)
             return nsnull;
         gfxFontCache::GetCache()->AddNew(font);
     }
     gfxFont *f = nsnull;
     font.swap(f);
     return static_cast<gfxWindowsFont *>(f);
 }
@@ -616,19 +614,17 @@ SetupDCFont(HDC dc, gfxWindowsFont *aFon
 {
     HFONT hfont = aFont->GetHFONT();
     if (!hfont)
         return PR_FALSE;
     SelectObject(dc, hfont);
 
     /* GetGlyphIndices is buggy for bitmap and vector fonts,
        so send them to uniscribe */
-    TEXTMETRIC metrics;
-    GetTextMetrics(dc, &metrics);
-    if ((metrics.tmPitchAndFamily & (TMPF_TRUETYPE)) == 0)
+    if (!aFont->GetFontEntry()->mTrueType)
         return PR_FALSE;
 
     return PR_TRUE;
 }
 
 static PRBool
 IsAnyGlyphMissing(WCHAR *aGlyphs, PRUint32 aLength)
 {
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -140,16 +140,18 @@ gfxWindowsPlatform::FontEnumProc(const E
     fe = new FontEntry(ff);
     /* don't append it until the end in case of error */
 
     fe->mItalic = (logFont.lfItalic == 0xFF);
     fe->mWeight = logFont.lfWeight;
 
     if (metrics.ntmFlags & NTM_TYPE1)
         fe->mIsType1 = PR_TRUE;
+    if (metrics.ntmFlags & (NTM_PS_OPENTYPE | NTM_TT_OPENTYPE))
+        fe->mTrueType = PR_TRUE;
 
     // mark the charset bit
     fe->mCharset[metrics.tmCharSet] = 1;
 
     fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
     fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
 
     if (nmetrics->ntmFontSig.fsUsb[0] == 0x00000000 &&
@@ -547,67 +549,58 @@ struct FontSearch {
     nsRefPtr<FontEntry> bestMatch;
 };
 
 PLDHashOperator PR_CALLBACK
 gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                         nsRefPtr<FontFamily>& aFontFamily,
                                         void* userArg)
 {
-    // XXX Improve this to look at the variations to find a better font
-    nsRefPtr<FontEntry> aFontEntry = aFontFamily->mVariations[0];
-
-    // bitmap fonts suck
-    if (aFontEntry->IsCrappyFont())
-        return PL_DHASH_NEXT;
-
     FontSearch *data = (FontSearch*)userArg;
 
-    PRUint32 ch = data->ch;
+    const PRUint32 ch = data->ch;
+
+    nsRefPtr<FontEntry> fe = GetPlatform()->FindFontEntry(aFontFamily, data->fontToMatch->GetStyle());
 
-    for (PRUint32 i = 0; i < aFontFamily->mVariations.Length(); ++i) {
-        PRInt32 rank = 0;
-
-        nsRefPtr<FontEntry> fe = aFontFamily->mVariations[i];
+    // skip over non-unicode and bitmap fonts and fonts that don't have
+    // the code point we're looking for
+    if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
+        return PL_DHASH_NEXT;
 
-        if (fe->mCharacterMap.test(ch)) {
-            // fonts that claim to support the range are more
-            // likely to be "better fonts" than ones that don't... (in theory)
-            if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
-                rank += 1;
-        } else {
-            // if we didn't match any characters don't bother wasting more time.
-            continue;
-        }
+    PRInt32 rank = 0;
+    // fonts that claim to support the range are more
+    // likely to be "better fonts" than ones that don't... (in theory)
+    if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
+        rank += 1;
 
-        if (fe->SupportsLangGroup(data->fontToMatch->GetStyle()->langGroup))
-            rank += 10;
+    if (fe->SupportsLangGroup(data->fontToMatch->GetStyle()->langGroup))
+        rank += 2;
 
-        if (fe->mWindowsFamily == data->fontToMatch->GetFontEntry()->mWindowsFamily)
-            rank += 5;
-        if (fe->mWindowsPitch == data->fontToMatch->GetFontEntry()->mWindowsFamily)
-            rank += 5;
+    if (fe->mWindowsFamily == data->fontToMatch->GetFontEntry()->mWindowsFamily)
+        rank += 3;
+    if (fe->mWindowsPitch == data->fontToMatch->GetFontEntry()->mWindowsFamily)
+        rank += 3;
 
-        /* italic */
-        const PRBool italic = (data->fontToMatch->GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE;
-        if (fe->mItalic == italic)
-            rank += 55;
+    /* italic */
+    const PRBool italic = (data->fontToMatch->GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE;
+    if (fe->mItalic != italic)
+        rank += 3;
 
-        /* weight */
-        PRInt8 baseWeight, weightDistance;
-        data->fontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
-        PRUint16 targetWeight = (baseWeight * 100) + (weightDistance * 100);
-        if (fe->mWeight == targetWeight)
-            rank += 50;
+    /* weight */
+    PRInt8 baseWeight, weightDistance;
+    data->fontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
+    if (fe->mWeight == (baseWeight * 100) + (weightDistance * 100))
+        rank += 2;
+    else if (fe->mWeight == data->fontToMatch->GetFontEntry()->mWeight)
+        rank += 1;
 
-        if (rank > data->matchRank ||
-            (rank == data->matchRank && Compare(fe->GetName(), data->bestMatch->GetName()) > 0)) {
-            data->bestMatch = fe;
-            data->matchRank = rank;
-        }
+    if (rank > data->matchRank ||
+        (rank == data->matchRank && Compare(fe->GetName(), data->bestMatch->GetName()) > 0)) {
+        data->bestMatch = fe;
+        data->matchRank = rank;
     }
 
     return PL_DHASH_NEXT;
 }
 
 
 FontEntry *
 gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
@@ -654,27 +647,33 @@ gfxWindowsPlatform::FindFontFamily(const
 
 FontEntry *
 gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle *aFontStyle)
 {
     nsRefPtr<FontFamily> ff = FindFontFamily(aName);
     if (!ff)
         return nsnull;
 
+    return FindFontEntry(ff, aFontStyle);
+}
+
+FontEntry *
+gfxWindowsPlatform::FindFontEntry(FontFamily *aFontFamily, const gfxFontStyle *aFontStyle)
+{
     PRUint8 bestMatch = 0;
     nsRefPtr<FontEntry> matchFE;
     const PRBool italic = (aFontStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? PR_TRUE : PR_FALSE;
 
     // build up an array of weights that match the italicness we're looking for
     nsAutoTArray<nsRefPtr<FontEntry>, 10> weightList;
     weightList.AppendElements(10);
-    for (PRInt32 i = 0; i < ff->mVariations.Length(); i++) {
-        nsRefPtr<FontEntry> fe = ff->mVariations[i];
+    for (PRInt32 i = 0; i < aFontFamily->mVariations.Length(); i++) {
+        nsRefPtr<FontEntry> fe = aFontFamily->mVariations[i];
         const PRUint8 weight = (fe->mWeight / 100) - 1;
-        if (italic == fe->mItalic)
+        if (fe->mItalic == italic)
             weightList[weight] = fe;
     }
 
     PRInt8 baseWeight, weightDistance;
     aFontStyle->ComputeWeightAndOffset(&baseWeight, &weightDistance);
 
     PRUint32 chosenWeight = 0;
     PRUint8 direction = (weightDistance >= 0) ? 1 : -1;
@@ -704,26 +703,29 @@ gfxWindowsPlatform::FindFontEntry(const 
 
     // If we end up with something like 900 here but only have 600,
     // search backwards until we find a match
     const PRUint32 index = (chosenWeight / 100) - 1;
     for (PRInt32 j = index; j >= 0; --j) {
         if (matchFE = weightList[j])
             break;
     }
-    
+
     if (!matchFE) {
-        NS_ASSERTION(italic, "Italic isn't set.  This is bad");
-        // We should only ever hit this code in the case where we're looking for an
-        // italic font and there is no face for one, so ask for a match for a normal one.
-        // The font rendering code can still specify italic and Windows will
-        // do synthetic italic
+        // Not having a match can occur in 2 ways:
+        // The font only has an italic face and we're looking for a normal one.
+        // The font has no italic face and we're looking for italic.
+        // So search for the opposite of what we're looking for
         gfxFontStyle style(*aFontStyle);
-        style.style = FONT_STYLE_NORMAL;
-        matchFE = FindFontEntry(aName, &style);
+        if (aFontStyle->style == FONT_STYLE_NORMAL)
+            style.style = FONT_STYLE_ITALIC;
+        else
+            style.style = FONT_STYLE_NORMAL;
+
+        matchFE = FindFontEntry(aFontFamily, &style);
     }
     return matchFE;
 }
 
 cmsHPROFILE
 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
 {
     WCHAR str[1024+1];