diff options
author | Tor Lillqvist <tml@novell.com> | 2005-04-28 12:05:42 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 2005-04-28 12:05:42 +0000 |
commit | 4a3c59e65bf14ab441574503021c0daff9af3e76 (patch) | |
tree | 32b46a51aff04254df6940071d7c22bca5925762 /pango | |
parent | ea07aa3da32d81825a62313a4788868aa95bad99 (diff) | |
download | pango-4a3c59e65bf14ab441574503021c0daff9af3e76.tar.gz |
Add support to pangowin32 for TrueType fonts covering more than the BMP.
2005-04-28 Tor Lillqvist <tml@novell.com>
Add support to pangowin32 for TrueType fonts covering more than
the BMP. Fix handling of surrogate pairs in the Uniscribe
shaper. (#302238)
* pango/pangowin32-private.h (PangoWin32Face): Rename the
unicode_table field to cmap. Keep track of its format (4 or 12).
(format_12_cmap): Add struct for a format 12 cmap.
* pango/pangowin32.c: Corresponding changes. Rename internal
functions a bit.
(get_format_12_cmap): New function, reads a format 12 cmap.
(font_get_cmap): Look for both format 12 (which is preferred) and
format 4 cmaps.
(pango_win32_font_get_glyph_index,
pango_win32_font_calc_coverage): Handle also format 12 cmaps.
* modules/basic/basic-win32.c: Handle surrogate pairs in wchar_t
strings properly.
(unichar_index): New function. Given a wchar_t string and an index
into it, calculate the index of the corresponding Unicode
character. Each surrogate pair in the wchar_t is just one Unicode
character.
(set_up_pango_log_clusters, itemize_shape_and_place): Use
unichar_index() instead of direct index into wchar_t string.
Diffstat (limited to 'pango')
-rw-r--r-- | pango/pangowin32-fontmap.c | 6 | ||||
-rw-r--r-- | pango/pangowin32-private.h | 22 | ||||
-rw-r--r-- | pango/pangowin32.c | 358 |
3 files changed, 259 insertions, 127 deletions
diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index 92bf7f64..e71fefd7 100644 --- a/pango/pangowin32-fontmap.c +++ b/pango/pangowin32-fontmap.c @@ -192,12 +192,13 @@ pango_win32_enum_proc (LOGFONT *lfp, { LOGFONT lf; + PING(("%s", lfp->lfFaceName)); + if (fontType != TRUETYPE_FONTTYPE) return 1; lf = *lfp; - PING(("%s", lf.lfFaceName)); EnumFontFamiliesExA (pango_win32_hdc, &lf, (FONTENUMPROC) pango_win32_inner_enum_proc, lParam, 0); @@ -769,7 +770,8 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, for (i = 0; i < PANGO_WIN32_N_COVERAGES; i++) win32face->coverages[i] = NULL; win32face->logfont = *lfp; - win32face->unicode_table = NULL; + win32face->cmap_format = 0; + win32face->cmap = NULL; font_family->font_entries = g_slist_append (font_family->font_entries, win32face); win32fontmap->n_fonts++; diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h index e51f2d55..a7a7b159 100644 --- a/pango/pangowin32-private.h +++ b/pango/pangowin32-private.h @@ -103,7 +103,8 @@ struct _PangoWin32Face PangoCoverage *coverages[PANGO_WIN32_N_COVERAGES]; char *face_name; - gpointer unicode_table; + guint16 cmap_format; + gpointer cmap; GSList *cached_fonts; }; @@ -137,15 +138,17 @@ struct _PangoWin32GlyphInfo #define UNICODE_ENCODING_ID 1 #define UCS4_ENCODING_ID 10 +/* All the below structs must be packed! */ + struct cmap_encoding_subtable -{ /* Must be packed! */ +{ guint16 platform_id; guint16 encoding_id; guint32 offset; }; -struct type_4_cmap -{ /* Must be packed! */ +struct format_4_cmap +{ guint16 format; guint16 length; guint16 language; @@ -159,6 +162,17 @@ struct type_4_cmap guint16 arrays[1]; }; +struct format_12_cmap +{ + guint16 format; + guint16 reserved; + guint32 length; + guint32 language; + guint32 count; + + guint32 groups[1]; +}; + struct name_header { guint16 format_selector; diff --git a/pango/pangowin32.c b/pango/pangowin32.c index 62af6bdd..2cf613f9 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -41,6 +41,11 @@ #define PANGO_WIN32_UNKNOWN_FLAG 0x10000000 +#define CH_IS_UNIHAN_BMP(ch) ((ch) >= 0x3400 && (ch) <= 0x9FFF) +#define CH_IS_UNIHAN(ch) (CH_IS_UNIHAN_BMP (ch) || \ + ((ch) >= 0x20000 && (ch) <= 0x2A6DF) || \ + ((ch) >= 0x2F800 && (ch) <= 0x2FA1F)) + HDC pango_win32_hdc; OSVERSIONINFO pango_win32_os_version_info; gboolean pango_win32_debug = FALSE; @@ -994,7 +999,8 @@ pango_win32_get_item_properties (PangoItem *item, } static guint -get_unicode_mapping_offset (HDC hdc) +get_cmap_offset (HDC hdc, + guint16 encoding_id) { guint16 n_tables; struct cmap_encoding_subtable *table; @@ -1003,8 +1009,8 @@ get_unicode_mapping_offset (HDC hdc) guint32 offset; /* Get The number of encoding tables, at offset 2 */ - res = GetFontData (hdc, CMAP, 2, &n_tables, sizeof (guint16)); - if (res != sizeof (guint16)) + res = GetFontData (hdc, CMAP, 2, &n_tables, 2); + if (res != 2) return 0; n_tables = GUINT16_FROM_BE (n_tables); @@ -1018,7 +1024,7 @@ get_unicode_mapping_offset (HDC hdc) for (i = 0; i < n_tables; i++) { if (table[i].platform_id == GUINT16_TO_BE (MICROSOFT_PLATFORM_ID) && - table[i].encoding_id == GUINT16_TO_BE (UNICODE_ENCODING_ID)) + table[i].encoding_id == GUINT16_TO_BE (encoding_id)) { offset = GUINT32_FROM_BE (table[i].offset); g_free (table); @@ -1029,31 +1035,33 @@ get_unicode_mapping_offset (HDC hdc) return 0; } -static struct type_4_cmap * -get_unicode_mapping (HDC hdc) +static gpointer +get_format_4_cmap (HDC hdc) { guint32 offset; guint32 res; guint16 length; guint16 *tbl, *tbl_end; - struct type_4_cmap *table; + struct format_4_cmap *table; /* FIXME: Could look here at the CRC for the font in the DC and return a cached copy if the same */ - offset = get_unicode_mapping_offset (hdc); + offset = get_cmap_offset (hdc, UNICODE_ENCODING_ID); if (offset == 0) return NULL; - res = GetFontData (hdc, CMAP, offset + 2, &length, sizeof (guint16)); - if (res != sizeof (guint16)) + res = GetFontData (hdc, CMAP, offset + 2, &length, 2); + if (res != 2) return NULL; length = GUINT16_FROM_BE (length); table = g_malloc (length); res = GetFontData (hdc, CMAP, offset, table, length); - if (res != length) + if (res != length || + GUINT16_FROM_BE (table->format) != 4 || + (GUINT16_FROM_BE (table->length) % 2) != 0) { g_free (table); return NULL; @@ -1067,12 +1075,6 @@ get_unicode_mapping (HDC hdc) table->entry_selector = GUINT16_FROM_BE (table->entry_selector); table->range_shift = GUINT16_FROM_BE (table->range_shift); - if (table->format != 4) - { - g_free (table); - return NULL; - } - tbl_end = (guint16 *)((char *)table + length); tbl = &table->reserved; @@ -1086,28 +1088,28 @@ get_unicode_mapping (HDC hdc) } static guint16 * -get_id_range_offset (struct type_4_cmap *table) +get_id_range_offset (struct format_4_cmap *table) { gint32 seg_count = table->seg_count_x_2/2; return &table->arrays[seg_count*3]; } static guint16 * -get_id_delta (struct type_4_cmap *table) +get_id_delta (struct format_4_cmap *table) { gint32 seg_count = table->seg_count_x_2/2; return &table->arrays[seg_count*2]; } static guint16 * -get_start_count (struct type_4_cmap *table) +get_start_count (struct format_4_cmap *table) { gint32 seg_count = table->seg_count_x_2/2; return &table->arrays[seg_count*1]; } static guint16 * -get_end_count (struct type_4_cmap *table) +get_end_count (struct format_4_cmap *table) { gint32 seg_count = table->seg_count_x_2/2; /* Apparently the reseved spot is not reserved for @@ -1115,11 +1117,10 @@ get_end_count (struct type_4_cmap *table) return (&table->arrays[seg_count*0])-1; } - static gboolean -find_segment (struct type_4_cmap *table, - guint16 wc, - guint16 *segment) +find_segment (struct format_4_cmap *table, + guint16 wc, + guint16 *segment) { guint16 start, end, i; guint16 seg_count = table->seg_count_x_2/2; @@ -1177,23 +1178,85 @@ find_segment (struct type_4_cmap *table, return FALSE; } -static struct type_4_cmap * -font_get_unicode_table (PangoFont *font) +static gpointer +get_format_12_cmap (HDC hdc) +{ + guint32 offset; + guint32 res; + guint32 length; + guint32 *tbl, *tbl_end; + struct format_12_cmap *table; + + offset = get_cmap_offset (hdc, UCS4_ENCODING_ID); + if (offset == 0) + return NULL; + + res = GetFontData (hdc, CMAP, offset + 4, &length, 4); + if (res != 4) + return NULL; + length = GUINT32_FROM_BE (length); + + table = g_malloc (length); + + res = GetFontData (hdc, CMAP, offset, table, length); + if (res != length) + { + g_free (table); + return NULL; + } + + table->format = GUINT16_FROM_BE (table->format); + table->length = GUINT32_FROM_BE (table->length); + table->language = GUINT32_FROM_BE (table->language); + table->count = GUINT32_FROM_BE (table->count); + + if (table->format != 12 || + (table->length % 4) != 0 || + table->length > length || + table->length < 16 + table->count * 12) + { + g_free (table); + return NULL; + } + + tbl_end = (guint32 *) ((char *) table + length); + tbl = table->groups; + + while (tbl < tbl_end) + { + *tbl = GUINT32_FROM_BE (*tbl); + tbl++; + } + + return table; +} + +static gpointer +font_get_cmap (PangoFont *font) { PangoWin32Font *win32font = (PangoWin32Font *)font; HFONT hfont; - struct type_4_cmap *table; + gpointer cmap; - if (win32font->win32face->unicode_table) - return (struct type_4_cmap *)win32font->win32face->unicode_table; + if (win32font->win32face->cmap) + return win32font->win32face->cmap; hfont = pango_win32_get_hfont (font); SelectObject (pango_win32_hdc, hfont); - table = get_unicode_mapping (pango_win32_hdc); - - win32font->win32face->unicode_table = table; - return table; + /* Prefer the format 12 cmap */ + if ((cmap = get_format_12_cmap (pango_win32_hdc)) != NULL) + { + win32font->win32face->cmap_format = 12; + win32font->win32face->cmap = cmap; + } + else if ((cmap = get_format_4_cmap (pango_win32_hdc)) != NULL) + { + win32font->win32face->cmap_format = 4; + win32font->win32face->cmap = cmap; + } + + return cmap; } /** @@ -1209,40 +1272,67 @@ gint pango_win32_font_get_glyph_index (PangoFont *font, gunichar wc) { - struct type_4_cmap *table; - guint16 *id_range_offset; - guint16 *id_delta; - guint16 *start_count; - guint16 segment; - guint16 id; - guint16 ch = wc; + PangoWin32Font *win32font = (PangoWin32Font *)font; + gpointer cmap; guint16 glyph; /* Do GetFontData magic on font->hfont here. */ - table = font_get_unicode_table (font); + cmap = font_get_cmap (font); - if (table == NULL) + if (cmap == NULL) return 0; + + if (win32font->win32face->cmap_format == 4) + { + struct format_4_cmap *cmap4 = cmap; + guint16 *id_range_offset; + guint16 *id_delta; + guint16 *start_count; + guint16 segment; + guint16 id; + guint16 ch = wc; - if (!find_segment (table, ch, &segment)) - return 0; + if (wc > 0xFFFF) + return 0; - id_range_offset = get_id_range_offset (table); - id_delta = get_id_delta (table); - start_count = get_start_count (table); + if (!find_segment (cmap4, ch, &segment)) + return 0; - if (id_range_offset[segment] == 0) - glyph = (id_delta[segment] + ch) % 65536; - else - { - id = *(id_range_offset[segment]/2 + - (ch - start_count[segment]) + - &id_range_offset[segment]); - if (id) - glyph = (id_delta[segment] + id) %65536; + id_range_offset = get_id_range_offset (cmap4); + id_delta = get_id_delta (cmap4); + start_count = get_start_count (cmap4); + + if (id_range_offset[segment] == 0) + glyph = (id_delta[segment] + ch) % 65536; else - glyph = 0; + { + id = *(id_range_offset[segment]/2 + + (ch - start_count[segment]) + + &id_range_offset[segment]); + if (id) + glyph = (id_delta[segment] + id) %65536; + else + glyph = 0; + } + } + else if (win32font->win32face->cmap_format == 12) + { + struct format_12_cmap *cmap12 = cmap; + guint32 i; + + glyph = 0; + for (i = 0; i < cmap12->count; i++) + { + if (cmap12->groups[i*3+0] <= wc && wc <= cmap12->groups[i*3+1]) + { + glyph = cmap12->groups[i*3+2] + (wc - cmap12->groups[i*3+0]); + break; + } + } } + else + g_assert_not_reached (); + return glyph; } @@ -1345,14 +1435,10 @@ pango_win32_font_calc_coverage (PangoFont *font, PangoCoverage *coverage, PangoLanguage *lang) { - struct type_4_cmap *table; - guint16 *id_range_offset; - guint16 *start_count; - guint16 *end_count; - guint16 seg_count; - guint16 id; + PangoWin32Font *win32font = (PangoWin32Font *)font; + gpointer cmap; guint32 ch; - int i; + guint32 i; PangoWin32CoverageLanguageClass cjkv; gboolean hide_unihan = FALSE; @@ -1369,70 +1455,87 @@ pango_win32_font_calc_coverage (PangoFont *font, } /* Do GetFontData magic on font->hfont here. */ - - table = font_get_unicode_table (font); - - if (table == NULL) + cmap = font_get_cmap (font); + if (cmap == NULL) { PING(("no table")); return; } - seg_count = table->seg_count_x_2/2; - end_count = get_end_count (table); - start_count = get_start_count (table); - id_range_offset = get_id_range_offset (table); - PING (("coverage:")); - for (i = 0; i < seg_count; i++) + if (win32font->win32face->cmap_format == 4) { - if (id_range_offset[i] == 0) + struct format_4_cmap *cmap4 = cmap; + guint16 *id_range_offset; + guint16 *start_count; + guint16 *end_count; + guint16 seg_count; + guint16 id; + + seg_count = cmap4->seg_count_x_2/2; + end_count = get_end_count (cmap4); + start_count = get_start_count (cmap4); + id_range_offset = get_id_range_offset (cmap4); + + for (i = 0; i < seg_count; i++) { -#ifdef PANGO_WIN32_DEBUGGING - if (pango_win32_debug) + if (id_range_offset[i] == 0) { - if (end_count[i] == start_count[i]) - printf ("%04x ", start_count[i]); - else - printf ("%04x:%04x ", start_count[i], end_count[i]); - } +#ifdef PANGO_WIN32_DEBUGGING + if (pango_win32_debug) + { + if (end_count[i] == start_count[i]) + printf ("%04x ", start_count[i]); + else + printf ("%04x:%04x ", start_count[i], end_count[i]); + } #endif - for (ch = start_count[i]; - ch <= end_count[i]; - ch++) - if (hide_unihan && ch >= 0x3400 && ch <= 0x9FAF) - pango_coverage_set (coverage, ch, PANGO_COVERAGE_APPROXIMATE); - else - pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT); - } - else - { + for (ch = start_count[i]; ch <= end_count[i]; ch++) + if (hide_unihan && CH_IS_UNIHAN_BMP (ch)) + pango_coverage_set (coverage, ch, PANGO_COVERAGE_APPROXIMATE); + else + pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT); + } + else + { #ifdef PANGO_WIN32_DEBUGGING - guint32 ch0 = G_MAXUINT; + guint32 ch0 = G_MAXUINT; #endif - for (ch = start_count[i]; - ch <= end_count[i]; - ch++) - { - if (ch == 0xFFFF) - break; - - id = *(id_range_offset[i]/2 + - (ch - start_count[i]) + - &id_range_offset[i]); - if (id) + for (ch = start_count[i]; ch <= end_count[i]; ch++) { + if (ch == 0xFFFF) + break; + + id = *(id_range_offset[i]/2 + + (ch - start_count[i]) + + &id_range_offset[i]); + if (id) + { #ifdef PANGO_WIN32_DEBUGGING - if (ch0 == G_MAXUINT) - ch0 = ch; + if (ch0 == G_MAXUINT) + ch0 = ch; +#endif + if (hide_unihan && CH_IS_UNIHAN_BMP (ch)) + pango_coverage_set (coverage, ch, PANGO_COVERAGE_APPROXIMATE); + else + pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT); + } +#ifdef PANGO_WIN32_DEBUGGING + else if (ch0 < G_MAXUINT) + { + if (pango_win32_debug) + { + if (ch > ch0 + 2) + printf ("%04x:%04x ", ch0, ch - 1); + else + printf ("%04x ", ch0); + } + ch0 = G_MAXUINT; + } #endif - if (hide_unihan && ch >= 0x3400 && ch <= 0x9FAF) - pango_coverage_set (coverage, ch, PANGO_COVERAGE_APPROXIMATE); - else - pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT); } #ifdef PANGO_WIN32_DEBUGGING - else if (ch0 < G_MAXUINT) + if (ch0 < G_MAXUINT) { if (pango_win32_debug) { @@ -1441,24 +1544,37 @@ pango_win32_font_calc_coverage (PangoFont *font, else printf ("%04x ", ch0); } - ch0 = G_MAXUINT; } #endif } + } + } + else if (win32font->win32face->cmap_format == 12) + { + struct format_12_cmap *cmap12 = cmap; + + for (i = 0; i < cmap12->count; i++) + { #ifdef PANGO_WIN32_DEBUGGING - if (ch0 < G_MAXUINT) + if (pango_win32_debug) { - if (pango_win32_debug) - { - if (ch > ch0 + 2) - printf ("%04x:%04x ", ch0, ch - 1); - else - printf ("%04x ", ch0); - } + if (cmap12->groups[i*3+0] == cmap12->groups[i*3+1]) + printf ("%04x ", cmap12->groups[i*3+0]); + else + printf ("%04x:%04x ", cmap12->groups[i*3+0], cmap12->groups[i*3+1]); } #endif + for (ch = cmap12->groups[i*3+0]; ch <= cmap12->groups[i*3+1]; ch++) + { + if (hide_unihan && CH_IS_UNIHAN (ch)) + pango_coverage_set (coverage, ch, PANGO_COVERAGE_APPROXIMATE); + else + pango_coverage_set (coverage, ch, PANGO_COVERAGE_EXACT); + } } } + else + g_assert_not_reached (); #ifdef PANGO_WIN32_DEBUGGING if (pango_win32_debug) printf ("\n"); |