diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-07-04 11:16:05 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-07-04 11:17:21 -0400 |
commit | bcdce34c8ac0adffd589e9fb68b62ff09368bb0f (patch) | |
tree | 7b92ba875b22212d15ffb9d9620d517cfa427a1e /pango2/pangodwrite-fontmap.cpp | |
parent | b197cc08b18bc44a3e93f859ca7e61dfe335bbc5 (diff) | |
download | pango-bcdce34c8ac0adffd589e9fb68b62ff09368bb0f.tar.gz |
Move the code from pango/ to pango2/
Life is easier if the src path matches the installed
header path prefix, so make them match. Update all
users.
Diffstat (limited to 'pango2/pangodwrite-fontmap.cpp')
-rw-r--r-- | pango2/pangodwrite-fontmap.cpp | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/pango2/pangodwrite-fontmap.cpp b/pango2/pangodwrite-fontmap.cpp new file mode 100644 index 00000000..37307a3d --- /dev/null +++ b/pango2/pangodwrite-fontmap.cpp @@ -0,0 +1,392 @@ +/* Pango + * pangodwrite-fontmap.cpp: Fontmap using DirectWrite + * + * Copyright (C) 2022 the GTK team + * + * 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 <windows.h> +#include <initguid.h> +#include <dwrite.h> + +#include <hb-ot.h> +#include <hb-directwrite.h> + +#include "pangodwrite-fontmap.h" +#include "pango-hbfamily-private.h" +#include "pango-fontmap-private.h" +#include "pango-hbface-private.h" +#include "pango-hbfont-private.h" +#include "pango-context.h" +#include "pango-impl-utils.h" +#include "pango-trace-private.h" + + +/** + * PangoDirectWriteFontMap: + * + * `PangoDirectWriteFontMap` is a subclass of `PangoFontMap` that + * uses DirectWrite to populate the fontmap with the available fonts. + */ + + +struct _PangoDirectWriteFontMap +{ + PangoFontMap parent_instance; + + IDWriteFactory *dwrite_factory; +}; + +struct _PangoDirectWriteFontMapClass +{ + PangoFontMapClass parent_class; +}; + +#ifdef _MSC_VER +# define UUID_OF_IDWriteFactory __uuidof (IDWriteFactory) +#else +# define UUID_OF_IDWriteFactory IID_IDWriteFactory +#endif + +/* {{{ DirectWrite utilities */ + +static PangoStretch +util_to_pango_stretch (DWRITE_FONT_STRETCH stretch) +{ + int value = (int) stretch; + + if G_UNLIKELY (stretch <= DWRITE_FONT_STRETCH_UNDEFINED || + stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) + return PANGO_STRETCH_NORMAL; + + return (PangoStretch) --value; +} + +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 values + * range from 100 to 1000. */ + + return (PangoWeight) util_map_weight (weight); +} + +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_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_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); +} + +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 PangoHbFace* +util_create_pango_hb_face (IDWriteFontFamily *family, + IDWriteFont *font, + IDWriteFontFace *face) +{ + char *family_name = util_dwrite_get_font_family_name (family); + char *variant_name = util_dwrite_get_font_variant_name (font); + PangoHbFace *pango_face = NULL; + + if (family_name && variant_name) + { + PangoFontDescription *description = util_get_pango_font_description (font, family_name); + hb_face_t *hb_face = hb_directwrite_face_create (face); + char *name = g_strconcat (family_name, " ", variant_name, NULL); + + hb_face_make_immutable (hb_face); + + pango_face = pango_hb_face_new_from_hb_face (hb_face, -1, name, description); + + g_free (name); + hb_face_destroy (hb_face); + pango_font_description_free (description); + } + + g_free (family_name); + g_free (variant_name); + + return pango_face; +} + +/* }}} */ +/* {{{ PangoFontMap implementation */ + +static void +pango_direct_write_font_map_populate (PangoFontMap *map) +{ + PangoDirectWriteFontMap *dwrite_map = PANGO_DIRECT_WRITE_FONT_MAP (map); + IDWriteFontCollection *collection = NULL; + UINT32 count; + HRESULT hr; + + hr = dwrite_map->dwrite_factory->GetSystemFontCollection (&collection, FALSE); + if (FAILED (hr) || collection == NULL) + g_error ("IDWriteFactory::GetSystemFontCollection failed with error code %x\n", (unsigned)hr); + + 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; + PangoHbFace *pango_face = NULL; + + hr = family->GetFont (j, &font); + if (FAILED (hr) || font == NULL) + { + g_warning ("IDWriteFontFamily::GetFont failed with error code %x\n", (unsigned)hr); + break; + } + + hr = font->CreateFontFace (&face); + if (FAILED (hr) || face == NULL) + { + g_warning ("IDWriteFont::CreateFontFace failed with error code %x\n", (unsigned)hr); + font->Release (); + continue; + } + + pango_face = util_create_pango_hb_face (family, font, face); + if (pango_face) + pango_font_map_add_face (map, PANGO_FONT_FACE (pango_face)); + + face->Release (); + font->Release (); + } + + family->Release (); + } + + collection->Release (); + collection = NULL; + + /* Add generic aliases */ + struct { + const char *alias_name; + const char *family_name; + } aliases[] = { + { "Monospace", "Consolas" }, + { "Sans-serif", "Arial" }, + { "Sans", "Arial" }, + { "Serif", "Times New Roman" }, + { "System-ui", "Segoe UI" }, + { "Emoji", "Segoe UI Emoji" } + }; + +#if 0 + if (IsWindows11OrLater ()) + aliases[0].family_name = "Cascadia Mono"; +#endif + + for (gsize i = 0; i < G_N_ELEMENTS (aliases); i++) + { + PangoFontFamily *family = pango_font_map_get_family (map, aliases[i].family_name); + + if (family) + { + PangoGenericFamily *alias_family; + + alias_family = pango_generic_family_new (aliases[i].alias_name); + pango_generic_family_add_family (alias_family, family); + pango_font_map_add_family (map, PANGO_FONT_FAMILY (alias_family)); + } + } +} + +/* }}} */ +/* {{{ PangoDirectWriteFontMap implementation */ + +G_DEFINE_FINAL_TYPE (PangoDirectWriteFontMap, pango_direct_write_font_map, PANGO_TYPE_FONT_MAP) + +static void +pango_direct_write_font_map_init (PangoDirectWriteFontMap *self) +{ + HRESULT hr; + + hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, + UUID_OF_IDWriteFactory, + reinterpret_cast<IUnknown**> (&self->dwrite_factory)); + + if (FAILED (hr) || !self->dwrite_factory) + g_error ("DWriteCreateFactory failed with error code %x", (unsigned)hr); + + pango_font_map_repopulate (PANGO_FONT_MAP (self), TRUE); +} + +static void +pango_direct_write_font_map_finalize (GObject *object) +{ + PangoDirectWriteFontMap *dwrite_map = PANGO_DIRECT_WRITE_FONT_MAP (object); + + dwrite_map->dwrite_factory->Release (); + dwrite_map->dwrite_factory = NULL; + + G_OBJECT_CLASS (pango_direct_write_font_map_parent_class)->finalize (object); +} + +static void +pango_direct_write_font_map_class_init (PangoDirectWriteFontMapClass *class_) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class_); + PangoFontMapClass *font_map_class = PANGO_FONT_MAP_CLASS (class_); + + object_class->finalize = pango_direct_write_font_map_finalize; + + font_map_class->populate = pango_direct_write_font_map_populate; +} + +/* }}} */ + /* {{{ Public API */ + +/** + * pango_direct_write_font_map_new: + * + * Creates a new `PangoDirectWriteFontMap` object. + * + * Returns: a new `PangoDirectWriteFontMap` + */ +PangoDirectWriteFontMap * +pango_direct_write_font_map_new (void) +{ + return (PangoDirectWriteFontMap *) g_object_new (PANGO_TYPE_DIRECT_WRITE_FONT_MAP, NULL); +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ |