diff options
author | James Bursa <james@netsurf-browser.org> | 2006-01-29 12:20:25 +0000 |
---|---|---|
committer | James Bursa <james@netsurf-browser.org> | 2006-01-29 12:20:25 +0000 |
commit | 87d2b7aa8e9b6e2209776a73da67398c795cbcb3 (patch) | |
tree | fac5f022fcebbfe684643055813f8489138819af | |
parent | 4581f7a89f79a828d161191f336a4444c8d2f9e8 (diff) | |
download | librufl-87d2b7aa8e9b6e2209776a73da67398c795cbcb3.tar.gz librufl-87d2b7aa8e9b6e2209776a73da67398c795cbcb3.tar.bz2 |
[project @ 2006-01-29 12:20:25 by bursa]
Improve handling of font weights. Now detects available weights better and supports up to 9 weights. Ignore control characters and spaces that are not spaces when scanning available characters.
svn path=/import/rufl/; revision=2470
-rw-r--r-- | rufl.h | 34 | ||||
-rw-r--r-- | rufl_chars.c | 70 | ||||
-rw-r--r-- | rufl_dump_state.c | 21 | ||||
-rw-r--r-- | rufl_init.c | 340 | ||||
-rw-r--r-- | rufl_internal.h | 22 | ||||
-rw-r--r-- | rufl_paint.c | 145 | ||||
-rw-r--r-- | rufl_test.c | 12 |
7 files changed, 365 insertions, 279 deletions
@@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #ifndef RUFL_H @@ -29,15 +29,22 @@ typedef enum { rufl_IO_EOF, } rufl_code; - +/** Font weight and slant. Normal weight is 400, 700 gives the "Bold" weight of + * fonts. */ typedef enum { - rufl_REGULAR = 0, - rufl_SLANTED = 1, - rufl_BOLD = 2, - rufl_BOLD_SLANTED = 3, + rufl_WEIGHT_100 = 1, + rufl_WEIGHT_200 = 2, + rufl_WEIGHT_300 = 3, + rufl_WEIGHT_400 = 4, + rufl_WEIGHT_500 = 5, + rufl_WEIGHT_600 = 6, + rufl_WEIGHT_700 = 7, + rufl_WEIGHT_800 = 8, + rufl_WEIGHT_900 = 9, + rufl_SLANTED = 0x100, } rufl_style; -/** rufl_paint(_transformed) flags */ +/** rufl_paint flags */ #define rufl_BLEND_FONT 0x01 /** Last Font Manager error. */ @@ -69,19 +76,6 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style, /** - * Render Unicode text with a transformation matrix. - * - * Only transformations which keep the x-axis direction unchanged are - * supported. - */ - -rufl_code rufl_paint_transformed(const char *font_family, rufl_style font_style, - unsigned int font_size, - const char *string, size_t length, - int x, int y, os_trfm *trfm, unsigned int flags); - - -/** * Measure the width of Unicode text. */ diff --git a/rufl_chars.c b/rufl_chars.c index ff7013a..d9b9d6f 100644 --- a/rufl_chars.c +++ b/rufl_chars.c @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #include <errno.h> @@ -16,7 +16,7 @@ unsigned int font = 0; -bool bold = false; +unsigned int weight = rufl_WEIGHT_400; bool italic = false; @@ -73,7 +73,7 @@ int main(void) try(rufl_init(), "rufl_init"); - menu = malloc(wimp_SIZEOF_MENU(2 + rufl_family_list_entries)); + menu = malloc(wimp_SIZEOF_MENU(10 + rufl_family_list_entries)); if (!menu) die("Out of memory"); strcpy(menu->title_data.text, "Fonts"); @@ -84,34 +84,38 @@ int main(void) menu->width = 200; menu->height = wimp_MENU_ITEM_HEIGHT; menu->gap = wimp_MENU_ITEM_GAP; - menu->entries[0].menu_flags = 0; - menu->entries[0].sub_menu = wimp_NO_SUB_MENU; - menu->entries[0].icon_flags = wimp_ICON_TEXT | - (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | - (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); - strcpy(menu->entries[0].data.text, "Bold"); - menu->entries[1].menu_flags = wimp_MENU_SEPARATE; - menu->entries[1].sub_menu = wimp_NO_SUB_MENU; - menu->entries[1].icon_flags = wimp_ICON_TEXT | + for (i = 0; i != 10; i++) { + menu->entries[i].menu_flags = 0; + menu->entries[i].sub_menu = wimp_NO_SUB_MENU; + menu->entries[i].icon_flags = wimp_ICON_TEXT | + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); + strcpy(menu->entries[i].data.text, "100"); + menu->entries[i].data.text[0] = '1' + i; + } + menu->entries[9].menu_flags = wimp_MENU_SEPARATE; + menu->entries[9].sub_menu = wimp_NO_SUB_MENU; + menu->entries[9].icon_flags = wimp_ICON_TEXT | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); - strcpy(menu->entries[1].data.text, "Italic"); + strcpy(menu->entries[9].data.text, "Italic"); for (i = 0; i != rufl_family_list_entries; i++) { - menu->entries[2 + i].menu_flags = 0; - menu->entries[2 + i].sub_menu = wimp_NO_SUB_MENU; - menu->entries[2 + i].icon_flags = wimp_ICON_TEXT | + menu->entries[10 + i].menu_flags = 0; + menu->entries[10 + i].sub_menu = wimp_NO_SUB_MENU; + menu->entries[10 + i].icon_flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); - menu->entries[2 + i].data.indirected_text.text = + menu->entries[10 + i].data.indirected_text.text = rufl_family_list[i]; - menu->entries[2 + i].data.indirected_text.validation = + menu->entries[10 + i].data.indirected_text.validation = (char *) -1; - menu->entries[2 + i].data.indirected_text.size = + menu->entries[10 + i].data.indirected_text.size = strlen(rufl_family_list[i]); } - menu->entries[2].menu_flags |= wimp_MENU_TICKED; - menu->entries[i + 1].menu_flags |= wimp_MENU_LAST; + menu->entries[3].menu_flags |= wimp_MENU_TICKED; + menu->entries[10].menu_flags |= wimp_MENU_TICKED; + menu->entries[i + 9].menu_flags |= wimp_MENU_LAST; error = xwimp_create_window((wimp_window *) &window, &w); if (error) @@ -181,17 +185,20 @@ int main(void) error = xwimp_get_pointer_info(&pointer); if (error) die(error->errmess); - if (block.selection.items[0] == 0) { - bold = !bold; - menu->entries[0].menu_flags ^= wimp_MENU_TICKED; - } else if (block.selection.items[0] == 1) { + if (block.selection.items[0] <= 8) { + menu->entries[weight - 1].menu_flags ^= + wimp_MENU_TICKED; + weight = block.selection.items[0] + 1; + menu->entries[weight - 1].menu_flags ^= + wimp_MENU_TICKED; + } else if (block.selection.items[0] == 9) { italic = !italic; - menu->entries[1].menu_flags ^= wimp_MENU_TICKED; + menu->entries[9].menu_flags ^= wimp_MENU_TICKED; } else { - menu->entries[2 + font].menu_flags ^= + menu->entries[10 + font].menu_flags ^= wimp_MENU_TICKED; - font = block.selection.items[0] - 2; - menu->entries[2 + font].menu_flags ^= + font = block.selection.items[0] - 10; + menu->entries[10 + font].menu_flags ^= wimp_MENU_TICKED; } error = xwimp_force_redraw(w, @@ -239,10 +246,7 @@ rufl_code redraw(int x, int y, int y0, int y1) unsigned int l; unsigned int u; rufl_code code; - rufl_style style = bold && italic ? rufl_BOLD_SLANTED : - bold ? rufl_BOLD : - italic ? rufl_SLANTED : - rufl_REGULAR; + rufl_style style = weight | (italic ? rufl_SLANTED : 0); for (u = y0 / 40 * 32; (int) u != (y1 / 40 + 1) * 32; u++) { if (u <= 0x7f) diff --git a/rufl_dump_state.c b/rufl_dump_state.c index 81b7fb3..e1ba483 100644 --- a/rufl_dump_state.c +++ b/rufl_dump_state.c @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #include <stdio.h> @@ -42,10 +42,21 @@ void rufl_dump_state(void) printf("rufl_family_list:\n"); for (i = 0; i != rufl_family_list_entries; i++) { printf(" %u \"%s\"\n", i, rufl_family_list[i]); - for (j = 0; j != rufl_STYLES; j++) - printf(" %u \"%s\"\n", j, rufl_font_list - [rufl_family_map[rufl_STYLES * i + j]] - .identifier); + for (j = 0; j != 9; j++) { + struct rufl_family_map_entry *e = &rufl_family_map[i]; + printf(" %u ", j); + if (e->font[j][0] == NO_FONT) + printf("- "); + else + printf("\"%s\" ", rufl_font_list[e->font[j][0]]. + identifier); + if (e->font[j][1] == NO_FONT) + printf("- "); + else + printf("\"%s\" ", rufl_font_list[e->font[j][1]]. + identifier); + printf("\n"); + } } printf("rufl_substitution_table:\n"); diff --git a/rufl_init.c b/rufl_init.c index ed3d9ff..a195cd9 100644 --- a/rufl_init.c +++ b/rufl_init.c @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #define _GNU_SOURCE /* for strndup */ @@ -23,7 +23,7 @@ struct rufl_font_list_entry *rufl_font_list = 0; unsigned int rufl_font_list_entries = 0; char **rufl_family_list = 0; unsigned int rufl_family_list_entries = 0; -unsigned int *rufl_family_map = 0; +struct rufl_family_map_entry *rufl_family_map = 0; os_error *rufl_fm_error = 0; unsigned short *rufl_substitution_table; struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE]; @@ -31,31 +31,41 @@ int rufl_cache_time = 0; bool rufl_old_font_manager = false; -/** An entry in rufl_style_table. */ -struct rufl_style_table_entry { +/** An entry in rufl_weight_table. */ +struct rufl_weight_table_entry { const char *name; - unsigned int style; + unsigned int weight; }; -/** Map from font name tail to font style. Must be sorted by name. */ -const struct rufl_style_table_entry rufl_style_table[] = { - { "Bold", rufl_BOLD }, - { "Bold.Italic", rufl_BOLD_SLANTED }, - { "Bold.Oblique", rufl_BOLD_SLANTED }, - { "Italic", rufl_SLANTED }, - { "Medium", rufl_REGULAR }, - { "Medium.Italic", rufl_SLANTED }, - { "Medium.Oblique", rufl_SLANTED }, - { "Oblique", rufl_SLANTED }, - { "Regular", rufl_REGULAR }, - { "Regular.Italic", rufl_SLANTED }, - { "Regular.Oblique", rufl_SLANTED }, +/** Map from font name part to font weight. Must be case-insensitive sorted by + * name. */ +const struct rufl_weight_table_entry rufl_weight_table[] = { + { "Black", 9 }, + { "Bold", 7 }, + { "Book", 3 }, + { "Demi", 6 }, + { "DemiBold", 6 }, + { "Extra", 8 }, + { "ExtraBlack", 9 }, + { "ExtraBold", 8 }, + { "ExtraLight", 1 }, + { "Heavy", 8 }, + { "Light", 2 }, + { "Medium", 5 }, + { "Regular", 4 }, + { "Semi", 6 }, + { "SemiBold", 6 }, + { "SemiLight", 3 }, + { "UltraBlack", 9 }, + { "UltraBold", 9 }, }; static rufl_code rufl_init_font_list(void); -static int rufl_style_table_cmp(const void *keyval, const void *datum); +static rufl_code rufl_init_add_font(char *identifier); +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_read_encoding(font_f font, struct rufl_unicode_map *umap); @@ -189,137 +199,133 @@ rufl_code rufl_init(void) rufl_code rufl_init_font_list(void) { - int size; - struct rufl_font_list_entry *font_list; - char *identifier; - char *dot; - char **family_list; - char *family; - unsigned int *family_map; - unsigned int i; + rufl_code code; font_list_context context = 0; - font_list_context context2; - struct rufl_style_table_entry *entry; + char identifier[80]; while (context != -1) { - /* find length of next identifier */ - rufl_fm_error = xfont_list_fonts(0, - font_RETURN_FONT_NAME | context, - 0, 0, 0, 0, - &context2, &size, 0); - if (rufl_fm_error) { - LOG("xfont_list_fonts: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; - } - if (context2 == -1) - break; - - /* get next identifier */ - identifier = malloc(size); - if (!identifier) - return rufl_OUT_OF_MEMORY; - /* read identifier */ rufl_fm_error = xfont_list_fonts(identifier, font_RETURN_FONT_NAME | context, - size, 0, 0, 0, + sizeof identifier, 0, 0, 0, &context, 0, 0); if (rufl_fm_error) { - free(identifier); LOG("xfont_list_fonts: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); return rufl_FONT_MANAGER_ERROR; } + if (context == -1) + break; - /* Check that: - * a) it's got some Outlines data - * b) it's not a RiScript generated font - * c) it's not a TeX font - * - * If it's any of the above, we ignore it. - */ - char pathname[size+6]; /* Fontname + ".Out*" + \0 */ - snprintf(pathname, sizeof pathname, "%s.Out*", identifier); - - /* Read required buffer size */ - rufl_fm_error = xosfscontrol_canonicalise_path(pathname, 0, - "Font$Path", 0, 0, &size); - if (rufl_fm_error) { - free(identifier); - LOG("xosfscontrol_canonicalise_path: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; - } + code = rufl_init_add_font(identifier); + if (code != rufl_OK) + return code; + } - /* size is -(space required - 1) so negate and add 1 */ - size = -size + 1; + return rufl_OK; +} - /* Create buffer and canonicalise path */ - char fullpath[size]; - rufl_fm_error = xosfscontrol_canonicalise_path(pathname, - fullpath, "Font$Path", 0, size, 0); - if (rufl_fm_error) { - free(identifier); - LOG("xosfscontrol_canonicalise_path: 0x%x: %s", - rufl_fm_error->errnum, - rufl_fm_error->errmess); - return rufl_FONT_MANAGER_ERROR; - } - /* LOG("%s (%c)", fullpath, fullpath[size - 2]); */ +rufl_code rufl_init_add_font(char *identifier) +{ + char pathname[100]; + size_t size; + struct rufl_font_list_entry *font_list; + char *dot; + char **family_list; + char *family, *part; + unsigned int weight = 0; + unsigned int slant = 0; + bool special = false; + struct rufl_family_map_entry *family_map; + unsigned int i; + struct rufl_weight_table_entry *entry; - /* If the last character is an asterisk, - * there's no Outlines file. */ - if (fullpath[size - 2] == '*' || - strstr(fullpath, "RiScript") || - strstr(fullpath, "!TeXFonts")) { - /* Ignore this font */ - free(identifier); - continue; - } + /* Check that: + * a) it's got some Outlines data + * b) it's not a RiScript generated font + * c) it's not a TeX font */ + snprintf(pathname, sizeof pathname, "%s.Out*", identifier); - /* (re)allocate buffers */ - font_list = realloc(rufl_font_list, sizeof rufl_font_list[0] * - (rufl_font_list_entries + 1)); - if (!font_list) { - free(identifier); - return rufl_OUT_OF_MEMORY; - } - rufl_font_list = font_list; - - rufl_font_list[rufl_font_list_entries].identifier = identifier; - rufl_font_list[rufl_font_list_entries].charset = 0; - rufl_font_list[rufl_font_list_entries].umap = 0; - rufl_font_list_entries++; - - /*LOG("%u \"%s\"", rufl_font_list_entries - 1, identifier);*/ - - /* add family to list, if it is new */ - dot = strchr(identifier, '.'); - if (2 <= rufl_font_list_entries && dot && - strncmp(identifier, rufl_font_list - [rufl_font_list_entries - 2].identifier, - dot - identifier) == 0) { - /* same family as last font */ - entry = bsearch(dot + 1, rufl_style_table, - sizeof rufl_style_table / - sizeof rufl_style_table[0], - sizeof rufl_style_table[0], - rufl_style_table_cmp); - if (entry) - rufl_family_map[rufl_STYLES * - (rufl_family_list_entries - 1) + - entry->style] = - rufl_font_list_entries - 1; + /* Read required buffer size */ + rufl_fm_error = xosfscontrol_canonicalise_path(pathname, 0, + "Font$Path", 0, 0, &size); + if (rufl_fm_error) { + LOG("xosfscontrol_canonicalise_path: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + /* size is -(space required - 1) so negate and add 1 */ + size = -size + 1; + + /* Create buffer and canonicalise path */ + char fullpath[size]; + rufl_fm_error = xosfscontrol_canonicalise_path(pathname, + fullpath, "Font$Path", 0, size, 0); + if (rufl_fm_error) { + LOG("xosfscontrol_canonicalise_path: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + /* LOG("%s (%c)", fullpath, fullpath[size - 2]); */ + + /* If the last character is an asterisk, there's no Outlines file. */ + if (fullpath[size - 2] == '*' || + strstr(fullpath, "RiScript") || + strstr(fullpath, "!TeXFonts")) + /* Ignore this font */ + return rufl_OK; + + /* add identifier to rufl_font_list */ + font_list = realloc(rufl_font_list, sizeof rufl_font_list[0] * + (rufl_font_list_entries + 1)); + if (!font_list) + return rufl_OUT_OF_MEMORY; + rufl_font_list = font_list; + rufl_font_list[rufl_font_list_entries].identifier = strdup(identifier); + if (!rufl_font_list[rufl_font_list_entries].identifier) + return rufl_OUT_OF_MEMORY; + rufl_font_list[rufl_font_list_entries].charset = 0; + rufl_font_list[rufl_font_list_entries].umap = 0; + rufl_font_list_entries++; + + /* determine family, weight, and slant */ + dot = strchr(identifier, '.'); + family = identifier; + if (dot) + *dot = 0; + while (dot && (!weight || !slant)) { + part = dot + 1; + dot = strchr(part, '.'); + if (dot) + *dot = 0; + if (strcasecmp(part, "Italic") == 0 || + strcasecmp(part, "Oblique") == 0) { + slant = 1; continue; } + entry = bsearch(part, rufl_weight_table, + sizeof rufl_weight_table / + sizeof rufl_weight_table[0], + sizeof rufl_weight_table[0], + rufl_weight_table_cmp); + if (entry) + weight = entry->weight; + else + special = true; /* unknown weight or style */ + } + if (!weight) + weight = 4; + weight--; + if (rufl_family_list_entries == 0 || strcasecmp(family, + rufl_family_list[rufl_family_list_entries - 1]) != 0) { /* new family */ - /*LOG("new family %u", rufl_family_list_entries);*/ family_list = realloc(rufl_family_list, sizeof rufl_family_list[0] * (rufl_family_list_entries + 1)); @@ -328,35 +334,45 @@ rufl_code rufl_init_font_list(void) rufl_family_list = family_list; family_map = realloc(rufl_family_map, - rufl_STYLES * sizeof rufl_family_map[0] * + sizeof rufl_family_map[0] * (rufl_family_list_entries + 1)); if (!family_map) return rufl_OUT_OF_MEMORY; rufl_family_map = family_map; - if (dot) - family = strndup(identifier, dot - identifier); - else - family = strdup(identifier); + family = strdup(family); if (!family) return rufl_OUT_OF_MEMORY; rufl_family_list[rufl_family_list_entries] = family; - for (i = 0; i != rufl_STYLES; i++) - rufl_family_map[rufl_STYLES * rufl_family_list_entries + - i] = rufl_font_list_entries - 1; + for (i = 0; i != 9; i++) + rufl_family_map[rufl_family_list_entries].font[i][0] = + rufl_family_map[rufl_family_list_entries].font[i][1] = + NO_FONT; rufl_family_list_entries++; } + struct rufl_family_map_entry *e = + &rufl_family_map[rufl_family_list_entries - 1]; + /* prefer fonts with no unknown weight or style in their name, so that, + * for example, Alps.Light takes priority over Alps.Cond.Light */ + if (e->font[weight][slant] == NO_FONT || !special) + e->font[weight][slant] = rufl_font_list_entries - 1; + + rufl_font_list[rufl_font_list_entries - 1].family = + rufl_family_list_entries - 1; + rufl_font_list[rufl_font_list_entries - 1].weight = weight; + rufl_font_list[rufl_font_list_entries - 1].slant = slant; + return rufl_OK; } -int rufl_style_table_cmp(const void *keyval, const void *datum) +int rufl_weight_table_cmp(const void *keyval, const void *datum) { const char *key = keyval; - const struct rufl_style_table_entry *entry = datum; - return strcmp(key, entry->name); + const struct rufl_weight_table_entry *entry = datum; + return strcasecmp(key, entry->name); } @@ -397,7 +413,13 @@ rufl_code rufl_init_scan_font(unsigned int font_index) } /* scan through all characters */ - for (u = 32; u != 0x10000; u++) { + for (u = 0x0020; u != 0x10000; u++) { + if (u == 0x007f) { + /* skip DELETE and C1 controls */ + u = 0x009f; + continue; + } + string[0] = u; rufl_fm_error = xfont_scan_string(font, (char *) string, font_RETURN_BBOX | font_GIVEN32_BIT | @@ -409,11 +431,17 @@ rufl_code rufl_init_scan_font(unsigned int font_index) if (rufl_fm_error) break; - if (block.bbox.x0 == 0x20000000 || - (x_out == 0 && y_out == 0 && + if (block.bbox.x0 == 0x20000000) { + /* absent (no definition) */ + } else if (x_out == 0 && y_out == 0 && block.bbox.x0 == 0 && block.bbox.y0 == 0 && - block.bbox.x1 == 0 && block.bbox.y1 == 0)) { - /* absent */ + block.bbox.x1 == 0 && block.bbox.y1 == 0) { + /* absent (empty) */ + } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0 && + !rufl_is_space(u)) { + /* absent (space but not a space character - some + * fonts do this) */ } else { /* present */ byte = (u >> 3) & 31; @@ -467,6 +495,18 @@ rufl_code rufl_init_scan_font(unsigned int font_index) /** + * A character is one of the Unicode space characters. + */ + +bool rufl_is_space(unsigned int u) +{ + return u == 0x0020 || u == 0x00a0 || + (0x2000 <= u && u <= 0x200b) || + u == 0x202f || u == 0x3000; +} + + +/** * Scan a font for available characters (old font manager version). */ @@ -528,11 +568,17 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index) if (rufl_fm_error) break; - if (block.bbox.x0 == 0x20000000 || - (x_out == 0 && y_out == 0 && + if (block.bbox.x0 == 0x20000000) { + /* absent (no definition) */ + } else if (x_out == 0 && y_out == 0 && block.bbox.x0 == 0 && block.bbox.y0 == 0 && - block.bbox.x1 == 0 && block.bbox.y1 == 0)) { - /* absent */ + block.bbox.x1 == 0 && block.bbox.y1 == 0) { + /* absent (empty) */ + } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0 && + !rufl_is_space(u)) { + /* absent (space but not a space character - some + * fonts do this) */ } else { /* present */ if (charset->index[u >> 8] == BLOCK_EMPTY) { diff --git a/rufl_internal.h b/rufl_internal.h index 8cd1759..670fcb2 100644 --- a/rufl_internal.h +++ b/rufl_internal.h @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #include <limits.h> @@ -66,6 +66,13 @@ struct rufl_font_list_entry { struct rufl_character_set *charset; /** Mapping 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). */ + unsigned int family; + /** Font weight (0 to 8). */ + unsigned int weight; + /** Font slant (0 or 1). */ + unsigned int slant; }; /** List of all available fonts. */ extern struct rufl_font_list_entry *rufl_font_list; @@ -73,10 +80,15 @@ extern struct rufl_font_list_entry *rufl_font_list; extern unsigned int rufl_font_list_entries; -#define rufl_STYLES 4 - -/** Map from font family to fonts. rufl_STYLES entries per family. */ -extern unsigned int *rufl_family_map; +/** An entry in rufl_family_map. */ +struct rufl_family_map_entry { + /** This style does not exist in this family. */ +# define NO_FONT UINT_MAX + /** Map from weight and slant to index in rufl_font_list, or NO_FONT. */ + unsigned int font[9][2]; +}; +/** Map from font family to fonts, rufl_family_list_entries entries. */ +extern struct rufl_family_map_entry *rufl_family_map; /** No font contains this character. */ diff --git a/rufl_paint.c b/rufl_paint.c index 37ed75b..28144e1 100644 --- a/rufl_paint.c +++ b/rufl_paint.c @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #include <assert.h> @@ -20,32 +20,35 @@ typedef enum { rufl_PAINT, rufl_WIDTH, rufl_X_TO_OFFSET, bool rufl_can_background_blend = false; +static const os_trfm trfm_oblique = + { { { 65536, 0 }, { 13930, 65536 }, { 0, 0 } } }; + static rufl_code rufl_process(rufl_action action, const char *font_family, rufl_style font_style, unsigned int font_size, const char *string0, size_t length, - int x, int y, os_trfm *trfm, unsigned int flags, + 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 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, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context); static rufl_code rufl_process_span_old(rufl_action action, unsigned short *s, unsigned int n, - unsigned int font, unsigned int font_size, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context); static int rufl_unicode_map_search_cmp(const void *keyval, const void *datum); static rufl_code rufl_process_not_available(rufl_action action, unsigned short *s, unsigned int n, unsigned int font_size, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context); static rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, @@ -63,25 +66,7 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style, { return rufl_process(rufl_PAINT, font_family, font_style, font_size, string, - length, x, y, 0, flags, 0, 0, 0, 0, 0, 0); -} - - -/** - * Render Unicode text with a transformation matrix. - * - * Only transformations which keep the x-axis direction unchanged are - * supported. - */ - -rufl_code rufl_paint_transformed(const char *font_family, rufl_style font_style, - unsigned int font_size, - const char *string, size_t length, - int x, int y, os_trfm *trfm, unsigned int flags) -{ - return rufl_process(rufl_PAINT, - font_family, font_style, font_size, string, - length, x, y, trfm, flags, 0, 0, 0, 0, 0, 0); + length, x, y, flags, 0, 0, 0, 0, 0, 0); } @@ -96,7 +81,7 @@ rufl_code rufl_width(const char *font_family, rufl_style font_style, { return rufl_process(rufl_WIDTH, font_family, font_style, font_size, string, - length, 0, 0, 0, 0, width, 0, 0, 0, 0, 0); + length, 0, 0, 0, width, 0, 0, 0, 0, 0); } @@ -113,7 +98,7 @@ rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style, { return rufl_process(rufl_X_TO_OFFSET, font_family, font_style, font_size, string, - length, 0, 0, 0, 0, 0, + length, 0, 0, 0, 0, click_x, char_offset, actual_x, 0, 0); } @@ -130,7 +115,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style, { return rufl_process(rufl_SPLIT, font_family, font_style, font_size, string, - length, 0, 0, 0, 0, 0, + length, 0, 0, 0, 0, width, char_offset, actual_x, 0, 0); } @@ -147,7 +132,7 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style, { return rufl_process(rufl_PAINT_CALLBACK, font_family, font_style, font_size, string, - length, x, y, 0, 0, 0, 0, 0, 0, callback, context); + length, x, y, 0, 0, 0, 0, 0, callback, context); } @@ -159,7 +144,7 @@ rufl_code rufl_process(rufl_action action, const char *font_family, rufl_style font_style, unsigned int font_size, const char *string0, size_t length, - int x, int y, os_trfm *trfm, unsigned int flags, + 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) { @@ -172,6 +157,8 @@ rufl_code rufl_process(rufl_action action, size_t offset_u; size_t offset_map[rufl_PROCESS_CHUNK]; char **family; + unsigned int weight, slant, used_weight; + unsigned int search_direction; const char *string = string0; struct rufl_character_set *charset; rufl_code code; @@ -210,13 +197,49 @@ rufl_code rufl_process(rufl_action action, sizeof rufl_family_list[0], rufl_family_list_cmp); if (!family) return rufl_FONT_NOT_FOUND; - font = rufl_family_map[rufl_STYLES * (family - rufl_family_list) + - font_style]; + 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 <= 4) + 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; + } + } + charset = rufl_font_list[font].charset; offset_u = 0; rufl_utf8_read(string, length, u); - if (charset && rufl_character_set_test(charset, u)) + if (u <= 0x001f || (0x007f <= u && u <= 0x009f)) + font1 = NOT_AVAILABLE; + else if (charset && rufl_character_set_test(charset, u)) font1 = font; else if (u < 0x10000) font1 = rufl_substitution_table[u]; @@ -233,7 +256,9 @@ rufl_code rufl_process(rufl_action action, rufl_utf8_read(string, length, u); s[n] = u; offset_map[n] = offset_u; - if (charset && rufl_character_set_test(charset, u)) + if (u <= 0x001f || (0x007f <= u && u <= 0x009f)) + font1 = NOT_AVAILABLE; + else if (charset && rufl_character_set_test(charset, u)) font1 = font; else if (u < 0x10000) font1 = rufl_substitution_table[u]; @@ -251,15 +276,15 @@ rufl_code rufl_process(rufl_action action, if (font0 == NOT_AVAILABLE) code = rufl_process_not_available(action, s, n, - font_size, &x, y, trfm, flags, + font_size, &x, y, flags, click_x, &offset, callback, context); else if (rufl_old_font_manager) code = rufl_process_span_old(action, s, n, font0, - font_size, &x, y, trfm, flags, + font_size, slant, &x, y, flags, click_x, &offset, callback, context); else code = rufl_process_span(action, s, n, font0, - font_size, &x, y, trfm, flags, + font_size, slant, &x, y, flags, click_x, &offset, callback, context); if ((action == rufl_X_TO_OFFSET || action == rufl_SPLIT) && @@ -295,8 +320,8 @@ int rufl_family_list_cmp(const void *keyval, const void *datum) rufl_code rufl_process_span(rufl_action action, unsigned short *s, unsigned int n, - unsigned int font, unsigned int font_size, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context) { @@ -304,6 +329,7 @@ rufl_code rufl_process_span(rufl_action action, unsigned short *split_point; int x_out, y_out; unsigned int i; + bool oblique = slant && !rufl_font_list[font].slant; font_f f; rufl_code code; @@ -339,13 +365,13 @@ rufl_code rufl_process_span(rufl_action action, /* paint span */ rufl_fm_error = xfont_paint(f, (const char *) s, font_OS_UNITS | - (trfm ? font_GIVEN_TRFM : 0) | + (oblique ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | font_GIVEN16_BIT | ((flags & rufl_BLEND_FONT) ? font_BLEND_FONT : 0), - *x, y, 0, trfm, n * 2); + *x, y, 0, &trfm_oblique, n * 2); if (rufl_fm_error) { LOG("xfont_paint: 0x%x: %s", rufl_fm_error->errnum, @@ -364,21 +390,19 @@ rufl_code rufl_process_span(rufl_action action, /* increment x by width of span */ if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { rufl_fm_error = xfont_scan_string(f, (const char *) s, - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | font_GIVEN16_BIT | ((action == rufl_X_TO_OFFSET) ? font_RETURN_CARET_POS : 0), - (click_x - *x) * 400, 0x7fffffff, 0, trfm, + (click_x - *x) * 400, 0x7fffffff, 0, 0, n * 2, (char **) &split_point, &x_out, &y_out, 0); *offset = split_point - s; } else { rufl_fm_error = xfont_scan_string(f, (const char *) s, - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | font_GIVEN16_BIT, - 0x7fffffff, 0x7fffffff, 0, trfm, n * 2, + 0x7fffffff, 0x7fffffff, 0, 0, n * 2, 0, &x_out, &y_out, 0); } if (rufl_fm_error) { @@ -400,8 +424,8 @@ rufl_code rufl_process_span(rufl_action action, rufl_code rufl_process_span_old(rufl_action action, unsigned short *s, unsigned int n, - unsigned int font, unsigned int font_size, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context) { @@ -410,6 +434,7 @@ rufl_code rufl_process_span_old(rufl_action action, 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; font_f f; rufl_code code; struct rufl_unicode_map_entry *entry; @@ -449,12 +474,12 @@ rufl_code rufl_process_span_old(rufl_action action, if (action == rufl_PAINT) { /* paint span */ rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS | - (trfm ? font_GIVEN_TRFM : 0) | + (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, n); + *x, y, 0, &trfm_oblique, n); if (rufl_fm_error) return rufl_FONT_MANAGER_ERROR; } else if (action == rufl_PAINT_CALLBACK) { @@ -464,19 +489,17 @@ rufl_code rufl_process_span_old(rufl_action action, /* increment x by width of span */ if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { rufl_fm_error = xfont_scan_string(f, s2, - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | ((action == rufl_X_TO_OFFSET) ? font_RETURN_CARET_POS : 0), - (click_x - *x) * 400, 0x7fffffff, 0, trfm, n, + (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, - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN, - 0x7fffffff, 0x7fffffff, 0, trfm, n, + 0x7fffffff, 0x7fffffff, 0, 0, n, 0, &x_out, &y_out, 0); } if (rufl_fm_error) @@ -506,15 +529,13 @@ int rufl_unicode_map_search_cmp(const void *keyval, const void *datum) rufl_code rufl_process_not_available(rufl_action action, unsigned short *s, unsigned int n, unsigned int font_size, int *x, int y, - os_trfm *trfm, unsigned int flags, + unsigned int flags, int click_x, size_t *offset, rufl_callback_t callback, void *context) { char missing[] = "0000"; - int dx = 7 * font_size * - (trfm ? trfm->entries[0][0] / 0x10000 : 1) / 64; - int top_y = y + (trfm ? trfm->entries[1][1] / 0x10000 : 1) * 5 * - font_size / 64; + int dx = 7 * font_size / 64; + int top_y = y + 5 * font_size / 64; unsigned int i; font_f f; rufl_code code; @@ -567,12 +588,11 @@ rufl_code rufl_process_not_available(rufl_action action, /* first two characters in top row */ if (action == rufl_PAINT) { rufl_fm_error = xfont_paint(f, missing, font_OS_UNITS | - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | ((flags & rufl_BLEND_FONT) ? font_BLEND_FONT : 0), - *x, top_y, 0, trfm, 2); + *x, top_y, 0, 0, 2); if (rufl_fm_error) return rufl_FONT_MANAGER_ERROR; } else { @@ -585,12 +605,11 @@ rufl_code rufl_process_not_available(rufl_action action, if (action == rufl_PAINT) { rufl_fm_error = xfont_paint(f, missing + 2, font_OS_UNITS | - (trfm ? font_GIVEN_TRFM : 0) | font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN | ((flags & rufl_BLEND_FONT) ? font_BLEND_FONT : 0), - *x, y, 0, trfm, 2); + *x, y, 0, 0, 2); if (rufl_fm_error) return rufl_FONT_MANAGER_ERROR; } else { diff --git a/rufl_test.c b/rufl_test.c index f851832..ad536a7 100644 --- a/rufl_test.c +++ b/rufl_test.c @@ -2,7 +2,7 @@ * This file is part of RUfl * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license - * Copyright 2005 James Bursa <james@semichrome.net> + * Copyright 2006 James Bursa <james@semichrome.net> */ #include <errno.h> @@ -29,28 +29,28 @@ int main(void) try(rufl_init(), "rufl_init"); rufl_dump_state(); - try(rufl_paint("NewHall", rufl_REGULAR, 240, + try(rufl_paint("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, 1200, 1000, 0), "rufl_paint"); - try(rufl_width("NewHall", rufl_REGULAR, 240, + try(rufl_width("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, &width), "rufl_width"); printf("width: %i\n", width); for (x = 0; x < width + 100; x += 100) { - try(rufl_x_to_offset("NewHall", rufl_REGULAR, 240, + try(rufl_x_to_offset("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, x, &char_offset, &actual_x), "rufl_x_to_offset"); printf("x to offset: %i -> %i %i \"%s\"\n", x, actual_x, char_offset, utf8_test + char_offset); - try(rufl_split("NewHall", rufl_REGULAR, 240, + try(rufl_split("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, x, &char_offset, &actual_x), "rufl_split"); printf("split: %i -> %i %i \"%s\"\n", x, actual_x, char_offset, utf8_test + char_offset); } - try(rufl_paint_callback("NewHall", rufl_REGULAR, 240, + try(rufl_paint_callback("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, 1200, 1000, callback, 0), "rufl_paint_callback"); rufl_quit(); |