summaryrefslogtreecommitdiff
path: root/rufl_paint.c
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2005-01-08 21:02:32 +0000
committerJames Bursa <james@netsurf-browser.org>2005-01-08 21:02:32 +0000
commitc4580a33f78825e385626610fbbff9a675b248a4 (patch)
treed4ab197d183e4a917202415cb7bd44b75d5c7866 /rufl_paint.c
downloadlibrufl-c4580a33f78825e385626610fbbff9a675b248a4.tar.gz
librufl-c4580a33f78825e385626610fbbff9a675b248a4.tar.bz2
[project @ 2005-01-08 21:02:32 by bursa]
Initial version of RISC OS Unicode font library. Require Unicode (RO5) Font Manager. svn path=/import/rufl/; revision=2443
Diffstat (limited to 'rufl_paint.c')
-rw-r--r--rufl_paint.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/rufl_paint.c b/rufl_paint.c
new file mode 100644
index 0000000..9014d96
--- /dev/null
+++ b/rufl_paint.c
@@ -0,0 +1,255 @@
+/*
+ * 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>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "oslib/font.h"
+#include "rufl_internal.h"
+
+
+static int rufl_family_list_cmp(const void *keyval, const void *datum);
+static rufl_code rufl_paint_span(unsigned short *s, unsigned int n,
+ unsigned int font, unsigned int font_size, int *x, int y);
+static rufl_code rufl_paint_not_available(unsigned short *s, unsigned int n,
+ unsigned int font_size, int *x, int y);
+static rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size,
+ font_f f);
+
+
+/**
+ * Render Unicode text.
+ */
+
+rufl_code rufl_paint(const char *font_family, rufl_style font_style,
+ unsigned int font_size,
+ const char *string, size_t length,
+ int x, int y)
+{
+ unsigned short s[80];
+ unsigned int font;
+ unsigned int font0, font1;
+ unsigned int n;
+ unsigned int u;
+ char **family;
+ struct rufl_character_set *charset;
+ rufl_code code;
+
+ if (length == 0)
+ return rufl_OK;
+
+ 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;
+ font = rufl_family_map[rufl_STYLES * (family - rufl_family_list) +
+ font_style];
+ charset = rufl_font_list[font].charset;
+
+ rufl_utf8_read(string, length, u);
+ if (rufl_character_set_test(charset, u))
+ font1 = font;
+ else
+ font1 = rufl_substitution_lookup(u);
+ do {
+ s[0] = u;
+ n = 1;
+ font0 = font1;
+ /* invariant: s[0..n) is in font font0 */
+ while (0 < length && n < 70 && font1 == font0) {
+ rufl_utf8_read(string, length, u);
+ s[n] = u;
+ if (rufl_character_set_test(charset, u))
+ font1 = font;
+ else
+ font1 = rufl_substitution_lookup(u);
+ if (font1 == font0)
+ n++;
+ }
+ s[n] = 0;
+
+ if (font0 == NOT_AVAILABLE)
+ code = rufl_paint_not_available(s, n, font_size, &x, y);
+ else
+ code = rufl_paint_span(s, n, font0, font_size, &x, y);
+
+ if (code != rufl_OK)
+ return code;
+
+ } while (!(length == 0 && font1 == font0));
+
+ return rufl_OK;
+}
+
+
+int rufl_family_list_cmp(const void *keyval, const void *datum)
+{
+ const char *key = keyval;
+ const char * const *entry = datum;
+ return strcmp(key, *entry);
+}
+
+
+/**
+ * Render a string of characters from a single RISC OS font.
+ */
+
+rufl_code rufl_paint_span(unsigned short *s, unsigned int n,
+ unsigned int font, unsigned int font_size, int *x, int y)
+{
+ char font_name[80];
+ int x_out, y_out;
+ unsigned int i;
+ font_f f;
+ rufl_code code;
+
+ /* search cache */
+ 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 */
+ 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)
+ return rufl_FONT_MANAGER_ERROR;
+ /* place in cache */
+ code = rufl_place_in_cache(font, font_size, f);
+ if (code != rufl_OK)
+ return code;
+ }
+
+ /* paint span */
+ rufl_fm_error = xfont_paint(f, (const char *) s, font_OS_UNITS |
+ font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN |
+ font_GIVEN16_BIT,
+ *x, y, 0, 0, n * 2);
+ if (rufl_fm_error) {
+ xfont_lose_font(f);
+ return rufl_FONT_MANAGER_ERROR;
+ }
+
+ /* increment x by width of span */
+ rufl_fm_error = xfont_scan_string(f, (const char *) s,
+ font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN |
+ font_GIVEN16_BIT,
+ 0x7fffffff, 0x7fffffff, 0, 0, n * 2,
+ 0, &x_out, &y_out, 0);
+ if (rufl_fm_error) {
+ xfont_lose_font(f);
+ return rufl_FONT_MANAGER_ERROR;
+ }
+ *x += x_out / 400;
+
+ return rufl_OK;
+}
+
+
+/**
+ * Render a string of characters not available in any font as their hex code.
+ */
+
+rufl_code rufl_paint_not_available(unsigned short *s, unsigned int n,
+ unsigned int font_size, int *x, int y)
+{
+ char missing[] = "0000";
+ unsigned int i;
+ font_f f;
+ rufl_code code;
+
+ /* 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\\EUTF8",
+ 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;
+ }
+
+ for (i = 0; i != n; i++) {
+ missing[0] = "0123456789abcdef"[(s[i] >> 12) & 0xf];
+ missing[1] = "0123456789abcdef"[(s[i] >> 8) & 0xf];
+ missing[2] = "0123456789abcdef"[(s[i] >> 4) & 0xf];
+ missing[3] = "0123456789abcdef"[(s[i] >> 0) & 0xf];
+
+ /* first two characters in top row */
+ rufl_fm_error = xfont_paint(f, missing, font_OS_UNITS |
+ font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN,
+ *x, y + 5 * font_size / 64,
+ 0, 0, 2);
+ if (rufl_fm_error)
+ return rufl_FONT_MANAGER_ERROR;
+
+ /* last two characters underneath */
+ rufl_fm_error = xfont_paint(f, missing + 2, font_OS_UNITS |
+ font_GIVEN_LENGTH | font_GIVEN_FONT | font_KERN,
+ *x, y, 0, 0, 2);
+ if (rufl_fm_error)
+ return rufl_FONT_MANAGER_ERROR;
+
+ *x += 7 * font_size / 64;
+ }
+
+ return rufl_OK;
+}
+
+
+/**
+ * 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;
+ }
+ }
+ 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;
+}