summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--makefile3
-rw-r--r--rufl.h44
-rw-r--r--rufl_decompose.c159
-rw-r--r--rufl_find.c191
-rw-r--r--rufl_internal.h5
-rw-r--r--rufl_metrics.c289
-rw-r--r--rufl_paint.c212
-rw-r--r--rufl_test.c36
8 files changed, 742 insertions, 197 deletions
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.
@@ -126,6 +137,39 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
/**
+ * 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 <jmb202@ecs.soton.ac.uk>
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#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 <james@semichrome.net>
+ * Copyright 2005 John-Mark Bell <jmb202@ecs.soton.ac.uk>
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#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 <jmb202@ecs.soton.ac.uk>
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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))
@@ -297,73 +291,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,