Commit 37cd678f authored by Aaron Boxer's avatar Aaron Boxer Committed by GStreamer Marge Bot
Browse files

pango: fix font corruption on windows

1. provide windows font fallbacks
2. do not share windows HDC across threads

Part-of: <!574>
parent 4bebbb90
Pipeline #207999 canceled with stages
in 66 minutes and 36 seconds
......@@ -19,6 +19,10 @@ class Recipe(recipe.Recipe):
name + '/0001-meson-Set-the-compatibility-version-correctly-on-mac.patch',
# https://gitlab.gnome.org/GNOME/pango/-/merge_requests/181
name + '/0001-meson-Fix-check-for-builtype-arguments.patch',
name + '/0001-pangowin32-fontmap-read-windows-fallbacks-from-regis.patch',
# https://gitlab.gnome.org/GNOME/pango/-/merge_requests/34
name + '/0002-win32-Use-GPrivate-managed-display-device-context.patch',
# https://gitlab.freedesktop.org/gstreamer/cerbero/-/merge_requests/574
]
files_libs = ['libpangocairo-1.0', 'libpango-1.0', 'libpangoft2-1.0']
......
From e88684bafe932035bea279d71e2e2905b3541807 Mon Sep 17 00:00:00 2001
From: Aaron Boxer <Aaron Boxer>
Date: Thu, 24 Sep 2020 11:10:54 -0400
Subject: [PATCH 1/2] pangowin32-fontmap: read windows fallbacks from registry
and add to alias hash
---
pango/pangowin32-fontmap.c | 130 +++++++++++++++++++++++++++++++++++--
1 file changed, 126 insertions(+), 4 deletions(-)
diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c
index 12fa4f26..afb8272f 100644
--- a/pango/pangowin32-fontmap.c
+++ b/pango/pangowin32-fontmap.c
@@ -30,10 +30,11 @@
#include <string.h>
#include <errno.h>
#include <glib/gstdio.h>
-
#include "pango-fontmap.h"
#include "pango-impl-utils.h"
#include "pangowin32-private.h"
+#include <windows.h>
+#include <winreg.h>
typedef struct _PangoWin32Family PangoWin32Family;
typedef PangoFontFamilyClass PangoWin32FamilyClass;
@@ -445,17 +446,16 @@ handle_alias_line (GString *line_buffer,
g_string_free (tmp_buffer2, TRUE);
}
+
#ifdef HAVE_CAIRO_WIN32
static const char * const builtin_aliases[] = {
"courier = \"courier new\"",
- "\"segoe ui\" = \"segoe ui,meiryo,malgun gothic,microsoft jhenghei,microsoft yahei,gisha,leelawadee,arial unicode ms,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
- "tahoma = \"tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
/* It sucks to use the same GulimChe, MS Gothic, Sylfaen, Kartika,
* Latha, Mangal and Raavi fonts for all three of sans, serif and
* mono, but it isn't like there would be much choice. For most
* non-Latin scripts that Windows includes any font at all for, it
- * has ony one. One solution is to install the free DejaVu fonts
+ * has only one. One solution is to install the free DejaVu fonts
* that are popular on Linux. They are listed here first.
*/
"sans = \"dejavu sans,tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
@@ -464,6 +464,9 @@ static const char * const builtin_aliases[] = {
"mono = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
"monospace = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
"emoji = \"segoe ui emoji,segoe ui symbol,segoe ui\"",
+ "cursive = \"commic sans ms\"",
+ "fantasy = \"gabriola,impact\"",
+ "system-ui = \"yu gothic ui,segoe ui,meiryo\"",
};
static void
@@ -490,6 +493,124 @@ read_builtin_aliases (GHashTable *ht_aliases)
g_string_free (line_buffer, TRUE);
}
+
+#define MAX_VALUE_NAME 16383
+
+static void
+read_windows_fallbacks (GHashTable *ht_aliases)
+{
+
+#if 0
+ DWORD value_index;
+ HKEY hkey;
+ LSTATUS status;
+ GString *line_buffer;
+
+ /* https://docs.microsoft.com/en-us/globalization/input/font-technology */
+ status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
+ L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
+ 0,
+ KEY_READ,
+ &hkey);
+ if (status != ERROR_SUCCESS)
+ return;
+
+ line_buffer = g_string_new (NULL);
+ status = ERROR_SUCCESS;
+ for (value_index = 0; status != ERROR_NO_MORE_ITEMS; value_index++)
+ {
+ wchar_t name[MAX_VALUE_NAME];
+ DWORD name_length = MAX_VALUE_NAME, value_length = 0;
+ char *errstring = NULL;
+ gchar *utf8_name;
+ wchar_t *value_data, *entry;
+ size_t entry_len;
+
+ status = RegEnumValueW (hkey, value_index, name, &name_length,
+ NULL, NULL, NULL, NULL);
+
+ if (status != ERROR_SUCCESS)
+ continue;
+
+ utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
+ if (utf8_name == NULL)
+ continue;
+ g_string_truncate (line_buffer, 0);
+ g_string_append_printf (line_buffer,
+ "\"%s\" = \"%s",
+ utf8_name,
+ utf8_name);
+ g_free (utf8_name);
+
+ status = RegGetValueW (hkey, NULL, name, RRF_RT_REG_MULTI_SZ,
+ NULL, NULL, &value_length);
+ if (status != ERROR_SUCCESS)
+ continue;
+
+ value_data = g_malloc (value_length);
+ status = RegGetValueW (hkey, NULL, name, RRF_RT_REG_MULTI_SZ, NULL,
+ value_data, &value_length);
+ if (status != ERROR_SUCCESS)
+ {
+ g_free (value_data);
+ continue;
+ }
+
+ entry = value_data;
+ entry_len = wcslen (entry);
+ while (entry_len > 0)
+ {
+ wchar_t *comma;
+ gchar *entry_utf8;
+
+ comma = wcsstr (entry, L",");
+ /* The value after the first comma, as long as it isn't followed
+ * by another comma with a font scale */
+ if (comma && wcsstr (comma + 1, L",") == NULL)
+ {
+ g_string_append (line_buffer, ",");
+ entry_utf8 = g_utf16_to_utf8 (comma + 1, -1, NULL, NULL, NULL);
+ if (entry_utf8 != NULL)
+ {
+ g_string_append (line_buffer, entry_utf8);
+ g_free (entry_utf8);
+ }
+ }
+
+ entry += entry_len + 1;
+ entry_len = wcslen (entry);
+ }
+ g_free (value_data);
+
+ /* For some reason the default fallback list doesn't cover all of Unicode
+ * and Windows has additional fonts for certain languages.
+ * Some of them are listed in
+ * SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontMapperFamilyFallback
+ * but I couldn't find any docs for it. Feel free to improve this */
+ g_string_append (line_buffer,
+ ",gisha,leelawadee,arial unicode ms,browallia new,"
+ "mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,"
+ "latha,mangal,raavi");
+
+ g_string_append (line_buffer, "\"");
+
+ handle_alias_line (line_buffer, &errstring, ht_aliases);
+ if (errstring != NULL)
+ {
+ g_warning ("error in windows fallback: %s (%s)\n",
+ errstring, line_buffer->str);
+ g_free (errstring);
+ errstring = NULL;
+ }
+ }
+
+ RegCloseKey (hkey);
+ g_string_free (line_buffer, TRUE);
+#endif
+}
+
+
+
#endif
@@ -502,6 +623,7 @@ load_aliases (void)
NULL);
#ifdef HAVE_CAIRO_WIN32
+ read_windows_fallbacks (ht_aliases);
read_builtin_aliases (ht_aliases);
#endif
--
2.17.1
From 01ee140274f85c4fb3e153b39c0b320bb2f89ada Mon Sep 17 00:00:00 2001
From: Aaron Boxer <Aaron Boxer>
Date: Thu, 24 Sep 2020 11:11:18 -0400
Subject: [PATCH 2/2] win32: Use GPrivate-managed display device context
The document of [CreateDCA][1] says:
> If lpszDriver or lpszDevice is DISPLAY, the thread that calls
> CreateDC owns the HDC that is created. When this thread is
> destroyed, the HDC is no longer valid. Thus, if you create the HDC
> and pass it to another thread, then exit the first thread,
> the second thread will not be able to use the HDC.
So this change introduces GPrivate to fix potential problem.
This also fixes the problem caused by accessing the global
variable DC directly, which makes some early call to Pango functions
fail.
(e.g., failure of calling pango_win32_font_description_from_logfontw
from _get_system_font_name in GTK.)
[1]: https://docs.microsoft.com/windows/win32/api/wingdi/nf-wingdi-createdca
---
pango/pangocairo-win32fontmap.c | 2 +-
pango/pangowin32-fontmap.c | 59 ++++++++++++++--------
pango/pangowin32-private.h | 4 +-
pango/pangowin32-shape.c | 2 +-
pango/pangowin32.c | 89 ++++++++++++++++++---------------
5 files changed, 93 insertions(+), 63 deletions(-)
diff --git a/pango/pangocairo-win32fontmap.c b/pango/pangocairo-win32fontmap.c
index b58d16f6..94500fd6 100644
--- a/pango/pangocairo-win32fontmap.c
+++ b/pango/pangocairo-win32fontmap.c
@@ -121,5 +121,5 @@ static void
pango_cairo_win32_font_map_init (PangoCairoWin32FontMap *cwfontmap)
{
cwfontmap->serial = 1;
- cwfontmap->dpi = GetDeviceCaps (pango_win32_get_dc (), LOGPIXELSY);
+ cwfontmap->dpi = GetDeviceCaps (_pango_win32_get_display_dc (), LOGPIXELSY);
}
diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c
index afb8272f..eab44765 100644
--- a/pango/pangowin32-fontmap.c
+++ b/pango/pangowin32-fontmap.c
@@ -200,6 +200,12 @@ pango_win32_inner_enum_proc (LOGFONTW *lfp,
return 1;
}
+struct EnumProcData
+{
+ HDC hdc;
+ PangoWin32FontMap *font_map;
+};
+
static int CALLBACK
pango_win32_enum_proc (LOGFONTW *lfp,
NEWTEXTMETRICW *metrics,
@@ -207,6 +213,7 @@ pango_win32_enum_proc (LOGFONTW *lfp,
LPARAM lParam)
{
LOGFONTW lf;
+ struct EnumProcData *data = (struct EnumProcData *) lParam;
PING (("%S: %lu %lx", lfp->lfFaceName, fontType, metrics->ntmFlags));
@@ -216,9 +223,9 @@ pango_win32_enum_proc (LOGFONTW *lfp,
{
lf = *lfp;
- EnumFontFamiliesExW (_pango_win32_hdc, &lf,
+ EnumFontFamiliesExW (data->hdc, &lf,
(FONTENUMPROCW) pango_win32_inner_enum_proc,
- lParam, 0);
+ (LPARAM) data->font_map, 0);
}
return 1;
@@ -725,6 +732,12 @@ static void
_pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
{
LOGFONTW logfont;
+ HDC hdc = _pango_win32_get_display_dc ();
+
+ struct EnumProcData enum_proc_data = {
+ .hdc = hdc,
+ .font_map = win32fontmap,
+ };
win32fontmap->families =
g_hash_table_new_full ((GHashFunc) case_insensitive_str_hash,
@@ -738,9 +751,9 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
memset (&logfont, 0, sizeof (logfont));
logfont.lfCharSet = DEFAULT_CHARSET;
- EnumFontFamiliesExW (_pango_win32_hdc, &logfont,
+ EnumFontFamiliesExW (hdc, &logfont,
(FONTENUMPROCW) pango_win32_enum_proc,
- (LPARAM) win32fontmap, 0);
+ (LPARAM) &enum_proc_data, 0);
g_hash_table_foreach (win32fontmap->families, synthesize_foreach, win32fontmap);
@@ -749,7 +762,7 @@ _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
create_standard_family (win32fontmap, "Serif");
create_standard_family (win32fontmap, "Monospace");
- win32fontmap->resolution = (PANGO_SCALE / (double) GetDeviceCaps (_pango_win32_hdc, LOGPIXELSY)) * 72.0;
+ win32fontmap->resolution = (PANGO_SCALE / (double) GetDeviceCaps (hdc, LOGPIXELSY)) * 72.0;
}
static void
@@ -802,7 +815,7 @@ _pango_win32_font_map_class_init (PangoWin32FontMapClass *class)
fontmap_class->list_families = pango_win32_font_map_list_families;
fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_WIN32;
- pango_win32_get_dc ();
+ _pango_win32_get_display_dc ();
}
/**
@@ -1125,6 +1138,7 @@ get_family_nameA (const LOGFONTA *lfp)
{
HFONT hfont;
HFONT oldhfont;
+ HDC hdc;
struct name_header header;
struct name_record record;
@@ -1155,17 +1169,19 @@ get_family_nameA (const LOGFONTA *lfp)
if ((hfont = CreateFontIndirect (lfp)) == NULL)
goto fail0;
- if ((oldhfont = SelectObject (_pango_win32_hdc, hfont)) == NULL)
+ hdc = _pango_win32_get_display_dc ();
+
+ if ((oldhfont = SelectObject (hdc, hfont)) == NULL)
goto fail1;
- if (!_pango_win32_get_name_header (_pango_win32_hdc, &header))
+ if (!_pango_win32_get_name_header (hdc, &header))
goto fail2;
PING (("%d name records", header.num_records));
for (i = 0; i < header.num_records; i++)
{
- if (!_pango_win32_get_name_record (_pango_win32_hdc, i, &record))
+ if (!_pango_win32_get_name_record (hdc, i, &record))
goto fail2;
if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0)
@@ -1199,11 +1215,11 @@ get_family_nameA (const LOGFONTA *lfp)
else
goto fail2;
- if (!_pango_win32_get_name_record (_pango_win32_hdc, name_ix, &record))
+ if (!_pango_win32_get_name_record (hdc, name_ix, &record))
goto fail2;
string = g_malloc (record.string_length + 1);
- if (GetFontData (_pango_win32_hdc, NAME,
+ if (GetFontData (hdc, NAME,
header.string_storage_offset + record.string_offset,
string, record.string_length) != record.string_length)
goto fail2;
@@ -1229,14 +1245,14 @@ get_family_nameA (const LOGFONTA *lfp)
PING (("%s", name));
- SelectObject (_pango_win32_hdc, oldhfont);
+ SelectObject (hdc, oldhfont);
DeleteObject (hfont);
return name;
fail2:
g_free (string);
- SelectObject (_pango_win32_hdc, oldhfont);
+ SelectObject (hdc, oldhfont);
fail1:
DeleteObject (hfont);
@@ -1308,6 +1324,7 @@ get_family_nameW (const LOGFONTW *lfp)
{
HFONT hfont;
HFONT oldhfont;
+ HDC hdc;
struct name_header header;
struct name_record record;
@@ -1338,17 +1355,19 @@ get_family_nameW (const LOGFONTW *lfp)
if ((hfont = CreateFontIndirectW (lfp)) == NULL)
goto fail0;
- if ((oldhfont = SelectObject (_pango_win32_hdc, hfont)) == NULL)
+ hdc = _pango_win32_get_display_dc ();
+
+ if ((oldhfont = SelectObject (hdc, hfont)) == NULL)
goto fail1;
- if (!_pango_win32_get_name_header (_pango_win32_hdc, &header))
+ if (!_pango_win32_get_name_header (hdc, &header))
goto fail2;
PING (("%d name records", header.num_records));
for (i = 0; i < header.num_records; i++)
{
- if (!_pango_win32_get_name_record (_pango_win32_hdc, i, &record))
+ if (!_pango_win32_get_name_record (hdc, i, &record))
goto fail2;
if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0)
@@ -1382,11 +1401,11 @@ get_family_nameW (const LOGFONTW *lfp)
else
goto fail2;
- if (!_pango_win32_get_name_record (_pango_win32_hdc, name_ix, &record))
+ if (!_pango_win32_get_name_record (hdc, name_ix, &record))
goto fail2;
string = g_malloc (record.string_length + 1);
- if (GetFontData (_pango_win32_hdc, NAME,
+ if (GetFontData (hdc, NAME,
header.string_storage_offset + record.string_offset,
string, record.string_length) != record.string_length)
goto fail2;
@@ -1412,14 +1431,14 @@ get_family_nameW (const LOGFONTW *lfp)
PING (("%s", name));
- SelectObject (_pango_win32_hdc, oldhfont);
+ SelectObject (hdc, oldhfont);
DeleteObject (hfont);
return name;
fail2:
g_free (string);
- SelectObject (_pango_win32_hdc, oldhfont);
+ SelectObject (hdc, oldhfont);
fail1:
DeleteObject (hfont);
diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h
index 88e5655d..72cae50e 100644
--- a/pango/pangowin32-private.h
+++ b/pango/pangowin32-private.h
@@ -291,7 +291,9 @@ _pango_win32_shape (PangoFont *font,
const char *paragraph_text G_GNUC_UNUSED,
unsigned int paragraph_length G_GNUC_UNUSED);
-extern HDC _pango_win32_hdc;
+_PANGO_EXTERN
+HDC _pango_win32_get_display_dc (void);
+
extern OSVERSIONINFO _pango_win32_os_version_info;
extern gboolean _pango_win32_debug;
diff --git a/pango/pangowin32-shape.c b/pango/pangowin32-shape.c
index aad0243e..36d43413 100644
--- a/pango/pangowin32-shape.c
+++ b/pango/pangowin32-shape.c
@@ -607,7 +607,7 @@ uniscribe_shape (PangoFont *font,
{
wchar_t *wtext;
long wlen;
- HDC hdc = _pango_win32_hdc;
+ HDC hdc = _pango_win32_get_display_dc ();
gboolean retval = TRUE;
if (!pango_win32_font_select_font (font, hdc))
diff --git a/pango/pangowin32.c b/pango/pangowin32.c
index 630898e0..71204606 100644
--- a/pango/pangowin32.c
+++ b/pango/pangowin32.c
@@ -47,7 +47,6 @@
((ch) >= 0x20000 && (ch) <= 0x2A6DF) || \
((ch) >= 0x2F800 && (ch) <= 0x2FA1F))
-HDC _pango_win32_hdc;
OSVERSIONINFO _pango_win32_os_version_info;
gboolean _pango_win32_debug = FALSE;
@@ -143,24 +142,17 @@ _pango_win32_font_init (PangoWin32Font *win32font)
win32font->glyph_info = g_hash_table_new_full (NULL, NULL, NULL, g_free);
}
-/**
- * pango_win32_get_dc:
- *
- * Obtains a handle to the Windows device context that is used by Pango.
- *
- * Return value: A handle to the Windows device context that is used by Pango.
- **/
+static GPrivate display_dc_key = G_PRIVATE_INIT ((GDestroyNotify) DeleteDC);
+
HDC
-pango_win32_get_dc (void)
+_pango_win32_get_display_dc (void)
{
- if (g_once_init_enter (&_pango_win32_hdc))
+ HDC hdc = g_private_get (&display_dc_key);
+
+ if (hdc == NULL)
{
- HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
- memset (&_pango_win32_os_version_info, 0,
- sizeof (_pango_win32_os_version_info));
- _pango_win32_os_version_info.dwOSVersionInfoSize =
- sizeof (OSVERSIONINFO);
- GetVersionEx (&_pango_win32_os_version_info);
+ hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
+ g_private_set (&display_dc_key, hdc);
/* Also do some generic pangowin32 initialisations... this function
* is a suitable place for those as it is called from a couple
@@ -170,10 +162,22 @@ pango_win32_get_dc (void)
if (getenv ("PANGO_WIN32_DEBUG") != NULL)
_pango_win32_debug = TRUE;
#endif
- g_once_init_leave (&_pango_win32_hdc, hdc);
}
- return _pango_win32_hdc;
+ return hdc;
+}
+
+/**
+ * pango_win32_get_dc:
+ *
+ * Obtains a handle to the Windows device context that is used by Pango.
+ *
+ * Return value: A handle to the Windows device context that is used by Pango.
+ **/
+HDC
+pango_win32_get_dc (void)
+{
+ return _pango_win32_get_display_dc ();
}
/**
@@ -212,7 +216,7 @@ _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;
- pango_win32_get_dc ();
+ _pango_win32_get_display_dc ();
}
/**
@@ -462,15 +466,14 @@ pango_win32_font_get_glyph_extents (PangoFont *font,
if (!info)
{
+ HDC hdc = _pango_win32_get_display_dc ();
info = g_new0 (PangoWin32GlyphInfo, 1);
memset (&gm, 0, sizeof (gm));
hfont = _pango_win32_font_get_hfont (font);
- SelectObject (_pango_win32_hdc, hfont);
- /* FIXME: (Alex) This constant reuse of _pango_win32_hdc is
- not thread-safe */
- res = GetGlyphOutlineA (_pango_win32_hdc,
+ SelectObject (hdc, hfont);
+ res = GetGlyphOutlineA (hdc,
glyph_index,
GGO_METRICS | GGO_GLYPH_INDEX,
&gm,
@@ -492,7 +495,7 @@ pango_win32_font_get_glyph_extents (PangoFont *font,
info->ink_rect.y = - PANGO_SCALE * gm.gmptGlyphOrigin.y;
info->ink_rect.height = PANGO_SCALE * gm.gmBlackBoxY;
- GetTextMetrics (_pango_win32_hdc, &tm);
+ GetTextMetrics (hdc, &tm);
info->logical_rect.x = 0;
info->logical_rect.width = PANGO_SCALE * gm.gmCellIncX;
info->logical_rect.y = - PANGO_SCALE * tm.tmAscent;
@@ -569,9 +572,10 @@ pango_win32_font_get_metrics (PangoFont *font,
{
PangoCoverage *coverage;
TEXTMETRIC tm;
+ HDC hdc = _pango_win32_get_display_dc ();
- SelectObject (_pango_win32_hdc, hfont);
- GetTextMetrics (_pango_win32_hdc, &tm);
+ SelectObject (hdc, hfont);
+ GetTextMetrics (hdc, &tm);
metrics->ascent = tm.tmAscent * PANGO_SCALE;
metrics->descent = tm.tmDescent * PANGO_SCALE;
@@ -1489,19 +1493,20 @@ font_get_cmap (PangoFont *font)
{
PangoWin32Font *win32font = (PangoWin32Font *)font;
gpointer cmap;
+ HDC hdc = _pango_win32_get_display_dc ();
if (win32font->win32face->cmap)
return win32font->win32face->cmap;