summaryrefslogtreecommitdiff
path: root/pango/pangowin32.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pangowin32.c')
-rw-r--r--pango/pangowin32.c358
1 files changed, 237 insertions, 121 deletions
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");