From 902c839ab1725dac7e7a8a4ba2bf4b91c0cb1629 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Thu, 21 Jul 2022 14:53:42 +0800 Subject: PangoWin32: Implement is_hinted on Windows using DirectWrite ... by querying the font table 'gasp' and see whether the bits needed for hinting are there. Codewise, it is simpler with GDI+, but it would then require more overhead since GDI(+) operations are needed (this means "slower") and we need to put boilerplates for using GDI+ from our plain-C code. --- pango/pangocairo-win32font.c | 1 + pango/pangowin32-dwrite-fontmap.cpp | 83 +++++++++++++++++++++++++++++++++++++ pango/pangowin32-fontmap.c | 1 + pango/pangowin32-private.h | 6 +++ pango/pangowin32.c | 13 ++++++ 5 files changed, 104 insertions(+) diff --git a/pango/pangocairo-win32font.c b/pango/pangocairo-win32font.c index 9f4f5c14..5b860bab 100644 --- a/pango/pangocairo-win32font.c +++ b/pango/pangocairo-win32font.c @@ -268,6 +268,7 @@ _pango_cairo_win32_font_new (PangoCairoWin32FontMap *cwfontmap, win32font->size, &win32font->logfontw); + win32font->is_hinted = pango_win32_dwrite_font_check_is_hinted (win32font); cairo_matrix_init_identity (&font_matrix); cairo_matrix_scale (&font_matrix, size, size); diff --git a/pango/pangowin32-dwrite-fontmap.cpp b/pango/pangowin32-dwrite-fontmap.cpp index ae1d11af..6be9b87a 100644 --- a/pango/pangowin32-dwrite-fontmap.cpp +++ b/pango/pangowin32-dwrite-fontmap.cpp @@ -420,6 +420,89 @@ pango_win32_font_description_from_logfontw_dwrite (const LOGFONTW *logfontw) return desc; } +/* macros to help parse the 'gasp' font table, referring to FreeType2 */ +#define DWRITE_UCHAR_USHORT( p, i, s ) ( (unsigned short)( ((const unsigned char *)(p))[(i)] ) << (s) ) + +#define DWRITE_PEEK_USHORT( p ) (unsigned short)( DWRITE_UCHAR_USHORT( p, 0, 8 ) | DWRITE_UCHAR_USHORT( p, 1, 0 ) ) + +#define DWRITE_NEXT_USHORT( buffer ) ( (unsigned short)( buffer += 2, DWRITE_PEEK_USHORT( buffer - 2 ) ) ) + +/* values to indicate that grid fit (hinting) is supported by the font */ +#define GASP_GRIDFIT 0x0001 +#define GASP_SYMMETRIC_GRIDFIT 0x0004 + +gboolean +pango_win32_dwrite_font_check_is_hinted (PangoWin32Font *font) +{ + IDWriteFont *dwrite_font = NULL; + IDWriteFontFace *dwrite_font_face = NULL; + gboolean failed = FALSE; + gboolean result = FALSE; + gboolean dwrite_font_release = FALSE; + + gboolean succeeded = FALSE; + PangoWin32DWriteItems *dwrite_items = pango_win32_get_direct_write_items (); + dwrite_font = (IDWriteFont *) g_hash_table_lookup (PANGO_WIN32_FONT_MAP (font->fontmap)->dwrite_fonts, + &font->logfontw); + + /* create the IDWriteFont from the logfont underlying the PangoWin32Font if needed */ + if (dwrite_font == NULL) + { + if (FAILED (dwrite_items->gdi_interop->CreateFontFromLOGFONT (&font->logfontw, + &dwrite_font)) || + dwrite_font == NULL) + failed = TRUE; + else + dwrite_font_release = TRUE; + } + + if (!failed && SUCCEEDED (dwrite_font->CreateFontFace (&dwrite_font_face)) && dwrite_font_face != NULL) + { + UINT32 gasp_tag = DWRITE_MAKE_OPENTYPE_TAG ('g', 'a', 's', 'p'); + UINT32 table_size; + const unsigned short *table_data; + void *table_ctx; + gboolean exists; + + /* The 'gasp' table may not exist for the font, so no 'gasp' == no hinting */ + if (SUCCEEDED (dwrite_font_face->TryGetFontTable (gasp_tag, + (const void **)(&table_data), + &table_size, + &table_ctx, + &exists))) + { + if (exists) + { + guint16 version = DWRITE_NEXT_USHORT (table_data); + + if (version == 0 || version == 1) + { + guint16 num_ranges = DWRITE_NEXT_USHORT (table_data); + guint16 i; + + for (i = 0; !result && i < num_ranges && i < (table_size / sizeof (guint16)); i ++) + { + guint16 ppem = DWRITE_NEXT_USHORT (table_data); + guint16 behavior = DWRITE_NEXT_USHORT (table_data); + + if (behavior & (GASP_GRIDFIT | GASP_SYMMETRIC_GRIDFIT)) + result = TRUE; + } + } + } + + dwrite_font_face->ReleaseFontTable (table_ctx); + } + + dwrite_font_face->Release (); + } + + if (dwrite_font_release) + dwrite_font->Release (); + + return result; +} + void pango_win32_dwrite_font_release (gpointer dwrite_font) { diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index 78fd7b30..4cc95787 100644 --- a/pango/pangowin32-fontmap.c +++ b/pango/pangowin32-fontmap.c @@ -1147,6 +1147,7 @@ pango_win32_font_neww (PangoFontMap *fontmap, result->size = size; _pango_win32_make_matching_logfontw (fontmap, lfp, size, &result->logfontw); + result->is_hinted = pango_win32_dwrite_font_check_is_hinted (result); return result; } diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h index d0ef6dbc..c66795fb 100644 --- a/pango/pangowin32-private.h +++ b/pango/pangowin32-private.h @@ -142,6 +142,9 @@ struct _PangoWin32Font */ gboolean in_cache; GHashTable *glyph_info; + + /* whether the font supports hinting */ + gboolean is_hinted; }; struct _PangoWin32FontClass @@ -284,6 +287,9 @@ _PANGO_EXTERN gpointer _pango_win32_copy_cmap (gpointer cmap, guint16 cmap_format); +_PANGO_EXTERN +gboolean pango_win32_dwrite_font_check_is_hinted (PangoWin32Font *font); + extern gboolean _pango_win32_debug; void pango_win32_insert_font (PangoWin32FontMap *win32fontmap, diff --git a/pango/pangowin32.c b/pango/pangowin32.c index 55a079c9..5a26ee98 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -56,6 +56,7 @@ static gboolean pango_win32_font_real_select_font (PangoFont *font, HDC hdc); static void pango_win32_font_real_done_font (PangoFont *font); static double pango_win32_font_real_get_metrics_factor (PangoFont *font); +static gboolean pango_win32_font_is_hinted (PangoFont *font); static void pango_win32_get_item_properties (PangoItem *item, PangoUnderline *uline, @@ -202,6 +203,7 @@ _pango_win32_font_class_init (PangoWin32FontClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); PangoFontClass *font_class = PANGO_FONT_CLASS (class); + PangoFontClassPrivate *pclass; object_class->finalize = pango_win32_font_finalize; object_class->dispose = pango_win32_font_dispose; @@ -218,6 +220,9 @@ _pango_win32_font_class_init (PangoWin32FontClass *class) class->done_font = pango_win32_font_real_done_font; class->get_metrics_factor = pango_win32_font_real_get_metrics_factor; + pclass = g_type_class_get_private ((GTypeClass *) class, PANGO_TYPE_FONT); + pclass->is_hinted = pango_win32_font_is_hinted; + _pango_win32_get_display_dc (); } @@ -662,6 +667,14 @@ pango_win32_font_real_get_metrics_factor (PangoFont *font) return PANGO_SCALE; } +static gboolean +pango_win32_font_is_hinted (PangoFont *font) +{ + g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), FALSE); + + return PANGO_WIN32_FONT (font)->is_hinted; +} + /** * pango_win32_font_logfont: * @font: a `PangoFont` which must be from the Win32 backend -- cgit v1.2.1