[pango/pango1-dwrite: 1/2] pangowin32: Use DirectWrite to enumerate system fonts




commit f44f44e51fb758a7aa6a27a40f1e81848fbd8a4b
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Thu Jul 7 12:36:26 2022 +0800

    pangowin32: Use DirectWrite to enumerate system fonts
    
    ...instead of using EnumFontFamiliesEx() if we have DirectWrite support, and
    retrieve the LOGFONTW's that we need via DirectWrite's GDI interop.  Also
    cache up our IDWriteFont's that we obtained, so that we can use DirectWrite to
    query font properties better than what GDI/Uniscribe can do for us, such as
    obtaining stretch info from the font.  Also update synthesize_foreach()
    accordingly, since we should also record the IDWriteFonts as well for
    synthesized LOGFONTWs.
    
    Portions based on Luca Bacci's implementation of the DirectWrite fontmap
    support in the upcoming Pango2.

 pango/pangowin32-dwrite-fontmap.cpp | 118 ++++++++++++++++++++++++++++++++++++
 pango/pangowin32-fontmap.c          |  41 ++++++++-----
 pango/pangowin32-private.h          |  22 ++++++-
 3 files changed, 164 insertions(+), 17 deletions(-)
---
diff --git a/pango/pangowin32-dwrite-fontmap.cpp b/pango/pangowin32-dwrite-fontmap.cpp
index b2e690c25..e7c7bc9c1 100644
--- a/pango/pangowin32-dwrite-fontmap.cpp
+++ b/pango/pangowin32-dwrite-fontmap.cpp
@@ -93,6 +93,112 @@ pango_win32_dwrite_font_map_destroy (PangoWin32FontMap *map)
   g_free (dwrite_items);
 }
 
+void
+pango_win32_dwrite_font_map_populate (PangoWin32FontMap *map)
+{
+  IDWriteFontCollection *collection = NULL;
+  UINT32 count;
+  HRESULT hr;
+  gboolean failed = FALSE;
+  PangoWin32DWriteItems *dwrite_items = map->dwrite_items;
+
+  hr = dwrite_items->dwrite_factory->GetSystemFontCollection (&collection, FALSE);
+  if (FAILED (hr) || collection == NULL)
+    {
+      g_error ("IDWriteFactory::GetSystemFontCollection failed with error code %x\n", (unsigned)hr);
+      return;
+    }
+
+  count = collection->GetFontFamilyCount ();
+
+  for (UINT32 i = 0; i < count; i++)
+    {
+      IDWriteFontFamily *family = NULL;
+      UINT32 font_count;
+
+      hr = collection->GetFontFamily (i, &family);
+      if G_UNLIKELY (FAILED (hr) || family == NULL)
+        {
+          g_warning ("IDWriteFontCollection::GetFontFamily failed with error code %x\n", (unsigned)hr);
+          continue;
+        }
+
+      font_count = family->GetFontCount ();
+
+      for (UINT32 j = 0; j < font_count; j++)
+        {
+          IDWriteFont *font = NULL;
+          IDWriteFontFace *face = NULL;
+          DWRITE_FONT_FACE_TYPE font_face_type;
+
+          hr = family->GetFont (j, &font);
+          if (FAILED (hr) || font == NULL)
+            {
+              g_warning ("IDWriteFontFamily::GetFont failed with error code %x\n", (unsigned)hr);
+              break;
+            }
+
+          hr = font->CreateFontFace (&face);
+          if (FAILED (hr) || face == NULL)
+            {
+              g_warning ("IDWriteFont::CreateFontFace failed with error code %x\n", (unsigned)hr);
+              font->Release ();
+              continue;
+            }
+
+          font_face_type = face->GetType ();
+
+          /* don't include Type-1 fonts */
+          if (font_face_type != DWRITE_FONT_FACE_TYPE_TYPE1)
+            {
+              LOGFONTW lfw;
+              BOOL is_sys_font;
+
+              hr = dwrite_items->gdi_interop->ConvertFontToLOGFONT (font, &lfw, &is_sys_font);
+
+              if (SUCCEEDED (hr))
+                pango_win32_insert_font (map, &lfw, font, FALSE);
+              else
+                g_warning ("GDIInterop::ConvertFontToLOGFONT failed with error code %x\n",
+                           (unsigned)hr);
+            }
+
+          face->Release ();
+        }
+
+      family->Release ();
+    }
+
+  collection->Release ();
+  collection = NULL;
+}
+
+gpointer
+pango_win32_font_map_logfontw_get_dwrite_font (PangoWin32FontMap *map,
+                                               LOGFONTW          *logfontw)
+{
+  PangoWin32DWriteItems *dwrite_items = map->dwrite_items;
+  IDWriteFont *font = NULL;
+  HRESULT hr;
+
+  hr = dwrite_items->gdi_interop->CreateFontFromLOGFONT (logfontw, &font);
+
+  if (FAILED (hr) || font == NULL)
+    g_warning ("IDWriteFactory::GdiInterop::CreateFontFromLOGFONT failed with error %x\n",
+               (unsigned)hr);
+
+  return font;
+}
+
+void
+pango_win32_dwrite_font_release (gpointer dwrite_font)
+{
+  IDWriteFont *font = static_cast<IDWriteFont *>(dwrite_font);
+
+  if (font != NULL)
+    font->Release ();
+}
+
 #else
 /* no-op's, no DirectWrite support */
 void
@@ -104,4 +210,16 @@ void
 pango_win32_dwrite_font_map_destroy (PangoWin32FontMap *map)
 {
 }
+
+void
+pango_win32_dwrite_font_release (gpointer dwrite_font)
+{
+}
+
+gpointer
+pango_win32_font_map_logfontw_get_dwrite_font (PangoWin32FontMap *map,
+                                               LOGFONTW          *logfontw)
+{
+  return NULL;
+}
 #endif
\ No newline at end of file
diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c
index e6b64eb0d..e91f1bbe3 100644
--- a/pango/pangowin32-fontmap.c
+++ b/pango/pangowin32-fontmap.c
@@ -101,10 +101,6 @@ static PangoFont *pango_win32_font_map_real_find_font (PangoWin32FontMap
 
 static void       pango_win32_fontmap_cache_clear    (PangoWin32FontMap            *win32fontmap);
 
-static void       pango_win32_insert_font            (PangoWin32FontMap            *fontmap,
-                                                      LOGFONTW                     *lfp,
-                                                      gboolean                      is_synthetic);
-
 static PangoWin32Family *pango_win32_get_font_family (PangoWin32FontMap            *win32fontmap,
                                                       const char                   *family_name);
 
@@ -197,7 +193,7 @@ pango_win32_inner_enum_proc (LOGFONTW    *lfp,
    * Asian fonts with @ prepended to their name, ignore them.
    */
   if (lfp->lfFaceName[0] != '@')
-    pango_win32_insert_font (win32fontmap, lfp, FALSE);
+    pango_win32_insert_font (win32fontmap, lfp, NULL, FALSE);
 
   return 1;
 }
@@ -282,7 +278,7 @@ synthesize_foreach (gpointer key,
       lf = variant[NORMAL]->logfontw;
       lf.lfWeight = FW_BOLD;
       
-      pango_win32_insert_font (win32fontmap, &lf, TRUE);
+      pango_win32_insert_font (win32fontmap, &lf, NULL, TRUE);
     }
 
   if (variant[NORMAL] != NULL && variant[SLANTED] == NULL)
@@ -290,7 +286,7 @@ synthesize_foreach (gpointer key,
       lf = variant[NORMAL]->logfontw;
       lf.lfItalic = 255;
       
-      pango_win32_insert_font (win32fontmap, &lf, TRUE);
+      pango_win32_insert_font (win32fontmap, &lf, NULL, TRUE);
     }
 
   if (variant[NORMAL] != NULL &&
@@ -300,7 +296,7 @@ synthesize_foreach (gpointer key,
       lf.lfWeight = FW_BOLD;
       lf.lfItalic = 255;
 
-      pango_win32_insert_font (win32fontmap, &lf, TRUE);
+      pango_win32_insert_font (win32fontmap, &lf, NULL, TRUE);
     }
   else if (variant[BOLDER] != NULL &&
            variant[BOLDER+SLANTED] == NULL)
@@ -308,7 +304,7 @@ synthesize_foreach (gpointer key,
       lf = variant[BOLDER]->logfontw;
       lf.lfItalic = 255;
 
-      pango_win32_insert_font (win32fontmap, &lf, TRUE);
+      pango_win32_insert_font (win32fontmap, &lf, NULL, TRUE);
     }
   else if (variant[SLANTED] != NULL &&
            variant[BOLDER+SLANTED] == NULL)
@@ -316,7 +312,7 @@ synthesize_foreach (gpointer key,
       lf = variant[SLANTED]->logfontw;
       lf.lfWeight = FW_BOLD;
 
-      pango_win32_insert_font (win32fontmap, &lf, TRUE);
+      pango_win32_insert_font (win32fontmap, &lf, NULL, TRUE);
     }
 }
 
@@ -705,7 +701,7 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
 {
   LOGFONTW logfont;
   HDC hdc = _pango_win32_get_display_dc ();
-  struct EnumProcData enum_proc_data;
+  struct EnumProcData enum_proc_data = {hdc, win32fontmap};
   pango_win32_dwrite_font_map_init (win32fontmap);
 
   win32fontmap->families =
@@ -714,6 +710,11 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
   win32fontmap->fonts =
     g_hash_table_new_full ((GHashFunc) logfontw_nosize_hash,
                            (GEqualFunc) logfontw_nosize_equal, NULL, g_free);
+  win32fontmap->dwrite_fonts =
+    g_hash_table_new_full ((GHashFunc) logfontw_nosize_hash,
+                           (GEqualFunc) logfontw_nosize_equal,
+                           NULL,
+                           pango_win32_dwrite_font_release);
 
   win32fontmap->font_cache = pango_win32_font_cache_new ();
   win32fontmap->freed_fonts = g_queue_new ();
@@ -722,15 +723,16 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
                                                       g_free,
                                                       NULL);
 
+#ifdef HAVE_DIRECTWRITE
+  pango_win32_dwrite_font_map_populate (win32fontmap);
+#else
   memset (&logfont, 0, sizeof (logfont));
   logfont.lfCharSet = DEFAULT_CHARSET;
 
-  enum_proc_data.hdc = hdc;
-  enum_proc_data.font_map = win32fontmap;
-
   EnumFontFamiliesExW (hdc, &logfont,
                        (FONTENUMPROCW) pango_win32_enum_proc,
                        (LPARAM) &enum_proc_data, 0);
+#endif
 
   g_hash_table_foreach (win32fontmap->families, synthesize_foreach, win32fontmap);
 
@@ -866,6 +868,7 @@ pango_win32_font_map_finalize (GObject *object)
 
   pango_win32_font_cache_free (win32fontmap->font_cache);
 
+  g_hash_table_destroy (win32fontmap->dwrite_fonts);
   g_hash_table_destroy (win32fontmap->warned_fonts);
   g_hash_table_destroy (win32fontmap->fonts);
   g_hash_table_destroy (win32fontmap->families);
@@ -1653,9 +1656,10 @@ ff_name (int ff, char* num)
     }
 }
 
-static void
+void
 pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
                          LOGFONTW          *lfp,
+                         gpointer           dwrite_font,
                          gboolean           is_synthetic)
 {
   LOGFONTW *lfp2 = NULL;
@@ -1692,8 +1696,15 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
   PING (("not found"));
   lfp2 = g_new (LOGFONTW, 1);
   *lfp2 = *lfp;
+
+  if (dwrite_font == NULL)
+    dwrite_font = pango_win32_font_map_logfontw_get_dwrite_font (win32fontmap, lfp2);
+
   g_hash_table_insert (win32fontmap->fonts, lfp2, lfp2);
 
+  if (dwrite_font != NULL)
+    g_hash_table_insert (win32fontmap->dwrite_fonts, lfp2, dwrite_font);
+
   description = pango_win32_font_description_from_logfontw (lfp2);
 
   /* In some cases, extracting a name for a font can fail; such fonts
diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h
index db7d73a3c..ea574c0e5 100644
--- a/pango/pangowin32-private.h
+++ b/pango/pangowin32-private.h
@@ -109,6 +109,11 @@ struct _PangoWin32FontMap
 
   /* keep track of DirectWrite boiler plate items */
   PangoWin32DWriteItems *dwrite_items;
+
+  /* Map LOGFONTWs to IDWriteFonts corresponding to actual fonts
+   * installed, if applicable.
+   */
+  GHashTable *dwrite_fonts;
 };
 
 struct _PangoWin32FontMapClass
@@ -287,9 +292,22 @@ gpointer        _pango_win32_copy_cmap (gpointer cmap,
 
 extern gboolean _pango_win32_debug;
 
-void            pango_win32_dwrite_font_map_init    (PangoWin32FontMap *map);
 
-void            pango_win32_dwrite_font_map_destroy (PangoWin32FontMap *map);
+void            pango_win32_insert_font              (PangoWin32FontMap *win32fontmap,
+                                                      LOGFONTW          *lfp,
+                                                      gpointer           dwrite_font,
+                                                      gboolean           is_synthetic);
+
+void            pango_win32_dwrite_font_map_init     (PangoWin32FontMap *map);
+
+void            pango_win32_dwrite_font_map_populate (PangoWin32FontMap *map);
+
+void            pango_win32_dwrite_font_map_destroy  (PangoWin32FontMap *map);
+
+gpointer        pango_win32_font_map_logfontw_get_dwrite_font (PangoWin32FontMap *map,
+                                                               LOGFONTW *logfontw);
+
+void            pango_win32_dwrite_font_release      (gpointer dwrite_font);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]