Add _cairo_truetype_index_to_ucs4()

for doing reverse cmap lookups on truetype/opentype fonts one glyph at
a time.
This commit is contained in:
Adrian Johnson 2008-06-29 19:31:47 +09:30
parent 95771d62c5
commit 2f99a294cd
2 changed files with 173 additions and 0 deletions

View file

@ -554,4 +554,26 @@ _cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
cairo_private cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_truetype_index_to_ucs4:
* @scaled_font: the #cairo_scaled_font_t
* @index: the glyph index
* @ucs4: return value for the unicode value of the glyph
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) assign
* the unicode character of the glyph to @ucs4.
*
* If mapping glyph indices to unicode is supported but the unicode
* value of the specified glyph is not available, @ucs4 is set to -1.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if mapping glyph indices to unicode
* is not supported. Possible errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4);
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */

View file

@ -1318,3 +1318,154 @@ cleanup:
return status;
}
static cairo_int_status_t
_cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
unsigned long table_offset,
unsigned long index,
uint32_t *ucs4)
{
cairo_status_t status;
const cairo_scaled_font_backend_t *backend;
tt_segment_map_t *map;
char buf[4];
unsigned int num_segments, i;
unsigned long size;
uint16_t *start_code;
uint16_t *end_code;
uint16_t *delta;
uint16_t *range_offset;
uint16_t *glyph_array;
uint16_t c;
backend = scaled_font->backend;
size = 4;
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) &buf,
&size);
if (status)
return status;
/* All table formats have the same first two words */
map = (tt_segment_map_t *) buf;
if (be16_to_cpu (map->format) != 4)
return CAIRO_INT_STATUS_UNSUPPORTED;
size = be16_to_cpu (map->length);
map = malloc (size);
if (map == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) map,
&size);
if (status)
goto fail;
num_segments = be16_to_cpu (map->segCountX2)/2;
end_code = map->endCount;
start_code = &(end_code[num_segments + 1]);
delta = &(start_code[num_segments]);
range_offset = &(delta[num_segments]);
glyph_array = &(range_offset[num_segments]);
/* search for glyph in segments
* with rangeOffset=0 */
for (i = 0; i < num_segments; i++) {
c = index - be16_to_cpu (delta[i]);
if (range_offset[i] == 0 &&
c >= be16_to_cpu (start_code[i]) &&
c <= be16_to_cpu (end_code[i]))
{
*ucs4 = c;
goto found;
}
}
/* search for glyph in segments with rangeOffset=1 */
for (i = 0; i < num_segments; i++) {
if (range_offset[i] != 0) {
uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2;
int range_size = be16_to_cpu (end_code[i]) - be16_to_cpu (start_code[i]) + 1;
uint16_t g_id_be = cpu_to_be16 (index);
int j;
for (j = 0; j < range_size; j++) {
if (glyph_ids[j] == g_id_be) {
*ucs4 = be16_to_cpu (start_code[i]) + j;
goto found;
}
}
}
}
/* glyph not found */
*ucs4 = -1;
found:
status = CAIRO_STATUS_SUCCESS;
fail:
free (map);
return status;
}
cairo_int_status_t
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4)
{
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
const cairo_scaled_font_backend_t *backend;
tt_cmap_t *cmap;
char buf[4];
int num_tables, i;
unsigned long size;
backend = scaled_font->backend;
if (!backend->load_truetype_table)
return CAIRO_INT_STATUS_UNSUPPORTED;
size = 4;
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) &buf,
&size);
if (status)
return status;
cmap = (tt_cmap_t *) buf;
num_tables = be16_to_cpu (cmap->num_tables);
size = 4 + num_tables*sizeof(tt_cmap_index_t);
cmap = malloc (size);
if (cmap == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) cmap,
&size);
if (status)
goto cleanup;
/* Find a table with Unicode mapping */
for (i = 0; i < num_tables; i++) {
if (be16_to_cpu (cmap->index[i].platform) == 3 &&
be16_to_cpu (cmap->index[i].encoding) == 1) {
status = _cairo_truetype_reverse_cmap (scaled_font,
be32_to_cpu (cmap->index[i].offset),
index,
ucs4);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
break;
}
}
cleanup:
free (cmap);
return status;
}