From a1d61c4f2f32f1dfb1f8a2dbef140050e6179da4 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 6 May 2009 23:35:37 +0000 Subject: Make RUfl take account of the multitude of font encodings on old font managers. This now utilises the Latin2, 3, and 4 sets in the standard ROM fonts, for example. svn path=/trunk/rufl/; revision=7410 --- rufl_dump_state.c | 14 ++- rufl_find.c | 18 ++- rufl_init.c | 364 +++++++++++++++++++++++++++++++++++++++++++++++------- rufl_internal.h | 19 ++- rufl_metrics.c | 36 ++++-- rufl_paint.c | 168 ++++++++++++++++--------- 6 files changed, 498 insertions(+), 121 deletions(-) diff --git a/rufl_dump_state.c b/rufl_dump_state.c index e1ba483..06a1f22 100644 --- a/rufl_dump_state.c +++ b/rufl_dump_state.c @@ -33,9 +33,14 @@ void rufl_dump_state(void) printf(" (no charset table)\n"); } if (rufl_font_list[i].umap) { - printf(" "); - rufl_dump_unicode_map(rufl_font_list[i].umap); - printf("\n"); + for (j = 0; j < rufl_font_list[i].num_umaps; j++) { + struct rufl_unicode_map *map = + rufl_font_list[i].umap + j; + + printf(" "); + rufl_dump_unicode_map(map); + printf("\n"); + } } } @@ -103,6 +108,9 @@ void rufl_dump_unicode_map(struct rufl_unicode_map *umap) { unsigned int i; + if (umap->encoding) + printf("%s: ", umap->encoding); + for (i = 0; i != umap->entries; i++) printf("%x:%x ", umap->map[i].u, umap->map[i].c); } diff --git a/rufl_find.c b/rufl_find.c index 6aad027..a1c2785 100644 --- a/rufl_find.c +++ b/rufl_find.c @@ -16,7 +16,7 @@ static int rufl_family_list_cmp(const void *keyval, const void *datum); static rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, - font_f f); + const char *encoding, font_f f); /** * Find a font family. @@ -99,8 +99,17 @@ rufl_code rufl_find_font(unsigned int font, unsigned int font_size, assert(fhandle != NULL); for (i = 0; i != rufl_CACHE_SIZE; i++) { + /* Comparing pointers for the encoding is fine, as the + * encoding string passed to us is either: + * + * a) NULL + * or b) statically allocated + * or c) resides in the font's umap, which is constant + * for the lifetime of the application. + */ if (rufl_cache[i].font == font && - rufl_cache[i].size == font_size) + rufl_cache[i].size == font_size && + rufl_cache[i].encoding == encoding) break; } if (i != rufl_CACHE_SIZE) { @@ -136,7 +145,7 @@ rufl_code rufl_find_font(unsigned int font, unsigned int font_size, return rufl_FONT_MANAGER_ERROR; } /* place in cache */ - code = rufl_place_in_cache(font, font_size, f); + code = rufl_place_in_cache(font, font_size, encoding, f); if (code != rufl_OK) return code; } @@ -160,7 +169,7 @@ int rufl_family_list_cmp(const void *keyval, const void *datum) */ rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, - font_f f) + const char *encoding, font_f f) { unsigned int i; unsigned int max_age = 0; @@ -184,6 +193,7 @@ rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, } rufl_cache[evict].font = font; rufl_cache[evict].size = font_size; + rufl_cache[evict].encoding = encoding; rufl_cache[evict].f = f; rufl_cache[evict].last_used = rufl_cache_time++; diff --git a/rufl_init.c b/rufl_init.c index 6e75758..5f4089b 100644 --- a/rufl_init.c +++ b/rufl_init.c @@ -25,7 +25,7 @@ struct rufl_font_list_entry *rufl_font_list = 0; -unsigned int rufl_font_list_entries = 0; +size_t rufl_font_list_entries = 0; const char **rufl_family_list = 0; unsigned int rufl_family_list_entries = 0; struct rufl_family_map_entry *rufl_family_map = 0; @@ -70,11 +70,15 @@ const struct rufl_weight_table_entry rufl_weight_table[] = { static rufl_code rufl_init_font_list(void); -static rufl_code rufl_init_add_font(const char *identifier, const char *local_name); +static rufl_code rufl_init_add_font(const char *identifier, + const char *local_name); static int rufl_weight_table_cmp(const void *keyval, const void *datum); static rufl_code rufl_init_scan_font(unsigned int font); static bool rufl_is_space(unsigned int u); static rufl_code rufl_init_scan_font_old(unsigned int font_index); +static rufl_code rufl_init_scan_font_in_encoding(const char *font_name, + const char *encoding, struct rufl_character_set *charset, + struct rufl_unicode_map *umap, unsigned int *last); static rufl_code rufl_init_read_encoding(font_f font, struct rufl_unicode_map *umap); static int rufl_glyph_map_cmp(const void *keyval, const void *datum); @@ -112,7 +116,7 @@ rufl_code rufl_init(void) rufl_init_status_open(); - /* determine if the font manager support Unicode */ + /* determine if the font manager supports Unicode */ rufl_fm_error = xfont_find_font("Homerton.Medium\\EUTF8", 160, 160, 0, 0, &font, 0, 0); if (rufl_fm_error) { @@ -142,7 +146,7 @@ rufl_code rufl_init(void) xhourglass_off(); return code; } - LOG("%u faces, %zu families", rufl_font_list_entries, + LOG("%zu faces, %u families", rufl_font_list_entries, rufl_family_list_entries); code = rufl_load_cache(); @@ -540,18 +544,15 @@ bool rufl_is_space(unsigned int u) rufl_code rufl_init_scan_font_old(unsigned int font_index) { const char *font_name = rufl_font_list[font_index].identifier; - char string[2] = { 0, 0 }; - int x_out, y_out; - unsigned int byte, bit; - unsigned int i; - unsigned int last_used = 0; - unsigned int u; struct rufl_character_set *charset; struct rufl_character_set *charset2; - struct rufl_unicode_map *umap; + struct rufl_unicode_map *umap = NULL; + unsigned int num_umaps = 0; + unsigned int i; + unsigned int last_used = 0; rufl_code code; - font_f font; - font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } }; + font_list_context context = 0; + char encoding[80]; /*LOG("font %u \"%s\"", font_index, font_name);*/ @@ -561,25 +562,171 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index) for (i = 0; i != 256; i++) charset->index[i] = BLOCK_EMPTY; - umap = calloc(1, sizeof *umap); - if (!umap) { + /* Firstly, search through available encodings (Symbol fonts fail) */ + while (context != -1) { + struct rufl_unicode_map *temp; + + rufl_fm_error = xfont_list_fonts((byte *) encoding, + font_RETURN_FONT_NAME | + 0x400000 /* Return encoding name, instead */ | + context, + sizeof(encoding), NULL, 0, NULL, + &context, NULL, NULL); + if (rufl_fm_error) { + LOG("xfont_list_fonts: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return rufl_FONT_MANAGER_ERROR; + } + if (context == -1) + break; + + temp = realloc(umap, (num_umaps + 1) * sizeof *umap); + if (!temp) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return rufl_OUT_OF_MEMORY; + } + + memset(temp + num_umaps, 0, sizeof *umap); + + umap = temp; + num_umaps++; + + code = rufl_init_scan_font_in_encoding(font_name, encoding, + charset, umap + (num_umaps - 1), &last_used); + if (code != rufl_OK) { + /* Not finding the font isn't fatal */ + if (code != rufl_FONT_MANAGER_ERROR || + (rufl_fm_error->errnum != + error_FONT_NOT_FOUND && + rufl_fm_error->errnum != + error_FILE_NOT_FOUND)) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return code; + } + + /* Ensure we reuse the currently allocated umap */ + num_umaps--; + } else { + /* If this mapping is identical to an existing one, + * then we can discard it */ + for (i = 0; i != num_umaps - 1; i++) { + const struct rufl_unicode_map *a = (umap + i); + const struct rufl_unicode_map *b = + (umap + num_umaps - 1); + + if (a->entries == b->entries && + memcmp(a->map, b->map, + sizeof a->map) == 0) { + /* Found identical map; discard */ + num_umaps--; + break; + } + } + } + } + + if (num_umaps == 0) { + /* This is a symbol font and can only be used + * without an encoding */ + struct rufl_unicode_map *temp; + + temp = realloc(umap, (num_umaps + 1) * sizeof *umap); + if (!temp) { + free(charset); + free(umap); + return rufl_OUT_OF_MEMORY; + } + + memset(temp + num_umaps, 0, sizeof *umap); + + umap = temp; + num_umaps++; + + code = rufl_init_scan_font_in_encoding(font_name, NULL, + charset, umap, &last_used); + if (code != rufl_OK) { + /* Not finding the font isn't fatal */ + if (code != rufl_FONT_MANAGER_ERROR || + (rufl_fm_error->errnum != + error_FONT_NOT_FOUND && + rufl_fm_error->errnum != + error_FILE_NOT_FOUND)) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return code; + } + + num_umaps--; + } + } + + /* shrink-wrap */ + charset->size = offsetof(struct rufl_character_set, block) + + 32 * last_used; + charset2 = realloc(charset, charset->size); + if (!charset2) { + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); free(charset); return rufl_OUT_OF_MEMORY; } - rufl_fm_error = xfont_find_font(font_name, 160, 160, 0, 0, &font, 0, 0); + rufl_font_list[font_index].charset = charset; + rufl_font_list[font_index].umap = umap; + rufl_font_list[font_index].num_umaps = num_umaps; + + return rufl_OK; +} + +/** + * Helper function for rufl_init_scan_font_old. + * Scans the given font using the given font encoding (or none, if NULL) + */ + +rufl_code rufl_init_scan_font_in_encoding(const char *font_name, + const char *encoding, struct rufl_character_set *charset, + struct rufl_unicode_map *umap, unsigned int *last) +{ + char string[2] = { 0, 0 }; + int x_out, y_out; + unsigned int byte, bit; + unsigned int i; + unsigned int last_used = *last; + unsigned int u; + rufl_code code; + font_f font; + font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } }; + char buf[80]; + + if (encoding) + snprintf(buf, sizeof buf, "%s\\E%s", font_name, encoding); + else + snprintf(buf, sizeof buf, "%s", font_name); + + rufl_fm_error = xfont_find_font(buf, 160, 160, 0, 0, &font, 0, 0); if (rufl_fm_error) { - LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name, + LOG("xfont_find_font(\"%s\"): 0x%x: %s", buf, rufl_fm_error->errnum, rufl_fm_error->errmess); - free(umap); - free(charset); - return rufl_OK; + return rufl_FONT_MANAGER_ERROR; } code = rufl_init_read_encoding(font, umap); if (code != rufl_OK) { - free(umap); - free(charset); + xfont_lose_font(font); return code; } @@ -618,32 +765,26 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index) byte = (u >> 3) & 31; bit = u & 7; - charset->block[last_used - 1][byte] |= 1 << bit; + charset->block[charset->index[u >> 8]][byte] |= + 1 << bit; } } xfont_lose_font(font); if (rufl_fm_error) { - free(umap); - free(charset); LOG("xfont_scan_string: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); return rufl_FONT_MANAGER_ERROR; } - /* shrink-wrap */ - charset->size = offsetof(struct rufl_character_set, block) + - 32 * last_used; - charset2 = realloc(charset, charset->size); - if (!charset2) { - free(umap); - free(charset); - return rufl_OUT_OF_MEMORY; + if (encoding) { + umap->encoding = strdup(encoding); + if (!umap->encoding) + return rufl_OUT_OF_MEMORY; } - rufl_font_list[font_index].charset = charset; - rufl_font_list[font_index].umap = umap; + *last = last_used; return rufl_OK; } @@ -865,13 +1006,57 @@ rufl_code rufl_save_cache(void) /* unicode map */ if (rufl_old_font_manager) { - if (fwrite(rufl_font_list[i].umap, - sizeof *rufl_font_list[i].umap, 1, + unsigned int j; + + if (fwrite(&rufl_font_list[i].num_umaps, + sizeof rufl_font_list[i].num_umaps, 1, fp) != 1) { LOG("fwrite: 0x%x: %s", errno, strerror(errno)); fclose(fp); return rufl_OK; } + + for (j = 0; j < rufl_font_list[i].num_umaps; j++) { + const struct rufl_unicode_map *umap = + rufl_font_list[i].umap + j; + + len = umap->encoding ? + strlen(umap->encoding) : 0; + + if (fwrite(&len, sizeof len, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + if (umap->encoding) { + if (fwrite(umap->encoding, len, 1, + fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + } + + if (fwrite(&umap->entries, sizeof umap->entries, + 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + if (fwrite(umap->map, umap->entries * + sizeof(struct rufl_unicode_map_entry), + 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + } } } @@ -901,6 +1086,7 @@ rufl_code rufl_load_cache(void) struct rufl_font_list_entry *entry; struct rufl_character_set *charset; struct rufl_unicode_map *umap = 0; + unsigned int num_umaps; fp = fopen(rufl_CACHE, "rb"); if (!fp) { @@ -1000,7 +1186,22 @@ rufl_code rufl_load_cache(void) /* unicode map */ if (rufl_old_font_manager) { - umap = malloc(sizeof *umap); + rufl_code code = rufl_OK; + unsigned int entry; + + /* Number of maps */ + if (fread(&num_umaps, sizeof num_umaps, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + free(charset); + free(identifier); + break; + } + + umap = calloc(num_umaps, sizeof *umap); if (!umap) { LOG("malloc(%zu) failed", sizeof *umap); free(charset); @@ -1009,15 +1210,83 @@ rufl_code rufl_load_cache(void) return rufl_OUT_OF_MEMORY; } - if (fread(umap, sizeof *umap, 1, fp) != 1) { - if (feof(fp)) - LOG("fread: %s", "unexpected eof"); - else - LOG("fread: 0x%x: %s", errno, + /* Load them */ + for (entry = 0; entry < num_umaps; entry++) { + struct rufl_unicode_map *map = umap + entry; + + if (fread(&len, sizeof(len), 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + + if (len > 0) { + map->encoding = malloc(len + 1); + if (!map->encoding) { + LOG("malloc(%zu) failed", + len + 1); + code = rufl_OUT_OF_MEMORY; + break; + } + + if (fread(map->encoding, len, 1, + fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", + errno, strerror(errno)); + break; + } + map->encoding[len] = 0; + } + + if (fread(&map->entries, sizeof(map->entries), + 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + + if (fread(map->map, map->entries * + sizeof(struct rufl_unicode_map_entry), + 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + } + + /* Clean up if loading failed */ + if (entry != num_umaps) { + for (num_umaps = 0; num_umaps <= entry; + num_umaps++) { + struct rufl_unicode_map *map = + umap + num_umaps; + + free(map->encoding); + } free(umap); free(charset); free(identifier); + + if (code != rufl_OK) + return code; + break; } } @@ -1029,9 +1298,18 @@ rufl_code rufl_load_cache(void) if (entry) { entry->charset = charset; entry->umap = umap; + entry->num_umaps = num_umaps; i++; } else { LOG("\"%s\" not in font list", identifier); + while (num_umaps > 0) { + struct rufl_unicode_map *map = + umap + num_umaps - 1; + + free(map->encoding); + + num_umaps--; + } free(umap); free(charset); } diff --git a/rufl_internal.h b/rufl_internal.h index 407ef01..1c01e36 100644 --- a/rufl_internal.h +++ b/rufl_internal.h @@ -49,9 +49,14 @@ struct rufl_unicode_map_entry { /** Old font manager: mapping from Unicode to character code. This is simply - * an array sorted by Unicode value, suitable for bsearch(). */ + * an array sorted by Unicode value, suitable for bsearch(). If a font has + * support for multiple encodings, then it will have multiple unicode maps. + * The encoding field contains the name of the encoding to pass to the + * font manager. This will be NULL if the font is a Symbol font. */ struct rufl_unicode_map { - /** Number of valid entries in u and c. */ + /** Corresponding encoding name */ + char *encoding; + /** Number of valid entries in map. */ unsigned int entries; /** Map from Unicode to character code. */ struct rufl_unicode_map_entry map[256]; @@ -64,7 +69,9 @@ struct rufl_font_list_entry { char *identifier; /** Character set of font. */ struct rufl_character_set *charset; - /** Mapping from Unicode to character code. */ + /** Number of Unicode mapping tables */ + unsigned int num_umaps; + /** Mappings from Unicode to character code. */ struct rufl_unicode_map *umap; /** Family that this font belongs to (index in rufl_family_list and * rufl_family_map). */ @@ -77,7 +84,7 @@ struct rufl_font_list_entry { /** List of all available fonts. */ extern struct rufl_font_list_entry *rufl_font_list; /** Number of entries in rufl_font_list. */ -extern unsigned int rufl_font_list_entries; +extern size_t rufl_font_list_entries; /** An entry in rufl_family_map. */ @@ -111,6 +118,8 @@ struct rufl_cache_entry { #define rufl_CACHE_CORPUS (UINT_MAX - 1) /** Font size. */ unsigned int size; + /** Font encoding */ + const char *encoding; /** Value of rufl_cache_time when last used. */ unsigned int last_used; /** RISC OS font handle. */ @@ -161,7 +170,7 @@ bool rufl_character_set_test(struct rufl_character_set *charset, } #define rufl_CACHE ".RUfl_cache" -#define rufl_CACHE_VERSION 2 +#define rufl_CACHE_VERSION 3 struct rufl_glyph_map_entry { diff --git a/rufl_metrics.c b/rufl_metrics.c index 2ed4681..af4727f 100644 --- a/rufl_metrics.c +++ b/rufl_metrics.c @@ -119,15 +119,18 @@ rufl_code rufl_glyph_metrics(const char *font_family, int *width, int *height, int *x_advance, int *y_advance) { + const char *font_encoding = NULL; unsigned int font, font1, u; unsigned short u1[2]; struct rufl_character_set *charset; + struct rufl_unicode_map_entry *umap_entry = NULL; font_f f; rufl_code code; font_scan_block block; font_string_flags flags; int xa, ya; + /* Find font family containing glyph */ code = rufl_find_font_family(font_family, font_style, &font, NULL, &charset); if (code != rufl_OK) @@ -141,7 +144,28 @@ rufl_code rufl_glyph_metrics(const char *font_family, else font1 = rufl_CACHE_CORPUS; - code = rufl_find_font(font1, font_size, NULL, &f); + /* Old font managers need the font encoding, too */ + if (rufl_old_font_manager && font1 != rufl_CACHE_CORPUS) { + unsigned int i; + unsigned short u16 = (unsigned short) u; + + for (i = 0; i < rufl_font_list[font1].num_umaps; i++) { + struct rufl_unicode_map *map = + rufl_font_list[font1].umap + i; + + umap_entry = bsearch(&u16, map->map, map->entries, + sizeof map->map[0], + rufl_unicode_map_search_cmp); + if (umap_entry) { + font_encoding = map->encoding; + break; + } + } + + assert(umap_entry != NULL); + } + + code = rufl_find_font(font1, font_size, font_encoding, &f); if (code != rufl_OK) return code; @@ -224,12 +248,10 @@ rufl_code rufl_glyph_metrics(const char *font_family, } else if (rufl_old_font_manager) { /* Old Font Manager */ char s[2]; - struct rufl_unicode_map_entry *entry; - entry = bsearch(&u1[0], rufl_font_list[font1].umap->map, - rufl_font_list[font1].umap->entries, - sizeof rufl_font_list[font1].umap->map[0], - rufl_unicode_map_search_cmp); - s[0] = entry->c; + + /* We found the correct umap entry when + * looking for the font encoding */ + s[0] = umap_entry->c; s[1] = 0; rufl_fm_error = xfont_scan_string(f, s, flags, diff --git a/rufl_paint.c b/rufl_paint.c index 8a8392a..084fea5 100644 --- a/rufl_paint.c +++ b/rufl_paint.c @@ -355,7 +355,8 @@ rufl_code rufl_process_span(rufl_action action, font_RETURN_CARET_POS : 0), (click_x - *x) * 400, 0x7fffffff, 0, 0, n * 2, - (char **)(void *)&split_point, &x_out, &y_out, 0); + (char **)(void *)&split_point, + &x_out, &y_out, 0); *offset = split_point - s; } else { rufl_fm_error = xfont_scan_string(f, (const char *) s, @@ -395,13 +396,13 @@ rufl_code rufl_process_span_old(rufl_action action, bool oblique = slant && !rufl_font_list[font].slant; font_f f; rufl_code code; - struct rufl_unicode_map_entry *entry; - - code = rufl_find_font(font, font_size, NULL, &f); - if (code != rufl_OK) - return code; if (action == rufl_FONT_BBOX) { + /* Don't need encoding for bounding box */ + code = rufl_find_font(font, font_size, NULL, &f); + if (code != rufl_OK) + return code; + rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]); if (rufl_fm_error) { LOG("xfont_read_info: 0x%x: %s", @@ -412,68 +413,117 @@ rufl_code rufl_process_span_old(rufl_action action, return rufl_OK; } - /* convert Unicode string into character string */ - for (i = 0; i != n; i++) { - entry = bsearch(&s[i], rufl_font_list[font].umap->map, - rufl_font_list[font].umap->entries, - sizeof rufl_font_list[font].umap->map[0], + if (offset) + *offset = 0; + + /* Process the span in map-coherent chunks */ + do { + struct rufl_unicode_map *map; + struct rufl_unicode_map_entry *entry = NULL; + unsigned int j; + + i = 0; + + /* Find map for first character */ + for (j = 0; j < rufl_font_list[font].num_umaps; j++) { + map = rufl_font_list[font].umap + j; + + entry = bsearch(&s[i], map->map, map->entries, + sizeof map->map[0], rufl_unicode_map_search_cmp); - s2[i] = entry->c; - } - s2[i] = 0; + if (entry) + break; + } + assert(map != NULL); + assert(entry != NULL); - if (action == rufl_PAINT) { - /* paint span */ - /* call Font_SetFont to work around broken PS printer driver, - * which doesn't use the font handle from Font_Paint */ - rufl_fm_error = xfont_set_font(f); - if (rufl_fm_error) { - LOG("xfont_set_font: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; + /* Collect characters: s[0..i) use map */ + do { + entry = bsearch(&s[i], map->map, map->entries, + sizeof map->map[0], + rufl_unicode_map_search_cmp); + + if (entry) + s2[i++] = entry->c; + } while (i != n && entry != NULL); + + s2[i] = 0; + + code = rufl_find_font(font, font_size, map->encoding, &f); + if (code != rufl_OK) + return code; + + if (action == rufl_PAINT) { + /* paint span */ + /* call Font_SetFont to work around broken PS printer + * driver, which doesn't use the font handle from + * Font_Paint */ + rufl_fm_error = xfont_set_font(f); + if (rufl_fm_error) { + LOG("xfont_set_font: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS | + (oblique ? font_GIVEN_TRFM : 0) | + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((flags & rufl_BLEND_FONT) ? + font_BLEND_FONT : 0), + *x, y, 0, &trfm_oblique, i); + if (rufl_fm_error) { + LOG("xfont_paint: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + } else if (action == rufl_PAINT_CALLBACK) { + char font_name[80]; + + if (map->encoding) + snprintf(font_name, sizeof font_name, "%s\\E%s", + rufl_font_list[font].identifier, + map->encoding); + else + snprintf(font_name, sizeof font_name, "%s", + rufl_font_list[font].identifier); + + callback(context, font_name, font_size, + s2, 0, i, *x, y); + } + + /* increment x by width of span */ + if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + rufl_fm_error = xfont_scan_string(f, s2, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((action == rufl_X_TO_OFFSET) ? + font_RETURN_CARET_POS : 0), + (click_x - *x) * 400, 0x7fffffff, + 0, 0, i, + &split_point, &x_out, &y_out, 0); + *offset += split_point - s2; + } else { + rufl_fm_error = xfont_scan_string(f, s2, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN, + 0x7fffffff, 0x7fffffff, 0, 0, i, + 0, &x_out, &y_out, 0); } - rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS | - (oblique ? font_GIVEN_TRFM : 0) | - font_GIVEN_LENGTH | font_GIVEN_FONT | - font_KERN | - ((flags & rufl_BLEND_FONT) ? - font_BLEND_FONT : 0), - *x, y, 0, &trfm_oblique, n); if (rufl_fm_error) { - LOG("xfont_paint: 0x%x: %s", + LOG("xfont_scan_string: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); return rufl_FONT_MANAGER_ERROR; } - } else if (action == rufl_PAINT_CALLBACK) { - callback(context, rufl_font_list[font].identifier, - font_size, s2, 0, n, *x, y); - } + *x += x_out / 400; - /* increment x by width of span */ - if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { - rufl_fm_error = xfont_scan_string(f, s2, - font_GIVEN_LENGTH | font_GIVEN_FONT | - font_KERN | - ((action == rufl_X_TO_OFFSET) ? - font_RETURN_CARET_POS : 0), - (click_x - *x) * 400, 0x7fffffff, 0, 0, n, - &split_point, &x_out, &y_out, 0); - *offset = split_point - s2; - } else { - rufl_fm_error = xfont_scan_string(f, s2, - font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN, - 0x7fffffff, 0x7fffffff, 0, 0, n, - 0, &x_out, &y_out, 0); - } - if (rufl_fm_error) { - LOG("xfont_scan_string: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; - } - *x += x_out / 400; + /* Now update s and n for the next chunk */ + s += i; + n -= i; + } while (n != 0); return rufl_OK; } -- cgit v1.2.3