From 406f2c0a523141829e14b98068e3905e6f89c3ac Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 20 Jul 2006 23:09:09 +0000 Subject: Merge my local changes into head; I've been sitting on these for far too long. This comprises: 1) Centralised internal font family / sized font lookup (rufl_find.c) 2) Methods to provide access to font and glyph metrics (rufl_metrics.c) 3) Glyph decomposition into path segments (rufl_decompose.c) svn path=/trunk/rufl/; revision=2788 --- makefile | 3 +- rufl.h | 44 +++++++++ rufl_decompose.c | 159 ++++++++++++++++++++++++++++++ rufl_find.c | 191 ++++++++++++++++++++++++++++++++++++ rufl_internal.h | 5 + rufl_metrics.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rufl_paint.c | 212 +++------------------------------------- rufl_test.c | 36 +++++++ 8 files changed, 742 insertions(+), 197 deletions(-) create mode 100644 rufl_decompose.c create mode 100644 rufl_find.c create mode 100644 rufl_metrics.c diff --git a/makefile b/makefile index 12985d7..1d8e6da 100644 --- a/makefile +++ b/makefile @@ -12,7 +12,8 @@ COMPILER = gcc SOURCE = rufl_init.c rufl_quit.c rufl_dump_state.c \ rufl_character_set_test.c \ - rufl_paint.c rufl_glyph_map.c rufl_invalidate_cache.c + rufl_paint.c rufl_glyph_map.c rufl_invalidate_cache.c \ + rufl_find.c rufl_decompose.c rufl_metrics.c ifeq ($(COMPILER), gcc) diff --git a/rufl.h b/rufl.h index b2a8d1f..1e541aa 100644 --- a/rufl.h +++ b/rufl.h @@ -55,6 +55,17 @@ extern char **rufl_family_list; /** Number of entries in rufl_family_list. */ extern unsigned int rufl_family_list_entries; +/* Callbacks used by rufl_decompose_glyph */ +typedef int (*rufl_move_to_func)(os_coord *to, void *user); +typedef int (*rufl_line_to_func)(os_coord *to, void *user); +typedef int (*rufl_cubic_to_func)(os_coord *control1, os_coord *control2, + os_coord *to, void *user); + +struct rufl_decomp_funcs { + rufl_move_to_func move_to; + rufl_line_to_func line_to; + rufl_cubic_to_func cubic_to; +}; /** * Initialise RUfl. @@ -125,6 +136,39 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style, rufl_callback_t callback, void *context); +/** + * Decompose a glyph to a path. + */ + +rufl_code rufl_decompose_glyph(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t length, + struct rufl_decomp_funcs *funcs, void *user); + + +/** + * Read metrics for a font + */ + +rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style, + os_box *bbox, int *xkern, int *ykern, int *italic, + int *ascent, int *descent, + int *xheight, int *cap_height, + signed char *uline_position, unsigned char *uline_thickness); + + +/** + * Read metrics for a glyph + */ + +rufl_code rufl_glyph_metrics(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t length, + int *x_bearing, int *y_bearing, + int *width, int *height, + int *x_advance, int *y_advance); + + /** * Determine the maximum bounding box of a font. */ diff --git a/rufl_decompose.c b/rufl_decompose.c new file mode 100644 index 0000000..ad0e98e --- /dev/null +++ b/rufl_decompose.c @@ -0,0 +1,159 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 John-Mark Bell + */ + +#include +#include + +#include "oslib/font.h" + +#include "rufl_internal.h" + +/** + * Process a Draw path object + * + * \param path Pointer to path block + * \param funcs Struct of callback functions + * \param user User pointer to be passed to callbacks + * \return Pointer to word after this path, or NULL to terminate processing + */ +static int *process_path(int *path, struct rufl_decomp_funcs *funcs, + void *user) +{ + /* skip forward to style entry */ + path += 9; + + /* skip dash pattern */ + if (path[0] & (1<<7)) + path += path[2] + 2; + + /* and move to start of path components */ + path++; + + while (path[0] != 0) { + switch (path[0]) { + case 2: /* Move to */ + if (funcs->move_to((os_coord *)(path + 1), user)) + return NULL; + path += 3; + break; + case 5: /* Close path */ + path++; + break; + case 6: /* Cubic Bezier to */ + if (funcs->cubic_to((os_coord *)(path + 1), + (os_coord *)(path + 3), + (os_coord *)(path + 5), + user)) + return NULL; + path += 7; + break; + case 8: /* Line to */ + if (funcs->line_to((os_coord *)(path + 1), user)) + return NULL; + path += 3; + break; + default: /* Anything else is broken */ + assert(0); + } + } + + /* + 1 to account for tag 0 - end of path */ + return path + 1; +} + +rufl_code rufl_decompose_glyph(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t len, + struct rufl_decomp_funcs *funcs, void *user) +{ + int *buf, *p, *ep; + int buf_size; + rufl_code err; + + /* Get required buffer size */ + rufl_fm_error = xfont_switch_output_to_buffer( + font_NO_OUTPUT | font_ADD_HINTS, (byte *)8, 0); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + err = rufl_paint(font_family, font_style, font_size, string, len, + 0, 0, rufl_BLEND_FONT); + if (err) { + /* reset font redirection - too bad if this fails */ + xfont_switch_output_to_buffer(0, 0, 0); + return err; + } + + rufl_fm_error = xfont_switch_output_to_buffer(0, 0, + (char **)&buf_size); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + /* Allocate and initialise buffer */ + buf = malloc(buf_size); + if (!buf) { + LOG("Failed allocating buffer", 0); + return rufl_OUT_OF_MEMORY; + } + buf[0] = 0; + buf[1] = buf_size - 8; + + /* Populate buffer */ + rufl_fm_error = xfont_switch_output_to_buffer( + font_ADD_HINTS, (byte *)buf, 0); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(buf); + return rufl_FONT_MANAGER_ERROR; + } + + err = rufl_paint(font_family, font_style, font_size, string, len, + 0, 0, rufl_BLEND_FONT); + if (err) { + /* reset font redirection - too bad if this fails */ + xfont_switch_output_to_buffer(0, 0, 0); + free(buf); + return err; + } + + rufl_fm_error = xfont_switch_output_to_buffer(0, 0, (char **)&ep); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(buf); + return rufl_FONT_MANAGER_ERROR; + } + + /* Parse buffer, calling callbacks as required */ + for (p = buf; p < ep;) { + if (p[0] != 2) { + LOG("Object type %d not known", p[0]); + break; + } + + p = process_path(p, funcs, user); + + /* Have the callbacks asked for us to stop? */ + if (p == NULL) + break; + } + + free(buf); + + return rufl_OK; +} diff --git a/rufl_find.c b/rufl_find.c new file mode 100644 index 0000000..2ad4c92 --- /dev/null +++ b/rufl_find.c @@ -0,0 +1,191 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 James Bursa + * Copyright 2005 John-Mark Bell + */ + +#include +#include +#include +#include +#include + +#include "rufl_internal.h" + +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); + +/** + * Find a font family. + */ +rufl_code rufl_find_font_family(const char *font_family, + rufl_style font_style, unsigned int *font, + unsigned int *slanted, struct rufl_character_set **charset) +{ + char **family; + unsigned int f; + unsigned int weight, slant, used_weight; + unsigned int search_direction; + + family = bsearch(font_family, rufl_family_list, + rufl_family_list_entries, + sizeof rufl_family_list[0], rufl_family_list_cmp); + if (!family) + return rufl_FONT_NOT_FOUND; + + weight = (font_style & 0xf) - 1; + assert(weight <= 8); + slant = font_style & rufl_SLANTED ? 1 : 0; + + struct rufl_family_map_entry *e = + &rufl_family_map[family - rufl_family_list]; + used_weight = weight; + if (weight <= 2) + search_direction = -1; + else + search_direction = +1; + while (1) { + if (e->font[used_weight][slant] != NO_FONT) { + /* the weight and slant is available */ + f = e->font[used_weight][slant]; + break; + } + if (e->font[used_weight][1 - slant] != NO_FONT) { + /* slanted, and non-slanted weight exists, or vv. */ + f = e->font[used_weight][1 - slant]; + break; + } + if (used_weight == 0) { + /* searched down without finding a weight: search up */ + used_weight = weight + 1; + search_direction = +1; + } else if (used_weight == 8) { + /* searched up without finding a weight: search down */ + used_weight = weight - 1; + search_direction = -1; + } else { + /* try the next weight in the current direction */ + used_weight += search_direction; + } + } + + if (font) + (*font) = f; + + if (slanted) + (*slanted) = slant; + + if (charset) + (*charset) = rufl_font_list[f].charset; + + return rufl_OK; +} + + +/** + * Find a sized font, placing in the cache if necessary. + */ +rufl_code rufl_find_font(unsigned int font, unsigned int font_size, + const char *encoding, font_f *fhandle) +{ + font_f f; + char font_name[80]; + unsigned int i; + rufl_code code; + + assert(fhandle != NULL); + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + if (rufl_cache[i].font == font && + rufl_cache[i].size == font_size) + break; + } + if (i != rufl_CACHE_SIZE) { + /* found in cache */ + f = rufl_cache[i].f; + rufl_cache[i].last_used = rufl_cache_time++; + } else { + /* not found */ + if (font == rufl_CACHE_CORPUS) { + if (encoding) + snprintf(font_name, sizeof font_name, + "Corpus.Medium\\E%s", encoding); + else + snprintf(font_name, sizeof font_name, + "Corpus.Medium"); + } else { + if (encoding) + snprintf(font_name, sizeof font_name, + "%s\\E%s", + rufl_font_list[font].identifier, + encoding); + else + snprintf(font_name, sizeof font_name, "%s", + rufl_font_list[font].identifier); + } + + rufl_fm_error = xfont_find_font(font_name, + font_size, font_size, 0, 0, &f, 0, 0); + if (rufl_fm_error) { + LOG("xfont_find_font: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + /* place in cache */ + code = rufl_place_in_cache(font, font_size, f); + if (code != rufl_OK) + return code; + } + + (*fhandle) = f; + + return rufl_OK; +} + + +int rufl_family_list_cmp(const void *keyval, const void *datum) +{ + const char *key = keyval; + const char * const *entry = datum; + return strcasecmp(key, *entry); +} + + +/** + * Place a font into the recent-use cache, making space if necessary. + */ + +rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, + font_f f) +{ + unsigned int i; + unsigned int max_age = 0; + unsigned int evict = 0; + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + if (rufl_cache[i].font == rufl_CACHE_NONE) { + evict = i; + break; + } else if (max_age < rufl_cache_time - + rufl_cache[i].last_used) { + max_age = rufl_cache_time - + rufl_cache[i].last_used; + evict = i; + } + } + if (rufl_cache[evict].font != rufl_CACHE_NONE) { + rufl_fm_error = xfont_lose_font(rufl_cache[evict].f); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + } + rufl_cache[evict].font = font; + rufl_cache[evict].size = font_size; + rufl_cache[evict].f = f; + rufl_cache[evict].last_used = rufl_cache_time++; + + return rufl_OK; +} diff --git a/rufl_internal.h b/rufl_internal.h index 670fcb2..407ef01 100644 --- a/rufl_internal.h +++ b/rufl_internal.h @@ -127,6 +127,11 @@ extern bool rufl_old_font_manager; /** Font manager supports background blending */ extern bool rufl_can_background_blend; +rufl_code rufl_find_font_family(const char *family, rufl_style font_style, + unsigned int *font, unsigned int *slanted, + struct rufl_character_set **charset); +rufl_code rufl_find_font(unsigned int font, unsigned int font_size, + const char *encoding, font_f *fhandle); bool rufl_character_set_test(struct rufl_character_set *charset, unsigned int c); diff --git a/rufl_metrics.c b/rufl_metrics.c new file mode 100644 index 0000000..9309139 --- /dev/null +++ b/rufl_metrics.c @@ -0,0 +1,289 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 John-Mark Bell + */ + +#include +#include +#include + +#include "oslib/font.h" + +#include "rufl_internal.h" + +static int rufl_unicode_map_search_cmp(const void *keyval, const void *datum); + +/** + * Read a font's metrics (sized for a 1pt font) + */ +rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style, + os_box *bbox, int *xkern, int *ykern, int *italic, + int *ascent, int *descent, + int *xheight, int *cap_height, + signed char *uline_position, unsigned char *uline_thickness) +{ + unsigned int font; + font_f f; + int misc_size; + font_metrics_misc_info *misc_info; + rufl_code code; + + code = rufl_find_font_family(font_family, font_style, &font, + NULL, NULL); + if (code != rufl_OK) + return code; + + code = rufl_find_font(font, 16 /* 1pt */, NULL, &f); + if (code != rufl_OK) + return code; + + rufl_fm_error = xfont_read_font_metrics(f, 0, 0, 0, 0, 0, + 0, 0, 0, 0, &misc_size, 0); + if (rufl_fm_error) { + LOG("xfont_read_font_metrics: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + if (misc_size == 0) { + LOG("No font metrics in file", 0); + /** \todo better error code */ + return rufl_FONT_NOT_FOUND; + } + + misc_info = (font_metrics_misc_info *)malloc(misc_size); + if (!misc_info) + return rufl_OUT_OF_MEMORY; + + rufl_fm_error = xfont_read_font_metrics(f, 0, 0, 0, misc_info, 0, + 0, 0, 0, 0, 0, 0); + if (rufl_fm_error) { + LOG("xfont_read_font_metrics: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(misc_info); + return rufl_FONT_MANAGER_ERROR; + } + + /* and fill in output */ + if (bbox) { + bbox->x0 = misc_info->x0; + bbox->y0 = misc_info->y0; + bbox->x1 = misc_info->x1; + bbox->y1 = misc_info->y1; + } + + if (xkern) + (*xkern) = misc_info->xkern; + + if (ykern) + (*ykern) = misc_info->ykern; + + if (italic) + (*italic) = misc_info->italic_correction; + + if (ascent) + (*ascent) = misc_info->ascender; + + if (descent) + (*descent) = misc_info->descender; + + if (xheight) + (*xheight) = misc_info->xheight; + + if (cap_height) + (*cap_height) = misc_info->cap_height; + + if (uline_position) + (*uline_position) = misc_info->underline_position; + + if (uline_thickness) + (*uline_thickness) = misc_info->underline_thickness; + + free(misc_info); + + return rufl_OK; +} + +/** + * Read a glyph's metrics + */ +rufl_code rufl_glyph_metrics(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t length, + int *x_bearing, int *y_bearing, + int *width, int *height, + int *x_advance, int *y_advance) +{ + unsigned int font, font1, u; + unsigned short u1[2]; + struct rufl_character_set *charset; + font_f f; + rufl_code code; + font_scan_block block; + font_string_flags flags; + int xa, ya; + + code = rufl_find_font_family(font_family, font_style, + &font, NULL, &charset); + if (code != rufl_OK) + return code; + + rufl_utf8_read(string, length, u); + if (charset && rufl_character_set_test(charset, u)) + font1 = font; + else if (u < 0x10000) + font1 = rufl_substitution_table[u]; + else + font1 = rufl_CACHE_CORPUS; + + code = rufl_find_font(font1, font_size, NULL, &f); + if (code != rufl_OK) + return code; + + /* + * Glyph Metrics for horizontal text: + * + * ^ x0 x1 ¦ + * | ¦ ¦ ¦ Xbearing : x0 - oX + * | +-----+---¦----- y1 Ybearing : y1 - oY + * | | | ¦ Xadvance : aX - oX + * | | | ¦ Yadvance : 0 + * o---|-----|---a--> Glyph width : x1 - x0 + * | | | ¦ Glyph height : y1 - y0 + * | +-----+---¦----- y0 Right side bearing: aX - x1 + * | ¦ + * + * The rectangle (x0,y0),(x1,y1) is the glyph bounding box. + * + * Glyph Metrics for vertical text: + * + * -------o---------> + * y1--+--|--+ Xbearing : x0 - oX + * | | | Ybearing : oY - y1 + * | | | Xadvance : 0 + * | | | Yadvance : aY - oY + * | | | Glyph width : x1 - x0 + * y0--+-----+ Glyph height : y1 - y0 + * ----¦--a--¦--------- Right side bearing: N/A + * x0 v x1 + * + * The rectangle (x0,y0),(x1,y1) is the glyph bounding box. + * + * + * In order to extract the information we want from the + * Font Manager, a little bit of hackery is required. + * + * Firstly, we can take the origin as being (0,0). This is an + * arbitrary choice but makes the maths simpler. + * + * Secondly, the bounding box returned by Font_CharBBox / + * Font_ScanString / Font_StringBBox represents the ink area of + * the glyph (i.e. the smallest box needed to contain all the + * glyph path segments). This means that, for glyphs with no + * displayed content (such as a space), the bounding box will be 0. + * These SWIs therefore allow us to retrieve the (x0,y0),(x1,y1) + * coordinates marked in the diagrams above. + * + * Finally, we need to retrieve the glyph advance distance. This is + * returned in R3/R4 on exit from Font_ScanString (providing bit 17 + * of the flags word on entry is clear). It is important to note, + * however, that the height will be returned as 0 for fonts with no + * Yadvance values in the font data file. Therefore, in order to + * achieve vertical layout of text, further work will be needed + * (We're also ignoring the fact that the X coordinates of all + * values will be in the wrong place and the Y coordinates will have + * the wrong sign due to the differing definitions of the Y axis for + * horizontal and vertical text.) + * + * Note that all values (that we're interested in, at least) + * returned by the SWIs mentioned above are in _millipoints_. + */ + + block.space.x = block.space.y = 0; + block.letter.x = block.letter.y = 0; + block.split_char = -1; + + flags = font_GIVEN_BLOCK | font_GIVEN_LENGTH | font_GIVEN_FONT | + font_RETURN_BBOX; + + u1[0] = (unsigned short)u; + u1[1] = 0; + + if (font1 == rufl_CACHE_CORPUS) { + /* Fallback Glyph */ + /** \todo implement this properly */ + xa = 1000 * font_size; + ya = 0; + block.bbox.x0 = block.bbox.y0 = 0; + block.bbox.x1 = block.bbox.y1 = xa; + } 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; + s[1] = 0; + + rufl_fm_error = xfont_scan_string(f, s, flags, + 0x7fffffff, 0x7fffffff, &block, 0, 1, + 0, &xa, &ya, 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; + } + } else { + /* UCS Font Manager */ + rufl_fm_error = xfont_scan_string(f, (const char *)u1, + flags | font_GIVEN16_BIT, + 0x7fffffff, 0x7fffffff, &block, 0, 2, + 0, &xa, &ya, 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; + } + } + + /** \todo handle vertical text */ + if (x_bearing) + (*x_bearing) = block.bbox.x0; + + if (y_bearing) + (*y_bearing) = block.bbox.y1; + + if (width) + (*width) = block.bbox.x1 - block.bbox.x0; + + if (height) + (*height) = block.bbox.y1 - block.bbox.y0; + + if (x_advance) + (*x_advance) = xa; + + if (y_advance) + (*y_advance) = ya; + + return rufl_OK; +} + + +int rufl_unicode_map_search_cmp(const void *keyval, const void *datum) +{ + const unsigned short *key = keyval; + const struct rufl_unicode_map_entry *entry = datum; + if (*key < entry->u) + return -1; + else if (entry->u < *key) + return 1; + return 0; +} diff --git a/rufl_paint.c b/rufl_paint.c index c08c4a0..2975179 100644 --- a/rufl_paint.c +++ b/rufl_paint.c @@ -31,9 +31,6 @@ static rufl_code rufl_process(rufl_action action, int x, int y, unsigned int flags, int *width, int click_x, size_t *char_offset, int *actual_x, rufl_callback_t callback, void *context); -static bool rufl_find_font(const char *font_family, rufl_style font_style, - unsigned int *font_index, unsigned int *slanted); -static int rufl_family_list_cmp(const void *keyval, const void *datum); static rufl_code rufl_process_span(rufl_action action, unsigned short *s, unsigned int n, unsigned int font, unsigned int font_size, unsigned int slant, @@ -53,9 +50,6 @@ static rufl_code rufl_process_not_available(rufl_action action, unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context); -static font_f rufl_search_cache(unsigned int font, unsigned int font_size); -static rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, - font_f f); /** @@ -208,8 +202,10 @@ rufl_code rufl_process(rufl_action action, return rufl_OK; } - if (!rufl_find_font(font_family, font_style, &font, &slant)) - return rufl_FONT_NOT_FOUND; + code = rufl_find_font_family(font_family, font_style, + &font, &slant, &charset); + if (code != rufl_OK) + return code; if (action == rufl_FONT_BBOX) { if (rufl_old_font_manager) @@ -223,8 +219,6 @@ rufl_code rufl_process(rufl_action action, return code; } - charset = rufl_font_list[font].charset; - offset_u = 0; rufl_utf8_read(string, length, u); if (u <= 0x001f || (0x007f <= u && u <= 0x009f)) @@ -296,73 +290,6 @@ rufl_code rufl_process(rufl_action action, } -/** - * Determine the index in rufl_font_list for a font family and style. - */ - -bool rufl_find_font(const char *font_family, rufl_style font_style, - unsigned int *font_index, unsigned int *slanted) -{ - char **family; - unsigned int font, weight, slant, used_weight; - unsigned int search_direction; - - family = bsearch(font_family, rufl_family_list, - rufl_family_list_entries, - sizeof rufl_family_list[0], rufl_family_list_cmp); - if (!family) - return false; - weight = (font_style & 0xf) - 1; - assert(weight <= 8); - slant = font_style & rufl_SLANTED ? 1 : 0; - - struct rufl_family_map_entry *e = - &rufl_family_map[family - rufl_family_list]; - used_weight = weight; - if (weight <= 2) - search_direction = -1; - else - search_direction = +1; - while (1) { - if (e->font[used_weight][slant] != NO_FONT) { - /* the weight and slant is available */ - font = e->font[used_weight][slant]; - break; - } - if (e->font[used_weight][1 - slant] != NO_FONT) { - /* slanted, and non-slanted weight exists, or vv. */ - font = e->font[used_weight][1 - slant]; - break; - } - if (used_weight == 0) { - /* searched down without finding a weight: search up */ - used_weight = weight + 1; - search_direction = +1; - } else if (used_weight == 8) { - /* searched up without finding a weight: search down */ - used_weight = weight - 1; - search_direction = -1; - } else { - /* try the next weight in the current direction */ - used_weight += search_direction; - } - } - - *font_index = font; - *slanted = slant; - - return true; -} - - -int rufl_family_list_cmp(const void *keyval, const void *datum) -{ - const char *key = keyval; - const char * const *entry = datum; - return strcasecmp(key, *entry); -} - - /** * Render a string of characters from a single RISC OS font. */ @@ -374,32 +301,17 @@ rufl_code rufl_process_span(rufl_action action, int click_x, size_t *offset, rufl_callback_t callback, void *context) { - char font_name[80]; unsigned short *split_point; int x_out, y_out; unsigned int i; + char font_name[80]; bool oblique = slant && !rufl_font_list[font].slant; font_f f; rufl_code code; - /* search cache */ - f = rufl_search_cache(font, font_size); - if (!f) { - snprintf(font_name, sizeof font_name, "%s\\EUTF8", - rufl_font_list[font].identifier); - rufl_fm_error = xfont_find_font(font_name, - font_size, font_size, 0, 0, &f, 0, 0); - if (rufl_fm_error) { - LOG("xfont_find_font: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; - } - /* place in cache */ - code = rufl_place_in_cache(font, font_size, f); - if (code != rufl_OK) - return code; - } + code = rufl_find_font(font, font_size, "UTF8", &f); + if (code != rufl_OK) + return code; if (action == rufl_FONT_BBOX) { rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]); @@ -478,7 +390,6 @@ rufl_code rufl_process_span_old(rufl_action action, { char s2[rufl_PROCESS_CHUNK]; char *split_point; - const char *font_name = rufl_font_list[font].identifier; int x_out, y_out; unsigned int i; bool oblique = slant && !rufl_font_list[font].slant; @@ -486,18 +397,9 @@ rufl_code rufl_process_span_old(rufl_action action, rufl_code code; struct rufl_unicode_map_entry *entry; - /* search cache */ - f = rufl_search_cache(font, font_size); - if (!f) { - rufl_fm_error = xfont_find_font(font_name, - font_size, font_size, 0, 0, &f, 0, 0); - if (rufl_fm_error) - return rufl_FONT_MANAGER_ERROR; - /* place in cache */ - code = rufl_place_in_cache(font, font_size, f); - if (code != rufl_OK) - return code; - } + code = rufl_find_font(font, font_size, NULL, &f); + if (code != rufl_OK) + return code; if (action == rufl_FONT_BBOX) { rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]); @@ -528,7 +430,8 @@ rufl_code rufl_process_span_old(rufl_action action, if (rufl_fm_error) return rufl_FONT_MANAGER_ERROR; } else if (action == rufl_PAINT_CALLBACK) { - callback(context, font_name, font_size, s2, 0, n, *x, y); + callback(context, rufl_font_list[font].identifier, + font_size, s2, 0, n, *x, y); } /* increment x by width of span */ @@ -597,32 +500,9 @@ rufl_code rufl_process_not_available(rufl_action action, return rufl_OK; } - if (action == rufl_PAINT) { - /* search cache */ - for (i = 0; i != rufl_CACHE_SIZE; i++) { - if (rufl_cache[i].font == rufl_CACHE_CORPUS && - rufl_cache[i].size == font_size) - break; - } - if (i != rufl_CACHE_SIZE) { - /* found in cache */ - f = rufl_cache[i].f; - rufl_cache[i].last_used = rufl_cache_time++; - } else { - /* not found */ - rufl_fm_error = xfont_find_font( - "Corpus.Medium\\ELatin1", - font_size / 2, font_size / 2, 0, 0, - &f, 0, 0); - if (rufl_fm_error) - return rufl_FONT_MANAGER_ERROR; - /* place in cache */ - code = rufl_place_in_cache(rufl_CACHE_CORPUS, - font_size, f); - if (code != rufl_OK) - return code; - } - } + code = rufl_find_font(rufl_CACHE_CORPUS, font_size / 2, "Latin1", &f); + if (code != rufl_OK) + return code; for (i = 0; i != n; i++) { missing[0] = "0123456789abcdef"[(s[i] >> 12) & 0xf]; @@ -668,63 +548,3 @@ rufl_code rufl_process_not_available(rufl_action action, return rufl_OK; } - - -/** - * Find a font in the recent-use cache. - */ - -font_f rufl_search_cache(unsigned int font, unsigned int font_size) -{ - unsigned int i; - - for (i = 0; i != rufl_CACHE_SIZE; i++) { - if (rufl_cache[i].font == font && - rufl_cache[i].size == font_size) - break; - } - if (i != rufl_CACHE_SIZE) { - /* found in cache */ - rufl_cache[i].last_used = rufl_cache_time++; - return rufl_cache[i].f; - } else { - /* not found */ - return 0; - } -} - - -/** - * Place a font into the recent-use cache, making space if necessary. - */ - -rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, - font_f f) -{ - unsigned int i; - unsigned int max_age = 0; - unsigned int evict = 0; - - for (i = 0; i != rufl_CACHE_SIZE; i++) { - if (rufl_cache[i].font == rufl_CACHE_NONE) { - evict = i; - break; - } else if (max_age < rufl_cache_time - - rufl_cache[i].last_used) { - max_age = rufl_cache_time - - rufl_cache[i].last_used; - evict = i; - } - } - if (rufl_cache[evict].font != rufl_CACHE_NONE) { - rufl_fm_error = xfont_lose_font(rufl_cache[evict].f); - if (rufl_fm_error) - return rufl_FONT_MANAGER_ERROR; - } - rufl_cache[evict].font = font; - rufl_cache[evict].size = font_size; - rufl_cache[evict].f = f; - rufl_cache[evict].last_used = rufl_cache_time++; - - return rufl_OK; -} diff --git a/rufl_test.c b/rufl_test.c index 843db1f..a72017f 100644 --- a/rufl_test.c +++ b/rufl_test.c @@ -12,6 +12,10 @@ static void try(rufl_code code, const char *context); +static int move_to(os_coord *to, void *user); +static int line_to(os_coord *to, void *user); +static int cubic_to(os_coord *control1, os_coord *control2, os_coord *to, + void *user); static void callback(void *context, const char *font_name, unsigned int font_size, const char *s8, unsigned short *s16, unsigned int n, @@ -26,6 +30,7 @@ int main(void) size_t char_offset; int x; int actual_x; + struct rufl_decomp_funcs funcs = { move_to, line_to, cubic_to }; int bbox[4]; try(rufl_init(), "rufl_init"); @@ -51,6 +56,9 @@ int main(void) printf("split: %i -> %i %i \"%s\"\n", x, actual_x, char_offset, utf8_test + char_offset); } + try(rufl_decompose_glyph("Homerton", rufl_WEIGHT_400, 1280, + "A", 1, &funcs, 0), + "rufl_decompose_glyph"); try(rufl_paint_callback("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, 1200, 1000, callback, 0), "rufl_paint_callback"); @@ -87,6 +95,34 @@ void try(rufl_code code, const char *context) } +int move_to(os_coord *to, void *user) +{ + printf("Move to (%d,%d)\n", to->x, to->y); + + return 0; +} + + +int line_to(os_coord *to, void *user) +{ + printf("Line to (%d,%d)\n", to->x, to->y); + + return 0; +} + + +int cubic_to(os_coord *control1, os_coord *control2, os_coord *to, + void *user) +{ + printf("Bezier to (%d,%d),(%d,%d),(%d,%d)\n", + control1->x, control1->y, + control2->x, control2->y, + to->x, to->y); + + return 0; +} + + void callback(void *context, const char *font_name, unsigned int font_size, const char *s8, unsigned short *s16, unsigned int n, -- cgit v1.2.3