[pango/win32-font-language: 2/2] PangoWin32: Initialize DirectWrite as well




commit 497ee87d5105fb3b6a957abdaf4754ab1d6c6533
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Wed Nov 11 20:15:25 2020 +0800

    PangoWin32: Initialize DirectWrite as well
    
    We want to start using DirectWrite to help us implement some features
    that are not that easily done with GDI/Uniscribe, via a GDI interop
    layer as provided by DirectWrite, and by creating and keeping track of
    the IDWriteFont's that are created from each of the LOGFONTs that we
    acquire by quering the fonts that is installed on the system.

 pango/meson.build          |   1 +
 pango/pangowin32-fontmap.c |  57 ++++++++++++
 pango/pangowin32-private.h |   7 ++
 pango/pangowin32.c         | 217 +++++++++++++++++++++++++++++++++++++++++++++
 pango/pangowin32.h         |   3 +
 5 files changed, 285 insertions(+)
---
diff --git a/pango/meson.build b/pango/meson.build
index 91261274..21b620ec 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -413,6 +413,7 @@ if host_system == 'windows'
   pangowin32_deps = pango_deps + [
     libpango_dep,
     cc.find_library('gdi32'),
+    cc.find_library('dwrite'),
   ]
 
   pangowin32_rc = configure_file(
diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c
index 6bc10a7a..23902981 100644
--- a/pango/pangowin32-fontmap.c
+++ b/pango/pangowin32-fontmap.c
@@ -1588,12 +1588,19 @@ ff_name (int ff, char* num)
     }
 }
 
+/* remove later... */
+extern GHashTable *
+_pango_win32_acquire_script_locale_ht (void);
+
 static void
 pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
                          LOGFONTW          *lfp,
                          gboolean           is_synthetic)
 {
   LOGFONTW *lfp2 = NULL;
+  IDWriteGdiInterop *gdi_interop = _pango_win32_acquire_dwrite_gdi_interop ();
+  IDWriteLocalizedStrings *dwrite_result_str;
+  gboolean exists = FALSE;
   PangoFontDescription *description;
   PangoWin32Family *win32family;
   PangoWin32Face *win32face;
@@ -1645,6 +1652,12 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
   PING (("win32face created: %p for %S", win32face, lfp->lfFaceName));
 
   win32face->logfontw = *lfp;
+
+  if (IDWriteGdiInterop_CreateFontFromLOGFONT (gdi_interop,
+                                              &win32face->logfontw,
+                                              &win32face->dwrite_font) != S_OK)
+    g_warning ("Failed to create DirectWriteFont from LOGFONTW");
+
   win32face->description = description;
 
   win32face->coverage = NULL;
@@ -1667,6 +1680,48 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
 
   win32family->faces = g_slist_append (win32family->faces, win32face);
 
+  if (IDWriteFont_GetInformationalStrings (win32face->dwrite_font,
+                                           DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG,
+                                          &dwrite_result_str,
+                                          &exists) != S_OK)
+    {
+      gchar *name = g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
+      g_warning ("Failed to get supported languages of font %p (name: %s)", lfp, name);
+      g_free (name);
+    }
+
+  if (exists)
+    {
+      gchar *name = g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
+      guint num_langs = IDWriteLocalizedStrings_GetCount (dwrite_result_str);
+      guint i = 0;
+         GHashTable *ht_script_language = _pango_win32_acquire_script_locale_ht();
+
+      for (i = 0; i < num_langs; i ++)
+        {
+          guint strlength = 0;
+          wchar_t *str_utf16 = NULL;
+          gchar *str_utf8 = NULL;
+          GSList *langs = NULL;
+          IDWriteLocalizedStrings_GetStringLength (dwrite_result_str, i, &strlength);
+          str_utf16 = g_new0 (wchar_t, strlength + 1);
+          IDWriteLocalizedStrings_GetString (dwrite_result_str, i, str_utf16, strlength + 1);
+          str_utf8 = g_utf16_to_utf8 (str_utf16, -1, NULL, NULL, NULL);
+          langs = g_hash_table_lookup (ht_script_language, str_utf8);
+          if (langs != NULL)
+            {
+               GSList *p;
+
+               for (p = g_slist_reverse (langs); p != NULL; p = p->next)
+                 if (pango_language_from_string (p->data) == NULL)
+                   g_print ("NULL!\n");
+            }
+          g_free (str_utf8);
+          g_free (str_utf16);
+        }
+      g_free (name);
+    }
+
   PING (("name=%s, length(faces)=%d",
         win32family->family_name, g_slist_length (win32family->faces)));
 }
@@ -1763,6 +1818,8 @@ pango_win32_face_finalize (GObject *object)
 
   g_slist_free (win32face->cached_fonts);
 //  g_slist_free_full (win32face->cached_fonts, g_object_unref); // This doesn't work.
+  if (win32face->dwrite_font != NULL)
+    IDWriteFont_Release (win32face->dwrite_font);
 
   G_OBJECT_CLASS (pango_win32_family_parent_class)->finalize (object);
 }
diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h
index 9ea00dbc..da957091 100644
--- a/pango/pangowin32-private.h
+++ b/pango/pangowin32-private.h
@@ -52,6 +52,10 @@
 #define PING(printlist)
 #endif
 
+/* this is a C-compatible counterpart of the DirectWrite headers */
+#define COBJMACROS
+#include "dwrite_c.h"
+
 #include "pangowin32.h"
 #include "pango-font-private.h"
 #include "pango-fontset-private.h"
@@ -152,6 +156,7 @@ struct _PangoWin32Face
 
   gpointer family;
   LOGFONTW logfontw;
+  IDWriteFont *dwrite_font;
   PangoFontDescription *description;
   PangoCoverage *coverage;
   char *face_name;
@@ -274,4 +279,6 @@ HDC             _pango_win32_get_display_dc                 (void);
 
 extern gboolean _pango_win32_debug;
 
+IDWriteGdiInterop * _pango_win32_acquire_dwrite_gdi_interop (void);
+
 #endif /* __PANGOWIN32_PRIVATE_H__ */
diff --git a/pango/pangowin32.c b/pango/pangowin32.c
index 7904c96d..8263c27b 100644
--- a/pango/pangowin32.c
+++ b/pango/pangowin32.c
@@ -32,6 +32,8 @@
  */
 #include "config.h"
 
+#include <initguid.h>
+
 #include <string.h>
 #include <stdlib.h>
 #include <glib.h>
@@ -133,7 +135,30 @@ _pango_win32_font_init (PangoWin32Font *win32font)
   win32font->glyph_info = g_hash_table_new_full (NULL, NULL, NULL, g_free);
 }
 
+typedef struct dwrite_init_items
+{
+  IDWriteFactory *factory;
+  IDWriteGdiInterop *gdi_interop;
+  GHashTable *ht_script_language;
+} dwrite_items;
+
+static void
+ShutdownDWrite (dwrite_items *items)
+{
+  if (items->ht_script_language != NULL)
+    g_hash_table_destroy (items->ht_script_language);
+
+  if (items->gdi_interop != NULL)
+    IDWriteGdiInterop_Release (items->gdi_interop);
+
+  if (items->factory != NULL)
+    IDWriteFactory_Release (items->factory);
+
+  g_free (items);
+}
+
 static GPrivate display_dc_key = G_PRIVATE_INIT ((GDestroyNotify) DeleteDC);
+static GPrivate dwrite_items_key = G_PRIVATE_INIT ((GDestroyNotify) ShutdownDWrite);
 
 HDC
 _pango_win32_get_display_dc (void)
@@ -190,6 +215,130 @@ pango_win32_get_debug_flag (void)
   return _pango_win32_debug;
 }
 
+static BOOL CALLBACK
+get_available_scripts_for_locales (wchar_t *locale,
+                                   DWORD    flags,
+                                   LPARAM  *data)
+{
+  GHashTable *ht_script_language = (GHashTable *)data;
+  wchar_t *scripts_w;
+  gchar *scripts_raw;
+  gchar **scripts_array;
+  int sz, i;
+  GSList *locale_list;
+
+  sz = GetLocaleInfoEx (locale, LOCALE_SSCRIPTS, NULL, 0);
+
+  if (sz == 0)
+    return FALSE;
+
+  scripts_w = g_new (wchar_t, sz);
+
+  if (GetLocaleInfoEx (locale, LOCALE_SSCRIPTS, scripts_w, sz) == 0)
+    {
+      g_free (scripts_w);
+      return FALSE;
+    }
+
+  scripts_raw = g_utf16_to_utf8 (scripts_w, -1, NULL, NULL, NULL);
+
+  scripts_array = g_strsplit_set (scripts_raw, ";", -1);
+
+  for (i = 0; scripts_array[i] != NULL; i ++)
+    {
+      if (g_ascii_strcasecmp ("", scripts_array[i]) != 0)
+        {
+          g_hash_table_steal_extended (ht_script_language, scripts_array[i], NULL, (void **)&locale_list);
+          locale_list = g_slist_prepend (locale_list, g_utf16_to_utf8 (locale, -1, NULL, NULL, NULL));
+          g_hash_table_replace (ht_script_language, scripts_array[i], locale_list);
+        }
+    }
+
+  g_free (scripts_w);
+  return TRUE;
+}
+
+static void
+remove_language_list (GSList *list)
+{
+  g_slist_free_full (list, g_free);
+}
+
+static dwrite_items *
+_pango_win32_setup_dwrite (void)
+{
+  dwrite_items *items = NULL;
+  IDWriteGdiInterop *dwrite_gdi = NULL;
+
+  items = g_private_get (&dwrite_items_key);
+
+  if (items == NULL)
+    {
+      gboolean failed = FALSE;
+      items = g_new0 (dwrite_items, 1);
+
+      if (DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
+                              &IID_IDWriteFactory,
+                              (IUnknown **)&items->factory) != S_OK)
+        {
+          g_warning ("DWrite factory creation failed!");
+          failed = TRUE;
+        }
+      else
+        {
+          if (IDWriteFactory_GetGdiInterop (items->factory,
+                                           &items->gdi_interop) != S_OK)
+            {
+              g_warning ("DWrite GDI interop creation failed!");
+              failed = TRUE;
+            }
+          else
+            {
+              items->ht_script_language = g_hash_table_new_full (g_str_hash,
+                                                                 g_str_equal,
+                                                                 g_free,
+                                                                 remove_language_list);
+
+              if (!EnumSystemLocalesEx (get_available_scripts_for_locales,
+                                        LOCALE_ALL,
+                                        (LPARAM)items->ht_script_language,
+                                        NULL))
+                {
+                  gchar *syserr = g_win32_error_message (GetLastError ());
+
+                  g_warning ("Failed to enumerate system locales, error: %s!", syserr);
+                  g_free (syserr);
+                  failed = TRUE;
+                }
+              else
+                g_private_set (&dwrite_items_key, items);
+            }
+        }
+
+      if (failed)
+        {
+          ShutdownDWrite (items);
+          items = NULL;
+        }
+    }
+
+  return items;
+}
+
+IDWriteGdiInterop *
+_pango_win32_acquire_dwrite_gdi_interop (void)
+{
+  dwrite_items *items = _pango_win32_setup_dwrite ();
+  return items->gdi_interop;
+}
+
+GHashTable *
+_pango_win32_acquire_script_locale_ht (void)
+{
+  dwrite_items *items = _pango_win32_setup_dwrite ();
+  return items->ht_script_language;
+}
+
 static void
 _pango_win32_font_class_init (PangoWin32FontClass *class)
 {
@@ -212,6 +361,7 @@ _pango_win32_font_class_init (PangoWin32FontClass *class)
   class->get_metrics_factor = pango_win32_font_real_get_metrics_factor;
 
   _pango_win32_get_display_dc ();
+  _pango_win32_setup_dwrite ();
 }
 
 /**
@@ -1288,3 +1438,70 @@ GType pango_win32_font_get_type (void)
 {
   return _pango_win32_font_get_type ();
 }
+
+PangoLanguage **
+pango_win32_font_get_languages (PangoFont *font)
+{
+  PangoWin32Font *win32font = NULL;
+  IDWriteGdiInterop *gdi_interop = NULL;
+  IDWriteFont *dwritefont = NULL;
+  IDWriteLocalizedStrings *dwrite_result_str;
+  gboolean exists = FALSE;
+  LOGFONTW lf = win32font->logfontw;
+  PangoLanguage **langs = NULL;
+  
+  g_return_val_if_fail (font != NULL, NULL);
+  g_return_val_if_fail (PANGO_IS_WIN32_FONT (font), NULL);
+
+  win32font = PANGO_WIN32_FONT (font);
+  gdi_interop = _pango_win32_acquire_dwrite_gdi_interop ();
+
+  if (IDWriteGdiInterop_CreateFontFromLOGFONT (gdi_interop,
+                                              &lf,
+                                              &dwritefont) != S_OK)
+    g_warning ("Faild to create DirectWriteFont from LOGFONTW");
+
+  if (IDWriteFont_GetInformationalStrings (dwritefont,
+                                           DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG,
+                                          &dwrite_result_str,
+                                          &exists) != S_OK)
+    {
+      gchar *name = g_utf16_to_utf8 (lf.lfFaceName, -1, NULL, NULL, NULL);
+      g_warning ("Failed to get supported languages of font %p (name: %s)", &lf, name);
+      g_free (name);
+    }
+
+  if (exists)
+    {
+      gchar *name = g_utf16_to_utf8 (lf.lfFaceName, -1, NULL, NULL, NULL);
+      guint num_langs = IDWriteLocalizedStrings_GetCount (dwrite_result_str);
+      guint i = 0;
+         GHashTable *ht_script_language = _pango_win32_acquire_script_locale_ht();
+
+      for (i = 0; i < num_langs; i ++)
+        {
+          guint strlength = 0;
+          wchar_t *str_utf16 = NULL;
+          gchar *str_utf8 = NULL;
+          GSList *langs = NULL;
+          IDWriteLocalizedStrings_GetStringLength (dwrite_result_str, i, &strlength);
+          str_utf16 = g_new0 (wchar_t, strlength + 1);
+          IDWriteLocalizedStrings_GetString (dwrite_result_str, i, str_utf16, strlength + 1);
+          str_utf8 = g_utf16_to_utf8 (str_utf16, -1, NULL, NULL, NULL);
+          langs = g_hash_table_lookup (ht_script_language, str_utf8);
+          if (langs != NULL)
+            {
+               GSList *p;
+
+               for (p = g_slist_reverse (langs); p != NULL; p = p->next)
+                 if (pango_language_from_string (p->data) == NULL)
+                   g_print ("NULL!\n");
+            }
+          g_free (str_utf8);
+          g_free (str_utf16);
+        }
+      g_free (name);
+    }
+
+  return langs;
+}
diff --git a/pango/pangowin32.h b/pango/pangowin32.h
index fe68cc31..c48f0cdf 100644
--- a/pango/pangowin32.h
+++ b/pango/pangowin32.h
@@ -153,6 +153,9 @@ PangoFontDescription *pango_win32_font_description_from_logfontw (const LOGFONTW
 PANGO_AVAILABLE_IN_1_48
 GType                 pango_win32_font_get_type                  (void) G_GNUC_CONST;
 
+PANGO_AVAILABLE_IN_1_48
+PangoLanguage       **pango_win32_font_get_languages             (PangoFont *font);
+
 G_END_DECLS
 
 #endif /* __PANGOWIN32_H__ */


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