diff options
-rw-r--r-- | meson.build | 27 | ||||
-rw-r--r-- | pango/meson.build | 2 | ||||
-rw-r--r-- | pango/pango-font-private.h | 4 | ||||
-rw-r--r-- | pango/pangocairo-win32font.c | 27 | ||||
-rw-r--r-- | pango/pangowin32-dwrite-fontmap.cpp | 590 | ||||
-rw-r--r-- | pango/pangowin32-fontmap.c | 167 | ||||
-rw-r--r-- | pango/pangowin32-private.h | 50 | ||||
-rw-r--r-- | pango/pangowin32.c | 67 |
8 files changed, 828 insertions, 106 deletions
diff --git a/meson.build b/meson.build index 8b14e38f..f63ce6cd 100644 --- a/meson.build +++ b/meson.build @@ -46,6 +46,7 @@ osx_current = pango_binary_age - pango_interface_age + 1 pango_osxversion = [osx_current, '@0@.@1@.0'.format(osx_current, pango_interface_age)] cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') host_system = host_machine.system() # Compiler and linker flags @@ -277,6 +278,24 @@ harfbuzz_dep = dependency('harfbuzz', fallback: ['harfbuzz', 'libharfbuzz_dep'], default_options: ['coretext=enabled']) +if host_system == 'windows' + if cpp.has_header_symbol( + 'hb-directwrite.h', + 'hb_directwrite_face_create', + dependencies: harfbuzz_dep, + prefix: '#include <dwrite.h>', + ) + pango_conf.set('HAVE_HARFBUZZ_DIRECT_WRITE', 1) + endif + if cc.has_header_symbol( + 'hb-gdi.h', + 'hb_gdi_face_create', + dependencies: harfbuzz_dep, + ) + pango_conf.set('HAVE_HARFBUZZ_GDI', 1) + endif +endif + pango_deps += harfbuzz_dep # If option is 'auto' or 'enabled' it is not required to find fontconfig on the @@ -390,9 +409,13 @@ endif cairo_found_type = '' cairo_dep = dependency('cairo', version: cairo_req_version, required: cairo_option) +cairo_dwrite_dep = disabler() # Only for Windows if cairo_dep.found() cairo_found_type = cairo_dep.type_name() + if host_system == 'windows' + cairo_dwrite_dep = dependency('cairo-win32-dwrite-font', version: cairo_req_version, required: false) + endif else if cc.get_id() == 'msvc' and cc.has_header('cairo.h') cairo_dep = cc.find_library('cairo', required: cairo_option) @@ -566,6 +589,10 @@ if cairo_dep.found() endif endif +if cairo_dwrite_dep.found() + pango_conf.set('HAVE_CAIRO_WIN32_DIRECTWRITE', 1) +endif + # libsysprof-capture support libsysprof_capture_dep = dependency('sysprof-capture-4', required: get_option('sysprof'), diff --git a/pango/meson.build b/pango/meson.build index 1a4b4141..7d18cb00 100644 --- a/pango/meson.build +++ b/pango/meson.build @@ -424,11 +424,13 @@ if host_system == 'windows' 'pangowin32.c', 'pangowin32-fontcache.c', 'pangowin32-fontmap.c', + 'pangowin32-dwrite-fontmap.cpp', ] pangowin32_deps = pango_deps + [ libpango_dep, cc.find_library('gdi32'), + cc.find_library('dwrite'), ] pangowin32_rc = configure_file( diff --git a/pango/pango-font-private.h b/pango/pango-font-private.h index e95abc7a..a77df662 100644 --- a/pango/pango-font-private.h +++ b/pango/pango-font-private.h @@ -61,7 +61,7 @@ void pango_font_get_matrix (PangoFont *font, static inline int pango_font_get_absolute_size (PangoFont *font) { GTypeClass *klass = (GTypeClass *) PANGO_FONT_GET_CLASS (font); - PangoFontClassPrivate *priv = g_type_class_get_private (klass, PANGO_TYPE_FONT); + PangoFontClassPrivate *priv = (PangoFontClassPrivate *) g_type_class_get_private (klass, PANGO_TYPE_FONT); return priv->get_absolute_size (font); } @@ -69,7 +69,7 @@ static inline PangoVariant pango_font_get_variant (PangoFont *font) { GTypeClass *klass = (GTypeClass *) PANGO_FONT_GET_CLASS (font); - PangoFontClassPrivate *priv = g_type_class_get_private (klass, PANGO_TYPE_FONT); + PangoFontClassPrivate *priv = (PangoFontClassPrivate *) g_type_class_get_private (klass, PANGO_TYPE_FONT); if (priv->get_variant) return priv->get_variant (font); else diff --git a/pango/pangocairo-win32font.c b/pango/pangocairo-win32font.c index 9f4f5c14..0141c414 100644 --- a/pango/pangocairo-win32font.c +++ b/pango/pangocairo-win32font.c @@ -75,6 +75,32 @@ pango_cairo_win32_font_create_font_face (PangoCairoFont *font) { PangoCairoWin32Font *cwfont = PANGO_CAIRO_WIN32_FONT (font); PangoWin32Font *win32font = &cwfont->font; + void *dwrite_font_face = NULL; + gpointer dwrite_font = NULL; + +#ifdef HAVE_CAIRO_WIN32_DIRECTWRITE + dwrite_font_face = pango_win32_font_get_dwrite_font_face (win32font); + if (dwrite_font_face != NULL) + { + cairo_font_face_t *cairo_face = cairo_dwrite_font_face_create_for_dwrite_fontface (dwrite_font_face); + + if (cairo_face != NULL) + { + static const cairo_user_data_key_t key; + + cairo_font_face_set_user_data (cairo_face, &key, + dwrite_font_face, + (cairo_destroy_func_t) pango_win32_dwrite_font_face_release); + + return cairo_face; + } + else + { + g_warning ("cairo_font_face creation failed with DirectWrite, fallback to GDI"); + pango_win32_dwrite_font_face_release (dwrite_font_face); + } + } +#endif return cairo_win32_font_face_create_for_logfontw (&win32font->logfontw); } @@ -268,6 +294,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 new file mode 100644 index 00000000..6e1d9f0a --- /dev/null +++ b/pango/pangowin32-dwrite-fontmap.cpp @@ -0,0 +1,590 @@ +/* Pango + * pangowin32-dwrite-fontmap.cpp: Win32 font handling with DirectWrite + * + * Copyright (C) 2022 Luca Bacci + * Copyright (C) 2022 Chun-wei Fan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include <initguid.h> +#include <dwrite_1.h> + +#ifdef HAVE_HARFBUZZ_DIRECT_WRITE +#include <hb-directwrite.h> +#endif + +#ifdef STRICT +#undef STRICT +#endif +#include "pangowin32-private.h" + +#ifdef _MSC_VER +# define UUID_OF_IDWriteFactory __uuidof (IDWriteFactory) +# define UUID_OF_IDWriteFont1 __uuidof (IDWriteFont1) +#else +# define UUID_OF_IDWriteFactory IID_IDWriteFactory +# define UUID_OF_IDWriteFont1 IID_IDWriteFont1 +#endif + +struct _PangoWin32DWriteItems +{ + IDWriteFactory *dwrite_factory; + IDWriteGdiInterop *gdi_interop; +}; + +PangoWin32DWriteItems * +pango_win32_init_direct_write (void) +{ + PangoWin32DWriteItems *dwrite_items = g_new0 (PangoWin32DWriteItems, 1); + HRESULT hr; + gboolean failed = FALSE; + + hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, + UUID_OF_IDWriteFactory, + reinterpret_cast<IUnknown**> (&dwrite_items->dwrite_factory)); + + if (SUCCEEDED (hr) && dwrite_items->dwrite_factory != NULL) + { + hr = dwrite_items->dwrite_factory->GetGdiInterop (&dwrite_items->gdi_interop); + if (FAILED (hr) || dwrite_items->gdi_interop == NULL) + { + g_error ("DWriteCreateFactory::GetGdiInterop failed with error code %x", (unsigned)hr); + dwrite_items->dwrite_factory->Release (); + failed = TRUE; + } + } + else + { + g_error ("DWriteCreateFactory failed with error code %x", (unsigned)hr); + failed = TRUE; + } + + + if (failed) + g_free (dwrite_items); + + return failed ? NULL : dwrite_items; +} + +void +pango_win32_dwrite_items_destroy (PangoWin32DWriteItems *dwrite_items) +{ + dwrite_items->gdi_interop->Release (); + dwrite_items->dwrite_factory->Release (); + + g_free (dwrite_items); +} + +static IDWriteFontFace * +_pango_win32_get_dwrite_font_face_from_dwrite_font (IDWriteFont *font) +{ + IDWriteFontFace *face = NULL; + HRESULT hr; + + g_return_val_if_fail (font != NULL, NULL); + + hr = font->CreateFontFace (&face); + if (SUCCEEDED (hr) && face != NULL) + return face; + + g_warning ("IDWriteFont::CreateFontFace failed with error code %x\n", (unsigned)hr); + return NULL; +} + +void * +pango_win32_font_get_dwrite_font_face (PangoWin32Font *font) +{ + PangoWin32Font *win32font = PANGO_WIN32_FONT (font); + PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (win32font->fontmap); + IDWriteFont *dwrite_font = NULL; + IDWriteFontFace *face = NULL; + + dwrite_font = (IDWriteFont *) g_hash_table_lookup (win32fontmap->dwrite_fonts, &win32font->logfontw); + + if (dwrite_font != NULL) + return (void *)_pango_win32_get_dwrite_font_face_from_dwrite_font (dwrite_font); + + return NULL; +} + +void +pango_win32_dwrite_font_map_populate (PangoWin32FontMap *map) +{ + IDWriteFontCollection *collection = NULL; + UINT32 count; + HRESULT hr; + gboolean failed = FALSE; + PangoWin32DWriteItems *dwrite_items = pango_win32_get_direct_write_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; + } + + face = _pango_win32_get_dwrite_font_face_from_dwrite_font (font); + if (face == NULL) + { + 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_logfontw_get_dwrite_font (LOGFONTW *logfontw) +{ + PangoWin32DWriteItems *dwrite_items = pango_win32_get_direct_write_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; +} + +gboolean +pango_win32_dwrite_font_is_monospace (gpointer dwrite_font, + gboolean *is_monospace) +{ + IDWriteFont *font = static_cast<IDWriteFont *>(dwrite_font); + IDWriteFont1 *font1 = NULL; + gboolean result = FALSE; + + if (SUCCEEDED (font->QueryInterface(UUID_OF_IDWriteFont1, + reinterpret_cast<void**>(&font1)))) + { + *is_monospace = font1->IsMonospacedFont (); + font1->Release (); + result = TRUE; + } + else + *is_monospace = FALSE; + + return result; +} + +static PangoStretch +util_to_pango_stretch (DWRITE_FONT_STRETCH stretch) +{ + PangoStretch pango_stretch = PANGO_STRETCH_NORMAL; + + switch (stretch) + { + case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: + pango_stretch = PANGO_STRETCH_ULTRA_CONDENSED; + break; + case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: + pango_stretch = PANGO_STRETCH_EXTRA_CONDENSED; + break; + case DWRITE_FONT_STRETCH_CONDENSED: + pango_stretch = PANGO_STRETCH_CONDENSED; + break; + case DWRITE_FONT_STRETCH_SEMI_CONDENSED: + pango_stretch = PANGO_STRETCH_SEMI_CONDENSED; + break; + case DWRITE_FONT_STRETCH_NORMAL: + /* also DWRITE_FONT_STRETCH_MEDIUM */ + pango_stretch = PANGO_STRETCH_NORMAL; + break; + case DWRITE_FONT_STRETCH_SEMI_EXPANDED: + pango_stretch = PANGO_STRETCH_SEMI_EXPANDED; + break; + case DWRITE_FONT_STRETCH_EXPANDED: + pango_stretch = PANGO_STRETCH_EXPANDED; + break; + case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: + pango_stretch = PANGO_STRETCH_EXTRA_EXPANDED; + break; + case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: + pango_stretch = PANGO_STRETCH_ULTRA_EXPANDED; + break; + case DWRITE_FONT_STRETCH_UNDEFINED: + default: + pango_stretch = PANGO_STRETCH_NORMAL; + } + + return pango_stretch; +} + +static PangoStyle +util_to_pango_style (DWRITE_FONT_STYLE style) +{ + switch (style) + { + case DWRITE_FONT_STYLE_NORMAL: + return PANGO_STYLE_NORMAL; + case DWRITE_FONT_STYLE_OBLIQUE: + return PANGO_STYLE_OBLIQUE; + case DWRITE_FONT_STYLE_ITALIC: + return PANGO_STYLE_ITALIC; + default: + g_assert_not_reached (); + return PANGO_STYLE_NORMAL; + } +} + +static int +util_map_weight (int weight) +{ + if G_UNLIKELY (weight < 100) + weight = 100; + + if G_UNLIKELY (weight > 1000) + weight = 1000; + + return weight; +} + +static PangoWeight +util_to_pango_weight (DWRITE_FONT_WEIGHT weight) +{ + /* DirectWrite weight values range from 1 to 999, Pango weight values + * range from 100 to 1000. */ + + return (PangoWeight) util_map_weight (weight); +} + +static PangoVariant +util_to_pango_variant (IDWriteFont *font) +{ + PangoVariant variant = PANGO_VARIANT_NORMAL; + + return variant; +} + +static PangoFontDescription* +util_get_pango_font_description (IDWriteFont *font, + const char *family_name) +{ + DWRITE_FONT_STRETCH stretch = font->GetStretch (); + DWRITE_FONT_STYLE style = font->GetStyle (); + DWRITE_FONT_WEIGHT weight = font->GetWeight (); + PangoFontDescription *description; + + description = pango_font_description_new (); + pango_font_description_set_family (description, family_name); + + pango_font_description_set_stretch (description, util_to_pango_stretch (stretch)); + pango_font_description_set_variant (description, util_to_pango_variant (font)); + pango_font_description_set_style (description, util_to_pango_style (style)); + pango_font_description_set_weight (description, util_to_pango_weight (weight)); + + return description; +} + +static char* +util_free_to_string (IDWriteLocalizedStrings *strings) +{ + char *string = NULL; + HRESULT hr; + + if (strings->GetCount() > 0) + { + UINT32 index = 0; + BOOL exists = FALSE; + UINT32 length = 0; + + hr = strings->FindLocaleName (L"en-us", &index, &exists); + if (FAILED (hr) || !exists || index == UINT32_MAX) + index = 0; + + hr = strings->GetStringLength (index, &length); + if (SUCCEEDED (hr) && length > 0) + { + gunichar2 *string_utf16 = g_new (gunichar2, length + 1); + + hr = strings->GetString (index, (wchar_t*) string_utf16, length + 1); + if (SUCCEEDED (hr)) + string = g_utf16_to_utf8 (string_utf16, -1, NULL, NULL, NULL); + + g_free (string_utf16); + } + } + + strings->Release (); + + return string; +} + +static char* +util_dwrite_get_font_family_name (IDWriteFontFamily *family) +{ + IDWriteLocalizedStrings *strings = NULL; + HRESULT hr; + + hr = family->GetFamilyNames (&strings); + if (FAILED (hr) || strings == NULL) + { + g_warning ("IDWriteFontFamily::GetFamilyNames failed with error code %x", (unsigned) hr); + + return NULL; + } + + return util_free_to_string (strings); +} + +static char* +util_dwrite_get_font_variant_name (IDWriteFont *font) +{ + IDWriteLocalizedStrings *strings = NULL; + HRESULT hr; + + hr = font->GetFaceNames (&strings); + if (FAILED (hr) || strings == NULL) + { + g_warning ("IDWriteFont::GetFaceNames failed with error code %x", (unsigned) hr); + return NULL; + } + + return util_free_to_string (strings); +} + +PangoFontDescription * +pango_win32_font_description_from_logfontw_dwrite (const LOGFONTW *logfontw) +{ + PangoFontDescription *desc = NULL; + IDWriteFont *font = NULL; + HRESULT hr; + gchar *family; + PangoStyle style; + PangoVariant variant; + PangoWeight weight; + PangoStretch stretch; + PangoWin32DWriteItems *dwrite_items; + + dwrite_items = pango_win32_init_direct_write (); + if (dwrite_items == NULL) + return NULL; + + hr = dwrite_items->gdi_interop->CreateFontFromLOGFONT (logfontw, &font); + + if (SUCCEEDED (hr) && font != NULL) + { + IDWriteFontFamily *family = NULL; + + hr = font->GetFontFamily (&family); + + if (SUCCEEDED (hr) && family != NULL) + { + char *family_name = util_dwrite_get_font_family_name (family); + + if (family_name != NULL) + desc = util_get_pango_font_description (font, family_name); + + family->Release (); + } + + font->Release (); + } + + return desc; +} + +static IDWriteFont * +get_dwrite_font_from_pango_win32_font (PangoWin32Font *font, + gboolean *is_cleanup_dwrite_font) +{ + PangoWin32DWriteItems *dwrite_items = pango_win32_get_direct_write_items (); + IDWriteFont *dwrite_font = NULL; + + 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 (SUCCEEDED (dwrite_items->gdi_interop->CreateFontFromLOGFONT (&font->logfontw, + &dwrite_font)) && + dwrite_font != NULL) + *is_cleanup_dwrite_font = TRUE; + else + dwrite_font = NULL; + } + + return dwrite_font; +} + +/* 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; + + dwrite_font_face = (IDWriteFontFace *)pango_win32_font_get_dwrite_font_face (font); + + if (dwrite_font_face == NULL) + { + dwrite_font = get_dwrite_font_from_pango_win32_font (font, &dwrite_font_release); + + if (dwrite_font != NULL) + dwrite_font_face = _pango_win32_get_dwrite_font_face_from_dwrite_font (dwrite_font); + else + { + g_warning ("Failed to retrieve IDWriteFont from PangoWin32Font"); + + return FALSE; + } + } + + if (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; +} + +#ifdef HAVE_HARFBUZZ_DIRECT_WRITE +hb_face_t * +pango_win32_dwrite_font_face_create_hb_face (gpointer face) +{ + return hb_directwrite_face_create ((IDWriteFontFace *)face); +} +#endif + +void +pango_win32_dwrite_font_release (gpointer dwrite_font) +{ + IDWriteFont *font = static_cast<IDWriteFont *>(dwrite_font); + + if (font != NULL) + font->Release (); +} + +void +pango_win32_dwrite_font_face_release (gpointer dwrite_font_face) +{ + IDWriteFontFace *face = static_cast<IDWriteFontFace *>(dwrite_font_face); + + if (face != NULL) + face->Release (); +} diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index 9b980122..4cc95787 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}; win32fontmap->families = g_hash_table_new_full ((GHashFunc) case_insensitive_str_hash, @@ -713,14 +709,18 @@ _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 (); - win32fontmap->warned_fonts = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - NULL); + pango_win32_dwrite_font_map_populate (win32fontmap); + +#if 0 /* XXX: Implement fallback mode to GDI? */ memset (&logfont, 0, sizeof (logfont)); logfont.lfCharSet = DEFAULT_CHARSET; @@ -730,6 +730,7 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap) EnumFontFamiliesExW (hdc, &logfont, (FONTENUMPROCW) pango_win32_enum_proc, (LPARAM) &enum_proc_data, 0); +#endif g_hash_table_foreach (win32fontmap->families, synthesize_foreach, win32fontmap); @@ -809,6 +810,7 @@ _pango_win32_font_map_class_init (PangoWin32FontMapClass *class) (GEqualFunc)alias_equal, (GDestroyNotify)alias_free, NULL); + #ifdef HAVE_CAIRO_WIN32 read_windows_fallbacks (class->aliases); read_builtin_aliases (class->aliases); @@ -864,7 +866,7 @@ pango_win32_font_map_finalize (GObject *object) pango_win32_font_cache_free (win32fontmap->font_cache); - g_hash_table_destroy (win32fontmap->warned_fonts); + g_hash_table_destroy (win32fontmap->dwrite_fonts); g_hash_table_destroy (win32fontmap->fonts); g_hash_table_destroy (win32fontmap->families); @@ -1145,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; } @@ -1193,6 +1196,8 @@ pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, return (PangoFont *)win32font; } +#if 0 +/* XXX: Add fallback for using GDI? */ static gboolean _pango_win32_get_name_header (HDC hdc, struct name_header *header) @@ -1353,6 +1358,7 @@ get_family_nameA (const LOGFONTA *lfp) fail0: return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); } +#endif /** * pango_win32_font_description_from_logfont: @@ -1376,6 +1382,34 @@ get_family_nameA (const LOGFONTA *lfp) PangoFontDescription * pango_win32_font_description_from_logfont (const LOGFONT *lfp) { + LOGFONTW lfw; + PangoFontDescription *desc = NULL; + gchar *facename_utf8 = g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); + wchar_t *facename_utf16 = g_utf8_to_utf16 (facename_utf8, -1, NULL, NULL, NULL); + + lfw.lfHeight = lfp->lfHeight; + lfw.lfWidth = lfp->lfWidth; + lfw.lfEscapement = lfp->lfEscapement; + lfw.lfOrientation = lfp->lfOrientation; + lfw.lfWeight = lfp->lfWeight; + lfw.lfItalic = lfp->lfItalic; + lfw.lfUnderline = lfp->lfUnderline; + lfw.lfStrikeOut = lfp->lfStrikeOut; + lfw.lfCharSet = lfp->lfCharSet; + lfw.lfOutPrecision = lfp->lfOutPrecision; + lfw.lfClipPrecision = lfp->lfClipPrecision; + lfw.lfQuality = lfp->lfQuality; + lfw.lfPitchAndFamily = lfp->lfPitchAndFamily; + wcscpy (lfw.lfFaceName, facename_utf16); + + desc = pango_win32_font_description_from_logfontw_dwrite (&lfw); + g_free (facename_utf16); + g_free (facename_utf8); + + return desc; + +#if 0 +/* XXX: Add fallback for using GDI? */ PangoFontDescription *description; gchar *family; PangoStyle style; @@ -1410,8 +1444,12 @@ pango_win32_font_description_from_logfont (const LOGFONT *lfp) pango_font_description_set_variant (description, variant); return description; +#endif } +#if 0 + +/* XXX: Add fallback for using GDI? */ static gchar * get_family_nameW (const LOGFONTW *lfp) { @@ -1538,6 +1576,7 @@ get_family_nameW (const LOGFONTW *lfp) fail0: return g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); } +#endif /** * pango_win32_font_description_from_logfontw: @@ -1561,6 +1600,9 @@ get_family_nameW (const LOGFONTW *lfp) PangoFontDescription * pango_win32_font_description_from_logfontw (const LOGFONTW *lfp) { + return pango_win32_font_description_from_logfontw_dwrite (lfp); + +#if 0 /* XXX: Add GDI fallback? */ PangoFontDescription *description; gchar *family; PangoStyle style; @@ -1597,6 +1639,7 @@ pango_win32_font_description_from_logfontw (const LOGFONTW *lfp) pango_font_description_set_variant (description, variant); return description; +#endif } static char * @@ -1650,9 +1693,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; @@ -1689,7 +1733,11 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, PING (("not found")); lfp2 = g_new (LOGFONTW, 1); *lfp2 = *lfp; + if (dwrite_font == NULL) + dwrite_font = pango_win32_logfontw_get_dwrite_font (lfp2); + g_hash_table_insert (win32fontmap->fonts, lfp2, lfp2); + g_hash_table_insert (win32fontmap->dwrite_fonts, lfp2, dwrite_font); description = pango_win32_font_description_from_logfontw (lfp2); @@ -1724,8 +1772,12 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, win32face->family = win32family = pango_win32_get_font_family (win32fontmap, pango_font_description_get_family (win32face->description)); - if ((lfp->lfPitchAndFamily & 0xF0) == FF_MODERN) - win32family->is_monospace = TRUE; + + if (!pango_win32_dwrite_font_is_monospace (dwrite_font, &win32family->is_monospace)) + { + if ((lfp->lfPitchAndFamily & 0xF0) == FF_MODERN) + win32family->is_monospace = TRUE; + } win32family->faces = g_slist_append (win32family->faces, win32face); @@ -1917,14 +1969,9 @@ pango_win32_font_map_load_fontset (PangoFontMap *fontmap, char **families; int i; PangoFontsetSimple *fonts; - PangoWin32FontMap *win32fontmap = NULL; - GHashTable *warned_fonts = NULL; g_return_val_if_fail (fontmap != NULL, NULL); - win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); - warned_fonts = win32fontmap->warned_fonts; - family = pango_font_description_get_family (desc); families = g_strsplit (family ? family : "", ",", -1); @@ -1939,79 +1986,7 @@ pango_win32_font_map_load_fontset (PangoFontMap *fontmap, g_strfreev (families); - /* The font description was completely unloadable, try with - * family == "Sans" - */ - if (pango_fontset_simple_size (fonts) == 0) - { - char *ctmp1, *ctmp2; - - pango_font_description_set_family_static (tmp_desc, - pango_font_description_get_family (desc)); - - ctmp1 = pango_font_description_to_string (desc); - pango_font_description_set_family_static (tmp_desc, "Sans"); - - if (!g_hash_table_lookup (warned_fonts, ctmp1)) - { - - g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1)); - - ctmp2 = pango_font_description_to_string (tmp_desc); - g_warning ("couldn't load font \"%s\", falling back to \"%s\", " - "expect ugly output.", ctmp1, ctmp2); - g_free (ctmp2); - } - - g_free (ctmp1); - - pango_win32_font_map_fontset_add_fonts (fontmap, - context, - fonts, - tmp_desc, - "Sans"); - } - - /* We couldn't try with Sans and the specified style. Try Sans Normal */ - if (pango_fontset_simple_size (fonts) == 0) - { - char *ctmp1, *ctmp2; - - pango_font_description_set_family_static (tmp_desc, "Sans"); - ctmp1 = pango_font_description_to_string (tmp_desc); - pango_font_description_set_style (tmp_desc, PANGO_STYLE_NORMAL); - pango_font_description_set_weight (tmp_desc, PANGO_WEIGHT_NORMAL); - pango_font_description_set_variant (tmp_desc, PANGO_VARIANT_NORMAL); - pango_font_description_set_stretch (tmp_desc, PANGO_STRETCH_NORMAL); - - - if (!g_hash_table_lookup (warned_fonts, ctmp1)) - { - g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1)); - - ctmp2 = pango_font_description_to_string (tmp_desc); - - g_warning ("couldn't load font \"%s\", falling back to \"%s\", " - "expect ugly output.", ctmp1, ctmp2); - g_free (ctmp2); - } - - g_free (ctmp1); - - pango_win32_font_map_fontset_add_fonts (fontmap, - context, - fonts, - tmp_desc, - "Sans"); - } - pango_font_description_free (tmp_desc); - /* Everything failed, we are screwed, there is no way to continue, - * but lets just not crash here. - */ - if (pango_fontset_simple_size (fonts) == 0) - g_warning ("All font fallbacks failed!!!!"); - return PANGO_FONTSET (fonts); } diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h index 9102662a..f69d2b6b 100644 --- a/pango/pangowin32-private.h +++ b/pango/pangowin32-private.h @@ -57,6 +57,8 @@ #include "pango-fontset.h" #include "pango-fontmap-private.h" +G_BEGIN_DECLS + #define PANGO_TYPE_WIN32_FONT_MAP (_pango_win32_font_map_get_type ()) #define PANGO_WIN32_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_WIN32_FONT_MAP, PangoWin32FontMap)) #define PANGO_WIN32_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_WIN32_FONT_MAP)) @@ -73,6 +75,7 @@ typedef struct _PangoWin32FontMap PangoWin32FontMap; typedef struct _PangoWin32FontMapClass PangoWin32FontMapClass; +typedef struct _PangoWin32DWriteItems PangoWin32DWriteItems; typedef struct _PangoWin32Font PangoWin32Font; typedef struct _PangoWin32FontClass PangoWin32FontClass; typedef struct _PangoWin32Face PangoWin32Face; @@ -96,12 +99,14 @@ struct _PangoWin32FontMap */ GHashTable *fonts; + /* Map LOGFONTWs to IDWriteFonts corresponding to actual fonts + * installed, if applicable. + */ + GHashTable *dwrite_fonts; + /* keeps track of the system font aliases that we might have */ GHashTable *aliases; - /* keeps track of the warned fonts that we might have */ - GHashTable *warned_fonts; - double resolution; /* (points / pixel) * PANGO_SCALE */ }; @@ -137,6 +142,9 @@ struct _PangoWin32Font */ gboolean in_cache; GHashTable *glyph_info; + + /* whether the font supports hinting */ + gboolean is_hinted; }; struct _PangoWin32FontClass @@ -279,6 +287,42 @@ _PANGO_EXTERN gpointer _pango_win32_copy_cmap (gpointer cmap, guint16 cmap_format); +_PANGO_EXTERN +gboolean pango_win32_dwrite_font_check_is_hinted (PangoWin32Font *font); + +_PANGO_EXTERN +void *pango_win32_font_get_dwrite_font_face (PangoWin32Font *font); + extern gboolean _pango_win32_debug; +void pango_win32_insert_font (PangoWin32FontMap *win32fontmap, + LOGFONTW *lfp, + gpointer dwrite_font, + gboolean is_synthetic); + +PangoWin32DWriteItems *pango_win32_init_direct_write (void); + +PangoWin32DWriteItems *pango_win32_get_direct_write_items (void); + +void pango_win32_dwrite_font_map_populate (PangoWin32FontMap *map); + +void pango_win32_dwrite_items_destroy (PangoWin32DWriteItems *items); + +gboolean pango_win32_dwrite_font_is_monospace (gpointer dwrite_font, + gboolean *is_monospace); + +void pango_win32_dwrite_font_release (gpointer dwrite_font); + +_PANGO_EXTERN +void pango_win32_dwrite_font_face_release (gpointer dwrite_font_face); + +gpointer pango_win32_logfontw_get_dwrite_font (LOGFONTW *logfontw); + +PangoFontDescription * +pango_win32_font_description_from_logfontw_dwrite (const LOGFONTW *logfontw); + +hb_face_t *pango_win32_dwrite_font_face_create_hb_face (gpointer face); + +G_END_DECLS + #endif /* __PANGOWIN32_PRIVATE_H__ */ diff --git a/pango/pangowin32.c b/pango/pangowin32.c index eed92dde..09b97a55 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -29,6 +29,10 @@ #include <glib.h> #include <hb.h> +#if defined (HAVE_HARFBUZZ_GDI) +#include <hb-gdi.h> +#endif + #include "pango-impl-utils.h" #include "pangowin32.h" #include "pangowin32-private.h" @@ -56,6 +60,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, @@ -126,11 +131,13 @@ _pango_win32_font_init (PangoWin32Font *win32font) } static GPrivate display_dc_key = G_PRIVATE_INIT ((GDestroyNotify) DeleteDC); +static GPrivate dwrite_items = G_PRIVATE_INIT ((GDestroyNotify) pango_win32_dwrite_items_destroy); HDC _pango_win32_get_display_dc (void) { HDC hdc = g_private_get (&display_dc_key); + PangoWin32DWriteItems *items; if (hdc == NULL) { @@ -151,9 +158,22 @@ _pango_win32_get_display_dc (void) #endif } + items = g_private_get (&dwrite_items); + if (items == NULL) + { + items = pango_win32_init_direct_write (); + g_private_set (&dwrite_items, items); + } + return hdc; } +PangoWin32DWriteItems * +pango_win32_get_direct_write_items (void) +{ + return g_private_get (&dwrite_items); +} + /** * pango_win32_get_dc: * @@ -187,6 +207,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; @@ -203,6 +224,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 (); } @@ -647,6 +671,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 @@ -1257,20 +1289,45 @@ hfont_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data) static hb_font_t * pango_win32_font_create_hb_font (PangoFont *font) { - PangoWin32Font *win32font = (PangoWin32Font *)font; - HFONT hfont; + PangoWin32Font *win32font = PANGO_WIN32_FONT (font); + HFONT hfont = NULL; hb_face_t *face = NULL; hb_font_t *hb_font = NULL; + static const hb_user_data_key_t key; + hb_destroy_func_t destroy_func = NULL; + void *destroy_obj = NULL; + gpointer dwrite_font_face = NULL; g_return_val_if_fail (font != NULL, NULL); - hfont = _pango_win32_font_get_hfont (font); +#ifdef HAVE_HARFBUZZ_DIRECT_WRITE + dwrite_font_face = pango_win32_font_get_dwrite_font_face (win32font); + + if (dwrite_font_face != NULL) + { + face = pango_win32_dwrite_font_face_create_hb_face (dwrite_font_face); + destroy_func = pango_win32_dwrite_font_face_release; + destroy_obj = dwrite_font_face; + } +#endif + if (face == NULL) + { + hfont = _pango_win32_font_get_hfont (font); - /* We are *not* allowed to destroy the HFONT here ! */ - face = hb_face_create_for_tables (hfont_reference_table, (void *)hfont, NULL); +#ifdef HAVE_HARFBUZZ_GDI + face = hb_gdi_face_create (hfont); +#else + face = hb_face_create_for_tables (hfont_reference_table, (void *)hfont, NULL); +#endif + } hb_font = hb_font_create (face); hb_font_set_scale (hb_font, win32font->size, win32font->size); + + /* We are supposed to destroy the IDWriteFontFace, but *not* the HFONT! */ + if (destroy_func != NULL && destroy_obj != NULL) + hb_font_set_user_data (hb_font, &key, destroy_obj, destroy_func, TRUE); + hb_face_destroy (face); return hb_font; |