Bug 947812 - use DirectWrite API for fullname/psname lookup. r=bas
authorJohn Daggett <jdaggett@mozilla.com>
Wed, 11 Dec 2013 09:58:19 +0900
changeset 159811 775dfb379e04d15fbca2a6d7b7b5c29ffb422af6
parent 159810 9de6643e665fd8ecf8d78c4c9ffcfd97a683a5b6
child 159812 75c565fcfa509b6ead918d434b1c9bb7320fb35a
push idunknown
push userunknown
push dateunknown
reviewersbas
bugs947812
milestone29.0a1
Bug 947812 - use DirectWrite API for fullname/psname lookup. r=bas
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -53,107 +53,214 @@ BuildKeyNameFromFontName(nsAString &aNam
 
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontFamily
 
 gfxDWriteFontFamily::~gfxDWriteFontFamily()
 {
 }
 
+static HRESULT
+GetDirectWriteFontName(IDWriteFont *aFont, nsAString& aFontName)
+{
+    HRESULT hr;
+
+    nsRefPtr<IDWriteLocalizedStrings> names;
+    hr = aFont->GetFaceNames(getter_AddRefs(names));
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    BOOL exists;
+    nsAutoTArray<wchar_t,32> faceName;
+    UINT32 englishIdx = 0;
+    hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    if (!exists) {
+        // No english found, use whatever is first in the list.
+        englishIdx = 0;
+    }
+    UINT32 length;
+    hr = names->GetStringLength(englishIdx, &length);
+    if (FAILED(hr)) {
+        return hr;
+    }
+    faceName.SetLength(length + 1);
+    hr = names->GetString(englishIdx, faceName.Elements(), length + 1);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    aFontName.Assign(faceName.Elements());
+    return S_OK;
+}
+
+// These strings are only defined in Win SDK 8+, so use #ifdef for now
+#if MOZ_WINSDK_TARGETVER > 0x08000000
+#define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_FULL_NAME
+#define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME
+#else
+#define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 1)
+#define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 2)
+#endif
+
+// for use in reading postscript or fullname
+static HRESULT
+GetDirectWriteFaceName(IDWriteFont *aFont,
+                       DWRITE_INFORMATIONAL_STRING_ID aWhichName,
+                       nsAString& aFontName)
+{
+    HRESULT hr;
+
+    BOOL exists;
+    nsRefPtr<IDWriteLocalizedStrings> infostrings;
+    hr = aFont->GetInformationalStrings(aWhichName, getter_AddRefs(infostrings), &exists);
+    if (FAILED(hr) || !exists) {
+        return E_FAIL;
+    }
+
+    nsAutoTArray<wchar_t,32> faceName;
+    UINT32 englishIdx = 0;
+    hr = infostrings->FindLocaleName(L"en-us", &englishIdx, &exists);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    if (!exists) {
+        // No english found, use whatever is first in the list.
+        englishIdx = 0;
+    }
+    UINT32 length;
+    hr = infostrings->GetStringLength(englishIdx, &length);
+    if (FAILED(hr)) {
+        return hr;
+    }
+    faceName.SetLength(length + 1);
+    hr = infostrings->GetString(englishIdx, faceName.Elements(), length + 1);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    aFontName.Assign(faceName.Elements());
+    return S_OK;
+}
+
 void
 gfxDWriteFontFamily::FindStyleVariations()
 {
     HRESULT hr;
     if (mHasStyles) {
         return;
     }
     mHasStyles = true;
 
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+
+    bool skipFaceNames = mFaceNamesInitialized ||
+                         !fp->NeedFullnamePostscriptNames();
+
     for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
         nsRefPtr<IDWriteFont> font;
         hr = mDWFamily->GetFont(i, getter_AddRefs(font));
         if (FAILED(hr)) {
             // This should never happen.
             NS_WARNING("Failed to get existing font from family.");
             continue;
         }
 
         if (font->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
             // We don't want these.
             continue;
         }
 
-        nsRefPtr<IDWriteLocalizedStrings> names;
-        hr = font->GetFaceNames(getter_AddRefs(names));
-        if (FAILED(hr)) {
-            continue;
-        }
-        
-        BOOL exists;
-        nsAutoTArray<WCHAR,32> faceName;
-        UINT32 englishIdx = 0;
-        hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
-        if (FAILED(hr)) {
-            continue;
-        }
-
-        if (!exists) {
-            // No english found, use whatever is first in the list.
-            englishIdx = 0;
-        }
-        UINT32 length;
-        hr = names->GetStringLength(englishIdx, &length);
+        // name
+        nsString fullID(mName);
+        nsAutoString faceName;
+        hr = GetDirectWriteFontName(font, faceName);
         if (FAILED(hr)) {
             continue;
         }
-        if (!faceName.SetLength(length + 1)) {
-            // Eeep - running out of memory. Unlikely to end well.
-            continue;
-        }
-
-        hr = names->GetString(englishIdx, faceName.Elements(), length + 1);
-        if (FAILED(hr)) {
-            continue;
-        }
+        fullID.Append(NS_LITERAL_STRING(" "));
+        fullID.Append(faceName);
 
-        nsString fullID(mName);
-        fullID.Append(NS_LITERAL_STRING(" "));
-        fullID.Append(faceName.Elements());
-
-        /**
-         * Faces do not have a localized name so we just put the en-us name in
-         * here.
-         */
-        gfxDWriteFontEntry *fe = 
-            new gfxDWriteFontEntry(fullID, font);
+        gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font);
         fe->SetForceGDIClassic(mForceGDIClassic);
         AddFontEntry(fe);
 
+        // postscript/fullname if needed
+        nsAutoString psname, fullname;
+        if (!skipFaceNames) {
+            hr = GetDirectWriteFaceName(font, PSNAME_ID, psname);
+            if (FAILED(hr)) {
+                skipFaceNames = true;
+            } else if (psname.Length() > 0) {
+                fp->AddPostscriptName(fe, psname);
+            }
+
+            hr = GetDirectWriteFaceName(font, FULLNAME_ID, fullname);
+            if (FAILED(hr)) {
+                skipFaceNames = true;
+            } else if (fullname.Length() > 0) {
+                fp->AddFullname(fe, fullname);
+            }
+        }
+
 #ifdef PR_LOGGING
         if (LOG_FONTLIST_ENABLED()) {
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %d stretch: %d",
+                 " with style: %s weight: %d stretch: %d psname: %s fullname: %s",
                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
                  (fe->IsItalic()) ? "italic" : "normal",
-                 fe->Weight(), fe->Stretch()));
+                 fe->Weight(), fe->Stretch(),
+                 NS_ConvertUTF16toUTF8(psname).get(),
+                 NS_ConvertUTF16toUTF8(fullname).get()));
         }
 #endif
     }
 
+    // assume that if no error, all postscript/fullnames were initialized
+    if (!skipFaceNames) {
+        mFaceNamesInitialized = true;
+    }
+
     if (!mAvailableFonts.Length()) {
         NS_WARNING("Family with no font faces in it.");
     }
 
     if (mIsBadUnderlineFamily) {
         SetBadUnderlineFonts();
     }
 }
 
 void
+gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
+                                   bool aNeedFullnamePostscriptNames)
+{
+    // if all needed names have already been read, skip
+    if (mOtherFamilyNamesInitialized &&
+        (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
+        return;
+    }
+
+    // DirectWrite version of this will try to read
+    // postscript/fullnames via DirectWrite API
+    FindStyleVariations();
+
+    // fallback to looking up via name table
+    if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
+        gfxFontFamily::ReadFaceNames(aPlatformFontList,
+                                     aNeedFullnamePostscriptNames);
+    }
+}
+
+void
 gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
 {
     aLocalizedName.AssignLiteral("Unknown Font");
     HRESULT hr;
     nsresult rv;
     nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID,
                                                   &rv);
     nsCOMPtr<nsILocale> locale;
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -42,16 +42,19 @@ public:
                         IDWriteFontFamily *aFamily)
       : gfxFontFamily(aName), mDWFamily(aFamily), mForceGDIClassic(false) {}
     virtual ~gfxDWriteFontFamily();
     
     virtual void FindStyleVariations();
 
     virtual void LocalizedName(nsAString& aLocalizedName);
 
+    virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
+                               bool aNeedFullnamePostscriptNames);
+
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
 protected: