diff options
Diffstat (limited to 'pango')
-rw-r--r-- | pango/pangocairo-win32font.c | 23 | ||||
-rw-r--r-- | pango/pangowin32-fontcache.c | 141 | ||||
-rw-r--r-- | pango/pangowin32-fontmap.c | 458 | ||||
-rw-r--r-- | pango/pangowin32-private.h | 16 | ||||
-rw-r--r-- | pango/pangowin32.c | 66 | ||||
-rw-r--r-- | pango/pangowin32.def | 6 | ||||
-rw-r--r-- | pango/pangowin32.h | 11 |
7 files changed, 508 insertions, 213 deletions
diff --git a/pango/pangocairo-win32font.c b/pango/pangocairo-win32font.c index edfce056..4710c3ff 100644 --- a/pango/pangocairo-win32font.c +++ b/pango/pangocairo-win32font.c @@ -84,20 +84,7 @@ pango_cairo_win32_font_get_font_face (PangoCairoFont *font) if (cwfont->font_face == NULL) { - LOGFONTW logfontw; - - /* Count here on the fact that all the struct fields are the - * same for LOGFONTW and LOGFONTA except lfFaceName which is the - * last field - */ - memcpy (&logfontw, &win32font->logfont, sizeof (LOGFONTA)); - - if (!MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, - win32font->logfont.lfFaceName, -1, - logfontw.lfFaceName, G_N_ELEMENTS (logfontw.lfFaceName))) - logfontw.lfFaceName[0] = 0; /* Hopefully this will select some font */ - - cwfont->font_face = cairo_win32_font_face_create_for_logfontw (&logfontw); + cwfont->font_face = cairo_win32_font_face_create_for_logfontw (&win32font->logfontw); /* Failure of the above should only occur for out of memory, * we can't proceed at that point @@ -544,10 +531,10 @@ _pango_cairo_win32_font_new (PangoCairoWin32FontMap *cwfontmap, else cairo_matrix_init_identity (&cwfont->ctm); - pango_win32_make_matching_logfont (win32font->fontmap, - &face->logfont, - win32font->size, - &win32font->logfont); + pango_win32_make_matching_logfontw (win32font->fontmap, + &face->logfontw, + win32font->size, + &win32font->logfontw); cwfont->options = cairo_font_options_copy (_pango_cairo_context_get_merged_font_options (context)); diff --git a/pango/pangowin32-fontcache.c b/pango/pangowin32-fontcache.c index 96005e59..88d2bc0c 100644 --- a/pango/pangowin32-fontcache.c +++ b/pango/pangowin32-fontcache.c @@ -1,8 +1,9 @@ /* Pango - * pangowin32-fontcache.c: Cache of HFONTs by LOGFONT + * pangowin32-fontcache.c: Cache of HFONTs by LOGFONTW * * Copyright (C) 2000 Red Hat Software * Copyright (C) 2000 Tor Lillqvist + * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -46,15 +47,15 @@ struct _PangoWin32FontCache struct _CacheEntry { - LOGFONT logfont; - HFONT hfont; + LOGFONTW logfontw; + HFONT hfont; gint ref_count; GList *mru; }; static void -free_cache_entry (LOGFONT *logfont, +free_cache_entry (LOGFONTW *logfont, CacheEntry *entry, PangoWin32FontCache *cache) { @@ -87,28 +88,42 @@ pango_win32_font_cache_free (PangoWin32FontCache *cache) } static guint -logfont_hash (gconstpointer v) +wcs_hash (gconstpointer v) +{ + /* 31 bit hash function */ + const wchar_t *p = v; + guint32 h = *p; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + return h; +} + +static guint +logfontw_hash (gconstpointer v) { - const LOGFONT *lfp = v; + const LOGFONTW *lfp = v; - return g_str_hash (lfp->lfFaceName) + - lfp->lfItalic + + return wcs_hash (lfp->lfFaceName) + + (lfp->lfItalic != 0) + lfp->lfWeight/10 + lfp->lfOrientation + abs (lfp->lfHeight) * 10; } static gint -logfont_equal (gconstpointer v1, - gconstpointer v2) +logfontw_equal (gconstpointer v1, + gconstpointer v2) { - const LOGFONT *lfp1 = v1, *lfp2 = v2; + const LOGFONTW *lfp1 = v1, *lfp2 = v2; - return (strcmp (lfp1->lfFaceName, lfp2->lfFaceName) == 0 + return (wcscmp (lfp1->lfFaceName, lfp2->lfFaceName) == 0 && lfp1->lfPitchAndFamily == lfp2->lfPitchAndFamily && lfp1->lfStrikeOut == lfp2->lfStrikeOut && lfp1->lfUnderline == lfp2->lfUnderline - && lfp1->lfItalic == lfp2->lfItalic + && (lfp1->lfItalic != 0) == (lfp2->lfItalic != 0) && lfp1->lfWeight == lfp2->lfWeight && lfp1->lfOrientation == lfp2->lfOrientation && lfp1->lfEscapement == lfp2->lfEscapement @@ -131,7 +146,7 @@ pango_win32_font_cache_new (void) cache = g_slice_new (PangoWin32FontCache); - cache->forward = g_hash_table_new (logfont_hash, logfont_equal); + cache->forward = g_hash_table_new (logfontw_hash, logfontw_equal); cache->back = g_hash_table_new (g_direct_hash, g_direct_equal); cache->mru = NULL; @@ -150,7 +165,7 @@ cache_entry_unref (PangoWin32FontCache *cache, { PING (("removing cache entry %p", entry->hfont)); - g_hash_table_remove (cache->forward, &entry->logfont); + g_hash_table_remove (cache->forward, &entry->logfontw); g_hash_table_remove (cache->back, entry->hfont); free_cache_entry (NULL, entry, cache); @@ -160,9 +175,9 @@ cache_entry_unref (PangoWin32FontCache *cache, /** * pango_win32_font_cache_load: * @cache: a #PangoWin32FontCache - * @logfont: a pointer to a LOGFONT structure describing the font to load. + * @logfont: a pointer to a LOGFONTA structure describing the font to load. * - * Creates a HFONT from a LOGFONT. The + * Creates a HFONT from a LOGFONTA. The * result may be newly loaded, or it may have been previously * stored * @@ -172,10 +187,42 @@ cache_entry_unref (PangoWin32FontCache *cache, **/ HFONT pango_win32_font_cache_load (PangoWin32FontCache *cache, - const LOGFONT *lfp) + const LOGFONTA *lfp) +{ + LOGFONTW lf; + + /* We know that the lfFaceName is the last member in the structs */ + *(LOGFONTA *)&lf = *lfp; + + if (!MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, + lfp->lfFaceName, -1, + lf.lfFaceName, G_N_ELEMENTS (lf.lfFaceName))) + return NULL; + + return pango_win32_font_cache_loadw (cache, &lf); +} + +/** + * pango_win32_font_cache_loadw: + * @cache: a #PangoWin32FontCache + * @logfont: a pointer to a LOGFONTW structure describing the font to load. + * + * Creates a HFONT from a LOGFONTW. The + * result may be newly loaded, or it may have been previously + * stored + * + * Return value: The font structure, or %NULL if the font could + * not be loaded. In order to free this structure, you must call + * pango_win32_font_cache_unload(). + * + * Since: 1.16 + **/ +HFONT +pango_win32_font_cache_loadw (PangoWin32FontCache *cache, + const LOGFONTW *lfp) { CacheEntry *entry; - LOGFONT lf; + LOGFONTW lf; HFONT hfont; int tries; @@ -229,14 +276,14 @@ pango_win32_font_cache_load (PangoWin32FontCache *cache, "height=%ld,width=%ld,escapement=%ld,orientation=%ld," "weight=%ld,%s%s%s" "charset=%d,outprecision=%d,clipprecision=%d," - "quality=%d,pitchandfamily=%#.02x,facename=\"%s\")", + "quality=%d,pitchandfamily=%#.02x,facename=\"%S\")", lf.lfHeight, lf.lfWidth, lf.lfEscapement, lf.lfOrientation, lf.lfWeight, (lf.lfItalic ? "italic," : ""), (lf.lfUnderline ? "underline," : ""), (lf.lfStrikeOut ? "strikeout," : ""), lf.lfCharSet, lf.lfOutPrecision, lf.lfClipPrecision, lf.lfQuality, lf.lfPitchAndFamily, lf.lfFaceName)); - hfont = CreateFontIndirect (&lf); + hfont = CreateFontIndirectW (&lf); if (hfont != NULL) { @@ -247,42 +294,50 @@ pango_win32_font_cache_load (PangoWin32FontCache *cache, /* If we fail, try some similar fonts often found on Windows. */ if (tries == 0) { - if (g_ascii_strcasecmp (lf.lfFaceName, "helvetica") == 0) - strcpy (lf.lfFaceName, "arial"); - else if (g_ascii_strcasecmp (lf.lfFaceName, "new century schoolbook") == 0) - strcpy (lf.lfFaceName, "century schoolbook"); - else if (g_ascii_strcasecmp (lf.lfFaceName, "courier") == 0) - strcpy (lf.lfFaceName, "courier new"); - else if (g_ascii_strcasecmp (lf.lfFaceName, "lucida") == 0) - strcpy (lf.lfFaceName, "lucida sans unicode"); - else if (g_ascii_strcasecmp (lf.lfFaceName, "lucidatypewriter") == 0) - strcpy (lf.lfFaceName, "lucida console"); - else if (g_ascii_strcasecmp (lf.lfFaceName, "times") == 0) - strcpy (lf.lfFaceName, "times new roman"); + gchar *p = g_utf16_to_utf8 (lf.lfFaceName, -1, NULL, NULL, NULL); + if (!p) + ; /* Nothing */ + else if (g_ascii_strcasecmp (p, "helvetica") == 0) + wcscpy (lf.lfFaceName, L"arial"); + else if (g_ascii_strcasecmp (p, "new century schoolbook") == 0) + wcscpy (lf.lfFaceName, L"century schoolbook"); + else if (g_ascii_strcasecmp (p, "courier") == 0) + wcscpy (lf.lfFaceName, L"courier new"); + else if (g_ascii_strcasecmp (p, "lucida") == 0) + wcscpy (lf.lfFaceName, L"lucida sans unicode"); + else if (g_ascii_strcasecmp (p, "lucidatypewriter") == 0) + wcscpy (lf.lfFaceName, L"lucida console"); + else if (g_ascii_strcasecmp (p, "times") == 0) + wcscpy (lf.lfFaceName, L"times new roman"); + g_free (p); } else if (tries == 1) { - if (g_ascii_strcasecmp (lf.lfFaceName, "courier") == 0) + gchar *p = g_utf16_to_utf8 (lf.lfFaceName, -1, NULL, NULL, NULL); + if (!p) + ; /* Nothing */ + else if (g_ascii_strcasecmp (p, "courier") == 0) { - strcpy (lf.lfFaceName, ""); + wcscpy (lf.lfFaceName, L""); lf.lfPitchAndFamily |= FF_MODERN; } - else if (g_ascii_strcasecmp (lf.lfFaceName, "times new roman") == 0) + else if (g_ascii_strcasecmp (p, "times new roman") == 0) { - strcpy (lf.lfFaceName, ""); + wcscpy (lf.lfFaceName, L""); lf.lfPitchAndFamily |= FF_ROMAN; } - else if (g_ascii_strcasecmp (lf.lfFaceName, "helvetica") == 0 - || g_ascii_strcasecmp (lf.lfFaceName, "lucida") == 0) + else if (g_ascii_strcasecmp (p, "helvetica") == 0 + || g_ascii_strcasecmp (p, "lucida") == 0) { - strcpy (lf.lfFaceName, ""); + wcscpy (lf.lfFaceName, L""); lf.lfPitchAndFamily |= FF_SWISS; } else { - strcpy (lf.lfFaceName, ""); + wcscpy (lf.lfFaceName, L""); lf.lfPitchAndFamily = (lf.lfPitchAndFamily & 0x0F) | FF_DONTCARE; } + g_free (p); } else break; @@ -294,13 +349,13 @@ pango_win32_font_cache_load (PangoWin32FontCache *cache, entry = g_slice_new (CacheEntry); - entry->logfont = lf; + entry->logfontw = lf; entry->hfont = hfont; entry->ref_count = 1; entry->mru = NULL; - g_hash_table_insert (cache->forward, &entry->logfont, entry); + g_hash_table_insert (cache->forward, &entry->logfontw, entry); g_hash_table_insert (cache->back, entry->hfont, entry); } diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index facaf25e..2f98d453 100644 --- a/pango/pangowin32-fontmap.c +++ b/pango/pangowin32-fontmap.c @@ -4,6 +4,7 @@ * Copyright (C) 2000 Red Hat Software * Copyright (C) 2000 Tor Lillqvist * Copyright (C) 2001 Alexander Larsson + * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -52,7 +53,7 @@ struct _PangoWin32Family struct _PangoWin32SizeInfo { - GSList *logfonts; + GSList *logfontws; }; #define PANGO_WIN32_TYPE_FAMILY (pango_win32_family_get_type ()) @@ -75,18 +76,18 @@ static PangoFont *pango_win32_font_map_load_font (PangoFontMap PangoContext *context, const PangoFontDescription *description); static void pango_win32_font_map_list_families (PangoFontMap *fontmap, - PangoFontFamily ***families, - int *n_families); + PangoFontFamily ***families, + int *n_families); -static PangoFont *pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, - PangoContext *context, - PangoWin32Face *face, - const PangoFontDescription *description); +static PangoFont *pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, + PangoContext *context, + PangoWin32Face *face, + const PangoFontDescription *description); static void pango_win32_fontmap_cache_clear (PangoWin32FontMap *win32fontmap); static void pango_win32_insert_font (PangoWin32FontMap *fontmap, - LOGFONT *lfp); + LOGFONTW *lfp); static PangoWin32FontMap *default_fontmap = NULL; @@ -96,7 +97,7 @@ G_DEFINE_TYPE (PangoWin32FontMap, pango_win32_font_map, PANGO_TYPE_FONT_MAP) (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c)) static guint -case_insensitive_hash (const char *key) +case_insensitive_str_hash (const char *key) { const char *p = key; guint h = TOLOWER (*p); @@ -111,37 +112,63 @@ case_insensitive_hash (const char *key) } static gboolean -case_insensitive_equal (const char *key1, - const char *key2) +case_insensitive_str_equal (const char *key1, + const char *key2) { - return (g_ascii_strcasecmp (key1, key2) == 0); + while (*key1 && *key2 && TOLOWER (*key1) == TOLOWER (*key2)) + key1++, key2++; + return (!*key1 && !*key2); } -/* A hash function for LOGFONTs that takes into consideration only +static guint +case_insensitive_wcs_hash (const wchar_t *key) +{ + const wchar_t *p = key; + guint h = TOLOWER (*p); + + if (h) + { + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + TOLOWER (*p); + } + + return h; +} + +static gboolean +case_insensitive_wcs_equal (const wchar_t *key1, + const wchar_t *key2) +{ + while (*key1 && *key2 && TOLOWER (*key1) == TOLOWER (*key2)) + key1++, key2++; + return (!*key1 && !*key2); +} + +/* A hash function for LOGFONTWs that takes into consideration only * those fields that indicate a specific .ttf file is in use: * lfFaceName, lfItalic and lfWeight. Dunno how correct this is. */ static guint -logfont_nosize_hash (const LOGFONT *lfp) +logfontw_nosize_hash (const LOGFONTW *lfp) { - return case_insensitive_hash (lfp->lfFaceName) + lfp->lfItalic + lfp->lfWeight; + return case_insensitive_wcs_hash (lfp->lfFaceName) + (lfp->lfItalic != 0) + lfp->lfWeight; } /* Ditto comparison function */ static gboolean -logfont_nosize_equal (const LOGFONT *lfp1, - const LOGFONT *lfp2) +logfontw_nosize_equal (const LOGFONTW *lfp1, + const LOGFONTW *lfp2) { - return (case_insensitive_equal (lfp1->lfFaceName, lfp2->lfFaceName) - && lfp1->lfItalic == lfp2->lfItalic + return (case_insensitive_wcs_equal (lfp1->lfFaceName, lfp2->lfFaceName) + && (lfp1->lfItalic != 0) == (lfp2->lfItalic != 0) && lfp1->lfWeight == lfp2->lfWeight); } static int CALLBACK -pango_win32_inner_enum_proc (LOGFONT *lfp, - TEXTMETRIC *metrics, - DWORD fontType, - LPARAM lParam) +pango_win32_inner_enum_proc (LOGFONTW *lfp, + TEXTMETRICW *metrics, + DWORD fontType, + LPARAM lParam) { PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)lParam; @@ -155,41 +182,27 @@ pango_win32_inner_enum_proc (LOGFONT *lfp, } static int CALLBACK -pango_win32_enum_proc (LOGFONT *lfp, - TEXTMETRIC *metrics, - DWORD fontType, - LPARAM lParam) +pango_win32_enum_proc (LOGFONTW *lfp, + TEXTMETRICW *metrics, + DWORD fontType, + LPARAM lParam) { - LOGFONT lf; + LOGFONTW lf; - PING(("%s", lfp->lfFaceName)); + PING(("%S", lfp->lfFaceName)); if (fontType != TRUETYPE_FONTTYPE) return 1; lf = *lfp; - EnumFontFamiliesExA (pango_win32_hdc, &lf, - (FONTENUMPROC) pango_win32_inner_enum_proc, + EnumFontFamiliesExW (pango_win32_hdc, &lf, + (FONTENUMPROCW) pango_win32_inner_enum_proc, lParam, 0); return 1; } -static gboolean -first_match (gpointer key, - gpointer value, - gpointer user_data) -{ - LOGFONT *lfp = (LOGFONT *)key; - LOGFONT *lfp2 = (LOGFONT *)((PangoWin32SizeInfo *)value)->logfonts->data; - gchar *name = (gchar *)user_data; - - if (strcmp (lfp->lfFaceName, name) == 0 && lfp->lfWeight == lfp2->lfWeight) - return TRUE; - return FALSE; -} - typedef struct _ItalicHelper { PangoWin32FontMap *fontmap; @@ -202,42 +215,41 @@ ensure_italic (gpointer key, gpointer user_data) { ItalicHelper *helper = (ItalicHelper *)user_data; - /* PangoWin32Family *win32family = (PangoWin32Family *)value; */ + PangoWin32SizeInfo *sip = (PangoWin32SizeInfo *) value; + GSList *list = sip->logfontws; - PangoWin32SizeInfo *sip = (PangoWin32SizeInfo *)g_hash_table_find (helper->fontmap->size_infos, first_match, key); - if (sip) + while (list) { - GSList *list = sip->logfonts; - - while (list) + LOGFONTW *lfp = (LOGFONTW *) list->data; + PING(("%S it=%d wt=%ld", lfp->lfFaceName, lfp->lfItalic, lfp->lfWeight)); + if (!lfp->lfItalic) { - LOGFONT *lfp = (LOGFONT *)list->data; - if (!lfp->lfItalic) + /* we have a non italic variant, look if there is an italic */ + LOGFONTW logfontw = *lfp; + logfontw.lfItalic = 1; + sip = (PangoWin32SizeInfo *) g_hash_table_lookup (helper->fontmap->size_infos, &logfontw); + if (!sip) { - /* we have a non italic variant, look if there is an italic */ - LOGFONT logfont = *lfp; - logfont.lfItalic = 1; - sip = (PangoWin32SizeInfo *)g_hash_table_find (helper->fontmap->size_infos, first_match, &logfont); - if (!sip) - { - /* remember the non italic variant to be added later as italic */ - helper->list = g_slist_append (helper->list, lfp); - } + /* remember the non italic variant to be added later as italic */ + PING(("synthesizing italic")); + helper->list = g_slist_append (helper->list, lfp); } - list = list->next; } + list = list->next; } } static void pango_win32_font_map_init (PangoWin32FontMap *win32fontmap) { - LOGFONT logfont; + LOGFONTW logfont; + ItalicHelper helper = { win32fontmap, NULL }; + GSList *list; - win32fontmap->families = g_hash_table_new ((GHashFunc) case_insensitive_hash, - (GEqualFunc) case_insensitive_equal); + win32fontmap->families = g_hash_table_new ((GHashFunc) case_insensitive_str_hash, + (GEqualFunc) case_insensitive_str_equal); win32fontmap->size_infos = - g_hash_table_new ((GHashFunc) logfont_nosize_hash, (GEqualFunc) logfont_nosize_equal); + g_hash_table_new ((GHashFunc) logfontw_nosize_hash, (GEqualFunc) logfontw_nosize_equal); win32fontmap->n_fonts = 0; win32fontmap->font_cache = pango_win32_font_cache_new (); @@ -245,26 +257,23 @@ pango_win32_font_map_init (PangoWin32FontMap *win32fontmap) memset (&logfont, 0, sizeof (logfont)); logfont.lfCharSet = DEFAULT_CHARSET; - EnumFontFamiliesExA (pango_win32_hdc, &logfont, (FONTENUMPROC) pango_win32_enum_proc, - (LPARAM)win32fontmap, 0); - - /* create synthetic italic entries */ - { - ItalicHelper helper = { win32fontmap, NULL }; - GSList *list; - - g_hash_table_foreach (win32fontmap->families, ensure_italic, &helper); - /* cant modify while iterating */ - list = helper.list; - while (list) - { - LOGFONT logfont = *((LOGFONT *)list->data); - logfont.lfItalic = 1; - pango_win32_insert_font (win32fontmap, &logfont); - list = list->next; - } - g_slist_free (helper.list); - } + EnumFontFamiliesExW (pango_win32_hdc, &logfont, + (FONTENUMPROCW) pango_win32_enum_proc, + (LPARAM) win32fontmap, 0); + + /* Create synthetic italic entries */ + g_hash_table_foreach (win32fontmap->size_infos, ensure_italic, &helper); + + /* Can't modify while iterating */ + list = helper.list; + while (list) + { + LOGFONTW logfontw = *((LOGFONTW *)list->data); + logfontw.lfItalic = 1; + pango_win32_insert_font (win32fontmap, &logfontw); + list = list->next; + } + g_slist_free (helper.list); win32fontmap->resolution = (PANGO_SCALE / (double) GetDeviceCaps (pango_win32_hdc, LOGPIXELSY)) * 72.0; } @@ -540,7 +549,7 @@ pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, if (pango_font_description_get_size_is_absolute (description)) size = (int) 0.5 + (size * win32fontmap->resolution) / PANGO_SCALE; - PING(("got best match:%s size=%d",face->logfont.lfFaceName,size)); + PING(("got best match:%S size=%d",face->logfontw.lfFaceName,size)); while (tmp_list) { @@ -558,7 +567,7 @@ pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, tmp_list = tmp_list->next; } - win32font = pango_win32_font_new (fontmap, &face->logfont, size); + win32font = pango_win32_font_neww (fontmap, &face->logfontw, size); if (!win32font) return NULL; @@ -571,7 +580,7 @@ pango_win32_font_map_real_find_font (PangoWin32FontMap *win32fontmap, } static gchar * -get_family_name (const LOGFONT *lfp) +get_family_nameA (const LOGFONTA *lfp) { HFONT hfont; HFONT oldhfont; @@ -696,13 +705,13 @@ get_family_name (const LOGFONT *lfp) /** * pango_win32_font_description_from_logfont: - * @lfp: a LOGFONT + * @lfp: a LOGFONTA * - * Creates a #PangoFontDescription that matches the specified LOGFONT. + * Creates a #PangoFontDescription that matches the specified LOGFONTA. * - * The face name, italicness and weight fields in the LOGFONT are used + * The face name, italicness and weight fields in the LOGFONTA are used * to set up the resulting #PangoFontDescription. If the face name in - * the LOGFONT contains non-ASCII characters the font is temporarily + * the LOGFONTA contains non-ASCII characters the font is temporarily * loaded (using CreateFontIndirect()) and an ASCII (usually English) * name for it is looked up from the font name tables in the font * data. If that doesn't work, the face name is converted from the @@ -723,7 +732,201 @@ pango_win32_font_description_from_logfont (const LOGFONT *lfp) PangoWeight weight; PangoStretch stretch; - family = get_family_name (lfp); + family = get_family_nameA (lfp); + + if (!lfp->lfItalic) + style = PANGO_STYLE_NORMAL; + else + style = PANGO_STYLE_ITALIC; + + variant = PANGO_VARIANT_NORMAL; + + /* The PangoWeight values PANGO_WEIGHT_* map exactly do Windows FW_* + * values. Is this on purpose? Quantize the weight to exact + * PANGO_WEIGHT_* values. Is this a good idea? + */ + if (lfp->lfWeight == FW_DONTCARE) + weight = PANGO_WEIGHT_NORMAL; + else if (lfp->lfWeight <= (FW_ULTRALIGHT + FW_LIGHT) / 2) + weight = PANGO_WEIGHT_ULTRALIGHT; + else if (lfp->lfWeight <= (FW_LIGHT + FW_NORMAL) / 2) + weight = PANGO_WEIGHT_LIGHT; + else if (lfp->lfWeight <= (FW_NORMAL + FW_BOLD) / 2) + weight = PANGO_WEIGHT_NORMAL; + else if (lfp->lfWeight <= (FW_BOLD + FW_ULTRABOLD) / 2) + weight = PANGO_WEIGHT_BOLD; + else if (lfp->lfWeight <= (FW_ULTRABOLD + FW_HEAVY) / 2) + weight = PANGO_WEIGHT_ULTRABOLD; + else + weight = PANGO_WEIGHT_HEAVY; + + /* XXX No idea how to figure out the stretch */ + stretch = PANGO_STRETCH_NORMAL; + + description = pango_font_description_new (); + pango_font_description_set_family (description, family); + pango_font_description_set_style (description, style); + pango_font_description_set_weight (description, weight); + pango_font_description_set_stretch (description, stretch); + pango_font_description_set_variant (description, variant); + + return description; +} + +static gchar * +get_family_nameW (const LOGFONTW *lfp) +{ + HFONT hfont; + HFONT oldhfont; + + struct name_header header; + struct name_record record; + + gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1; + gint name_ix; + gchar *codeset; + + gchar *string = NULL; + gchar *name; + + gint i, l; + gsize nbytes; + + /* If lfFaceName is ASCII, assume it is the common (English) name + * for the font. Is this valid? Do some TrueType fonts have + * different names in French, German, etc, and does the system + * return these if the locale is set to use French, German, etc? + */ + l = wcslen (lfp->lfFaceName); + for (i = 0; i < l; i++) + if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~') + break; + + if (i == l) + return g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); + + if ((hfont = CreateFontIndirectW (lfp)) == NULL) + goto fail0; + + if ((oldhfont = SelectObject (pango_win32_hdc, hfont)) == NULL) + goto fail1; + + if (!pango_win32_get_name_header (pango_win32_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)) + goto fail2; + + if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0) + continue; + + PING(("platform:%d encoding:%d language:%04x name_id:%d", + record.platform_id, record.encoding_id, record.language_id, record.name_id)); + + if (record.platform_id == APPLE_UNICODE_PLATFORM_ID || + record.platform_id == ISO_PLATFORM_ID) + unicode_ix = i; + else if (record.platform_id == MACINTOSH_PLATFORM_ID && + record.encoding_id == 0 && /* Roman */ + record.language_id == 0) /* English */ + mac_ix = i; + else if (record.platform_id == MICROSOFT_PLATFORM_ID) + if ((microsoft_ix == -1 || + PRIMARYLANGID (record.language_id) == LANG_ENGLISH) && + (record.encoding_id == SYMBOL_ENCODING_ID || + record.encoding_id == UNICODE_ENCODING_ID || + record.encoding_id == UCS4_ENCODING_ID)) + microsoft_ix = i; + } + + if (microsoft_ix >= 0) + name_ix = microsoft_ix; + else if (mac_ix >= 0) + name_ix = mac_ix; + else if (unicode_ix >= 0) + name_ix = unicode_ix; + else + goto fail2; + + if (!pango_win32_get_name_record (pango_win32_hdc, name_ix, &record)) + goto fail2; + + string = g_malloc (record.string_length + 1); + if (GetFontData (pango_win32_hdc, NAME, + header.string_storage_offset + record.string_offset, + string, record.string_length) != record.string_length) + goto fail2; + + string[record.string_length] = '\0'; + + if (name_ix == microsoft_ix) + if (record.encoding_id == SYMBOL_ENCODING_ID || + record.encoding_id == UNICODE_ENCODING_ID) + codeset = "UTF-16BE"; + else + codeset = "UCS-4BE"; + else if (name_ix == mac_ix) + codeset = "MacRoman"; + else /* name_ix == unicode_ix */ + codeset = "UCS-4BE"; + + name = g_convert (string, record.string_length, "UTF-8", codeset, NULL, &nbytes, NULL); + if (name == NULL) + goto fail2; + g_free (string); + + PING(("%s", name)); + + SelectObject (pango_win32_hdc, oldhfont); + DeleteObject (hfont); + + return name; + + fail2: + g_free (string); + SelectObject (pango_win32_hdc, oldhfont); + + fail1: + DeleteObject (hfont); + + fail0: + return g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); +} + +/** + * pango_win32_font_description_from_logfontw: + * @lfp: a LOGFONTW + * + * Creates a #PangoFontDescription that matches the specified LOGFONTW. + * + * The face name, italicness and weight fields in the LOGFONTW are used + * to set up the resulting #PangoFontDescription. If the face name in + * the LOGFONTW contains non-ASCII characters the font is temporarily + * loaded (using CreateFontIndirect()) and an ASCII (usually English) + * name for it is looked up from the font name tables in the font + * data. If that doesn't work, the face name is converted from UTF-16 + * to UTF-8 and that is used. + * + * Return value: the newly allocated #PangoFontDescription, which + * should be freed using pango_font_description_free() + * + * Since: 1.16 + */ +PangoFontDescription * +pango_win32_font_description_from_logfontw (const LOGFONTW *lfp) +{ + PangoFontDescription *description; + gchar *family; + PangoStyle style; + PangoVariant variant; + PangoWeight weight; + PangoStretch stretch; + + family = get_family_nameW (lfp); if (!lfp->lfItalic) style = PANGO_STYLE_NORMAL; @@ -764,24 +967,26 @@ pango_win32_font_description_from_logfont (const LOGFONT *lfp) return description; } -/* This inserts the given font into the size_infos table. If a SizeInfo - * already exists with the same typeface name, then the font is added - * to the SizeInfos list, else a new SizeInfo is created and inserted - * in the table. + +/* This inserts the given font into the size_infos table. If a + * SizeInfo already exists with the same typeface name, italicness and + * weight, then the font is added to the SizeInfo's list, else a + * new SizeInfo is created and inserted in the table. */ static void pango_win32_insert_font (PangoWin32FontMap *win32fontmap, - LOGFONT *lfp) + LOGFONTW *lfp) { - LOGFONT *lfp2 = NULL; + LOGFONTW *lfp2 = NULL; PangoFontDescription *description; PangoWin32Family *font_family; PangoWin32Face *win32face; PangoWin32SizeInfo *size_info; GSList *tmp_list; gint i; + gchar *p; - PING(("face=%s,charset=%d,it=%d,wt=%ld,ht=%ld",lfp->lfFaceName,lfp->lfCharSet,lfp->lfItalic,lfp->lfWeight,lfp->lfHeight)); + PING(("face=%S,charset=%d,it=%d,wt=%ld,ht=%ld",lfp->lfFaceName,lfp->lfCharSet,lfp->lfItalic,lfp->lfWeight,lfp->lfHeight)); /* Ignore Symbol fonts (which don't have any Unicode mapping * table). We could also be fancy and use the PostScript glyph name @@ -791,27 +996,28 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, if (lfp->lfCharSet == SYMBOL_CHARSET) return; - /* First insert the LOGFONT into the list of LOGFONTs for the typeface name + /* First insert the LOGFONTW into the list of LOGFONTWs for the + * typeface name, italicness and weight. */ size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); if (!size_info) { PING(("SizeInfo not found")); size_info = g_new (PangoWin32SizeInfo, 1); - size_info->logfonts = NULL; + size_info->logfontws = NULL; - lfp2 = g_new (LOGFONT, 1); + lfp2 = g_new (LOGFONTW, 1); *lfp2 = *lfp; g_hash_table_insert (win32fontmap->size_infos, lfp2, size_info); } else { - /* Don't store logfonts that differ only in charset + /* Don't store LOGFONTWs that differ only in charset */ - tmp_list = size_info->logfonts; + tmp_list = size_info->logfontws; while (tmp_list) { - LOGFONT *rover = tmp_list->data; + LOGFONTW *rover = tmp_list->data; /* We know that lfWeight, lfItalic and lfFaceName match. We * don't check lfHeight and lfWidth, those are used @@ -832,15 +1038,15 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, if (lfp2 == NULL) { - lfp2 = g_new (LOGFONT, 1); + lfp2 = g_new (LOGFONTW, 1); *lfp2 = *lfp; } - size_info->logfonts = g_slist_prepend (size_info->logfonts, lfp2); + size_info->logfontws = g_slist_prepend (size_info->logfontws, lfp2); - PING(("g_slist_length(size_info->logfonts)=%d", g_slist_length(size_info->logfonts))); + PING(("g_slist_length(size_info->logfontws)=%d", g_slist_length(size_info->logfontws))); - description = pango_win32_font_description_from_logfont (lfp2); + description = pango_win32_font_description_from_logfontw (lfp2); /* In some cases, extracting a name for a font can fail; such fonts * aren't usable for us @@ -858,7 +1064,7 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, for (i = 0; i < PANGO_WIN32_N_COVERAGES; i++) win32face->coverages[i] = NULL; - win32face->logfont = *lfp; + win32face->logfontw = *lfp; win32face->cmap_format = 0; win32face->cmap = NULL; @@ -905,31 +1111,33 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, /* Some other magic names */ /* Recognize just "courier" for "courier new" */ - if (g_ascii_strcasecmp (win32face->logfont.lfFaceName, "courier new") == 0) + p = g_utf16_to_utf8 (win32face->logfontw.lfFaceName, -1, NULL, NULL, NULL); + if (p && g_ascii_strcasecmp (p, "courier new") == 0) { font_family = pango_win32_get_font_family (win32fontmap, "courier"); font_family->font_entries = g_slist_append (font_family->font_entries, win32face); win32fontmap->n_fonts++; } + g_free (p); #endif } -/* Given a LOGFONT and size, make a matching LOGFONT corresponding to +/* Given a LOGFONTW and size, make a matching LOGFONTW corresponding to * an installed font. */ void -pango_win32_make_matching_logfont (PangoFontMap *fontmap, - const LOGFONT *lfp, - int size, - LOGFONT *out) +pango_win32_make_matching_logfontw (PangoFontMap *fontmap, + const LOGFONTW *lfp, + int size, + LOGFONTW *out) { PangoWin32FontMap *win32fontmap; GSList *tmp_list; PangoWin32SizeInfo *size_info; - LOGFONT *closest_match = NULL; + LOGFONTW *closest_match = NULL; gint match_distance = 0; - PING(("lfp.face=%s,wt=%ld,ht=%ld,size:%d",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight,size)); + PING(("lfp.face=%S,wt=%ld,ht=%ld,size:%d",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight,size)); win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); @@ -940,11 +1148,11 @@ pango_win32_make_matching_logfont (PangoFontMap *fontmap, return; } - tmp_list = size_info->logfonts; + tmp_list = size_info->logfontws; while (tmp_list) { - LOGFONT *tmp_logfont = tmp_list->data; - int font_size = abs (tmp_logfont->lfHeight); + LOGFONTW *tmp_logfontw = tmp_list->data; + int font_size = abs (tmp_logfontw->lfHeight); if (size != -1) { @@ -954,7 +1162,7 @@ pango_win32_make_matching_logfont (PangoFontMap *fontmap, new_distance < match_distance || (new_distance < PANGO_SCALE && font_size != 0)) { - closest_match = tmp_logfont; + closest_match = tmp_logfontw; match_distance = new_distance; } } diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h index 504e3c24..d91452be 100644 --- a/pango/pangowin32-private.h +++ b/pango/pangowin32-private.h @@ -98,7 +98,7 @@ struct _PangoWin32FontMap /* Map Pango family names to PangoWin32Family structs */ GHashTable *families; - /* Map LOGFONTS (taking into account only the lfFaceName, lfItalic + /* Map LOGFONTWs (taking into account only the lfFaceName, lfItalic * and lfWeight fields) to PangoWin32SizeInfo structs. */ GHashTable *size_infos; @@ -123,7 +123,7 @@ struct _PangoWin32Font { PangoFont font; - LOGFONT logfont; + LOGFONTW logfontw; int size; GSList *metrics_by_lang; @@ -159,7 +159,7 @@ struct _PangoWin32Face { PangoFontFace parent_instance; - LOGFONT logfont; + LOGFONTW logfontw; PangoFontDescription *description; PangoCoverage *coverages[PANGO_WIN32_N_COVERAGES]; char *face_name; @@ -258,14 +258,14 @@ struct name_record GType pango_win32_font_get_type (void); -PangoWin32Font *pango_win32_font_new (PangoFontMap *fontmap, - const LOGFONT *lfp, +PangoWin32Font *pango_win32_font_neww (PangoFontMap *fontmap, + const LOGFONTW *lfp, int size); PangoMap * pango_win32_get_shaper_map (PangoLanguage *lang); -void pango_win32_make_matching_logfont (PangoFontMap *fontmap, - const LOGFONT *lfp, +void pango_win32_make_matching_logfontw (PangoFontMap *fontmap, + const LOGFONTW *lfp, int size, - LOGFONT *out); + LOGFONTW *out); PangoCoverage * pango_win32_font_entry_get_coverage (PangoWin32Face *face, PangoLanguage *lang); void pango_win32_font_entry_set_coverage (PangoWin32Face *face, diff --git a/pango/pangowin32.c b/pango/pangowin32.c index b34182ae..c3aabb27 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -4,6 +4,7 @@ * Copyright (C) 1999 Red Hat Software * Copyright (C) 2000 Tor Lillqvist * Copyright (C) 2001 Alexander Larsson + * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -93,11 +94,11 @@ pango_win32_get_hfont (PangoFont *font) { cache = pango_win32_font_map_get_font_cache (win32font->fontmap); - win32font->hfont = pango_win32_font_cache_load (cache, &win32font->logfont); + win32font->hfont = pango_win32_font_cache_loadw (cache, &win32font->logfontw); if (!win32font->hfont) { - gchar *face_utf8 = g_locale_to_utf8 (win32font->logfont.lfFaceName, - -1, NULL, NULL, NULL); + gchar *face_utf8 = g_utf16_to_utf8 (win32font->logfontw.lfFaceName, + -1, NULL, NULL, NULL); g_warning ("Cannot load font '%s\n", face_utf8); g_free (face_utf8); return NULL; @@ -216,9 +217,9 @@ pango_win32_font_class_init (PangoWin32FontClass *class) } PangoWin32Font * -pango_win32_font_new (PangoFontMap *fontmap, - const LOGFONT *lfp, - int size) +pango_win32_font_neww (PangoFontMap *fontmap, + const LOGFONTW *lfp, + int size) { PangoWin32Font *result; @@ -231,8 +232,7 @@ pango_win32_font_new (PangoFontMap *fontmap, g_object_ref (fontmap); result->size = size; - pango_win32_make_matching_logfont (fontmap, lfp, size, - &result->logfont); + pango_win32_make_matching_logfontw (fontmap, lfp, size, &result->logfontw); return result; } @@ -676,22 +676,60 @@ pango_win32_font_real_get_metrics_factor (PangoFont *font) * pango_win32_font_logfont: * @font: a #PangoFont which must be from the Win32 backend * - * Determine the LOGFONT struct for the specified font. + * Determine the LOGFONTA struct for the specified font. Note that + * Pango internally uses LOGFONTW structs, so if converting the UTF-16 + * face name in the LOGFONTW struct to system codepage fails, the + * returned LOGFONTA will have an emppty face name. To get the + * LOGFONTW of a PangoFont, use pango_win32_font_logfontw(). It + * is recommended to do that always even if you don't expect + * to come across fonts with odd names. * - * Return value: A newly allocated LOGFONT struct. It must be + * Return value: A newly allocated LOGFONTA struct. It must be * freed with g_free(). **/ -LOGFONT * +LOGFONTA * pango_win32_font_logfont (PangoFont *font) { PangoWin32Font *win32font = (PangoWin32Font *)font; - LOGFONT *lfp; + LOGFONTA *lfp; g_return_val_if_fail (font != NULL, NULL); g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), NULL); - lfp = g_new (LOGFONT, 1); - *lfp = win32font->logfont; + lfp = g_new (LOGFONTA, 1); + + *lfp = *(LOGFONTA*) &win32font->logfontw; + if (!WideCharToMultiByte (CP_ACP, 0, + win32font->logfontw.lfFaceName, -1, + lfp->lfFaceName, G_N_ELEMENTS (lfp->lfFaceName), + NULL, NULL)) + lfp->lfFaceName[0] = '\0'; + + return lfp; +} + +/** + * pango_win32_font_logfontw: + * @font: a #PangoFont which must be from the Win32 backend + * + * Determine the LOGFONTW struct for the specified font. + * + * Return value: A newly allocated LOGFONTW struct. It must be + * freed with g_free(). + * + *Since: 1.16 + **/ +LOGFONTW * +pango_win32_font_logfontw (PangoFont *font) +{ + PangoWin32Font *win32font = (PangoWin32Font *)font; + LOGFONTW *lfp; + + g_return_val_if_fail (font != NULL, NULL); + g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), NULL); + + lfp = g_new (LOGFONTW, 1); + *lfp = win32font->logfontw; return lfp; } diff --git a/pango/pangowin32.def b/pango/pangowin32.def index 65d62c4f..0940d7d3 100644 --- a/pango/pangowin32.def +++ b/pango/pangowin32.def @@ -1,9 +1,11 @@ EXPORTS pango_win32_font_cache_free pango_win32_font_cache_load + pango_win32_font_cache_loadw pango_win32_font_cache_new pango_win32_font_cache_unload pango_win32_font_description_from_logfont + pango_win32_font_description_from_logfontw pango_win32_font_entry_get_coverage pango_win32_font_entry_remove pango_win32_font_get_glyph_index @@ -12,7 +14,7 @@ EXPORTS pango_win32_font_map_for_display pango_win32_font_map_get_font_cache pango_win32_font_map_get_type - pango_win32_font_new + pango_win32_font_neww pango_win32_font_logfont pango_win32_font_done_font pango_win32_font_get_metrics_factor @@ -24,7 +26,7 @@ EXPORTS pango_win32_get_debug_flag pango_win32_get_shaper_map pango_win32_get_unknown_glyph - pango_win32_make_matching_logfont + pango_win32_make_matching_logfontw pango_win32_render pango_win32_render_layout pango_win32_render_layout_line diff --git a/pango/pangowin32.h b/pango/pangowin32.h index 18293993..8e07218e 100644 --- a/pango/pangowin32.h +++ b/pango/pangowin32.h @@ -96,7 +96,9 @@ PangoWin32FontCache *pango_win32_font_cache_new (void); void pango_win32_font_cache_free (PangoWin32FontCache *cache); HFONT pango_win32_font_cache_load (PangoWin32FontCache *cache, - const LOGFONT *logfont); + const LOGFONTA *logfont); +HFONT pango_win32_font_cache_loadw (PangoWin32FontCache *cache, + const LOGFONTW *logfont); void pango_win32_font_cache_unload (PangoWin32FontCache *cache, HFONT hfont); @@ -104,9 +106,12 @@ PangoFontMap *pango_win32_font_map_for_display (void); void pango_win32_shutdown_display (void); PangoWin32FontCache *pango_win32_font_map_get_font_cache (PangoFontMap *font_map); -LOGFONT *pango_win32_font_logfont (PangoFont *font); +LOGFONTA *pango_win32_font_logfont (PangoFont *font); +LOGFONTW *pango_win32_font_logfontw (PangoFont *font); -PangoFontDescription *pango_win32_font_description_from_logfont (const LOGFONT *lfp); +PangoFontDescription *pango_win32_font_description_from_logfont (const LOGFONTA *lfp); + +PangoFontDescription *pango_win32_font_description_from_logfontw (const LOGFONTW *lfp); G_END_DECLS |