[gtk/wip/fanc999/fontchooser.win32.gtk3: 11/11] gtk/gtkfontfeatures.c: Add support for PangoWin32Font->FT_Face
- From: Chun-wei Fan <fanchunwei src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/fanc999/fontchooser.win32.gtk3: 11/11] gtk/gtkfontfeatures.c: Add support for PangoWin32Font->FT_Face
- Date: Thu, 3 Jan 2019 16:54:56 +0000 (UTC)
commit 3b10632fe0a305e43da25eccb73e6ce6d0a14a88
Author: Chun-wei Fan <fanchunwei src gnome org>
Date: Wed Dec 26 18:21:02 2018 +0800
gtk/gtkfontfeatures.c: Add support for PangoWin32Font->FT_Face
This is so that we can turn the LOGFONT that is retrieved from the
PangoFont so that we can load it with FreeType and feed it to HarfBuzz.
There is ongoing work in Pango to do shaping on all supported platforms
using HarfBuzz, but since this is GTK+-3.24.x, we will still need to
support the code path without it as well. PangoWin32 also needs to be
updated to apply the updates here to the PangoFont in question,
otherwise we will only be able to view the OpenType tags that are
tweakable.
gtk/gtkfontchooserwidget.c | 9 +-
gtk/gtkfontfeatures.c | 243 +++++++++++++++++++++++++++++++++++++++++--
gtk/gtkfontfeaturesprivate.h | 19 +++-
3 files changed, 260 insertions(+), 11 deletions(-)
---
diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c
index 20d6380af9..6040fd9ce8 100644
--- a/gtk/gtkfontchooserwidget.c
+++ b/gtk/gtkfontchooserwidget.c
@@ -713,7 +713,7 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser)
gtk_widget_init_template (GTK_WIDGET (fontchooser));
-#if defined(HAVE_HARFBUZZ) && defined (HAVE_PANGOFT)
+#ifdef HAVE_HARFBUZZ
priv->axes = g_hash_table_new_full (axis_hash, axis_equal, NULL, axis_free);
#endif
@@ -754,7 +754,7 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser)
/* Load data and set initial style-dependent parameters */
gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
-#if defined(HAVE_HARFBUZZ) && defined (HAVE_PANGOFT)
+#ifdef HAVE_HARFBUZZ
gtk_font_chooser_widget_populate_features (fontchooser);
#endif
gtk_font_chooser_widget_set_cell_size (fontchooser);
@@ -1063,6 +1063,9 @@ gtk_font_chooser_widget_finalize (GObject *object)
g_free (priv->font_features);
+ if (priv->ft_ext_items)
+ gtk_font_chooser_widget_release_extra_ft_items (fontchooser);
+
G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->finalize (object);
}
@@ -1379,7 +1382,7 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser
gtk_font_chooser_widget_update_marks (fontchooser);
-#if defined(HAVE_HARFBUZZ) && defined (HAVE_PANGOFT)
+#ifdef HAVE_HARFBUZZ
if (gtk_font_chooser_widget_update_font_features (fontchooser))
has_tweak = TRUE;
if (gtk_font_chooser_widget_update_font_variations (fontchooser))
diff --git a/gtk/gtkfontfeatures.c b/gtk/gtkfontfeatures.c
index 4133405527..c92cf9eee9 100644
--- a/gtk/gtkfontfeatures.c
+++ b/gtk/gtkfontfeatures.c
@@ -33,13 +33,49 @@
#include "gtkradiobutton.h"
#include "gtkgesturemultipress.h"
-#if defined (HAVE_HARFBUZZ) && defined (HAVE_PANGOFT)
-#include <pango/pangofc-font.h>
+#ifdef HAVE_HARFBUZZ
+
+#ifdef HAVE_PANGOFT
+# include <pango/pangofc-font.h>
+
+/* On Windows, we need to check whether the PangoFont is a FontConfig Font or a Win32/GDI font,
+ * and acquire/release the FT_Face accordingly.
+ */
+# ifdef GDK_WINDOWING_WIN32
+# define FT_FACE_FROM_PANGO_FONT(w,f) \
+ PANGO_IS_FC_FONT(f) ? \
+ pango_fc_font_lock_face (PANGO_FC_FONT (f)) : \
+ gtk_font_chooser_widget_win32_acquire_ftface (w, f)
+
+# define PANGO_FONT_RELEASE_FT_FACE(w,f) \
+ PANGO_IS_FC_FONT(f) ? \
+ pango_fc_font_unlock_face (PANGO_FC_FONT (f)) : \
+ gtk_font_chooser_widget_win32_release_ftface (w);
+
+# define RELEASE_EXTRA_FT_ITEMS(w) release_extra_ft_items(w)
+
+# else /* On non-Windows, acquire/release the FT_Face as we did before */
+# define FT_FACE_FROM_PANGO_FONT(w,f) pango_fc_font_lock_face (PANGO_FC_FONT (f))
+# define PANGO_FONT_RELEASE_FT_FACE(w,f) pango_fc_font_unlock_face (PANGO_FC_FONT (f))
+# define RELEASE_EXTRA_FT_ITEMS(w)
+# endif
+#elif defined (GDK_WINDOWING_WIN32)
+# include <pango/pangowin32.h>
+
+# define FT_FACE_FROM_PANGO_FONT(w,f) gtk_font_chooser_widget_win32_acquire_ftface (w, f)
+# define PANGO_FONT_RELEASE_FT_FACE(w,f) gtk_font_chooser_widget_win32_release_ftface (w)
+# define RELEASE_EXTRA_FT_ITEMS(w) release_extra_ft_items(w)
+
+/* Check for TTC fonts and get their font data */
+# define FONT_TABLE_TTCF (('t' << 0) + ('t' << 8) + ('c' << 16) + ('f' << 24))
+#endif
+
#include <hb.h>
#include <hb-ot.h>
#include <hb-ft.h>
#include <ft2build.h>
#include FT_FREETYPE_H
+#include FT_MODULE_H
#include FT_MULTIPLE_MASTERS_H
#include "language-names.h"
@@ -85,6 +121,199 @@ axis_remove (gpointer key,
gtk_widget_destroy (a->spin);
}
+/* Until Pango uses HarfBuzz for shaping on all platforms, we need to go through FreeType */
+#ifdef GDK_WINDOWING_WIN32
+
+typedef struct _gtk_win32_ft_items
+{
+ FT_Library ft_lib;
+ FT_Byte *font_data_stream;
+ FT_Face face;
+ HDC hdc;
+ LOGFONTW *logfont;
+ HFONT hfont;
+ PangoWin32FontCache *cache;
+} gtk_win32_ft_items;
+
+#define WIN32_FT_FACE_FAIL(msg) \
+{ \
+ g_warning(msg); \
+ goto ft_face_fail; \
+}
+
+FT_Face
+gtk_font_chooser_widget_win32_acquire_ftface (GtkFontChooserWidget *fontchooser,
+ PangoFont *font)
+{
+ GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
+ PangoWin32FontCache *cache = NULL;
+ PangoFontMap *font_map = NULL;
+ LOGFONTW *logfont = NULL;
+ HFONT hfont = NULL;
+ HDC hdc = NULL;
+ DWORD is_ttc_font;
+ FT_Face face;
+ FT_Byte *font_stream = NULL;
+ unsigned char buf[4];
+ gsize font_size;
+ gtk_win32_ft_items *item = NULL;
+
+ if (priv->font_map != NULL)
+ font_map = priv->font_map;
+ else
+ font_map = pango_cairo_font_map_get_default ();
+
+ cache = pango_win32_font_map_get_font_cache (font_map);
+
+ if (!cache)
+ WIN32_FT_FACE_FAIL ("Failed to acquire PangoWin32FontCache");
+
+ logfont = pango_win32_font_logfontw (font);
+
+ if (logfont == NULL)
+ WIN32_FT_FACE_FAIL ("Unable to acquire LOGFONT from PangoFont");
+
+ hfont = pango_win32_font_cache_loadw (cache, logfont);
+
+ if (hfont == NULL)
+ WIN32_FT_FACE_FAIL ("Unable to acquire HFONT from PangoWin32FontCache with LOGFONT (LOGFONT invalid?)");
+
+ hdc = GetDC (NULL);
+
+ if (hdc == NULL)
+ WIN32_FT_FACE_FAIL ("Failed to acquire DC");
+
+ if (priv->ft_ext_items == NULL)
+ priv->ft_ext_items = g_new0 (gtk_win32_ft_items, 1);
+
+ item = (gtk_win32_ft_items *) priv->ft_ext_items;
+
+ if (item->ft_lib == NULL)
+ {
+ if (FT_Init_FreeType (&item->ft_lib) != FT_Err_Ok)
+ WIN32_FT_FACE_FAIL ("Failed to initialize FreeType for PangoWin32Font->FT_Face transformation");
+ }
+
+ if (SelectObject (hdc, hfont) == HGDI_ERROR)
+ WIN32_FT_FACE_FAIL ("SelectObject() for the PangoFont failed");
+
+ /* is_ttc_font is GDI_ERROR if the HFONT does not refer to a font in a TTC when,
+ * specifying FONT_TABLE_TTCF for the Font Table type, otherwise it is 1,
+ * so try again without specifying FONT_TABLE_TTCF if is_ttc_font is not 1
+ */
+ is_ttc_font = GetFontData (hdc, FONT_TABLE_TTCF, 0, &buf, 1);
+
+ if (is_ttc_font == 1)
+ font_size = GetFontData (hdc, FONT_TABLE_TTCF, 0, NULL, 0);
+ else
+ font_size = GetFontData (hdc, 0, 0, NULL, 0);
+
+ if (font_size == GDI_ERROR)
+ WIN32_FT_FACE_FAIL ("Could not acquire font size from GetFontData()");
+
+ /* Now, get the font data stream that we need for creating the FT_Face */
+ font_stream = g_malloc (font_size);
+ if (GetFontData (hdc,
+ is_ttc_font == 1 ? FONT_TABLE_TTCF : 0,
+ 0,
+ font_stream,
+ font_size) == GDI_ERROR)
+ {
+ WIN32_FT_FACE_FAIL ("Unable to get data stream of font!");
+ }
+
+ /* Finally, create the FT_Face we need */
+ if (FT_New_Memory_Face (item->ft_lib,
+ font_stream,
+ font_size,
+ 0,
+ &face) == FT_Err_Ok)
+ {
+ /* We need to track these because we can only release/free those items *after* we
+ * are done with them in FreeType
+ */
+ item->cache = cache;
+ item->logfont = logfont;
+ item->hfont = hfont;
+ item->hdc = hdc;
+ item->font_data_stream = font_stream;
+ item->face = face;
+ return item->face;
+ }
+
+ else
+ WIN32_FT_FACE_FAIL ("Unable to create FT_Face from font data stream!");
+
+ft_face_fail:
+ if (font_stream != NULL)
+ g_free (font_stream);
+
+ if (hdc != NULL)
+ ReleaseDC (NULL, hdc);
+
+ if (cache != NULL && hfont != NULL)
+ pango_win32_font_cache_unload (cache, hfont);
+
+ if (logfont != NULL)
+ g_free (logfont);
+
+ return NULL;
+}
+
+#undef WIN32_FT_FACE_FAIL
+
+void
+gtk_font_chooser_widget_win32_release_ftface (GtkFontChooserWidget *widget)
+{
+ GtkFontChooserWidgetPrivate *priv = widget->priv;
+ gtk_win32_ft_items *item = (gtk_win32_ft_items *) priv->ft_ext_items;
+
+ FT_Done_Face (item->face);
+ g_free (item->font_data_stream);
+ ReleaseDC (NULL, item->hdc);
+ pango_win32_font_cache_unload (item->cache, item->hfont);
+ g_free (item->logfont);
+}
+
+static void
+release_extra_ft_items (GtkFontChooserWidget *fontchooser)
+{
+ GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
+
+ if (priv->ft_ext_items != NULL)
+ {
+ gtk_win32_ft_items *item = (gtk_win32_ft_items *) priv->ft_ext_items;
+
+ if (item->ft_lib != NULL)
+ FT_Done_Library (item->ft_lib);
+
+ g_free (priv->ft_ext_items);
+ priv->ft_ext_items = NULL;
+ }
+}
+
+#endif /* GDK_WINDOWING_WIN32 */
+
+static FT_Face
+get_ft_face_from_pango_font (GtkFontChooserWidget *fontchooser,
+ PangoFont *font)
+{
+ return FT_FACE_FROM_PANGO_FONT (fontchooser, font);
+}
+
+static void
+release_ft_face_from_pango_font (GtkFontChooserWidget *fontchooser,
+ PangoFont *font)
+{
+ PANGO_FONT_RELEASE_FT_FACE (fontchooser, font);
+}
+
+void
+gtk_font_chooser_widget_release_extra_ft_items (GtkFontChooserWidget *fontchooser)
+{
+ RELEASE_EXTRA_FT_ITEMS (fontchooser);
+}
+
/* OpenType variations */
#define FixedToFloat(f) (((float)(f))/65536.0)
@@ -241,6 +470,7 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose
FT_MM_Var *ft_mm_var;
FT_Error ret;
gboolean has_axis = FALSE;
+ PangoFontMap *font_map = NULL;
if (priv->updating_variations)
return FALSE;
@@ -254,7 +484,7 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose
pango_font = pango_context_load_font (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)),
priv->font_desc);
- ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font));
+ ft_face = get_ft_face_from_pango_font (fontchooser, pango_font);
ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
if (ret == 0)
@@ -286,7 +516,7 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose
free (ft_mm_var);
}
- pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
+ release_ft_face_from_pango_font (fontchooser, pango_font);
g_object_unref (pango_font);
@@ -775,6 +1005,7 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser)
int i, j;
GList *l;
gboolean has_feature = FALSE;
+ PangoFontMap *font_map = NULL;
for (l = priv->feature_items; l; l = l->next)
{
@@ -789,7 +1020,7 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser)
pango_font = pango_context_load_font (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)),
priv->font_desc);
- ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font));
+ ft_face = get_ft_face_from_pango_font (fontchooser, pango_font);
hb_font = hb_ft_font_create (ft_face, NULL);
@@ -850,7 +1081,7 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser)
hb_face_destroy (hb_face);
}
- pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
+ release_ft_face_from_pango_font (fontchooser, pango_font);
g_object_unref (pango_font);
diff --git a/gtk/gtkfontfeaturesprivate.h b/gtk/gtkfontfeaturesprivate.h
index d24c0ba31b..db00b062b8 100644
--- a/gtk/gtkfontfeaturesprivate.h
+++ b/gtk/gtkfontfeaturesprivate.h
@@ -70,6 +70,8 @@ struct _GtkFontChooserWidgetPrivate
GList *feature_items;
GAction *tweak_action;
+
+ gpointer ft_ext_items;
};
typedef struct {
@@ -87,6 +89,19 @@ void gtk_font_chooser_widget_take_font_desc (GtkFontChooserWid
gboolean gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser);
gboolean gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchooser);
void gtk_font_chooser_widget_update_preview_attributes (GtkFontChooserWidget *fontchooser);
+void gtk_font_chooser_widget_release_extra_ft_items (GtkFontChooserWidget *fontchooser);
+
+#if defined (GDK_WINDOWING_WIN32) && (HAVE_HARFBUZZ)
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+_GDK_EXTERN
+FT_Face gtk_font_chooser_widget_win32_acquire_ftface (GtkFontChooserWidget *fontchooser,
+ PangoFont *font);
+
+_GDK_EXTERN
+void gtk_font_chooser_widget_win32_release_ftface (GtkFontChooserWidget *fontchooser);
+#endif
-gboolean output_cb (GtkSpinButton *spin,
- gpointer data);
+gboolean output_cb (GtkSpinButton *spin,
+ gpointer data);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]