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




commit 079fec8057848be7201cdd257ecf6132e0b99140
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 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 282 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 1c9c1c09..ea0ce603 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"
@@ -155,6 +159,7 @@ struct _PangoWin32Face
 
   gpointer family;
   LOGFONTW logfontw;
+  IDWriteFont *dwrite_font;
   PangoFontDescription *description;
   PangoCoverage *coverage;
   char *face_name;
@@ -277,4 +282,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 213a665e..ab040e73 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);
+}
+
+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 ();
 }
 
 /**
@@ -1283,3 +1433,70 @@ pango_win32_font_create_hb_font (PangoFont *font)
 
   return hb_font;
 }
+
+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_WIN32_IS_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;
+}


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