]> granicus.if.org Git - libass/commitdiff
directwrite: multiple improvements to font scanning
authorGrigori Goronzy <greg@chown.ath.cx>
Sat, 13 Jun 2015 14:29:10 +0000 (16:29 +0200)
committerGrigori Goronzy <greg@chown.ath.cx>
Fri, 10 Jul 2015 08:43:16 +0000 (10:43 +0200)
There were various issues with font scanning. This addresses the following:

- Synthesized font faces (bold/oblique) were added to the list. Just skip
  those, this is handled internally by libass.
- Use the win32 font family names, if available. Traditionally, Windows
  groups font families in a different way, so that the number of
  variants is small (<= 4). With this, Arial Narrow and Arial Black
  appear as a separate family, which is what we want.
- Full names are not mandatory. Correctly handle the case that there
  are no full names.
- Don't use the bogus LOCALE_NAME_MAX_LENGTH constant to determine the
  size of the name buffer. Names can be almost arbitrarily long.
  Handle names up to 256 characters correctly and truncate longer names.

libass/ass_directwrite.cpp

index f8feecf03aabd8629e49d1203ee7211340a46934..9bc8ce9b1f5a35fb471373720af35eeae35ebee9 100644 (file)
@@ -27,6 +27,8 @@ extern "C" {
 #include "ass_utils.h"
 }
 
+#define NAME_MAX_LENGTH 256
+
 /*
  * The private data stored for every font, detected by this backend.
  */
@@ -177,9 +179,21 @@ static void destroy_font(void *data)
     free(priv);
 }
 
-static int map_width(int stretch)
+static int map_width(enum DWRITE_FONT_STRETCH stretch)
 {
-    return stretch * (100 / DWRITE_FONT_STRETCH_MEDIUM);
+    switch (stretch) {
+    case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return 50;
+    case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return 63;
+    case DWRITE_FONT_STRETCH_CONDENSED:       return FONT_WIDTH_CONDENSED;
+    case DWRITE_FONT_STRETCH_SEMI_CONDENSED:  return 88;
+    case DWRITE_FONT_STRETCH_MEDIUM:          return FONT_WIDTH_NORMAL;
+    case DWRITE_FONT_STRETCH_SEMI_EXPANDED:   return 113;
+    case DWRITE_FONT_STRETCH_EXPANDED:        return FONT_WIDTH_EXPANDED;
+    case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:  return 150;
+    case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:  return 200;
+    default:
+        assert(0);
+    }
 }
 
 /*
@@ -197,7 +211,7 @@ static void scan_fonts(IDWriteFactory *factory,
     DWRITE_FONT_STYLE style;
     ASS_FontProviderMetaData meta = ASS_FontProviderMetaData();
     hr = factory->GetSystemFontCollection(&fontCollection, FALSE);
-    wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+    wchar_t temp_name[NAME_MAX_LENGTH];
     int size_needed = 0;
 
     if (FAILED(hr) || !fontCollection)
@@ -215,7 +229,7 @@ static void scan_fonts(IDWriteFactory *factory,
 
         hr = fontCollection->GetFontFamily(i, &fontFamily);
         if (FAILED(hr))
-            return;
+            continue;
 
         UINT32 fontCount = fontFamily->GetFontCount();
         for (UINT32 j = 0; j < fontCount; ++j) {
@@ -223,6 +237,13 @@ static void scan_fonts(IDWriteFactory *factory,
             if (FAILED(hr))
                 continue;
 
+            // Simulations for bold or oblique are sometimes synthesized by
+            // DirectWrite. We are only interested in physical fonts.
+            if (font->GetSimulations() != 0) {
+                font->Release();
+                continue;
+            }
+
             meta.weight = font->GetWeight();
             meta.width = map_width(font->GetStretch());
             font->GetMetrics(&metrics);
@@ -232,68 +253,70 @@ static void scan_fonts(IDWriteFactory *factory,
                          (style == DWRITE_FONT_STYLE_ITALIC) ? FONT_SLANT_ITALIC : FONT_SLANT_NONE;
 
             hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames,&exists);
-
             if (FAILED(hr)) {
                 font->Release();
                 continue;
             }
 
             if (exists) {
-                hr = psNames->GetString(0, localeName, LOCALE_NAME_MAX_LENGTH + 1);
+                hr = psNames->GetString(0, temp_name, NAME_MAX_LENGTH);
                 if (FAILED(hr)) {
                     psNames->Release();
                     font->Release();
                     continue;
                 }
 
-                size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0,NULL, NULL);
+                temp_name[NAME_MAX_LENGTH-1] = 0;
+                size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL);
                 psName = (char *) malloc(size_needed);
-                WideCharToMultiByte(CP_UTF8, 0, localeName, -1, psName,size_needed, NULL, NULL);
+                WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, psName, size_needed, NULL, NULL);
+                psNames->Release();
             }
 
-            psNames->Release();
-
             hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames,&exists);
             if (FAILED(hr)) {
                 font->Release();
                 continue;
             }
 
-            meta.n_fullname = fontNames->GetCount();
-            meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *));
-            for (UINT32 k = 0; k < meta.n_fullname; ++k) {
-                hr = fontNames->GetString(k, localeName,LOCALE_NAME_MAX_LENGTH + 1);
-
-                if (FAILED(hr)) {
-                    continue;
+            if (exists) {
+                meta.n_fullname = fontNames->GetCount();
+                meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *));
+                for (UINT32 k = 0; k < meta.n_fullname; ++k) {
+                    hr = fontNames->GetString(k, temp_name, NAME_MAX_LENGTH);
+                    if (FAILED(hr)) {
+                        continue;
+                    }
+
+                    temp_name[NAME_MAX_LENGTH-1] = 0;
+                    size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL);
+                    char *mbName = (char *) malloc(size_needed);
+                    WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL);
+                    meta.fullnames[k] = mbName;
                 }
-
-                size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL);
-                char *mbName = (char *) malloc(size_needed);
-                WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName,size_needed, NULL, NULL);
-                meta.fullnames[k] = mbName;
+                fontNames->Release();
             }
-            fontNames->Release();
 
-            hr = fontFamily->GetFamilyNames(&familyNames);
+            hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &familyNames, &exists);
+            if (!exists)
+                hr = fontFamily->GetFamilyNames(&familyNames);
             if (FAILED(hr)) {
                 font->Release();
                 continue;
             }
 
-
             meta.n_family = familyNames->GetCount();
             meta.families = (char **) calloc(meta.n_family, sizeof(char *));
             for (UINT32 k = 0; k < meta.n_family; ++k) {
-                hr = familyNames->GetString(k, localeName, LOCALE_NAME_MAX_LENGTH + 1);
-
+                hr = familyNames->GetString(k, temp_name, NAME_MAX_LENGTH);
                 if (FAILED(hr)) {
                     continue;
                 }
 
-                size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0,NULL, NULL);
+                temp_name[NAME_MAX_LENGTH-1] = 0;
+                size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL);
                 char *mbName = (char *) malloc(size_needed);
-                WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName,size_needed, NULL, NULL);
+                WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL);
                 meta.families[k] = mbName;
             }
             familyNames->Release();