netsurf: branch chris/ndk32 updated. release/3.10-170-gb0a9388
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/b0a9388db8c81a28c449d...
...commit http://git.netsurf-browser.org/netsurf.git/commit/b0a9388db8c81a28c449d5c...
...tree http://git.netsurf-browser.org/netsurf.git/tree/b0a9388db8c81a28c449d5cc8...
The branch, chris/ndk32 has been updated
via b0a9388db8c81a28c449d5cc84e4d1a4930c7222 (commit)
via 6431c62472f27e99a8ff5ed34d6e598c76e60c30 (commit)
from 2535d48321b3a40131c5246b3c560bbf95f4bd35 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=b0a9388db8c81a28c44...
commit b0a9388db8c81a28c449d5cc84e4d1a4930c7222
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Amiga: Manually define mc68000 required for NDK3.2 inlines
diff --git a/frontends/amiga/Makefile b/frontends/amiga/Makefile
index 99745c9..80b6f83 100644
--- a/frontends/amiga/Makefile
+++ b/frontends/amiga/Makefile
@@ -7,7 +7,7 @@ CFLAGS += -std=c99 -Dnsamiga
ifneq ($(SUBTARGET),os3)
CFLAGS += -O2 -mstrict-align -finline-functions -U__STRICT_ANSI__ -D__USE_INLINE__ -D__USE_BASETYPE__
else
- CFLAGS += -O2 -DPATH_MAX=1024 -D__m68k__ -m68020
+ CFLAGS += -O2 -DPATH_MAX=1024 -D__m68k__ -m68020 -Dmc68000
endif
$(eval $(call feature_enabled,AMIGA_ICON,-DWITH_AMIGA_ICON,,Amiga icon))
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=6431c62472f27e99a8f...
commit 6431c62472f27e99a8ff5ed34d6e598c76e60c30
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Revert "Amiga: Fix some undefined references"
This reverts commit 2535d48321b3a40131c5246b3c560bbf95f4bd35.
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index aae3f30..fe94eb2 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -185,9 +185,6 @@ AMINS_LIB_STRUCT(Keymap);
AMINS_LIB_STRUCT(Layers);
AMINS_LIB_STRUCT(Locale);
AMINS_LIB_STRUCT(P96);
-#ifndef __amigaos4__
-AMINS_LIB_STRUCT(Utility);
-#endif
AMINS_LIB_STRUCT(Workbench);
AMINS_LIB_STRUCT(Codesets);
diff --git a/frontends/amiga/schedule.c b/frontends/amiga/schedule.c
index 533e7f6..18eb1af 100644
--- a/frontends/amiga/schedule.c
+++ b/frontends/amiga/schedule.c
@@ -42,11 +42,10 @@ struct nscallback
};
static struct nscallback *tioreq;
-#ifdef __amigaos4__
struct Device *TimerBase;
+#ifdef __amigaos4__
struct TimerIFace *ITimer;
#else
-struct Library *TimerBase;
static struct MsgPort *schedule_msgport = NULL;
#endif
@@ -82,7 +81,7 @@ static void ami_schedule_remove_timer_event(struct nscallback *nscb)
static nserror ami_schedule_add_timer_event(struct nscallback *nscb, int t)
{
struct TimeVal tv;
- ULONG time_us = t * 1000; /* t converted to microseconds */
+ ULONG time_us = t * 1000; /* t converted to �s */
tv.tv_secs = time_us / 1000000;
tv.tv_micro = time_us % 1000000;
-----------------------------------------------------------------------
Summary of changes:
frontends/amiga/Makefile | 2 +-
frontends/amiga/libs.c | 3 ---
frontends/amiga/schedule.c | 5 ++---
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/frontends/amiga/Makefile b/frontends/amiga/Makefile
index 99745c9..80b6f83 100644
--- a/frontends/amiga/Makefile
+++ b/frontends/amiga/Makefile
@@ -7,7 +7,7 @@ CFLAGS += -std=c99 -Dnsamiga
ifneq ($(SUBTARGET),os3)
CFLAGS += -O2 -mstrict-align -finline-functions -U__STRICT_ANSI__ -D__USE_INLINE__ -D__USE_BASETYPE__
else
- CFLAGS += -O2 -DPATH_MAX=1024 -D__m68k__ -m68020
+ CFLAGS += -O2 -DPATH_MAX=1024 -D__m68k__ -m68020 -Dmc68000
endif
$(eval $(call feature_enabled,AMIGA_ICON,-DWITH_AMIGA_ICON,,Amiga icon))
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index aae3f30..fe94eb2 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -185,9 +185,6 @@ AMINS_LIB_STRUCT(Keymap);
AMINS_LIB_STRUCT(Layers);
AMINS_LIB_STRUCT(Locale);
AMINS_LIB_STRUCT(P96);
-#ifndef __amigaos4__
-AMINS_LIB_STRUCT(Utility);
-#endif
AMINS_LIB_STRUCT(Workbench);
AMINS_LIB_STRUCT(Codesets);
diff --git a/frontends/amiga/schedule.c b/frontends/amiga/schedule.c
index 533e7f6..18eb1af 100644
--- a/frontends/amiga/schedule.c
+++ b/frontends/amiga/schedule.c
@@ -42,11 +42,10 @@ struct nscallback
};
static struct nscallback *tioreq;
-#ifdef __amigaos4__
struct Device *TimerBase;
+#ifdef __amigaos4__
struct TimerIFace *ITimer;
#else
-struct Library *TimerBase;
static struct MsgPort *schedule_msgport = NULL;
#endif
@@ -82,7 +81,7 @@ static void ami_schedule_remove_timer_event(struct nscallback *nscb)
static nserror ami_schedule_add_timer_event(struct nscallback *nscb, int t)
{
struct TimeVal tv;
- ULONG time_us = t * 1000; /* t converted to microseconds */
+ ULONG time_us = t * 1000; /* t converted to �s */
tv.tv_secs = time_us / 1000000;
tv.tv_micro = time_us % 1000000;
--
NetSurf Browser
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-36-ga1735a1
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/a1735a1171f484e982802...
...commit http://git.netsurf-browser.org/librufl.git/commit/a1735a1171f484e98280295...
...tree http://git.netsurf-browser.org/librufl.git/tree/a1735a1171f484e9828029576...
The branch, jmb/ac has been updated
via a1735a1171f484e9828029576c99cff12448060f (commit)
via 06fae32a7ae53ad113376befbc78414374f9326b (commit)
via deb692c00afecca0d73394feef6e99e51606b9b4 (commit)
via ce3664d296b9b2459c4251321cb3f90adc32972d (commit)
via 0358488cc592f217158a8c4ea9adacf652ee85ce (commit)
from d4468833b85b8c8f340bc9c3bb6572a245fd5982 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a1735a1171f484e9828...
commit a1735a1171f484e9828029576c99cff12448060f
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Introduce test infrastructure
Mock out every OS call made by the library (they all return an
unimplemented error for the timebeing). Add a trivial test case
that verifies that rufl_init() fails.
diff --git a/Makefile b/Makefile
index 1653ee9..bfaf61e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ PREFIX ?= /opt/netsurf
NSSHARED ?= $(PREFIX)/share/netsurf-buildsystem
include $(NSSHARED)/makefiles/Makefile.tools
-TESTRUNNER := $(ECHO)
+TESTRUNNER := $(PERL) $(NSTESTTOOLS)/testrunner.pl
# Toolchain flags
WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
diff --git a/test/INDEX b/test/INDEX
new file mode 100644
index 0000000..bd46e96
--- /dev/null
+++ b/test/INDEX
@@ -0,0 +1,4 @@
+# Index for testcases
+#
+# Test Description DataDir
+simple Trivial test to prove harness works
diff --git a/test/Makefile b/test/Makefile
index 2bfa58b..1ce2936 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,4 +1,10 @@
# Tests
-DIR_TEST_ITEMS := rufl_test:rufl_test.c rufl_chars:rufl_chars.c
+DIR_TEST_ITEMS := simple:simple.c;mocks.c
+
+ifeq ($(HOST),arm-unknown-riscos)
+ DIR_TEST_ITEMS := $(DIR_TEST_ITEMS) \
+ rufl_test:rufl_test.c \
+ rufl_chars:rufl_chars.c
+endif
include $(NSBUILD)/Makefile.subdir
diff --git a/test/mocks.c b/test/mocks.c
new file mode 100644
index 0000000..28cdf41
--- /dev/null
+++ b/test/mocks.c
@@ -0,0 +1,304 @@
+#include <oslib/font.h>
+#include <oslib/hourglass.h>
+#include <oslib/os.h>
+#include <oslib/osfscontrol.h>
+#include <oslib/taskwindow.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpreadsysinfo.h>
+
+static os_error unimplemented = { error_UNIMPLEMENTED, "Not implemented" };
+
+/****************************************************************************/
+
+os_error *xfont_cache_addr (int *version, int *cache_size, int *cache_used)
+{
+ (void) version;
+ (void) cache_size;
+ (void) cache_used;
+
+ return &unimplemented;
+}
+
+os_error *xfont_find_font (char const *font_name, int xsize, int ysize,
+ int xres, int yres, font_f *font, int *xres_out, int *yres_out)
+{
+ (void) font_name;
+ (void) xsize;
+ (void) ysize;
+ (void) xres;
+ (void) yres;
+ (void) font;
+ (void) xres_out;
+ (void) yres_out;
+
+ return &unimplemented;
+}
+
+os_error *xfont_lose_font (font_f font)
+{
+ (void) font;
+
+ return &unimplemented;
+}
+
+os_error *xfont_read_info (font_f font, int *x0, int *y0, int *x1, int *y1)
+{
+ (void) font;
+ (void) x0;
+ (void) y0;
+ (void) x1;
+ (void) y1;
+
+ return &unimplemented;
+}
+
+os_error *xfont_read_encoding_filename (font_f font, char *buffer, int size,
+ char **end)
+{
+ (void) font;
+ (void) buffer;
+ (void) size;
+ (void) end;
+
+ return &unimplemented;
+}
+
+os_error *xfont_list_fonts (byte *buffer1, font_list_context context,
+ int size1, byte *buffer2, int size2, char const *tick_font,
+ font_list_context *context_out, int *used1, int *used2)
+{
+ (void) buffer1;
+ (void) context;
+ (void) size1;
+ (void) buffer2;
+ (void) size2;
+ (void) tick_font;
+ (void) context_out;
+ (void) used1;
+ (void) used2;
+
+ return &unimplemented;
+}
+
+os_error *xfont_set_font (font_f font)
+{
+ (void) font;
+
+ return &unimplemented;
+}
+
+os_error *xfont_paint (font_f font, char const *string,
+ font_string_flags flags, int xpos, int ypos,
+ font_paint_block const *block, os_trfm const *trfm, int length)
+{
+ (void) font;
+ (void) string;
+ (void) flags;
+ (void) xpos;
+ (void) ypos;
+ (void) block;
+ (void) trfm;
+ (void) length;
+
+ return &unimplemented;
+}
+
+os_error *xfont_scan_string (font_f font, char const *s,
+ font_string_flags flags, int x, int y, font_scan_block *block,
+ os_trfm const *trfm, int length, char **split_point,
+ int *x_out, int *y_out, int *num_split_chars)
+{
+ (void) font;
+ (void) s;
+ (void) flags;
+ (void) x;
+ (void) y;
+ (void) block;
+ (void) trfm;
+ (void) length;
+ (void) split_point;
+ (void) x_out;
+ (void) y_out;
+ (void) num_split_chars;
+
+ return &unimplemented;
+}
+
+os_error *xfont_switch_output_to_buffer (font_output_flags flags,
+ byte *buffer, char **end)
+{
+ (void) flags;
+ (void) buffer;
+ (void) end;
+
+ return &unimplemented;
+}
+
+os_error *xfont_enumerate_characters (font_f font, int character,
+ int *next_character, int *internal_character_code)
+{
+ (void) font;
+ (void) character;
+ (void) next_character;
+ (void) internal_character_code;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xhourglass_on (void)
+{
+ return &unimplemented;
+}
+
+os_error *xhourglass_off (void)
+{
+ return &unimplemented;
+}
+
+os_error *xhourglass_percentage (int percent)
+{
+ (void) percent;
+
+ return &unimplemented;
+}
+
+os_error *xhourglass_leds (bits eor_mask, bits and_mask, bits *old_leds)
+{
+ (void) eor_mask;
+ (void) and_mask;
+ (void) old_leds;
+
+ return &unimplemented;
+}
+
+os_error *xhourglass_colours (os_colour sand, os_colour glass,
+ os_colour *old_sand, os_colour *old_glass)
+{
+ (void) sand;
+ (void) glass;
+ (void) old_sand;
+ (void) old_glass;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xos_read_monotonic_time (os_t *t)
+{
+ (void) t;
+
+ return &unimplemented;
+}
+
+os_error *xos_read_mode_variable (os_mode mode, os_mode_var var, int *var_val,
+ bits *psr)
+{
+ (void) mode;
+ (void) var;
+ (void) var_val;
+ (void) psr;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xosfscontrol_canonicalise_path (char const *path_name, char *buffer,
+ char const *var, char const *path, int size, int *spare)
+{
+ (void) path_name;
+ (void) buffer;
+ (void) var;
+ (void) path;
+ (void) size;
+ (void) spare;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xtaskwindowtaskinfo_window_task (osbool *window_task)
+{
+ (void) window_task;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xwimp_create_window (wimp_window const *window, wimp_w *w)
+{
+ (void) window;
+ (void) w;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_delete_window (wimp_w w)
+{
+ (void) w;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_get_window_state (wimp_window_state *state)
+{
+ (void) state;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_open_window (wimp_open *open)
+{
+ (void) open;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_set_icon_state (wimp_w w, wimp_i i, wimp_icon_flags eor_bits,
+ wimp_icon_flags clear_bits)
+{
+ (void) w;
+ (void) i;
+ (void) eor_bits;
+ (void) clear_bits;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_resize_icon (wimp_w w, wimp_i i, int x0, int y0, int x1, int y1)
+{
+ (void) w;
+ (void) i;
+ (void) x0;
+ (void) y0;
+ (void) x1;
+ (void) y1;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_poll (wimp_poll_flags mask, wimp_block *block, int *pollword,
+ wimp_event_no *event)
+{
+ (void) mask;
+ (void) block;
+ (void) pollword;
+ (void) event;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xwimpreadsysinfo_task (wimp_t *task, wimp_version_no *version)
+{
+ (void) task;
+ (void) version;
+
+ return &unimplemented;
+}
diff --git a/test/simple.c b/test/simple.c
new file mode 100644
index 0000000..44d668f
--- /dev/null
+++ b/test/simple.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "rufl.h"
+
+#include "testutils.h"
+
+int main(int argc, const char **argv)
+{
+ UNUSED(argc);
+ UNUSED(argv);
+
+ assert(rufl_FONT_MANAGER_ERROR == rufl_init());
+
+ printf("PASS\n");
+
+ return 0;
+}
diff --git a/test/testutils.h b/test/testutils.h
new file mode 100644
index 0000000..7fe6333
--- /dev/null
+++ b/test/testutils.h
@@ -0,0 +1,123 @@
+#ifndef test_testutils_h_
+#define test_testutils_h_
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef UNUSED
+#define UNUSED(x) ((void) (x))
+#endif
+
+/* Redefine assert, so we can simply use the standard assert mechanism
+ * within testcases and exit with the right output for the testrunner
+ * to do the right thing. */
+void __assert2(const char *expr, const char *function,
+ const char *file, int line);
+
+void __assert2(const char *expr, const char *function,
+ const char *file, int line)
+{
+ UNUSED(function);
+ UNUSED(file);
+
+ printf("FAIL - %s at line %d\n", expr, line);
+
+ exit(EXIT_FAILURE);
+}
+
+#define assert(expr) \
+ ((void) ((expr) || (__assert2 (#expr, __func__, __FILE__, __LINE__), 0)))
+
+
+typedef bool (*line_func)(const char *data, size_t datalen, void *pw);
+
+static size_t parse_strlen(const char *str, size_t limit);
+bool parse_testfile(const char *filename, line_func callback, void *pw);
+size_t parse_filesize(const char *filename);
+
+/**
+ * Testcase datafile parser driver
+ *
+ * \param filename Name of file to parse
+ * \param callback Pointer to function to handle each line of input data
+ * \param pw Pointer to client-specific private data
+ * \return true on success, false otherwise.
+ */
+bool parse_testfile(const char *filename, line_func callback, void *pw)
+{
+ FILE *fp;
+ char buf[300];
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ printf("Failed opening %s\n", filename);
+ return false;
+ }
+
+ while (fgets(buf, sizeof buf, fp)) {
+ if (buf[0] == '\n')
+ continue;
+
+ if (!callback(buf, parse_strlen(buf, sizeof buf - 1), pw)) {
+ fclose(fp);
+ return false;
+ }
+ }
+
+ fclose(fp);
+
+ return true;
+}
+
+/**
+ * Utility string length measurer; assumes strings are '\n' terminated
+ *
+ * \param str String to measure length of
+ * \param limit Upper bound on string length
+ * \return String length
+ */
+size_t parse_strlen(const char *str, size_t limit)
+{
+ size_t len = 0;
+
+ if (str == NULL)
+ return 0;
+
+ while (len < limit - 1 && *str != '\n') {
+ len++;
+ str++;
+ }
+
+ len++;
+
+ return len;
+}
+
+/**
+ * Read the size of a file
+ *
+ * \param filename Name of file to read size of
+ * \return File size (in bytes), or 0 on error
+ */
+size_t parse_filesize(const char *filename)
+{
+ FILE *fp;
+ size_t len = 0;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ printf("Failed opening %s\n", filename);
+ return 0;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+
+ fclose(fp);
+
+ return len;
+}
+
+
+#endif
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=06fae32a7ae53ad1133...
commit 06fae32a7ae53ad113376befbc78414374f9326b
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
RUfl_chars: fix undersized buffer
Compiling for other platforms has its benefits. The first of which
is x86_64 gcc rightly complaining that the buffer to receive the
error message is too small. Make it big enough.
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index fd0365c..0559d4e 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -302,7 +302,7 @@ rufl_code redraw(int x, int y, int y0, int y1)
void try(rufl_code code, const char *context)
{
- char s[200];
+ char s[400];
if (code == rufl_OK)
return;
else if (code == rufl_OUT_OF_MEMORY)
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=deb692c00afecca0d73...
commit deb692c00afecca0d73394feef6e99e51606b9b4
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Make it possible to build for non-RISC OS hosts
Linking fails, and the path to the OSLib headers is hard-coded,
but it's a start.
diff --git a/Makefile b/Makefile
index 75b49f2..1653ee9 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,10 @@ TESTRUNNER := $(ECHO)
# Toolchain flags
WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
- -Wmissing-declarations -Wnested-externs -pedantic
+ -Wmissing-declarations -Wnested-externs
+ifeq ($(HOST),arm-unknown-riscos)
+ WARNFLAGS := $(WARNFLAGS) -pedantic
+endif
# BeOS/Haiku/AmigaOS4 standard library headers create warnings
ifneq ($(BUILD),i586-pc-haiku)
ifneq ($(findstring amigaos,$(BUILD)),amigaos)
@@ -35,6 +38,12 @@ ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
CFLAGS := $(CFLAGS) -I$(PREFIX)/include
LDFLAGS := $(LDFLAGS) -lOSLib32
TESTLDFLAGS := $(TESTLDFLAGS) -static
+ else
+ # Regardless of the host platform we're building for, we
+ # still need the RISC OS build environment because we need the
+ # OSLib headers.
+ # XXX: is there a way to avoid this path being hard-coded?
+ CFLAGS := $(CFLAGS) -I/opt/netsurf/arm-unknown-riscos/env/include
endif
endif
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=ce3664d296b9b2459c4...
commit ce3664d296b9b2459c4251321cb3f90adc32972d
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Link RISC OS test binaries statically
diff --git a/Makefile b/Makefile
index 562cc5c..75b49f2 100644
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@ ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
ifeq ($(HOST),arm-unknown-riscos)
CFLAGS := $(CFLAGS) -I$(PREFIX)/include
LDFLAGS := $(LDFLAGS) -lOSLib32
+ TESTLDFLAGS := $(TESTLDFLAGS) -static
endif
endif
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=0358488cc592f217158...
commit 0358488cc592f217158a8c4ea9adacf652ee85ce
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Don't assume pointers are 32bits wide
Use uintptr_t to cast between pointers and integers, instead of
assuming that uint32_t will suffice.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 4005203..7915b9a 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1045,7 +1045,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
* a reset. As there are no "good" outcomes here, and we do
* not have a time machine to go back and fix long-ago released
* Font Managers, ensure we ignore UCS fonts here. */
- if ((uint32_t) umap->encoding > 256) {
+ if ((uintptr_t) umap->encoding > 256) {
static os_error err = {
error_FONT_TOO_MANY_CHUNKS, "Rejecting UCS font"};
LOG("%s", "Rejecting UCS font");
@@ -1131,7 +1131,7 @@ static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
/* Stash the total number of encoding file entries so that
* rufl_init_scan_font_in_encoding can detect the presence of a
* UCS font on a non-UCS capable system. It will clean up for us. */
- umap->encoding = (void *) (((uint32_t) umap->encoding) + 1);
+ umap->encoding = (void *) (((uintptr_t) umap->encoding) + 1);
return result;
}
-----------------------------------------------------------------------
Summary of changes:
Makefile | 14 ++-
src/rufl_init.c | 4 +-
test/INDEX | 4 +
test/Makefile | 8 +-
test/mocks.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++
test/rufl_chars.c | 2 +-
test/simple.c | 17 +++
test/testutils.h | 123 ++++++++++++++++++++++
8 files changed, 470 insertions(+), 6 deletions(-)
create mode 100644 test/INDEX
create mode 100644 test/mocks.c
create mode 100644 test/simple.c
create mode 100644 test/testutils.h
diff --git a/Makefile b/Makefile
index 562cc5c..bfaf61e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,12 +9,15 @@ PREFIX ?= /opt/netsurf
NSSHARED ?= $(PREFIX)/share/netsurf-buildsystem
include $(NSSHARED)/makefiles/Makefile.tools
-TESTRUNNER := $(ECHO)
+TESTRUNNER := $(PERL) $(NSTESTTOOLS)/testrunner.pl
# Toolchain flags
WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
- -Wmissing-declarations -Wnested-externs -pedantic
+ -Wmissing-declarations -Wnested-externs
+ifeq ($(HOST),arm-unknown-riscos)
+ WARNFLAGS := $(WARNFLAGS) -pedantic
+endif
# BeOS/Haiku/AmigaOS4 standard library headers create warnings
ifneq ($(BUILD),i586-pc-haiku)
ifneq ($(findstring amigaos,$(BUILD)),amigaos)
@@ -34,6 +37,13 @@ ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
ifeq ($(HOST),arm-unknown-riscos)
CFLAGS := $(CFLAGS) -I$(PREFIX)/include
LDFLAGS := $(LDFLAGS) -lOSLib32
+ TESTLDFLAGS := $(TESTLDFLAGS) -static
+ else
+ # Regardless of the host platform we're building for, we
+ # still need the RISC OS build environment because we need the
+ # OSLib headers.
+ # XXX: is there a way to avoid this path being hard-coded?
+ CFLAGS := $(CFLAGS) -I/opt/netsurf/arm-unknown-riscos/env/include
endif
endif
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 4005203..7915b9a 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1045,7 +1045,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
* a reset. As there are no "good" outcomes here, and we do
* not have a time machine to go back and fix long-ago released
* Font Managers, ensure we ignore UCS fonts here. */
- if ((uint32_t) umap->encoding > 256) {
+ if ((uintptr_t) umap->encoding > 256) {
static os_error err = {
error_FONT_TOO_MANY_CHUNKS, "Rejecting UCS font"};
LOG("%s", "Rejecting UCS font");
@@ -1131,7 +1131,7 @@ static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
/* Stash the total number of encoding file entries so that
* rufl_init_scan_font_in_encoding can detect the presence of a
* UCS font on a non-UCS capable system. It will clean up for us. */
- umap->encoding = (void *) (((uint32_t) umap->encoding) + 1);
+ umap->encoding = (void *) (((uintptr_t) umap->encoding) + 1);
return result;
}
diff --git a/test/INDEX b/test/INDEX
new file mode 100644
index 0000000..bd46e96
--- /dev/null
+++ b/test/INDEX
@@ -0,0 +1,4 @@
+# Index for testcases
+#
+# Test Description DataDir
+simple Trivial test to prove harness works
diff --git a/test/Makefile b/test/Makefile
index 2bfa58b..1ce2936 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,4 +1,10 @@
# Tests
-DIR_TEST_ITEMS := rufl_test:rufl_test.c rufl_chars:rufl_chars.c
+DIR_TEST_ITEMS := simple:simple.c;mocks.c
+
+ifeq ($(HOST),arm-unknown-riscos)
+ DIR_TEST_ITEMS := $(DIR_TEST_ITEMS) \
+ rufl_test:rufl_test.c \
+ rufl_chars:rufl_chars.c
+endif
include $(NSBUILD)/Makefile.subdir
diff --git a/test/mocks.c b/test/mocks.c
new file mode 100644
index 0000000..28cdf41
--- /dev/null
+++ b/test/mocks.c
@@ -0,0 +1,304 @@
+#include <oslib/font.h>
+#include <oslib/hourglass.h>
+#include <oslib/os.h>
+#include <oslib/osfscontrol.h>
+#include <oslib/taskwindow.h>
+#include <oslib/wimp.h>
+#include <oslib/wimpreadsysinfo.h>
+
+static os_error unimplemented = { error_UNIMPLEMENTED, "Not implemented" };
+
+/****************************************************************************/
+
+os_error *xfont_cache_addr (int *version, int *cache_size, int *cache_used)
+{
+ (void) version;
+ (void) cache_size;
+ (void) cache_used;
+
+ return &unimplemented;
+}
+
+os_error *xfont_find_font (char const *font_name, int xsize, int ysize,
+ int xres, int yres, font_f *font, int *xres_out, int *yres_out)
+{
+ (void) font_name;
+ (void) xsize;
+ (void) ysize;
+ (void) xres;
+ (void) yres;
+ (void) font;
+ (void) xres_out;
+ (void) yres_out;
+
+ return &unimplemented;
+}
+
+os_error *xfont_lose_font (font_f font)
+{
+ (void) font;
+
+ return &unimplemented;
+}
+
+os_error *xfont_read_info (font_f font, int *x0, int *y0, int *x1, int *y1)
+{
+ (void) font;
+ (void) x0;
+ (void) y0;
+ (void) x1;
+ (void) y1;
+
+ return &unimplemented;
+}
+
+os_error *xfont_read_encoding_filename (font_f font, char *buffer, int size,
+ char **end)
+{
+ (void) font;
+ (void) buffer;
+ (void) size;
+ (void) end;
+
+ return &unimplemented;
+}
+
+os_error *xfont_list_fonts (byte *buffer1, font_list_context context,
+ int size1, byte *buffer2, int size2, char const *tick_font,
+ font_list_context *context_out, int *used1, int *used2)
+{
+ (void) buffer1;
+ (void) context;
+ (void) size1;
+ (void) buffer2;
+ (void) size2;
+ (void) tick_font;
+ (void) context_out;
+ (void) used1;
+ (void) used2;
+
+ return &unimplemented;
+}
+
+os_error *xfont_set_font (font_f font)
+{
+ (void) font;
+
+ return &unimplemented;
+}
+
+os_error *xfont_paint (font_f font, char const *string,
+ font_string_flags flags, int xpos, int ypos,
+ font_paint_block const *block, os_trfm const *trfm, int length)
+{
+ (void) font;
+ (void) string;
+ (void) flags;
+ (void) xpos;
+ (void) ypos;
+ (void) block;
+ (void) trfm;
+ (void) length;
+
+ return &unimplemented;
+}
+
+os_error *xfont_scan_string (font_f font, char const *s,
+ font_string_flags flags, int x, int y, font_scan_block *block,
+ os_trfm const *trfm, int length, char **split_point,
+ int *x_out, int *y_out, int *num_split_chars)
+{
+ (void) font;
+ (void) s;
+ (void) flags;
+ (void) x;
+ (void) y;
+ (void) block;
+ (void) trfm;
+ (void) length;
+ (void) split_point;
+ (void) x_out;
+ (void) y_out;
+ (void) num_split_chars;
+
+ return &unimplemented;
+}
+
+os_error *xfont_switch_output_to_buffer (font_output_flags flags,
+ byte *buffer, char **end)
+{
+ (void) flags;
+ (void) buffer;
+ (void) end;
+
+ return &unimplemented;
+}
+
+os_error *xfont_enumerate_characters (font_f font, int character,
+ int *next_character, int *internal_character_code)
+{
+ (void) font;
+ (void) character;
+ (void) next_character;
+ (void) internal_character_code;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xhourglass_on (void)
+{
+ return &unimplemented;
+}
+
+os_error *xhourglass_off (void)
+{
+ return &unimplemented;
+}
+
+os_error *xhourglass_percentage (int percent)
+{
+ (void) percent;
+
+ return &unimplemented;
+}
+
+os_error *xhourglass_leds (bits eor_mask, bits and_mask, bits *old_leds)
+{
+ (void) eor_mask;
+ (void) and_mask;
+ (void) old_leds;
+
+ return &unimplemented;
+}
+
+os_error *xhourglass_colours (os_colour sand, os_colour glass,
+ os_colour *old_sand, os_colour *old_glass)
+{
+ (void) sand;
+ (void) glass;
+ (void) old_sand;
+ (void) old_glass;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xos_read_monotonic_time (os_t *t)
+{
+ (void) t;
+
+ return &unimplemented;
+}
+
+os_error *xos_read_mode_variable (os_mode mode, os_mode_var var, int *var_val,
+ bits *psr)
+{
+ (void) mode;
+ (void) var;
+ (void) var_val;
+ (void) psr;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xosfscontrol_canonicalise_path (char const *path_name, char *buffer,
+ char const *var, char const *path, int size, int *spare)
+{
+ (void) path_name;
+ (void) buffer;
+ (void) var;
+ (void) path;
+ (void) size;
+ (void) spare;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xtaskwindowtaskinfo_window_task (osbool *window_task)
+{
+ (void) window_task;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xwimp_create_window (wimp_window const *window, wimp_w *w)
+{
+ (void) window;
+ (void) w;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_delete_window (wimp_w w)
+{
+ (void) w;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_get_window_state (wimp_window_state *state)
+{
+ (void) state;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_open_window (wimp_open *open)
+{
+ (void) open;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_set_icon_state (wimp_w w, wimp_i i, wimp_icon_flags eor_bits,
+ wimp_icon_flags clear_bits)
+{
+ (void) w;
+ (void) i;
+ (void) eor_bits;
+ (void) clear_bits;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_resize_icon (wimp_w w, wimp_i i, int x0, int y0, int x1, int y1)
+{
+ (void) w;
+ (void) i;
+ (void) x0;
+ (void) y0;
+ (void) x1;
+ (void) y1;
+
+ return &unimplemented;
+}
+
+os_error *xwimp_poll (wimp_poll_flags mask, wimp_block *block, int *pollword,
+ wimp_event_no *event)
+{
+ (void) mask;
+ (void) block;
+ (void) pollword;
+ (void) event;
+
+ return &unimplemented;
+}
+
+/****************************************************************************/
+
+os_error *xwimpreadsysinfo_task (wimp_t *task, wimp_version_no *version)
+{
+ (void) task;
+ (void) version;
+
+ return &unimplemented;
+}
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index fd0365c..0559d4e 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -302,7 +302,7 @@ rufl_code redraw(int x, int y, int y0, int y1)
void try(rufl_code code, const char *context)
{
- char s[200];
+ char s[400];
if (code == rufl_OK)
return;
else if (code == rufl_OUT_OF_MEMORY)
diff --git a/test/simple.c b/test/simple.c
new file mode 100644
index 0000000..44d668f
--- /dev/null
+++ b/test/simple.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "rufl.h"
+
+#include "testutils.h"
+
+int main(int argc, const char **argv)
+{
+ UNUSED(argc);
+ UNUSED(argv);
+
+ assert(rufl_FONT_MANAGER_ERROR == rufl_init());
+
+ printf("PASS\n");
+
+ return 0;
+}
diff --git a/test/testutils.h b/test/testutils.h
new file mode 100644
index 0000000..7fe6333
--- /dev/null
+++ b/test/testutils.h
@@ -0,0 +1,123 @@
+#ifndef test_testutils_h_
+#define test_testutils_h_
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef UNUSED
+#define UNUSED(x) ((void) (x))
+#endif
+
+/* Redefine assert, so we can simply use the standard assert mechanism
+ * within testcases and exit with the right output for the testrunner
+ * to do the right thing. */
+void __assert2(const char *expr, const char *function,
+ const char *file, int line);
+
+void __assert2(const char *expr, const char *function,
+ const char *file, int line)
+{
+ UNUSED(function);
+ UNUSED(file);
+
+ printf("FAIL - %s at line %d\n", expr, line);
+
+ exit(EXIT_FAILURE);
+}
+
+#define assert(expr) \
+ ((void) ((expr) || (__assert2 (#expr, __func__, __FILE__, __LINE__), 0)))
+
+
+typedef bool (*line_func)(const char *data, size_t datalen, void *pw);
+
+static size_t parse_strlen(const char *str, size_t limit);
+bool parse_testfile(const char *filename, line_func callback, void *pw);
+size_t parse_filesize(const char *filename);
+
+/**
+ * Testcase datafile parser driver
+ *
+ * \param filename Name of file to parse
+ * \param callback Pointer to function to handle each line of input data
+ * \param pw Pointer to client-specific private data
+ * \return true on success, false otherwise.
+ */
+bool parse_testfile(const char *filename, line_func callback, void *pw)
+{
+ FILE *fp;
+ char buf[300];
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ printf("Failed opening %s\n", filename);
+ return false;
+ }
+
+ while (fgets(buf, sizeof buf, fp)) {
+ if (buf[0] == '\n')
+ continue;
+
+ if (!callback(buf, parse_strlen(buf, sizeof buf - 1), pw)) {
+ fclose(fp);
+ return false;
+ }
+ }
+
+ fclose(fp);
+
+ return true;
+}
+
+/**
+ * Utility string length measurer; assumes strings are '\n' terminated
+ *
+ * \param str String to measure length of
+ * \param limit Upper bound on string length
+ * \return String length
+ */
+size_t parse_strlen(const char *str, size_t limit)
+{
+ size_t len = 0;
+
+ if (str == NULL)
+ return 0;
+
+ while (len < limit - 1 && *str != '\n') {
+ len++;
+ str++;
+ }
+
+ len++;
+
+ return len;
+}
+
+/**
+ * Read the size of a file
+ *
+ * \param filename Name of file to read size of
+ * \return File size (in bytes), or 0 on error
+ */
+size_t parse_filesize(const char *filename)
+{
+ FILE *fp;
+ size_t len = 0;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ printf("Failed opening %s\n", filename);
+ return 0;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+
+ fclose(fp);
+
+ return len;
+}
+
+
+#endif
--
RISC OS Unicode Font Library
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-31-gd446883
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/d4468833b85b8c8f340bc...
...commit http://git.netsurf-browser.org/librufl.git/commit/d4468833b85b8c8f340bc9c...
...tree http://git.netsurf-browser.org/librufl.git/tree/d4468833b85b8c8f340bc9c3b...
The branch, jmb/ac has been updated
via d4468833b85b8c8f340bc9c3bb6572a245fd5982 (commit)
via 569a7dd761255ec0a04f9bc4e020440638395bb8 (commit)
via a4c41198bdcd21336f0921291c0e9a7b7da36fc3 (commit)
from 421bacf56744d00db7ccef93daa119ab8ea4ac55 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=d4468833b85b8c8f340...
commit d4468833b85b8c8f340bc9c3bb6572a245fd5982
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Restrict total font faces to 16 bit range
The substitution tables expect there to be no more than 65535
font faces available. Enforce this at load, so there aren't any
unwanted surprises later.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 2fa81c3..4005203 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -267,7 +267,9 @@ rufl_code rufl_init_font_list(void)
font_list_context context = 0;
char identifier[80], local_name[80];
- while (context != -1) {
+ /* Permit up to 65535 font faces (we rely on 16bits of storage
+ * being sufficient in the substitution tables. */
+ while (context != -1 && rufl_font_list_entries < UINT16_MAX) {
/* read identifier */
rufl_fm_error = xfont_list_fonts((byte *)identifier,
font_RETURN_FONT_NAME |
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=569a7dd761255ec0a04...
commit 569a7dd761255ec0a04f9bc4e020440638395bb8
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Clean up types in internal structures
diff --git a/src/rufl_init.c b/src/rufl_init.c
index e5ce5e5..2fa81c3 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -34,7 +34,7 @@ struct rufl_family_map_entry *rufl_family_map = 0;
os_error *rufl_fm_error = 0;
void *rufl_family_menu = 0;
struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
-int rufl_cache_time = 0;
+uint32_t rufl_cache_time = 0;
bool rufl_old_font_manager = false;
static bool rufl_broken_font_enumerate_characters = false;
wimp_w rufl_status_w = 0;
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 42f0def..8438bd8 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -116,7 +116,7 @@ struct rufl_unicode_map {
/** Corresponding encoding name */
char *encoding;
/** Number of valid entries in map. */
- unsigned int entries;
+ size_t entries;
/** Map from Unicode to character code. */
struct rufl_unicode_map_entry map[256];
};
@@ -129,16 +129,16 @@ struct rufl_font_list_entry {
/** Character set of font. */
struct rufl_character_set *charset;
/** Number of Unicode mapping tables */
- unsigned int num_umaps;
+ size_t num_umaps;
/** Mappings from Unicode to character code. */
struct rufl_unicode_map *umap;
/** Family that this font belongs to (index in rufl_family_list and
* rufl_family_map). */
- unsigned int family;
+ uint32_t family;
/** Font weight (0 to 8). */
- unsigned int weight;
+ uint32_t weight;
/** Font slant (0 or 1). */
- unsigned int slant;
+ uint32_t slant;
};
/** List of all available fonts. */
extern struct rufl_font_list_entry *rufl_font_list;
@@ -151,7 +151,7 @@ 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];
+ uint32_t font[9][2];
};
/** Map from font family to fonts, rufl_family_list_entries entries. */
extern struct rufl_family_map_entry *rufl_family_map;
@@ -167,24 +167,24 @@ extern struct rufl_family_map_entry *rufl_family_map;
/** An entry in rufl_cache. */
struct rufl_cache_entry {
/** Font number (index in rufl_font_list), or rufl_CACHE_*. */
- unsigned int font;
+ uint32_t font;
/** No font cached in this slot. */
#define rufl_CACHE_NONE UINT_MAX
/** Font for rendering hex substitutions in this slot. */
#define rufl_CACHE_CORPUS (UINT_MAX - 1)
/** Font size. */
- unsigned int size;
+ uint32_t size;
/** Font encoding */
const char *encoding;
/** Value of rufl_cache_time when last used. */
- unsigned int last_used;
+ uint32_t last_used;
/** RISC OS font handle. */
font_f f;
};
/** Cache of rufl_CACHE_SIZE most recently used font handles. */
extern struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
/** Counter for measuring age of cache entries. */
-extern int rufl_cache_time;
+extern uint32_t rufl_cache_time;
/** Font manager does not support Unicode. */
extern bool rufl_old_font_manager;
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a4c41198bdcd21336f0...
commit a4c41198bdcd21336f0921291c0e9a7b7da36fc3
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Clean up types in public API
diff --git a/include/rufl.h b/include/rufl.h
index 15e889e..bb44e49 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -8,6 +8,7 @@
#ifndef RUFL_H
#define RUFL_H
+#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include "oslib/os.h"
@@ -53,7 +54,7 @@ extern os_error *rufl_fm_error;
/** List of available font families. */
extern const char **rufl_family_list;
/** Number of entries in rufl_family_list. */
-extern unsigned int rufl_family_list_entries;
+extern size_t rufl_family_list_entries;
/** Menu of font families. */
extern void *rufl_family_menu;
@@ -85,7 +86,7 @@ rufl_code rufl_init(void);
rufl_code rufl_paint(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y, unsigned int flags);
@@ -95,7 +96,7 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style,
rufl_code rufl_width(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int *width);
@@ -105,7 +106,7 @@ rufl_code rufl_width(const char *font_family, rufl_style font_style,
rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int click_x,
size_t *char_offset, int *actual_x);
@@ -116,7 +117,7 @@ rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
rufl_code rufl_split(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int width,
size_t *char_offset, int *actual_x);
@@ -124,7 +125,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
/** Type of callback function for rufl_paint_callback(). */
typedef void (*rufl_callback_t)(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y);
@@ -134,7 +135,7 @@ typedef void (*rufl_callback_t)(void *context,
rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y,
rufl_callback_t callback, void *context);
@@ -145,7 +146,7 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
rufl_code rufl_decompose_glyph(const char *font_family,
rufl_style font_style, unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
struct rufl_decomp_funcs *funcs, void *user);
@@ -154,10 +155,10 @@ rufl_code rufl_decompose_glyph(const char *font_family,
*/
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);
+ os_box *bbox, int32_t *xkern, int32_t *ykern, int32_t *italic,
+ int32_t *ascent, int32_t *descent,
+ int32_t *xheight, int32_t *cap_height,
+ int8_t *uline_position, uint8_t *uline_thickness);
/**
@@ -166,10 +167,10 @@ rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style,
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);
+ const uint8_t *string, size_t length,
+ int32_t *x_bearing, int32_t *y_bearing,
+ int32_t *width, int32_t *height,
+ int32_t *x_advance, int32_t *y_advance);
/**
@@ -177,8 +178,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
*/
rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
- unsigned int font_size,
- int *bbox);
+ unsigned int font_size, os_box *bbox);
/**
diff --git a/src/rufl_decompose.c b/src/rufl_decompose.c
index 2085e8f..0e9f6ea 100644
--- a/src/rufl_decompose.c
+++ b/src/rufl_decompose.c
@@ -67,7 +67,7 @@ static int *process_path(int *path, struct rufl_decomp_funcs *funcs,
rufl_code rufl_decompose_glyph(const char *font_family,
rufl_style font_style, unsigned int font_size,
- const char *string, size_t len,
+ const uint8_t *string, size_t len,
struct rufl_decomp_funcs *funcs, void *user)
{
int *buf, *p, *ep;
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 6cf0be6..e5ce5e5 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -29,7 +29,7 @@
struct rufl_font_list_entry *rufl_font_list = 0;
size_t rufl_font_list_entries = 0;
const char **rufl_family_list = 0;
-unsigned int rufl_family_list_entries = 0;
+size_t rufl_family_list_entries = 0;
struct rufl_family_map_entry *rufl_family_map = 0;
os_error *rufl_fm_error = 0;
void *rufl_family_menu = 0;
@@ -180,7 +180,7 @@ rufl_code rufl_init(void)
xhourglass_off();
return code;
}
- LOG("%zu faces, %u families", rufl_font_list_entries,
+ LOG("%zu faces, %zu families", rufl_font_list_entries,
rufl_family_list_entries);
code = rufl_load_cache();
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index 0637ddb..876ac53 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -19,10 +19,10 @@ 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)
+ os_box *bbox, int32_t *xkern, int32_t *ykern, int32_t *italic,
+ int32_t *ascent, int32_t *descent,
+ int32_t *xheight, int32_t *cap_height,
+ int8_t *uline_position, uint8_t *uline_thickness)
{
unsigned int font;
font_f f;
@@ -114,10 +114,10 @@ rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style,
*/
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)
+ const uint8_t *string, size_t length,
+ int32_t *x_bearing, int32_t *y_bearing,
+ int32_t *width, int32_t *height,
+ int32_t *x_advance, int32_t *y_advance)
{
const char *font_encoding = NULL;
unsigned int font, font1, u;
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index 360baec..06ed509 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -27,7 +27,7 @@ static const os_trfm trfm_oblique =
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,
+ const uint8_t *string0, size_t length,
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);
@@ -58,7 +58,7 @@ static rufl_code rufl_process_not_available(rufl_action action,
rufl_code rufl_paint(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y, unsigned int flags)
{
return rufl_process(rufl_PAINT,
@@ -73,7 +73,7 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style,
rufl_code rufl_width(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int *width)
{
return rufl_process(rufl_WIDTH,
@@ -89,7 +89,7 @@ rufl_code rufl_width(const char *font_family, rufl_style font_style,
rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int click_x,
size_t *char_offset, int *actual_x)
{
@@ -106,7 +106,7 @@ rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
rufl_code rufl_split(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int width,
size_t *char_offset, int *actual_x)
{
@@ -123,7 +123,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y,
rufl_callback_t callback, void *context)
{
@@ -139,11 +139,11 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
unsigned int font_size,
- int *bbox)
+ os_box *bbox)
{
return rufl_process(rufl_FONT_BBOX,
font_family, font_style, font_size, 0,
- 0, 0, 0, 0, bbox, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, (int *) bbox, 0, 0, 0, 0, 0);
}
@@ -154,7 +154,7 @@ rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
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,
+ const uint8_t *string0, size_t length,
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)
@@ -168,7 +168,7 @@ rufl_code rufl_process(rufl_action action,
size_t offset_u;
size_t offset_map[rufl_PROCESS_CHUNK];
unsigned int slant;
- const char *string = string0;
+ const uint8_t *string = string0;
struct rufl_character_set *charset;
rufl_code code;
@@ -310,7 +310,9 @@ rufl_code rufl_process_span(rufl_action action,
return code;
if (action == rufl_FONT_BBOX) {
- rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]);
+ os_box *bbox = (os_box *) x;
+ rufl_fm_error = xfont_read_info(f, &bbox->x0, &bbox->y0,
+ &bbox->x1, &bbox->y1);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
return rufl_OK;
@@ -385,7 +387,7 @@ rufl_code rufl_process_span_old(rufl_action action,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char s2[rufl_PROCESS_CHUNK];
+ uint8_t s2[rufl_PROCESS_CHUNK];
char *split_point;
int x_out, y_out;
unsigned int i;
@@ -394,12 +396,15 @@ rufl_code rufl_process_span_old(rufl_action action,
rufl_code code;
if (action == rufl_FONT_BBOX) {
+ os_box *bbox = (os_box *) x;
+
/* Don't need encoding for bounding box */
code = rufl_find_font(font, font_size, NULL, &f);
if (code != rufl_OK)
return code;
- rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]);
+ rufl_fm_error = xfont_read_info(f, &bbox->x0, &bbox->y0,
+ &bbox->x1, &bbox->y1);
if (rufl_fm_error) {
LOG("xfont_read_info: 0x%x: %s",
rufl_fm_error->errnum,
@@ -462,7 +467,8 @@ rufl_code rufl_process_span_old(rufl_action action,
return rufl_FONT_MANAGER_ERROR;
}
- rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS |
+ rufl_fm_error = xfont_paint(f, (char *) s2,
+ font_OS_UNITS |
(oblique ? font_GIVEN_TRFM : 0) |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
@@ -492,7 +498,7 @@ 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,
+ rufl_fm_error = xfont_scan_string(f, (char *) s2,
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
((action == rufl_X_TO_OFFSET) ?
@@ -500,9 +506,9 @@ rufl_code rufl_process_span_old(rufl_action action,
(click_x - *x) * 400, 0x7fffffff,
0, 0, i,
&split_point, &x_out, &y_out, 0);
- *offset += split_point - s2;
+ *offset += split_point - (char *) s2;
} else {
- rufl_fm_error = xfont_scan_string(f, s2,
+ rufl_fm_error = xfont_scan_string(f, (char *) s2,
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN,
0x7fffffff, 0x7fffffff, 0, 0, i,
@@ -548,7 +554,7 @@ rufl_code rufl_process_not_available(rufl_action action,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char missing[] = "000000";
+ uint8_t missing[] = "000000";
const int dx = 7 * font_size / 64;
const int dx3 = 10.5 * font_size / 64;
int top_y = y + 5 * font_size / 64;
@@ -589,7 +595,8 @@ 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 + offset,
+ rufl_fm_error = xfont_paint(f,
+ (char *) (missing + offset),
font_OS_UNITS | font_GIVEN_LENGTH |
font_GIVEN_FONT | font_KERN |
((flags & rufl_BLEND_FONT) ?
@@ -605,7 +612,8 @@ rufl_code rufl_process_not_available(rufl_action action,
/* last two characters underneath */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing + offset + step,
+ rufl_fm_error = xfont_paint(f,
+ (char *) (missing + offset + step),
font_OS_UNITS |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index 1df86e3..fd0365c 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -262,7 +262,7 @@ int main(void)
rufl_code redraw(int x, int y, int y0, int y1)
{
- char s[10];
+ uint8_t s[10];
unsigned int l;
unsigned int u;
rufl_code code;
diff --git a/test/rufl_test.c b/test/rufl_test.c
index 5b76f81..3edbcf1 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -18,13 +18,13 @@ 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 int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y);
int main(void)
{
- char utf8_test[] = "Hello, world! ����������� "
+ const uint8_t utf8_test[] = "Hello, world! ����������� "
"Uhersk�� Hradi��t��. ����"
"\xf0\xa0\x80\xa1";
int width;
@@ -32,7 +32,7 @@ int main(void)
int x;
int actual_x;
struct rufl_decomp_funcs funcs = { move_to, line_to, cubic_to };
- int bbox[4];
+ os_box bbox;
try(rufl_init(), "rufl_init");
rufl_dump_state(false);
@@ -58,14 +58,14 @@ int main(void)
char_offset, utf8_test + char_offset);
}
try(rufl_decompose_glyph("Homerton", rufl_WEIGHT_400, 1280,
- "A", 1, &funcs, 0),
+ (const uint8_t *) "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");
- try(rufl_font_bbox("NewHall", rufl_WEIGHT_400, 240, bbox),
+ try(rufl_font_bbox("NewHall", rufl_WEIGHT_400, 240, &bbox),
"rufl_font_bbox");
- printf("bbox: %i %i %i %i\n", bbox[0], bbox[1], bbox[2], bbox[3]);
+ printf("bbox: %i %i %i %i\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);
rufl_quit();
return 0;
@@ -132,7 +132,7 @@ int cubic_to(os_coord *control1, os_coord *control2, os_coord *to,
void callback(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y)
{
(void) context;
@@ -141,7 +141,7 @@ void callback(void *context,
if (s8)
printf("s8 \"%.*s\" ", n, s8);
else {
- printf("s16 \"");
+ printf("s32 \"");
for (unsigned int i = 0; i != n; i++)
printf("%x ", (unsigned int) s32[i]);
printf("\" ");
-----------------------------------------------------------------------
Summary of changes:
include/rufl.h | 36 ++++++++++++++++++------------------
src/rufl_decompose.c | 2 +-
src/rufl_init.c | 10 ++++++----
src/rufl_internal.h | 20 ++++++++++----------
src/rufl_metrics.c | 16 ++++++++--------
src/rufl_paint.c | 48 ++++++++++++++++++++++++++++--------------------
test/rufl_chars.c | 2 +-
test/rufl_test.c | 16 ++++++++--------
8 files changed, 80 insertions(+), 70 deletions(-)
diff --git a/include/rufl.h b/include/rufl.h
index 15e889e..bb44e49 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -8,6 +8,7 @@
#ifndef RUFL_H
#define RUFL_H
+#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include "oslib/os.h"
@@ -53,7 +54,7 @@ extern os_error *rufl_fm_error;
/** List of available font families. */
extern const char **rufl_family_list;
/** Number of entries in rufl_family_list. */
-extern unsigned int rufl_family_list_entries;
+extern size_t rufl_family_list_entries;
/** Menu of font families. */
extern void *rufl_family_menu;
@@ -85,7 +86,7 @@ rufl_code rufl_init(void);
rufl_code rufl_paint(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y, unsigned int flags);
@@ -95,7 +96,7 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style,
rufl_code rufl_width(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int *width);
@@ -105,7 +106,7 @@ rufl_code rufl_width(const char *font_family, rufl_style font_style,
rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int click_x,
size_t *char_offset, int *actual_x);
@@ -116,7 +117,7 @@ rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
rufl_code rufl_split(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int width,
size_t *char_offset, int *actual_x);
@@ -124,7 +125,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
/** Type of callback function for rufl_paint_callback(). */
typedef void (*rufl_callback_t)(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y);
@@ -134,7 +135,7 @@ typedef void (*rufl_callback_t)(void *context,
rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y,
rufl_callback_t callback, void *context);
@@ -145,7 +146,7 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
rufl_code rufl_decompose_glyph(const char *font_family,
rufl_style font_style, unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
struct rufl_decomp_funcs *funcs, void *user);
@@ -154,10 +155,10 @@ rufl_code rufl_decompose_glyph(const char *font_family,
*/
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);
+ os_box *bbox, int32_t *xkern, int32_t *ykern, int32_t *italic,
+ int32_t *ascent, int32_t *descent,
+ int32_t *xheight, int32_t *cap_height,
+ int8_t *uline_position, uint8_t *uline_thickness);
/**
@@ -166,10 +167,10 @@ rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style,
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);
+ const uint8_t *string, size_t length,
+ int32_t *x_bearing, int32_t *y_bearing,
+ int32_t *width, int32_t *height,
+ int32_t *x_advance, int32_t *y_advance);
/**
@@ -177,8 +178,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
*/
rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
- unsigned int font_size,
- int *bbox);
+ unsigned int font_size, os_box *bbox);
/**
diff --git a/src/rufl_decompose.c b/src/rufl_decompose.c
index 2085e8f..0e9f6ea 100644
--- a/src/rufl_decompose.c
+++ b/src/rufl_decompose.c
@@ -67,7 +67,7 @@ static int *process_path(int *path, struct rufl_decomp_funcs *funcs,
rufl_code rufl_decompose_glyph(const char *font_family,
rufl_style font_style, unsigned int font_size,
- const char *string, size_t len,
+ const uint8_t *string, size_t len,
struct rufl_decomp_funcs *funcs, void *user)
{
int *buf, *p, *ep;
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 6cf0be6..4005203 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -29,12 +29,12 @@
struct rufl_font_list_entry *rufl_font_list = 0;
size_t rufl_font_list_entries = 0;
const char **rufl_family_list = 0;
-unsigned int rufl_family_list_entries = 0;
+size_t rufl_family_list_entries = 0;
struct rufl_family_map_entry *rufl_family_map = 0;
os_error *rufl_fm_error = 0;
void *rufl_family_menu = 0;
struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
-int rufl_cache_time = 0;
+uint32_t rufl_cache_time = 0;
bool rufl_old_font_manager = false;
static bool rufl_broken_font_enumerate_characters = false;
wimp_w rufl_status_w = 0;
@@ -180,7 +180,7 @@ rufl_code rufl_init(void)
xhourglass_off();
return code;
}
- LOG("%zu faces, %u families", rufl_font_list_entries,
+ LOG("%zu faces, %zu families", rufl_font_list_entries,
rufl_family_list_entries);
code = rufl_load_cache();
@@ -267,7 +267,9 @@ rufl_code rufl_init_font_list(void)
font_list_context context = 0;
char identifier[80], local_name[80];
- while (context != -1) {
+ /* Permit up to 65535 font faces (we rely on 16bits of storage
+ * being sufficient in the substitution tables. */
+ while (context != -1 && rufl_font_list_entries < UINT16_MAX) {
/* read identifier */
rufl_fm_error = xfont_list_fonts((byte *)identifier,
font_RETURN_FONT_NAME |
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 42f0def..8438bd8 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -116,7 +116,7 @@ struct rufl_unicode_map {
/** Corresponding encoding name */
char *encoding;
/** Number of valid entries in map. */
- unsigned int entries;
+ size_t entries;
/** Map from Unicode to character code. */
struct rufl_unicode_map_entry map[256];
};
@@ -129,16 +129,16 @@ struct rufl_font_list_entry {
/** Character set of font. */
struct rufl_character_set *charset;
/** Number of Unicode mapping tables */
- unsigned int num_umaps;
+ size_t num_umaps;
/** Mappings from Unicode to character code. */
struct rufl_unicode_map *umap;
/** Family that this font belongs to (index in rufl_family_list and
* rufl_family_map). */
- unsigned int family;
+ uint32_t family;
/** Font weight (0 to 8). */
- unsigned int weight;
+ uint32_t weight;
/** Font slant (0 or 1). */
- unsigned int slant;
+ uint32_t slant;
};
/** List of all available fonts. */
extern struct rufl_font_list_entry *rufl_font_list;
@@ -151,7 +151,7 @@ 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];
+ uint32_t font[9][2];
};
/** Map from font family to fonts, rufl_family_list_entries entries. */
extern struct rufl_family_map_entry *rufl_family_map;
@@ -167,24 +167,24 @@ extern struct rufl_family_map_entry *rufl_family_map;
/** An entry in rufl_cache. */
struct rufl_cache_entry {
/** Font number (index in rufl_font_list), or rufl_CACHE_*. */
- unsigned int font;
+ uint32_t font;
/** No font cached in this slot. */
#define rufl_CACHE_NONE UINT_MAX
/** Font for rendering hex substitutions in this slot. */
#define rufl_CACHE_CORPUS (UINT_MAX - 1)
/** Font size. */
- unsigned int size;
+ uint32_t size;
/** Font encoding */
const char *encoding;
/** Value of rufl_cache_time when last used. */
- unsigned int last_used;
+ uint32_t last_used;
/** RISC OS font handle. */
font_f f;
};
/** Cache of rufl_CACHE_SIZE most recently used font handles. */
extern struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
/** Counter for measuring age of cache entries. */
-extern int rufl_cache_time;
+extern uint32_t rufl_cache_time;
/** Font manager does not support Unicode. */
extern bool rufl_old_font_manager;
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index 0637ddb..876ac53 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -19,10 +19,10 @@ 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)
+ os_box *bbox, int32_t *xkern, int32_t *ykern, int32_t *italic,
+ int32_t *ascent, int32_t *descent,
+ int32_t *xheight, int32_t *cap_height,
+ int8_t *uline_position, uint8_t *uline_thickness)
{
unsigned int font;
font_f f;
@@ -114,10 +114,10 @@ rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style,
*/
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)
+ const uint8_t *string, size_t length,
+ int32_t *x_bearing, int32_t *y_bearing,
+ int32_t *width, int32_t *height,
+ int32_t *x_advance, int32_t *y_advance)
{
const char *font_encoding = NULL;
unsigned int font, font1, u;
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index 360baec..06ed509 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -27,7 +27,7 @@ static const os_trfm trfm_oblique =
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,
+ const uint8_t *string0, size_t length,
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);
@@ -58,7 +58,7 @@ static rufl_code rufl_process_not_available(rufl_action action,
rufl_code rufl_paint(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y, unsigned int flags)
{
return rufl_process(rufl_PAINT,
@@ -73,7 +73,7 @@ rufl_code rufl_paint(const char *font_family, rufl_style font_style,
rufl_code rufl_width(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int *width)
{
return rufl_process(rufl_WIDTH,
@@ -89,7 +89,7 @@ rufl_code rufl_width(const char *font_family, rufl_style font_style,
rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int click_x,
size_t *char_offset, int *actual_x)
{
@@ -106,7 +106,7 @@ rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style,
rufl_code rufl_split(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int width,
size_t *char_offset, int *actual_x)
{
@@ -123,7 +123,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
unsigned int font_size,
- const char *string, size_t length,
+ const uint8_t *string, size_t length,
int x, int y,
rufl_callback_t callback, void *context)
{
@@ -139,11 +139,11 @@ rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style,
rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
unsigned int font_size,
- int *bbox)
+ os_box *bbox)
{
return rufl_process(rufl_FONT_BBOX,
font_family, font_style, font_size, 0,
- 0, 0, 0, 0, bbox, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, (int *) bbox, 0, 0, 0, 0, 0);
}
@@ -154,7 +154,7 @@ rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
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,
+ const uint8_t *string0, size_t length,
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)
@@ -168,7 +168,7 @@ rufl_code rufl_process(rufl_action action,
size_t offset_u;
size_t offset_map[rufl_PROCESS_CHUNK];
unsigned int slant;
- const char *string = string0;
+ const uint8_t *string = string0;
struct rufl_character_set *charset;
rufl_code code;
@@ -310,7 +310,9 @@ rufl_code rufl_process_span(rufl_action action,
return code;
if (action == rufl_FONT_BBOX) {
- rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]);
+ os_box *bbox = (os_box *) x;
+ rufl_fm_error = xfont_read_info(f, &bbox->x0, &bbox->y0,
+ &bbox->x1, &bbox->y1);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
return rufl_OK;
@@ -385,7 +387,7 @@ rufl_code rufl_process_span_old(rufl_action action,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char s2[rufl_PROCESS_CHUNK];
+ uint8_t s2[rufl_PROCESS_CHUNK];
char *split_point;
int x_out, y_out;
unsigned int i;
@@ -394,12 +396,15 @@ rufl_code rufl_process_span_old(rufl_action action,
rufl_code code;
if (action == rufl_FONT_BBOX) {
+ os_box *bbox = (os_box *) x;
+
/* Don't need encoding for bounding box */
code = rufl_find_font(font, font_size, NULL, &f);
if (code != rufl_OK)
return code;
- rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]);
+ rufl_fm_error = xfont_read_info(f, &bbox->x0, &bbox->y0,
+ &bbox->x1, &bbox->y1);
if (rufl_fm_error) {
LOG("xfont_read_info: 0x%x: %s",
rufl_fm_error->errnum,
@@ -462,7 +467,8 @@ rufl_code rufl_process_span_old(rufl_action action,
return rufl_FONT_MANAGER_ERROR;
}
- rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS |
+ rufl_fm_error = xfont_paint(f, (char *) s2,
+ font_OS_UNITS |
(oblique ? font_GIVEN_TRFM : 0) |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
@@ -492,7 +498,7 @@ 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,
+ rufl_fm_error = xfont_scan_string(f, (char *) s2,
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
((action == rufl_X_TO_OFFSET) ?
@@ -500,9 +506,9 @@ rufl_code rufl_process_span_old(rufl_action action,
(click_x - *x) * 400, 0x7fffffff,
0, 0, i,
&split_point, &x_out, &y_out, 0);
- *offset += split_point - s2;
+ *offset += split_point - (char *) s2;
} else {
- rufl_fm_error = xfont_scan_string(f, s2,
+ rufl_fm_error = xfont_scan_string(f, (char *) s2,
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN,
0x7fffffff, 0x7fffffff, 0, 0, i,
@@ -548,7 +554,7 @@ rufl_code rufl_process_not_available(rufl_action action,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char missing[] = "000000";
+ uint8_t missing[] = "000000";
const int dx = 7 * font_size / 64;
const int dx3 = 10.5 * font_size / 64;
int top_y = y + 5 * font_size / 64;
@@ -589,7 +595,8 @@ 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 + offset,
+ rufl_fm_error = xfont_paint(f,
+ (char *) (missing + offset),
font_OS_UNITS | font_GIVEN_LENGTH |
font_GIVEN_FONT | font_KERN |
((flags & rufl_BLEND_FONT) ?
@@ -605,7 +612,8 @@ rufl_code rufl_process_not_available(rufl_action action,
/* last two characters underneath */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing + offset + step,
+ rufl_fm_error = xfont_paint(f,
+ (char *) (missing + offset + step),
font_OS_UNITS |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index 1df86e3..fd0365c 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -262,7 +262,7 @@ int main(void)
rufl_code redraw(int x, int y, int y0, int y1)
{
- char s[10];
+ uint8_t s[10];
unsigned int l;
unsigned int u;
rufl_code code;
diff --git a/test/rufl_test.c b/test/rufl_test.c
index 5b76f81..3edbcf1 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -18,13 +18,13 @@ 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 int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y);
int main(void)
{
- char utf8_test[] = "Hello, world! ����������� "
+ const uint8_t utf8_test[] = "Hello, world! ����������� "
"Uhersk�� Hradi��t��. ����"
"\xf0\xa0\x80\xa1";
int width;
@@ -32,7 +32,7 @@ int main(void)
int x;
int actual_x;
struct rufl_decomp_funcs funcs = { move_to, line_to, cubic_to };
- int bbox[4];
+ os_box bbox;
try(rufl_init(), "rufl_init");
rufl_dump_state(false);
@@ -58,14 +58,14 @@ int main(void)
char_offset, utf8_test + char_offset);
}
try(rufl_decompose_glyph("Homerton", rufl_WEIGHT_400, 1280,
- "A", 1, &funcs, 0),
+ (const uint8_t *) "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");
- try(rufl_font_bbox("NewHall", rufl_WEIGHT_400, 240, bbox),
+ try(rufl_font_bbox("NewHall", rufl_WEIGHT_400, 240, &bbox),
"rufl_font_bbox");
- printf("bbox: %i %i %i %i\n", bbox[0], bbox[1], bbox[2], bbox[3]);
+ printf("bbox: %i %i %i %i\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);
rufl_quit();
return 0;
@@ -132,7 +132,7 @@ int cubic_to(os_coord *control1, os_coord *control2, os_coord *to,
void callback(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned int *s32, unsigned int n,
+ const uint8_t *s8, const uint32_t *s32, unsigned int n,
int x, int y)
{
(void) context;
@@ -141,7 +141,7 @@ void callback(void *context,
if (s8)
printf("s8 \"%.*s\" ", n, s8);
else {
- printf("s16 \"");
+ printf("s32 \"");
for (unsigned int i = 0; i != n; i++)
printf("%x ", (unsigned int) s32[i]);
printf("\" ");
--
RISC OS Unicode Font Library
2 years, 1 month
netsurf: branch chris/ndk32 updated. release/3.10-168-g2535d48
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/2535d48321b3a40131c52...
...commit http://git.netsurf-browser.org/netsurf.git/commit/2535d48321b3a40131c5246...
...tree http://git.netsurf-browser.org/netsurf.git/tree/2535d48321b3a40131c5246b3...
The branch, chris/ndk32 has been updated
via 2535d48321b3a40131c5246b3c560bbf95f4bd35 (commit)
from a7e976b3fbc1038408b024b46dced0205514e109 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=2535d48321b3a40131c...
commit 2535d48321b3a40131c5246b3c560bbf95f4bd35
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Amiga: Fix some undefined references
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index fe94eb2..aae3f30 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -185,6 +185,9 @@ AMINS_LIB_STRUCT(Keymap);
AMINS_LIB_STRUCT(Layers);
AMINS_LIB_STRUCT(Locale);
AMINS_LIB_STRUCT(P96);
+#ifndef __amigaos4__
+AMINS_LIB_STRUCT(Utility);
+#endif
AMINS_LIB_STRUCT(Workbench);
AMINS_LIB_STRUCT(Codesets);
diff --git a/frontends/amiga/schedule.c b/frontends/amiga/schedule.c
index 18eb1af..533e7f6 100644
--- a/frontends/amiga/schedule.c
+++ b/frontends/amiga/schedule.c
@@ -42,10 +42,11 @@ struct nscallback
};
static struct nscallback *tioreq;
-struct Device *TimerBase;
#ifdef __amigaos4__
+struct Device *TimerBase;
struct TimerIFace *ITimer;
#else
+struct Library *TimerBase;
static struct MsgPort *schedule_msgport = NULL;
#endif
@@ -81,7 +82,7 @@ static void ami_schedule_remove_timer_event(struct nscallback *nscb)
static nserror ami_schedule_add_timer_event(struct nscallback *nscb, int t)
{
struct TimeVal tv;
- ULONG time_us = t * 1000; /* t converted to �s */
+ ULONG time_us = t * 1000; /* t converted to microseconds */
tv.tv_secs = time_us / 1000000;
tv.tv_micro = time_us % 1000000;
-----------------------------------------------------------------------
Summary of changes:
frontends/amiga/libs.c | 3 +++
frontends/amiga/schedule.c | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/frontends/amiga/libs.c b/frontends/amiga/libs.c
index fe94eb2..aae3f30 100644
--- a/frontends/amiga/libs.c
+++ b/frontends/amiga/libs.c
@@ -185,6 +185,9 @@ AMINS_LIB_STRUCT(Keymap);
AMINS_LIB_STRUCT(Layers);
AMINS_LIB_STRUCT(Locale);
AMINS_LIB_STRUCT(P96);
+#ifndef __amigaos4__
+AMINS_LIB_STRUCT(Utility);
+#endif
AMINS_LIB_STRUCT(Workbench);
AMINS_LIB_STRUCT(Codesets);
diff --git a/frontends/amiga/schedule.c b/frontends/amiga/schedule.c
index 18eb1af..533e7f6 100644
--- a/frontends/amiga/schedule.c
+++ b/frontends/amiga/schedule.c
@@ -42,10 +42,11 @@ struct nscallback
};
static struct nscallback *tioreq;
-struct Device *TimerBase;
#ifdef __amigaos4__
+struct Device *TimerBase;
struct TimerIFace *ITimer;
#else
+struct Library *TimerBase;
static struct MsgPort *schedule_msgport = NULL;
#endif
@@ -81,7 +82,7 @@ static void ami_schedule_remove_timer_event(struct nscallback *nscb)
static nserror ami_schedule_add_timer_event(struct nscallback *nscb, int t)
{
struct TimeVal tv;
- ULONG time_us = t * 1000; /* t converted to �s */
+ ULONG time_us = t * 1000; /* t converted to microseconds */
tv.tv_secs = time_us / 1000000;
tv.tv_micro = time_us % 1000000;
--
NetSurf Browser
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-28-g421bacf
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/421bacf56744d00db7cce...
...commit http://git.netsurf-browser.org/librufl.git/commit/421bacf56744d00db7ccef9...
...tree http://git.netsurf-browser.org/librufl.git/tree/421bacf56744d00db7ccef93d...
The branch, jmb/ac has been updated
via 421bacf56744d00db7ccef93daa119ab8ea4ac55 (commit)
via d59f17a6fb3d4f20a931ab45bf60ff910685b241 (commit)
via 01da1538227f4d139c0665b730211c665c821625 (commit)
via b547911ad6cba76439eeb9cd03a6af3fe0dc6be3 (commit)
via 5fd0f4c9161c5ab6163386598d04681f12858509 (commit)
via 7455528fedc1d6a03ba693307c441ffddcc3c164 (commit)
via c69d7fee4ef1820296cb1c0db072e01cf6970ce1 (commit)
via 158483bc75ac79cb2699d92e30f30aeefefe56ca (commit)
via 5741043b16e81f9673fdef791aeb225e522c9a41 (commit)
via a53a1e176218aba04ec13d91bbfbd103608c4eb2 (commit)
via c945837b458fc9ff4d37568be74ddb1a685e6431 (commit)
from 6dce21aa10a2d5f5a745a2f168d801d4baa7d4b2 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=421bacf56744d00db7c...
commit 421bacf56744d00db7ccef93daa119ab8ea4ac55
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Make dump of unicode maps optional
Add a verbose flag to rufl_dump_state() and use it to control
whether to dump the individual unicode maps generated when using
a non-UCS Font Manager.
Change rufl_test to not dump this state (ordinarily, anyway) as
it is generally uninteresting and highly verbose.
diff --git a/include/rufl.h b/include/rufl.h
index 0164df8..15e889e 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -185,7 +185,7 @@ rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
* Dump the internal library state to stdout.
*/
-void rufl_dump_state(void);
+void rufl_dump_state(bool verbose);
/**
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index 860d57e..f466333 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -18,7 +18,7 @@ static void rufl_dump_unicode_map(struct rufl_unicode_map *umap);
* Dump the internal library state to stdout.
*/
-void rufl_dump_state(void)
+void rufl_dump_state(bool verbose)
{
unsigned int i, j;
@@ -32,7 +32,7 @@ void rufl_dump_state(void)
} else {
printf(" (no charset table)\n");
}
- if (rufl_font_list[i].umap) {
+ if (verbose && rufl_font_list[i].umap) {
for (j = 0; j < rufl_font_list[i].num_umaps; j++) {
struct rufl_unicode_map *map =
rufl_font_list[i].umap + j;
diff --git a/test/rufl_test.c b/test/rufl_test.c
index d939467..5b76f81 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -35,7 +35,7 @@ int main(void)
int bbox[4];
try(rufl_init(), "rufl_init");
- rufl_dump_state();
+ rufl_dump_state(false);
try(rufl_paint("NewHall", rufl_WEIGHT_400, 240,
utf8_test, sizeof utf8_test - 1,
1200, 1000, 0), "rufl_paint");
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=d59f17a6fb3d4f20a93...
commit d59f17a6fb3d4f20a931ab45bf60ff910685b241
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Ignore UCS fonts if using a non-UCS Font Manager
Attempting to use fonts constructed for the UCS Font Manager on
older systems generally results in bad outcomes up to, and
including, complete system freezes. As fixing the Font Manager
on these systems is impractical, simply ignore these fonts
completely when scanning for glyph coverage.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 79433c3..6cf0be6 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1028,10 +1028,33 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
if (code != rufl_OK) {
LOG("rufl_init_read_encoding(\"%s\", ...): 0x%x",
buf, code);
+ umap->encoding = NULL;
xfont_lose_font(font);
return code;
}
+ /* Detect attempts to use UCS fonts with a non-UCS Font Manager.
+ * There is a bug in all known non-UCS Font Managers which is
+ * often triggered by scanning many fonts. The Font Manager will
+ * attempt to dereference a bogus pointer (at the start of
+ * getbbox_unscaled) and thus cause an abort in SVC mode.
+ * Fallout can be as (relatively) benign as the application
+ * crashing or escalate to an entire system freeze requiring
+ * a reset. As there are no "good" outcomes here, and we do
+ * not have a time machine to go back and fix long-ago released
+ * Font Managers, ensure we ignore UCS fonts here. */
+ if ((uint32_t) umap->encoding > 256) {
+ static os_error err = {
+ error_FONT_TOO_MANY_CHUNKS, "Rejecting UCS font"};
+ LOG("%s", "Rejecting UCS font");
+ umap->encoding = NULL;
+ xfont_lose_font(font);
+ rufl_fm_error = &err;
+ return rufl_FONT_MANAGER_ERROR;
+ }
+ /* Eliminate all trace of our (ab)use of the encoding field */
+ umap->encoding = NULL;
+
for (i = 0; i != umap->entries; i++) {
u = umap->map[i].u;
string[0] = umap->map[i].c;
@@ -1102,9 +1125,11 @@ static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
umap->map[umap->entries].u = ucs4;
umap->map[umap->entries].c = glyph_idx;
umap->entries++;
- if (umap->entries == 256)
- result = rufl_IO_EOF;
}
+ /* Stash the total number of encoding file entries so that
+ * rufl_init_scan_font_in_encoding can detect the presence of a
+ * UCS font on a non-UCS capable system. It will clean up for us. */
+ umap->encoding = (void *) (((uint32_t) umap->encoding) + 1);
return result;
}
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=01da1538227f4d139c0...
commit 01da1538227f4d139c0665b730211c665c821625
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Clean up logging in the non-UCS Font Manager path
To obtain the full extent of a "language" font's glyph coverage
we need to open and scan it in each of the available target
encodings. All of the Latin1-6 + Welsh target encodings declare
that they are based on the Base0 encoding and thus will cause the
Font Manager to demand the existence of corresponding
IntMetric0/Outlines0 font data files. A "language" font using a
different base encoding (and corresponding target encodings
based on it) would thus generate an error from the Font Manager.
Additionally, without reinventing the Font Manager's own logic
(and poking around the filesystem looking for IntMetrics and
Encoding files), we don't know if a font is a "language" or a
"symbol" font until we try to use it. Thus, we expect attempts to
open "symbol" fonts with an explicit target encoding to generate
an error from the Font Manager as well.
As these are expected errors, there is no point logging them as
it just produces a load of distracting noise.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 3a77588..79433c3 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -870,7 +870,20 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code = rufl_init_scan_font_in_encoding(font_name, encoding,
charset, umap + (num_umaps - 1), &last_used);
- if (code != rufl_OK) {
+ /* Not finding the font isn't fatal */
+ if (code == rufl_FONT_MANAGER_ERROR &&
+ (rufl_fm_error->errnum ==
+ error_FONT_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FILE_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FONT_ENCODING_NOT_FOUND ||
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum ==
+ error_FONT_TOO_MANY_CHUNKS)) {
+ /* Ensure we reuse the currently allocated umap */
+ num_umaps--;
+ } else if (code != rufl_OK) {
LOG("rufl_init_scan_font_in_encoding(\"%s\", \"%s\", "
"...): 0x%x (0x%x: %s)",
font_name, encoding, code,
@@ -879,26 +892,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code == rufl_FONT_MANAGER_ERROR ?
rufl_fm_error->errmess : "");
- /* Not finding the font isn't fatal */
- if (code != rufl_FONT_MANAGER_ERROR ||
- (rufl_fm_error->errnum !=
- error_FONT_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FILE_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND &&
- /* Neither is a too modern font */
- rufl_fm_error->errnum !=
- error_FONT_TOO_MANY_CHUNKS)) {
- free(charset);
- for (i = 0; i < num_umaps; i++)
- free((umap + i)->encoding);
- free(umap);
- return code;
- }
-
- /* Ensure we reuse the currently allocated umap */
- num_umaps--;
+ free(charset);
+ for (i = 0; i < num_umaps; i++)
+ free((umap + i)->encoding);
+ free(umap);
+ return code;
} else {
/* If this mapping is identical to an existing one,
* then we can discard it */
@@ -937,7 +935,20 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code = rufl_init_scan_font_in_encoding(font_name, NULL,
charset, umap, &last_used);
- if (code != rufl_OK) {
+ /* Not finding the font isn't fatal */
+ if (code == rufl_FONT_MANAGER_ERROR &&
+ (rufl_fm_error->errnum ==
+ error_FONT_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FILE_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FONT_ENCODING_NOT_FOUND ||
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum ==
+ error_FONT_TOO_MANY_CHUNKS)) {
+ /* Ensure we reuse the currently allocated umap */
+ num_umaps--;
+ } else if (code != rufl_OK) {
LOG("rufl_init_scan_font_in_encoding(\"%s\", NULL, "
"...): 0x%x (0x%x: %s)",
font_name, code,
@@ -946,25 +957,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code == rufl_FONT_MANAGER_ERROR ?
rufl_fm_error->errmess : "");
- /* Not finding the font isn't fatal */
- if (code != rufl_FONT_MANAGER_ERROR ||
- (rufl_fm_error->errnum !=
- error_FONT_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FILE_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND &&
- /* Neither is a too modern font */
- rufl_fm_error->errnum !=
- error_FONT_TOO_MANY_CHUNKS)) {
- free(charset);
- for (i = 0; i < num_umaps; i++)
- free((umap + i)->encoding);
- free(umap);
- return code;
- }
-
- num_umaps--;
+ free(charset);
+ for (i = 0; i < num_umaps; i++)
+ free((umap + i)->encoding);
+ free(umap);
+ return code;
}
}
@@ -1023,8 +1020,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
rufl_fm_error = xfont_find_font(buf, 160, 160, 0, 0, &font, 0, 0);
if (rufl_fm_error) {
- LOG("xfont_find_font(\"%s\"): 0x%x: %s", buf,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
+ /* Leave it to our caller to log, if they wish */
return rufl_FONT_MANAGER_ERROR;
}
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=b547911ad6cba76439e...
commit b547911ad6cba76439eeb9cd03a6af3fe0dc6be3
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Accept non-UCS Font Manager rejecting UCS fonts.
If you attempt to use fonts supported by the UCS Font Manager with
a non-UCS Font Manager, this will either work (in a limited way)
or fail because the font data is incomprehensible to the non-UCS
Font Manager. Cope with one particular instance of this.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 9beb992..3a77588 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -886,7 +886,10 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
rufl_fm_error->errnum !=
error_FILE_NOT_FOUND &&
rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND)) {
+ error_FONT_ENCODING_NOT_FOUND &&
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum !=
+ error_FONT_TOO_MANY_CHUNKS)) {
free(charset);
for (i = 0; i < num_umaps; i++)
free((umap + i)->encoding);
@@ -950,7 +953,10 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
rufl_fm_error->errnum !=
error_FILE_NOT_FOUND &&
rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND)) {
+ error_FONT_ENCODING_NOT_FOUND &&
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum !=
+ error_FONT_TOO_MANY_CHUNKS)) {
free(charset);
for (i = 0; i < num_umaps; i++)
free((umap + i)->encoding);
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=5fd0f4c9161c5ab6163...
commit 5fd0f4c9161c5ab6163386598d04681f12858509
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Fix font scanning on non-UCS Font Managers
We want to update the umap itself not whatever happens to be on the
stack in the vicinity of its address.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index cf85980..9beb992 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1118,7 +1118,7 @@ rufl_code rufl_init_populate_unicode_map(font_f f,
umap->entries = 0;
- result = rufl_init_read_encoding(f, rufl_init_umap_cb, &umap);
+ result = rufl_init_read_encoding(f, rufl_init_umap_cb, umap);
if (result == rufl_OK) {
/* sort by unicode */
qsort(umap->map, umap->entries, sizeof umap->map[0],
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=7455528fedc1d6a03ba...
commit 7455528fedc1d6a03ba693307c441ffddcc3c164
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Fix initialisation on UCS Font Manager 3.41-3.63
We cannot use Font_ReadEncodingFile to find the path to a font's
source encoding because that is not what the API returns (it
returns the path to the encoding file corresponding to the target
encoding used to open the font handle) and there is no public API
for obtaining the path of the source encoding. Additionally, there
is no reliable way to replicate the UCS Font Manager's mapping of
undefined and duplicate glyph names into the private use space
at U+E000-U+EFFF.
Therefore, take a different approach to supporting these versions
of the Font Manager: abuse Font_EnumerateCharacters by probing
every codepoint in the range [0, first_returned) to force the
Font Manager to reveal the information we want. Once we have
reached the first_returned codepoint, we can happily fall through
to the normal flow (which will make use of the sparse nature of
the Unicode space).
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 29ef415..cf85980 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -543,16 +543,56 @@ static rufl_code rufl_init_enumerate_characters(const char *font_name,
uint32_t glyph_idx, uint32_t ucs4),
void *pw)
{
- unsigned int u, next;
- rufl_code result;
+ unsigned int u = 0, next, internal;
+ rufl_code result = rufl_OK;
- if (rufl_broken_font_enumerate_characters)
- return rufl_init_read_encoding(font, callback, pw);
+ if (rufl_broken_font_enumerate_characters) {
+ /* We know that any codepoints in the first chunk will
+ * be missed because Font_EnumerateCharacters is broken
+ * on this version of the Font Manager. Find the first
+ * codepoint it will report. */
+ unsigned int first;
+ rufl_fm_error = xfont_enumerate_characters(font, 0,
+ (int *) &first, (int *) &internal);
+ if (rufl_fm_error) {
+ LOG("xfont_enumerate_characters(\"%s\", "
+ "U+%x, ...): 0x%x: %s",
+ font_name, 0,
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
+ return rufl_FONT_MANAGER_ERROR;
+ }
- /* Scan through mapped characters */
- for (u = 0; u != (unsigned int) -1; u = next) {
- unsigned int internal;
+ /* Search the entire space up to the first codepoint it
+ * reported. */
+ for (u = 0; u != (unsigned int) -1 && u != first; u++) {
+ rufl_fm_error = xfont_enumerate_characters(font, u,
+ (int *) &next, (int *) &internal);
+ if (rufl_fm_error) {
+ LOG("xfont_enumerate_characters(\"%s\", "
+ "U+%x, ...): 0x%x: %s",
+ font_name, u,
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
+ result = rufl_FONT_MANAGER_ERROR;
+ break;
+ }
+
+ /* Skip unmapped characters */
+ if (internal == (unsigned int) -1)
+ continue;
+
+ /* Character is mapped, emit it */
+ result = callback(pw, internal, u);
+ if (result != rufl_OK)
+ break;
+ }
+ /* Now fall through to the normal path */
+ }
+
+ /* Scan through mapped characters */
+ for (; u != (unsigned int) -1; u = next) {
rufl_fm_error = xfont_enumerate_characters(font, u,
(int *) &next, (int *) &internal);
if (rufl_fm_error) {
@@ -561,6 +601,7 @@ static rufl_code rufl_init_enumerate_characters(const char *font_name,
font_name, u,
rufl_fm_error->errnum,
rufl_fm_error->errmess);
+ result = rufl_FONT_MANAGER_ERROR;
break;
}
@@ -1225,13 +1266,9 @@ rufl_code rufl_init_read_encoding(font_f font,
}
fp = fopen(filename, "r");
- if (!fp) {
+ if (!fp && rufl_old_font_manager) {
/* many "symbol" fonts have no encoding file */
- const char *default_path =
- "Resources:$.Fonts.Encodings./Default";
- if (rufl_old_font_manager)
- default_path = "Resources:$.Fonts.Encodings.Latin1";
- fp = fopen(default_path, "r");
+ fp = fopen("Resources:$.Fonts.Encodings.Latin1", "r");
}
if (!fp)
return rufl_IO_ERROR;
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=c69d7fee4ef1820296c...
commit c69d7fee4ef1820296cb1c0db072e01cf6970ce1
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Fix shrinkwrap moving blocks
All blocks subsequent to a full one get moved up and all their
indices need rewriting.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index f49ceff..29ef415 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -472,31 +472,26 @@ static void rufl_init_shrinkwrap_plane(struct rufl_character_set *charset)
for (byte = 0; byte != 32; byte++)
bit &= charset->block[block][byte];
- if (bit == 0xff) {
- /* Block is full */
-
- /* Find a block whose index is after this one.
- * If such a block exists, move its data into
- * this block, as this block's bitmap is now free
- */
- for (byte = 0; byte != 256; byte++) {
- if (charset->index[byte] < BLOCK_EMPTY &&
- charset->index[byte] > block) {
- break;
- }
- }
- if (byte != 256) {
- memcpy(charset->block[block],
- charset->block[
- charset->index[byte]],
- 32);
- charset->index[byte] = block;
- }
- /* Now mark this block as full */
- charset->index[u] = BLOCK_FULL;
- last_used--;
+ if (bit != 0xff)
+ continue;
+
+ /* Block is full */
+
+ /* Move subsequent blocks up and rewrite their indices */
+ memmove(charset->block[block],
+ charset->block[block+1],
+ (254-(block+1)) * 32);
+ for (byte = 0; byte != 256; byte++) {
+ if (charset->index[byte] < BLOCK_EMPTY &&
+ charset->index[byte] > block) {
+ charset->index[byte]--;
+ }
}
+
+ /* Now mark this block as full */
+ charset->index[u] = BLOCK_FULL;
+ last_used--;
}
/* Fill in this plane's size now we know it */
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=158483bc75ac79cb269...
commit 158483bc75ac79cb2699d92e30f30aeefefe56ca
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Ensure dumping doesn't run off the end of a plane
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index 13a1564..860d57e 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -90,7 +90,7 @@ static void rufl_dump_character_set(const struct rufl_character_set *charset)
u++;
} else {
t = u;
- while (rufl_character_set_test(
+ while (u != 0x10000 && rufl_character_set_test(
charset, plane + u))
u++;
printf("%x-%x ", plane + t, plane + u - 1);
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=5741043b16e81f9673f...
commit 5741043b16e81f9673fdef791aeb225e522c9a41
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Fix bug in sparse encoding parser
Spaces are valid characters in the sparse encoding so ensure we
consume them correctly.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 5da9b50..f49ceff 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1273,8 +1273,9 @@ rufl_code rufl_init_read_encoding(font_f font,
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '.') || (c == '_') ||
- (c == ';')) {
- /* Printable: append */
+ (c == ';') ||
+ (c == ' ' && s[0] != '/')) {
+ /* Printable (or space in new-style): append */
s[n++] = c;
if (n >= sizeof(s)) {
/* Too long: garbage */
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a53a1e176218aba04ec...
commit a53a1e176218aba04ec13d91bbfbd103608c4eb2
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Add MedBold and Thin weights
diff --git a/src/rufl_init.c b/src/rufl_init.c
index a6c895f..5da9b50 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -60,11 +60,13 @@ const struct rufl_weight_table_entry rufl_weight_table[] = {
{ "ExtraLight", 1 },
{ "Heavy", 8 },
{ "Light", 2 },
+ { "MedBold", 6 },
{ "Medium", 5 },
{ "Regular", 4 },
{ "Semi", 6 },
{ "SemiBold", 6 },
{ "SemiLight", 3 },
+ { "Thin", 1 },
{ "UltraBlack", 9 },
{ "UltraBold", 9 },
};
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=c945837b458fc9ff4d3...
commit c945837b458fc9ff4d37568be74ddb1a685e6431
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Clean up logging
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 6ec21b7..a6c895f 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -512,14 +512,11 @@ static struct rufl_character_set *rufl_init_shrinkwrap_planes(
/* Shrink-wrap each plane, accumulating total required size as we go */
for (u = 0; u < 17; u++) {
if (planes[u]) {
- LOG("shrink-wrapping plane %d", u);
rufl_init_shrinkwrap_plane(planes[u]);
size += PLANE_SIZE(planes[u]->metadata);
}
}
- LOG("shrink-wrapped size: %u", size);
-
charset = malloc(size);
if (!charset)
return NULL;
@@ -531,8 +528,6 @@ static struct rufl_character_set *rufl_init_shrinkwrap_planes(
if (!planes[u-1])
continue;
- LOG("merging plane %d", u);
-
/* Set E bit if not the last plane */
if (pos != size)
planes[u-1]->metadata |= (1u<<31);
@@ -1430,12 +1425,7 @@ rufl_code rufl_save_cache(void)
}
/* character set (all planes) */
- LOG("writing character sets for %s",
- rufl_font_list[i].identifier);
while (EXTENSION_FOLLOWS(charset->metadata)) {
- LOG("writing plane %d (%u)",
- PLANE_ID(charset->metadata),
- PLANE_SIZE(charset->metadata));
if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
@@ -1445,9 +1435,6 @@ rufl_code rufl_save_cache(void)
charset = (void *)(((uint8_t *)charset) +
PLANE_SIZE(charset->metadata));
}
- LOG("writing plane %d (%u)",
- PLANE_ID(charset->metadata),
- PLANE_SIZE(charset->metadata));
if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
@@ -1606,7 +1593,6 @@ rufl_code rufl_load_cache(void)
identifier[len] = 0;
/* character set */
- LOG("reading character sets for %s", identifier);
do {
if (fread(&metadata, sizeof metadata, 1, fp) != 1) {
if (feof(fp))
@@ -1618,9 +1604,6 @@ rufl_code rufl_load_cache(void)
break;
}
- LOG("reading plane %d (%u)",
- PLANE_ID(metadata),
- PLANE_SIZE(metadata));
if (!charset) {
charset = cur_charset = malloc(
PLANE_SIZE(metadata));
-----------------------------------------------------------------------
Summary of changes:
include/rufl.h | 2 +-
src/rufl_dump_state.c | 6 +-
src/rufl_init.c | 233 +++++++++++++++++++++++++++++--------------------
test/rufl_test.c | 2 +-
4 files changed, 144 insertions(+), 99 deletions(-)
diff --git a/include/rufl.h b/include/rufl.h
index 0164df8..15e889e 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -185,7 +185,7 @@ rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style,
* Dump the internal library state to stdout.
*/
-void rufl_dump_state(void);
+void rufl_dump_state(bool verbose);
/**
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index 13a1564..f466333 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -18,7 +18,7 @@ static void rufl_dump_unicode_map(struct rufl_unicode_map *umap);
* Dump the internal library state to stdout.
*/
-void rufl_dump_state(void)
+void rufl_dump_state(bool verbose)
{
unsigned int i, j;
@@ -32,7 +32,7 @@ void rufl_dump_state(void)
} else {
printf(" (no charset table)\n");
}
- if (rufl_font_list[i].umap) {
+ if (verbose && rufl_font_list[i].umap) {
for (j = 0; j < rufl_font_list[i].num_umaps; j++) {
struct rufl_unicode_map *map =
rufl_font_list[i].umap + j;
@@ -90,7 +90,7 @@ static void rufl_dump_character_set(const struct rufl_character_set *charset)
u++;
} else {
t = u;
- while (rufl_character_set_test(
+ while (u != 0x10000 && rufl_character_set_test(
charset, plane + u))
u++;
printf("%x-%x ", plane + t, plane + u - 1);
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 6ec21b7..6cf0be6 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -60,11 +60,13 @@ const struct rufl_weight_table_entry rufl_weight_table[] = {
{ "ExtraLight", 1 },
{ "Heavy", 8 },
{ "Light", 2 },
+ { "MedBold", 6 },
{ "Medium", 5 },
{ "Regular", 4 },
{ "Semi", 6 },
{ "SemiBold", 6 },
{ "SemiLight", 3 },
+ { "Thin", 1 },
{ "UltraBlack", 9 },
{ "UltraBold", 9 },
};
@@ -470,31 +472,26 @@ static void rufl_init_shrinkwrap_plane(struct rufl_character_set *charset)
for (byte = 0; byte != 32; byte++)
bit &= charset->block[block][byte];
- if (bit == 0xff) {
- /* Block is full */
- /* Find a block whose index is after this one.
- * If such a block exists, move its data into
- * this block, as this block's bitmap is now free
- */
- for (byte = 0; byte != 256; byte++) {
- if (charset->index[byte] < BLOCK_EMPTY &&
- charset->index[byte] > block) {
- break;
- }
- }
- if (byte != 256) {
- memcpy(charset->block[block],
- charset->block[
- charset->index[byte]],
- 32);
- charset->index[byte] = block;
- }
+ if (bit != 0xff)
+ continue;
- /* Now mark this block as full */
- charset->index[u] = BLOCK_FULL;
- last_used--;
+ /* Block is full */
+
+ /* Move subsequent blocks up and rewrite their indices */
+ memmove(charset->block[block],
+ charset->block[block+1],
+ (254-(block+1)) * 32);
+ for (byte = 0; byte != 256; byte++) {
+ if (charset->index[byte] < BLOCK_EMPTY &&
+ charset->index[byte] > block) {
+ charset->index[byte]--;
+ }
}
+
+ /* Now mark this block as full */
+ charset->index[u] = BLOCK_FULL;
+ last_used--;
}
/* Fill in this plane's size now we know it */
@@ -512,14 +509,11 @@ static struct rufl_character_set *rufl_init_shrinkwrap_planes(
/* Shrink-wrap each plane, accumulating total required size as we go */
for (u = 0; u < 17; u++) {
if (planes[u]) {
- LOG("shrink-wrapping plane %d", u);
rufl_init_shrinkwrap_plane(planes[u]);
size += PLANE_SIZE(planes[u]->metadata);
}
}
- LOG("shrink-wrapped size: %u", size);
-
charset = malloc(size);
if (!charset)
return NULL;
@@ -531,8 +525,6 @@ static struct rufl_character_set *rufl_init_shrinkwrap_planes(
if (!planes[u-1])
continue;
- LOG("merging plane %d", u);
-
/* Set E bit if not the last plane */
if (pos != size)
planes[u-1]->metadata |= (1u<<31);
@@ -551,16 +543,56 @@ static rufl_code rufl_init_enumerate_characters(const char *font_name,
uint32_t glyph_idx, uint32_t ucs4),
void *pw)
{
- unsigned int u, next;
- rufl_code result;
+ unsigned int u = 0, next, internal;
+ rufl_code result = rufl_OK;
- if (rufl_broken_font_enumerate_characters)
- return rufl_init_read_encoding(font, callback, pw);
+ if (rufl_broken_font_enumerate_characters) {
+ /* We know that any codepoints in the first chunk will
+ * be missed because Font_EnumerateCharacters is broken
+ * on this version of the Font Manager. Find the first
+ * codepoint it will report. */
+ unsigned int first;
+ rufl_fm_error = xfont_enumerate_characters(font, 0,
+ (int *) &first, (int *) &internal);
+ if (rufl_fm_error) {
+ LOG("xfont_enumerate_characters(\"%s\", "
+ "U+%x, ...): 0x%x: %s",
+ font_name, 0,
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
+ return rufl_FONT_MANAGER_ERROR;
+ }
- /* Scan through mapped characters */
- for (u = 0; u != (unsigned int) -1; u = next) {
- unsigned int internal;
+ /* Search the entire space up to the first codepoint it
+ * reported. */
+ for (u = 0; u != (unsigned int) -1 && u != first; u++) {
+ rufl_fm_error = xfont_enumerate_characters(font, u,
+ (int *) &next, (int *) &internal);
+ if (rufl_fm_error) {
+ LOG("xfont_enumerate_characters(\"%s\", "
+ "U+%x, ...): 0x%x: %s",
+ font_name, u,
+ rufl_fm_error->errnum,
+ rufl_fm_error->errmess);
+ result = rufl_FONT_MANAGER_ERROR;
+ break;
+ }
+
+ /* Skip unmapped characters */
+ if (internal == (unsigned int) -1)
+ continue;
+
+ /* Character is mapped, emit it */
+ result = callback(pw, internal, u);
+ if (result != rufl_OK)
+ break;
+ }
+
+ /* Now fall through to the normal path */
+ }
+ /* Scan through mapped characters */
+ for (; u != (unsigned int) -1; u = next) {
rufl_fm_error = xfont_enumerate_characters(font, u,
(int *) &next, (int *) &internal);
if (rufl_fm_error) {
@@ -569,6 +601,7 @@ static rufl_code rufl_init_enumerate_characters(const char *font_name,
font_name, u,
rufl_fm_error->errnum,
rufl_fm_error->errmess);
+ result = rufl_FONT_MANAGER_ERROR;
break;
}
@@ -837,7 +870,20 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code = rufl_init_scan_font_in_encoding(font_name, encoding,
charset, umap + (num_umaps - 1), &last_used);
- if (code != rufl_OK) {
+ /* Not finding the font isn't fatal */
+ if (code == rufl_FONT_MANAGER_ERROR &&
+ (rufl_fm_error->errnum ==
+ error_FONT_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FILE_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FONT_ENCODING_NOT_FOUND ||
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum ==
+ error_FONT_TOO_MANY_CHUNKS)) {
+ /* Ensure we reuse the currently allocated umap */
+ num_umaps--;
+ } else if (code != rufl_OK) {
LOG("rufl_init_scan_font_in_encoding(\"%s\", \"%s\", "
"...): 0x%x (0x%x: %s)",
font_name, encoding, code,
@@ -846,23 +892,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code == rufl_FONT_MANAGER_ERROR ?
rufl_fm_error->errmess : "");
- /* Not finding the font isn't fatal */
- if (code != rufl_FONT_MANAGER_ERROR ||
- (rufl_fm_error->errnum !=
- error_FONT_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FILE_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND)) {
- free(charset);
- for (i = 0; i < num_umaps; i++)
- free((umap + i)->encoding);
- free(umap);
- return code;
- }
-
- /* Ensure we reuse the currently allocated umap */
- num_umaps--;
+ free(charset);
+ for (i = 0; i < num_umaps; i++)
+ free((umap + i)->encoding);
+ free(umap);
+ return code;
} else {
/* If this mapping is identical to an existing one,
* then we can discard it */
@@ -901,7 +935,20 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code = rufl_init_scan_font_in_encoding(font_name, NULL,
charset, umap, &last_used);
- if (code != rufl_OK) {
+ /* Not finding the font isn't fatal */
+ if (code == rufl_FONT_MANAGER_ERROR &&
+ (rufl_fm_error->errnum ==
+ error_FONT_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FILE_NOT_FOUND ||
+ rufl_fm_error->errnum ==
+ error_FONT_ENCODING_NOT_FOUND ||
+ /* Neither is a too modern font */
+ rufl_fm_error->errnum ==
+ error_FONT_TOO_MANY_CHUNKS)) {
+ /* Ensure we reuse the currently allocated umap */
+ num_umaps--;
+ } else if (code != rufl_OK) {
LOG("rufl_init_scan_font_in_encoding(\"%s\", NULL, "
"...): 0x%x (0x%x: %s)",
font_name, code,
@@ -910,22 +957,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
code == rufl_FONT_MANAGER_ERROR ?
rufl_fm_error->errmess : "");
- /* Not finding the font isn't fatal */
- if (code != rufl_FONT_MANAGER_ERROR ||
- (rufl_fm_error->errnum !=
- error_FONT_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FILE_NOT_FOUND &&
- rufl_fm_error->errnum !=
- error_FONT_ENCODING_NOT_FOUND)) {
- free(charset);
- for (i = 0; i < num_umaps; i++)
- free((umap + i)->encoding);
- free(umap);
- return code;
- }
-
- num_umaps--;
+ free(charset);
+ for (i = 0; i < num_umaps; i++)
+ free((umap + i)->encoding);
+ free(umap);
+ return code;
}
}
@@ -984,8 +1020,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
rufl_fm_error = xfont_find_font(buf, 160, 160, 0, 0, &font, 0, 0);
if (rufl_fm_error) {
- LOG("xfont_find_font(\"%s\"): 0x%x: %s", buf,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
+ /* Leave it to our caller to log, if they wish */
return rufl_FONT_MANAGER_ERROR;
}
@@ -993,10 +1028,33 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
if (code != rufl_OK) {
LOG("rufl_init_read_encoding(\"%s\", ...): 0x%x",
buf, code);
+ umap->encoding = NULL;
xfont_lose_font(font);
return code;
}
+ /* Detect attempts to use UCS fonts with a non-UCS Font Manager.
+ * There is a bug in all known non-UCS Font Managers which is
+ * often triggered by scanning many fonts. The Font Manager will
+ * attempt to dereference a bogus pointer (at the start of
+ * getbbox_unscaled) and thus cause an abort in SVC mode.
+ * Fallout can be as (relatively) benign as the application
+ * crashing or escalate to an entire system freeze requiring
+ * a reset. As there are no "good" outcomes here, and we do
+ * not have a time machine to go back and fix long-ago released
+ * Font Managers, ensure we ignore UCS fonts here. */
+ if ((uint32_t) umap->encoding > 256) {
+ static os_error err = {
+ error_FONT_TOO_MANY_CHUNKS, "Rejecting UCS font"};
+ LOG("%s", "Rejecting UCS font");
+ umap->encoding = NULL;
+ xfont_lose_font(font);
+ rufl_fm_error = &err;
+ return rufl_FONT_MANAGER_ERROR;
+ }
+ /* Eliminate all trace of our (ab)use of the encoding field */
+ umap->encoding = NULL;
+
for (i = 0; i != umap->entries; i++) {
u = umap->map[i].u;
string[0] = umap->map[i].c;
@@ -1067,9 +1125,11 @@ static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
umap->map[umap->entries].u = ucs4;
umap->map[umap->entries].c = glyph_idx;
umap->entries++;
- if (umap->entries == 256)
- result = rufl_IO_EOF;
}
+ /* Stash the total number of encoding file entries so that
+ * rufl_init_scan_font_in_encoding can detect the presence of a
+ * UCS font on a non-UCS capable system. It will clean up for us. */
+ umap->encoding = (void *) (((uint32_t) umap->encoding) + 1);
return result;
}
@@ -1085,7 +1145,7 @@ rufl_code rufl_init_populate_unicode_map(font_f f,
umap->entries = 0;
- result = rufl_init_read_encoding(f, rufl_init_umap_cb, &umap);
+ result = rufl_init_read_encoding(f, rufl_init_umap_cb, umap);
if (result == rufl_OK) {
/* sort by unicode */
qsort(umap->map, umap->entries, sizeof umap->map[0],
@@ -1233,13 +1293,9 @@ rufl_code rufl_init_read_encoding(font_f font,
}
fp = fopen(filename, "r");
- if (!fp) {
+ if (!fp && rufl_old_font_manager) {
/* many "symbol" fonts have no encoding file */
- const char *default_path =
- "Resources:$.Fonts.Encodings./Default";
- if (rufl_old_font_manager)
- default_path = "Resources:$.Fonts.Encodings.Latin1";
- fp = fopen(default_path, "r");
+ fp = fopen("Resources:$.Fonts.Encodings.Latin1", "r");
}
if (!fp)
return rufl_IO_ERROR;
@@ -1276,8 +1332,9 @@ rufl_code rufl_init_read_encoding(font_f font,
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '.') || (c == '_') ||
- (c == ';')) {
- /* Printable: append */
+ (c == ';') ||
+ (c == ' ' && s[0] != '/')) {
+ /* Printable (or space in new-style): append */
s[n++] = c;
if (n >= sizeof(s)) {
/* Too long: garbage */
@@ -1430,12 +1487,7 @@ rufl_code rufl_save_cache(void)
}
/* character set (all planes) */
- LOG("writing character sets for %s",
- rufl_font_list[i].identifier);
while (EXTENSION_FOLLOWS(charset->metadata)) {
- LOG("writing plane %d (%u)",
- PLANE_ID(charset->metadata),
- PLANE_SIZE(charset->metadata));
if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
@@ -1445,9 +1497,6 @@ rufl_code rufl_save_cache(void)
charset = (void *)(((uint8_t *)charset) +
PLANE_SIZE(charset->metadata));
}
- LOG("writing plane %d (%u)",
- PLANE_ID(charset->metadata),
- PLANE_SIZE(charset->metadata));
if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
@@ -1606,7 +1655,6 @@ rufl_code rufl_load_cache(void)
identifier[len] = 0;
/* character set */
- LOG("reading character sets for %s", identifier);
do {
if (fread(&metadata, sizeof metadata, 1, fp) != 1) {
if (feof(fp))
@@ -1618,9 +1666,6 @@ rufl_code rufl_load_cache(void)
break;
}
- LOG("reading plane %d (%u)",
- PLANE_ID(metadata),
- PLANE_SIZE(metadata));
if (!charset) {
charset = cur_charset = malloc(
PLANE_SIZE(metadata));
diff --git a/test/rufl_test.c b/test/rufl_test.c
index d939467..5b76f81 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -35,7 +35,7 @@ int main(void)
int bbox[4];
try(rufl_init(), "rufl_init");
- rufl_dump_state();
+ rufl_dump_state(false);
try(rufl_paint("NewHall", rufl_WEIGHT_400, 240,
utf8_test, sizeof utf8_test - 1,
1200, 1000, 0), "rufl_paint");
--
RISC OS Unicode Font Library
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-17-g6dce21a
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/6dce21aa10a2d5f5a745a...
...commit http://git.netsurf-browser.org/librufl.git/commit/6dce21aa10a2d5f5a745a2f...
...tree http://git.netsurf-browser.org/librufl.git/tree/6dce21aa10a2d5f5a745a2f16...
The branch, jmb/ac has been updated
via 6dce21aa10a2d5f5a745a2f168d801d4baa7d4b2 (commit)
from a1389acbc6234340c14f9236bfc9b6fd1776e8d8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=6dce21aa10a2d5f5a74...
commit 6dce21aa10a2d5f5a745a2f168d801d4baa7d4b2
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Use version-specific cache location.
Move the cache location to a subdirectory within Scrap and encode
the cache version in the filename.
This allows software using different versions of RUfl to coexist
on the same system without trying to share the same cache (and
thus rescanning fonts every time).
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 25753d6..6ec21b7 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -14,6 +14,8 @@
#include <string.h>
#include <strings.h>
#include <search.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <oslib/font.h>
#include <oslib/hourglass.h>
#include <oslib/os.h>
@@ -1329,6 +1331,52 @@ int rufl_unicode_map_cmp(const void *z1, const void *z2)
}
+static FILE *rufl_open_cache(const char *mode)
+{
+ const unsigned int version = rufl_CACHE_VERSION;
+ size_t len;
+ FILE *fp;
+ char fn[PATH_MAX];
+
+ if (!mode)
+ return NULL;
+
+ strcpy(fn, rufl_CACHE_TEMPLATE);
+ len = strlen(fn);
+
+ /* Fill in version suffix */
+ fn[len-4] = "0123456789abcdef"[(version>>12) & 0xf];
+ fn[len-3] = "0123456789abcdef"[(version>> 8) & 0xf];
+ fn[len-2] = "0123456789abcdef"[(version>> 4) & 0xf];
+ fn[len-1] = "0123456789abcdef"[version & 0xf];
+
+ if (mode[0] == 'a' || mode[0] == 'w') {
+ /* Wind back to directory separator */
+ while (len > 0 && fn[len] != '.')
+ len--;
+ if (len == 0) {
+ LOG("%s", "Malformed cache location");
+ return NULL;
+ }
+
+ /* Ensure directory exists */
+ fn[len] = '\0';
+ if (mkdir(fn, 0755) == -1 && errno != EEXIST) {
+ LOG("mkdir: 0x%x: %s", errno, strerror(errno));
+ return NULL;
+ }
+ fn[len] = '.';
+ }
+
+ fp = fopen(fn, mode);
+ if (!fp) {
+ LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ return NULL;;
+ }
+
+ return fp;
+}
+
/**
* Save character sets to cache.
*/
@@ -1340,11 +1388,9 @@ rufl_code rufl_save_cache(void)
size_t len;
FILE *fp;
- fp = fopen(rufl_CACHE, "wb");
- if (!fp) {
- LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ fp = rufl_open_cache("wb");
+ if (!fp)
return rufl_OK;
- }
/* cache format version */
if (fwrite(&version, sizeof version, 1, fp) != 1) {
@@ -1494,11 +1540,9 @@ rufl_code rufl_load_cache(void)
struct rufl_unicode_map *umap = NULL;
unsigned int num_umaps = 0;
- fp = fopen(rufl_CACHE, "rb");
- if (!fp) {
- LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ fp = rufl_open_cache("rb");
+ if (!fp)
return rufl_OK;
- }
/* cache format version */
if (fread(&version, sizeof version, 1, fp) != 1) {
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 6cf6b14..42f0def 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -235,7 +235,7 @@ void rufl_substitution_table_dump(void);
u = 0xfffd; \
}
-#define rufl_CACHE "<Wimp$ScrapDir>.RUfl_cache"
+#define rufl_CACHE_TEMPLATE "<Wimp$ScrapDir>.RUfl.CacheNNNN"
#define rufl_CACHE_VERSION 4
-----------------------------------------------------------------------
Summary of changes:
src/rufl_init.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-------
src/rufl_internal.h | 2 +-
2 files changed, 53 insertions(+), 9 deletions(-)
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 25753d6..6ec21b7 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -14,6 +14,8 @@
#include <string.h>
#include <strings.h>
#include <search.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <oslib/font.h>
#include <oslib/hourglass.h>
#include <oslib/os.h>
@@ -1329,6 +1331,52 @@ int rufl_unicode_map_cmp(const void *z1, const void *z2)
}
+static FILE *rufl_open_cache(const char *mode)
+{
+ const unsigned int version = rufl_CACHE_VERSION;
+ size_t len;
+ FILE *fp;
+ char fn[PATH_MAX];
+
+ if (!mode)
+ return NULL;
+
+ strcpy(fn, rufl_CACHE_TEMPLATE);
+ len = strlen(fn);
+
+ /* Fill in version suffix */
+ fn[len-4] = "0123456789abcdef"[(version>>12) & 0xf];
+ fn[len-3] = "0123456789abcdef"[(version>> 8) & 0xf];
+ fn[len-2] = "0123456789abcdef"[(version>> 4) & 0xf];
+ fn[len-1] = "0123456789abcdef"[version & 0xf];
+
+ if (mode[0] == 'a' || mode[0] == 'w') {
+ /* Wind back to directory separator */
+ while (len > 0 && fn[len] != '.')
+ len--;
+ if (len == 0) {
+ LOG("%s", "Malformed cache location");
+ return NULL;
+ }
+
+ /* Ensure directory exists */
+ fn[len] = '\0';
+ if (mkdir(fn, 0755) == -1 && errno != EEXIST) {
+ LOG("mkdir: 0x%x: %s", errno, strerror(errno));
+ return NULL;
+ }
+ fn[len] = '.';
+ }
+
+ fp = fopen(fn, mode);
+ if (!fp) {
+ LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ return NULL;;
+ }
+
+ return fp;
+}
+
/**
* Save character sets to cache.
*/
@@ -1340,11 +1388,9 @@ rufl_code rufl_save_cache(void)
size_t len;
FILE *fp;
- fp = fopen(rufl_CACHE, "wb");
- if (!fp) {
- LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ fp = rufl_open_cache("wb");
+ if (!fp)
return rufl_OK;
- }
/* cache format version */
if (fwrite(&version, sizeof version, 1, fp) != 1) {
@@ -1494,11 +1540,9 @@ rufl_code rufl_load_cache(void)
struct rufl_unicode_map *umap = NULL;
unsigned int num_umaps = 0;
- fp = fopen(rufl_CACHE, "rb");
- if (!fp) {
- LOG("fopen: 0x%x: %s", errno, strerror(errno));
+ fp = rufl_open_cache("rb");
+ if (!fp)
return rufl_OK;
- }
/* cache format version */
if (fread(&version, sizeof version, 1, fp) != 1) {
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 6cf6b14..42f0def 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -235,7 +235,7 @@ void rufl_substitution_table_dump(void);
u = 0xfffd; \
}
-#define rufl_CACHE "<Wimp$ScrapDir>.RUfl_cache"
+#define rufl_CACHE_TEMPLATE "<Wimp$ScrapDir>.RUfl.CacheNNNN"
#define rufl_CACHE_VERSION 4
--
RISC OS Unicode Font Library
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-16-ga1389ac
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/a1389acbc6234340c14f9...
...commit http://git.netsurf-browser.org/librufl.git/commit/a1389acbc6234340c14f923...
...tree http://git.netsurf-browser.org/librufl.git/tree/a1389acbc6234340c14f9236b...
The branch, jmb/ac has been updated
via a1389acbc6234340c14f9236bfc9b6fd1776e8d8 (commit)
from a520ed23f23e77b8c91b31814d9bbc2246df18a5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a1389acbc6234340c14...
commit a1389acbc6234340c14f9236bfc9b6fd1776e8d8
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Optimise substitution table storage
Consider each Unicode plane independently (as they have very
different properties). This means building a table for each
plane and allows us to reduce the size of each entry in the
CHD-addressed table from 64 to 32bits (which provides a
significant immediate saving).
Also introduce a direct linear mapping backend. This stores the
table in a series of 256-entry blocks which are addressed from
a fixed-size index. Block entries are either 8 or 16 bits wide
(depending upon the number of fonts found on the system). This
restores some of the storage efficiency of the old "giant array"
approach, which is generally more efficient than a CHD (or other)
hash-based implementation where the load factor is reasonably high
(or the glyph:block ratio is sufficiently high).
Select the direct or CHD storage mechanism based upon an estimate
of the storage size for the data collected for a plane. In the
testing I have performed (with the same fonts available as before)
the combined effect of the above is to reduce the storage used
significantly.
Without the 8bit direct mapping entry size (which is a somewhat
unfair comparison because even the "giant array" didn't have that
feature) we see:
Plane Codepoints Blocks Backend Storage Alternative
1 51483 224 Direct 115480 311328 (CHD)
2 1981 13 Direct 7448 9760 (CHD)
3 2293 201 CHD 17952 103704 (Direct)
Total 55757 140880 (~= 2.5 bytes/glyph)
The other 14 planes have no glyph coverage at all, so require no
storage.
With the 8bit direct mapping, we see:
Plane Codepoints Blocks Backend Storage Alternative
1 51483 224 Direct 57880 311328 (CHD)
2 1981 13 Direct 3864 9760 (CHD)
3 2293 201 CHD 17952 103704 (Direct)
Total 55757 79696 (~= 1.4 bytes/glyph)
In summary:
* separating the planes has shaved ~50% off the storage required
by the CHD backend
* introducing the direct mapping backend has shaved a further
~60% off that
* using 8bit direct mapping has shaved another ~50% off that
Cumulatively, then, storage requirements are now ~86% smaller
than with CHD only (and about 40% less than the BMP-only
"giant table", but now with astral character support).
diff --git a/src/rufl_substitution_table.c b/src/rufl_substitution_table.c
index 51c5b7a..0b201fa 100644
--- a/src/rufl_substitution_table.c
+++ b/src/rufl_substitution_table.c
@@ -14,6 +14,54 @@
#undef RUFL_SUBSTITUTION_TABLE_DEBUG
/**
+ * Base type for a substitution table.
+ */
+struct rufl_substitution_table {
+ /** Look up a Unicode codepoint. */
+ unsigned int (*lookup)(const struct rufl_substitution_table *t,
+ uint32_t u);
+ /** Free the resources used by this table */
+ void (*free)(struct rufl_substitution_table *t);
+ /** Dump the contents of this table to stdout */
+ void (*dump)(const struct rufl_substitution_table *t,
+ unsigned int plane);
+ /** Compute the storage size of this table */
+ size_t (*size)(const struct rufl_substitution_table *t);
+};
+
+/**
+ * Implementation of a substitution table using direct lookup.
+ */
+struct rufl_substitution_table_direct {
+ struct rufl_substitution_table base;
+
+ /** Table index.
+ *
+ * Each entry represents a block of 256 codepoints, so i[k] refers
+ * to codepoints [256*k, 256*(k+1)). The value is an offset into
+ * the block table.
+ */
+ uint8_t index[256];
+
+ /** Bits per block table entry. Will be 8 or 16. */
+ uint8_t bits_per_entry;
+
+ /** Substitution table.
+ *
+ * Entries are the index into rufl_font_list of a font providing a
+ * substitution glyph for this codepoint or NOT_AVAILABLE.
+ *
+ * Note that, although this is defined as a 16bit type,
+ * the actual field width is indicated by bits_per_entry (and,
+ * if bits_per_entry is 8, then (NOT_AVAILABLE & 0xff) represents
+ * a missing glyph).
+ */
+ uint16_t *table;
+};
+
+/**
+ * Implementation of a substitution table using a perfect hash.
+ *
* A perfect hash constructed at library initialisation time using the
* CHD algorithm. Hash entries are found via a two-step process:
*
@@ -23,7 +71,9 @@
* displacement value for the bucket to find the index
* into the substitution table.
*/
-struct rufl_substitution_table {
+struct rufl_substitution_table_chd {
+ struct rufl_substitution_table base;
+
uint32_t num_buckets; /**< Number of buckets in the hash */
uint32_t num_slots; /**< Number of slots in the table */
/** Substitution table.
@@ -33,18 +83,13 @@ struct rufl_substitution_table {
* 3 2 1 0
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Reserved | Unicode codepoint |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Reserved | Font identifier |
+ * | Unicode codepoint | Font identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* where:
*
- * reserved: 11 bits/16 bits
- * These bits are currently unused and must be set to 0.
- *
- * unicode codepoint: 21 bits
- * The Unicode codepoint value.
+ * unicode codepoint: 16 bits
+ * The low 16 bits of the Unicode codepoint value.
*
* font identifier: 16 bits
* The index into rufl_font_list of a font providing a
@@ -57,7 +102,7 @@ struct rufl_substitution_table {
* fail, no font provides a suitable glyph and the not available
* path should be taken.
*/
- uint64_t *table;
+ uint32_t *table;
uint8_t bits_per_entry; /**< Bits per displacement bitmap entry */
/** Displacement bitmap.
*
@@ -67,8 +112,8 @@ struct rufl_substitution_table {
*/
uint8_t displacement_map[];
};
-/** Font substitution table */
-static struct rufl_substitution_table *rufl_substitution_table;
+/** Font substitution tables -- one per plane */
+static struct rufl_substitution_table *rufl_substitution_table[17];
/**
* Round an unsigned 32bit value up to the next power of 2
@@ -170,8 +215,8 @@ static int table_chd_cmp(const void *a, const void *b)
{
/* We're only interested in the CHD metadata here.
* (i.e. the computed value of g(x) and the bucket size) */
- const uint64_t aa = (*(const uint64_t *) a) & 0x3fe00000ffff0000llu;
- const uint64_t bb = (*(const uint64_t *) b) & 0x3fe00000ffff0000llu;
+ const uint64_t aa = (*(const uint64_t *) a) & 0x000fffff00000000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x000fffff00000000llu;
if (aa > bb)
return -1;
@@ -214,6 +259,114 @@ static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
return result;
}
+static void rufl_substitution_table_free_chd(
+ struct rufl_substitution_table *t)
+{
+ free(((struct rufl_substitution_table_chd *)t)->table);
+ free(t);
+}
+
+
+static unsigned int rufl_substitution_table_lookup_chd(
+ const struct rufl_substitution_table *ts, uint32_t u)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ uint32_t displacement = 0;
+ uint32_t f, g = hash1(u & 0xffff) & (t->num_buckets - 1);
+ uint32_t bits_to_read = t->bits_per_entry;
+ uint32_t offset_bits = g * bits_to_read;
+ const uint8_t *pread = &t->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_read > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ if (space_available > bits_to_read)
+ space_available = bits_to_read;
+
+ displacement <<= space_available;
+ displacement |= (*pread & (0xff >> offset_bits)) >>
+ (8 - space_available - offset_bits);
+
+ offset_bits += space_available;
+ if (offset_bits >= 8) {
+ pread++;
+ offset_bits = 0;
+ }
+ bits_to_read -= space_available;
+ }
+
+ f = hash2((u & 0xffff), displacement) & (t->num_slots - 1);
+
+ if ((t->table[f] & 0xffff) != NOT_AVAILABLE &&
+ ((t->table[f] >> 16) & 0xffff) == (u & 0xffff))
+ return t->table[f] & 0xffff;
+
+ return NOT_AVAILABLE;
+}
+
+static int table_dump_cmp(const void *a, const void *b)
+{
+ const uint32_t aa = (*(const uint32_t *) a);
+ const uint32_t bb = (*(const uint32_t *) b);
+
+ if (aa > bb)
+ return 1;
+ else if (aa < bb)
+ return -1;
+ return 0;
+}
+
+static void rufl_substitution_table_dump_chd(
+ const struct rufl_substitution_table *ts, unsigned int plane)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ unsigned int font;
+ unsigned int u, prev;
+ uint32_t *table;
+
+ table = malloc(t->num_slots * sizeof(*table));
+ if (table == NULL)
+ return;
+
+ memcpy(table, t->table, t->num_slots * sizeof(*table));
+
+ qsort(table, t->num_slots, sizeof(*table), table_dump_cmp);
+
+ u = 0;
+ while (u < t->num_slots) {
+ prev = u;
+ font = table[prev] & 0xffff;
+ while (u < t->num_slots && font == (table[u] & 0xffff) &&
+ ((u == prev) ||
+ ((table[u - 1] >> 16) ==
+ ((table[u] >> 16) - 1))))
+ u++;
+ if (font != NOT_AVAILABLE)
+ printf(" %x-%x => %u \"%s\"\n",
+ (plane << 16) | (table[prev] >> 16),
+ (plane << 16) | (table[u - 1] >> 16),
+ font, rufl_font_list[font].identifier);
+ }
+
+ free(table);
+}
+
+static size_t rufl_substitution_table_size_chd(
+ const struct rufl_substitution_table *ts)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ size_t size = sizeof(*t);
+
+ /* Add on displacement map size */
+ size += (t->num_buckets * t->bits_per_entry + 7) >> 3;
+
+ /* Add on table size */
+ size += t->num_slots * sizeof(*t->table);
+
+ return size;
+}
+
/**
* Create the final substitution table from the intermediate parts
*
@@ -225,12 +378,13 @@ static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
* \param displacements Table of displacement values. One per bucket.
* \param substitution_table Location to receive result.
*/
-static rufl_code create_substitution_table(uint64_t *table,
+static rufl_code create_substitution_table_chd(uint64_t *table,
size_t table_entries, uint32_t buckets, uint32_t range,
uint32_t max_displacement, uint32_t *displacements,
struct rufl_substitution_table **substitution_table)
{
- struct rufl_substitution_table *subst_table;
+ struct rufl_substitution_table_chd *subst_table;
+ uint64_t *t64;
size_t subst_table_size;
unsigned int i;
@@ -239,7 +393,7 @@ static rufl_code create_substitution_table(uint64_t *table,
max_displacement, bits_needed(max_displacement));
#endif
- subst_table_size = offsetof(struct rufl_substitution_table,
+ subst_table_size = offsetof(struct rufl_substitution_table_chd,
displacement_map) +
((buckets * bits_needed(max_displacement) + 7) >> 3);
@@ -248,17 +402,23 @@ static rufl_code create_substitution_table(uint64_t *table,
return rufl_OUT_OF_MEMORY;
/* We know there are at least table_entries in the table, but
- * we should now resize it to the size of the target hashtable */
+ * we should now resize it to the size of the target hashtable.
+ * We still want each entry to be 64bits wide at this point. */
subst_table->table = realloc(table, range * sizeof(*table));
if (!subst_table->table) {
free(subst_table);
return rufl_OUT_OF_MEMORY;
}
+ t64 = (uint64_t *) subst_table->table;
/* Initialise unused slots */
for (i = table_entries; i < range; i++) {
- subst_table->table[i] = NOT_AVAILABLE;
+ t64[i] = NOT_AVAILABLE;
}
+ subst_table->base.lookup = rufl_substitution_table_lookup_chd;
+ subst_table->base.free = rufl_substitution_table_free_chd;
+ subst_table->base.dump = rufl_substitution_table_dump_chd;
+ subst_table->base.size = rufl_substitution_table_size_chd;
subst_table->num_buckets = buckets;
subst_table->num_slots = range;
subst_table->bits_per_entry = bits_needed(max_displacement);
@@ -300,32 +460,52 @@ static rufl_code create_substitution_table(uint64_t *table,
uint32_t f, g;
uint64_t tmp;
- if (subst_table->table[i] == NOT_AVAILABLE) {
+ if (t64[i] == NOT_AVAILABLE) {
i++;
continue;
}
- g = ((subst_table->table[i] >> 53) & 0x1f0000) |
- ((subst_table->table[i] >> 16) & 0xffff);
- f = hash2((subst_table->table[i] >> 32) & 0x1fffff,
+ g = ((t64[i] >> 32) & 0xffff);
+ f = hash2((t64[i] >> 16) & 0xffff,
displacements[g]) & (range - 1);
/* Exchange this entry with the one in the slot at f.*/
if (f != i) {
- tmp = subst_table->table[f];
- subst_table->table[f] = subst_table->table[i];
- subst_table->table[i] = tmp;
+ tmp = t64[f];
+ t64[f] = t64[i];
+ t64[i] = tmp;
} else {
/* Reconsider this slot unless it already
* had the correct entry */
i++;
}
}
- /* Strip all the CHD metadata out of the final table */
- for (i = 0; i < range; i++)
- subst_table->table[i] &= 0x001fffff0000ffffllu;
+ /* Strip all the CHD metadata out of the final table.
+ * We can simply drop the top 32bits of each entry by
+ * compacting the entries. */
+ for (i = 0; i < range; i++) {
+ subst_table->table[i] = t64[i] & 0xffffffffu;
+ }
+
+ /* Shrink the table to its final size. If this fails, leave
+ * the existing data intact as it's correct -- we just have
+ * twice the storage usage we need. */
+ table = realloc(subst_table->table,
+ range * sizeof(*subst_table->table));
+ if (table)
+ subst_table->table = (uint32_t *) table;
- *substitution_table = subst_table;
+ *substitution_table = &subst_table->base;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
+ subst_table->num_slots * sizeof(*subst_table->table),
+ table_entries,
+ subst_table->num_buckets,
+ subst_table->bits_per_entry,
+ (subst_table->num_buckets *
+ subst_table->bits_per_entry + 7) >> 3);
+#endif
return rufl_OK;
}
@@ -349,8 +529,8 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
{
/** Number of buckets assuming an average bucket size of 4 */
const uint32_t buckets = ceil2((table_entries + 3) & ~3);
- /** Number of output hash slots assuming a load factor of 0.95 */
- const uint32_t range = ceil2((table_entries * 100)/95);
+ /** Number of output hash slots assuming a load factor of 1 */
+ const uint32_t range = ceil2(table_entries);
uint32_t bucket_size, max_displacement = 0;
unsigned int i;
uint8_t *entries_per_bucket, *bitmap;
@@ -381,21 +561,18 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
/* Compute g(x) for each entry, placing them into buckets */
for (i = 0; i < table_entries; i++) {
- uint32_t g = hash1((table[i] >> 32) & 0x1fffff) & (buckets - 1);
+ uint64_t g = hash1((table[i] >> 16) & 0xffff) & (buckets - 1);
- /* Insert hash into entry (it's 21 bits at most, so
- * needs splitting between bits 16-31 and 53-57 of
- * the entry) */
- table[i] |= ((g & 0xffff) << 16);
- table[i] |= ((uint64_t)(g & 0x1f0000) << 53);
+ /* Insert hash into entry (it's 16 bits at most,
+ * so use bits 32-47) */
+ table[i] |= ((g & 0xffff) << 32);
entries_per_bucket[g]++;
}
/* Inject bucket size into entries */
for (i = 0; i < table_entries; i++) {
- uint32_t g = ((table[i] >> 53) & 0x1f0000) |
- ((table[i] >> 16) & 0xffff);
+ uint32_t g = ((table[i] >> 32) & 0xffff);
/* With a target bucket size of 4, do not expect
* >= twice that number of entries in the largest
@@ -406,11 +583,11 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
LOG("unexpectedly large bucket %u",
entries_per_bucket[g]);
- /* Stash bucket size into bits 58-61 of the entry */
- table[i] |= ((uint64_t)entries_per_bucket[g] << 58);
+ /* Stash bucket size into bits 48-51 of the entry */
+ table[i] |= ((uint64_t)entries_per_bucket[g] << 48);
}
- /* Bits 62-63 of table entries are currently unused */
+ /* Bits 52-63 of table entries are currently unused */
free(entries_per_bucket);
@@ -419,12 +596,11 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
/* Compute f(x) for each bucket, finding a unique mapping */
for (i = 0; i < table_entries; i += bucket_size) {
- const uint32_t g = ((table[i] >> 53) & 0x1f0000) |
- ((table[i] >> 16) & 0xffff);
+ const uint32_t g = ((table[i] >> 32) & 0xffff);
uint32_t hashes[8], num_hashes;
uint32_t d = 0;
- bucket_size = ((table[i] >> 58) & 0xf);
+ bucket_size = ((table[i] >> 48) & 0xf);
do {
uint32_t j, k;
@@ -434,7 +610,7 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
for (j = 0; j != bucket_size; j++) {
uint32_t f = hash2(
- (table[i+j] >> 32) & 0x1fffff, d) &
+ (table[i+j] >> 16) & 0xffff, d) &
(range - 1);
for (k = 0; k < num_hashes; k++) {
if (f == hashes[k])
@@ -455,7 +631,7 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
free(bitmap);
- result = create_substitution_table(table, table_entries,
+ result = create_substitution_table_chd(table, table_entries,
buckets, range, max_displacement, displacements,
substitution_table);
free(displacements);
@@ -463,6 +639,203 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
return result;
}
+static size_t rufl_substitution_table_estimate_size_chd(size_t table_entries,
+ size_t blocks_used)
+{
+ size_t size = sizeof(struct rufl_substitution_table_chd);
+
+ (void) blocks_used;
+
+ /** Number of buckets assuming an average bucket size of 4 */
+ const uint32_t buckets = ceil2((table_entries + 3) & ~3);
+ /** Number of output hash slots assuming a load factor of 1 */
+ const uint32_t range = ceil2(table_entries);
+
+ /* Conservatively assume 6 bits per displacement map entry */
+ size += (buckets * 6 + 7) >> 3;
+
+ /* Add on table size */
+ size += range * 4;
+
+ return size;
+}
+
+/****************************************************************************/
+
+static void rufl_substitution_table_free_direct(
+ struct rufl_substitution_table *t)
+{
+ free(((struct rufl_substitution_table_direct *)t)->table);
+ free(t);
+}
+
+
+static unsigned int rufl_substitution_table_lookup_direct(
+ const struct rufl_substitution_table *ts, uint32_t u)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ uint32_t block = (u >> 8) & 0xff;
+ uint32_t slot = (u & 0xff);
+ unsigned int font;
+
+ if (t->bits_per_entry == 8) {
+ font = ((uint8_t *) t->table)[t->index[block] * 256 + slot];
+ if (font == (NOT_AVAILABLE & 0xff))
+ font = NOT_AVAILABLE;
+ } else
+ font = t->table[t->index[block] * 256 + slot];
+
+ return font;
+}
+
+static void rufl_substitution_table_dump_direct(
+ const struct rufl_substitution_table *ts, unsigned int plane)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ unsigned int font, na;
+ unsigned int u, prev;
+ uint8_t *t8 = (uint8_t *) t->table;
+
+ na = NOT_AVAILABLE & ((t->bits_per_entry == 8) ? 0xff : 0xffff);
+
+#define LOOKUP(u) (t->bits_per_entry == 8 \
+ ? t8[t->index[(u >> 8) & 0xff] * 256 + (u & 0xff)] \
+ : t->table[t->index[(u >> 8) & 0xff] * 256 + (u & 0xff)])
+
+ u = 0;
+ while (u < 0x10000) {
+ prev = u;
+ font = LOOKUP(u);
+ while (u < 0x10000 && font == LOOKUP(u))
+ u++;
+ if (font != na)
+ printf(" %x-%x => %u \"%s\"\n",
+ (plane << 16) | prev,
+ (plane << 16) | (u - 1),
+ font, rufl_font_list[font].identifier);
+ }
+
+#undef LOOKUP
+}
+
+static size_t rufl_substitution_table_size_direct(
+ const struct rufl_substitution_table *ts)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ size_t size = sizeof(*t);
+ unsigned int i, block_idx = 0;
+
+ /* Find the largest block index (blocks are contiguous) */
+ for (i = 0; i < 256; i++)
+ if (t->index[i] > block_idx)
+ block_idx = t->index[i];
+
+ /* Add on table size */
+ size += (t->bits_per_entry * (block_idx + 1) * 256) >> 3;
+
+ return size;
+}
+
+/**
+ * Construct a direct-mapped substitution table
+ */
+static rufl_code direct(uint64_t *table, size_t table_entries,
+ size_t blocks_used, const uint8_t block_histogram[256],
+ struct rufl_substitution_table **substitution_table)
+{
+ struct rufl_substitution_table_direct *subst_table;
+ size_t blocks_needed, table_size;
+ unsigned int i, block;
+
+ subst_table = calloc(sizeof(*subst_table), 1);
+ if (!subst_table)
+ return rufl_OUT_OF_MEMORY;
+
+ subst_table->base.lookup = rufl_substitution_table_lookup_direct;
+ subst_table->base.free = rufl_substitution_table_free_direct;
+ subst_table->base.dump = rufl_substitution_table_dump_direct;
+ subst_table->base.size = rufl_substitution_table_size_direct;
+ /* We can use 8bits per entry if there are fewer than 255 fonts */
+ subst_table->bits_per_entry = rufl_font_list_entries < 255 ? 8 : 16;
+
+ /* Need one extra block if there's at least one free */
+ blocks_needed = (blocks_used < 256) ?
+ (blocks_used + 1) : blocks_used;
+
+ table_size = (256 * blocks_needed * subst_table->bits_per_entry) >> 3;
+
+ /* Populate block index */
+ for (i = 0, block = 0; i != 256; i++) {
+ if (block_histogram[i] == 0) {
+ subst_table->index[i] = blocks_used;
+ } else {
+ subst_table->index[i] = block;
+ block++;
+ }
+ }
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("blocks-used = %zu blocks-needed = %zu"
+ " bits-per-entry = %u size = %zu",
+ blocks_used, blocks_needed, subst_table->bits_per_entry,
+ table_size);
+#endif
+
+ /* Allocate table */
+ //XXX: can we just rearrange the existing one in-place?
+ subst_table->table = malloc(table_size);
+ if (!subst_table->table) {
+ free(subst_table);
+ return rufl_OUT_OF_MEMORY;
+ }
+ /* Fill it with NOT_AVAILABLE */
+ if (subst_table->bits_per_entry == 8) {
+ memset(subst_table->table, (NOT_AVAILABLE & 0xff), table_size);
+ } else {
+ for (i = 0; i < table_size; i++)
+ subst_table->table[i] = NOT_AVAILABLE;
+ }
+
+ /* Populate the table */
+ for (i = 0; i < table_entries; i++) {
+ uint64_t val = table[i];
+ uint32_t slot = (val >> 16) & 0xff;
+ block = subst_table->index[(val >> 24) & 0xff];
+
+ if (subst_table->bits_per_entry == 8) {
+ uint8_t *t8 = (uint8_t *) subst_table->table;
+ t8[256 * block + slot] = (val & 0xff);
+ } else {
+ subst_table->table[256 * block + slot] = (val & 0xffff);
+ }
+ }
+
+ free(table);
+
+ *substitution_table = &subst_table->base;
+
+ return rufl_OK;
+}
+
+static size_t rufl_substitution_table_estimate_size_direct(size_t table_entries,
+ size_t blocks_used)
+{
+ size_t size = sizeof(struct rufl_substitution_table_direct);
+
+ (void) table_entries;
+
+ /* Add one for empty block */
+ if (blocks_used < 256)
+ blocks_used += 1;
+
+ /* We can use 8bits per entry if there are fewer than 255 fonts */
+ size += blocks_used * 256 * (rufl_font_list_entries < 255 ? 1 : 2);
+
+ return size;
+}
+
+/****************************************************************************/
+
/**
* Populate the substitution map for a given block
*/
@@ -492,20 +865,23 @@ static void fill_map_for_block(const struct rufl_character_set **charsets,
}
}
-
/**
- * Construct the font substitution table.
+ * Create a substitution table for the plane specified
*/
-
-rufl_code rufl_substitution_table_init(void)
+static rufl_code create_substitution_table_for_plane(unsigned int plane)
{
unsigned int i;
- unsigned int plane, block;
+ unsigned int block;
unsigned int u;
const struct rufl_character_set **charsets;
+ const struct rufl_character_set *charset;
+ unsigned int num_charsets;
uint64_t *table;
size_t table_size;
size_t table_entries;
+ uint8_t block_histogram[256];
+ size_t blocks_used;
+ size_t direct_size, chd_size;
rufl_code result;
charsets = malloc(rufl_font_list_entries * sizeof(*charsets));
@@ -515,6 +891,34 @@ rufl_code rufl_substitution_table_init(void)
return rufl_OUT_OF_MEMORY;
}
+ /* Find fonts that have charsets for this plane */
+ num_charsets = 0;
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ charset = rufl_font_list[i].charset;
+ if (!charset) {
+ charsets[i] = NULL;
+ continue;
+ }
+
+ while (PLANE_ID(charset->metadata) != plane &&
+ EXTENSION_FOLLOWS(charset->metadata)) {
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ if (PLANE_ID(charset->metadata) != plane)
+ charset = NULL;
+ charsets[i] = charset;
+ num_charsets++;
+ }
+ if (num_charsets == 0) {
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("no charsets for plane %u", plane);
+#endif
+ rufl_substitution_table[plane] = NULL;
+ free(charsets);
+ return rufl_OK;
+ }
+
table = malloc(1024 * sizeof(*table));
if (!table) {
LOG("malloc(%zu) failed", 1024 * sizeof(*table));
@@ -524,76 +928,80 @@ rufl_code rufl_substitution_table_init(void)
table_size = 1024;
table_entries = 0;
- for (plane = 0; plane < 17; plane++) {
- const struct rufl_character_set *charset;
- unsigned int num_charsets = 0;
-
- /* Find fonts that have charsets for this plane */
- for (i = 0; i != rufl_font_list_entries; i++) {
- charset = rufl_font_list[i].charset;
- if (!charset) {
- charsets[i] = NULL;
- continue;
- }
+ /* Process each block, finding fonts that have glyphs */
+ blocks_used = 0;
+ memset(block_histogram, 0, 256);
+ for (block = 0; block != 256; block++) {
+ size_t prev_table_entries = table_entries;
+ uint16_t map_for_block[256];
+ for (i = 0; i != 256; i++)
+ map_for_block[i] = NOT_AVAILABLE;
- while (PLANE_ID(charset->metadata) != plane &&
- EXTENSION_FOLLOWS(charset->metadata)) {
- charset = (void *)(((uint8_t *)charset) +
- PLANE_SIZE(charset->metadata));
- }
- if (PLANE_ID(charset->metadata) != plane)
- charset = NULL;
- charsets[i] = charset;
- num_charsets++;
- }
- if (num_charsets == 0)
- continue;
-
- /* Process each block, finding fonts that have glyphs */
- for (block = 0; block != 256; block++) {
- uint16_t map_for_block[256];
- memset(map_for_block, 0xff, 512);
+ fill_map_for_block(charsets, block, map_for_block);
- fill_map_for_block(charsets, block, map_for_block);
-
- /* Merge block map into table */
- for (i = 0; i != 256; i++) {
- if (map_for_block[i] == NOT_AVAILABLE)
- continue;
+ /* Merge block map into table */
+ for (i = 0; i != 256; i++) {
+ if (map_for_block[i] == NOT_AVAILABLE)
+ continue;
- u = (plane << 16) | (block << 8) | i;
- table[table_entries] = ((uint64_t) u << 32) |
- map_for_block[i];
- if (++table_entries == table_size) {
- uint64_t *tmp = realloc(table,
- 2 * table_size *
+ u = (block << 8) | i;
+ table[table_entries] = (u << 16) | map_for_block[i];
+ if (++table_entries == table_size) {
+ uint64_t *tmp = realloc(table,
+ 2 * table_size *
+ sizeof(*table));
+ if (!tmp) {
+ LOG("realloc(%zu) failed",
+ 2 * table_size *
sizeof(*table));
- if (!tmp) {
- LOG("realloc(%zu) failed",
- 2 * table_size *
- sizeof(*table));
- free(table);
- return rufl_OUT_OF_MEMORY;
- }
-
- table = tmp;
- table_size *= 2;
+ free(table);
+ return rufl_OUT_OF_MEMORY;
}
+
+ table = tmp;
+ table_size *= 2;
}
}
+
+ block_histogram[block] = (table_entries != prev_table_entries);
+ if (block_histogram[block] != 0)
+ blocks_used++;
}
- /* Build hash from table */
- result = chd(table, table_entries, &rufl_substitution_table);
+ if (table_entries == 0) {
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("no glyphs for plane %u", plane);
+#endif
+ rufl_substitution_table[plane] = NULL;
+ free(table);
+ free(charsets);
+ return rufl_OK;
+ }
+
+ /* Build final substitution table using whichever implementation
+ * estimates the smallest storage requirements. */
+ direct_size = rufl_substitution_table_estimate_size_direct(
+ table_entries, blocks_used);
+ chd_size = rufl_substitution_table_estimate_size_chd(
+ table_entries, blocks_used);
+ if (direct_size <= chd_size) {
+ result = direct(table, table_entries, blocks_used,
+ block_histogram,
+ &rufl_substitution_table[plane]);
+ } else {
+ result = chd(table, table_entries,
+ &rufl_substitution_table[plane]);
+ }
#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
- LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
- rufl_substitution_table->num_slots * sizeof(*table),
- table_entries,
- rufl_substitution_table->num_buckets,
- rufl_substitution_table->bits_per_entry,
- (rufl_substitution_table->num_buckets *
- rufl_substitution_table->bits_per_entry + 7) >> 3);
+ LOG("plane %u: table-entries = %zu blocks-used = %zu"
+ " estimated-direct-size = %zu estimated-chd-size = %zu"
+ " actual-size = %zu",
+ plane, table_entries, blocks_used,
+ direct_size, chd_size,
+ rufl_substitution_table[plane] ?
+ rufl_substitution_table[plane]->size(
+ rufl_substitution_table[plane]) : 0);
#endif
free(charsets);
@@ -602,69 +1010,60 @@ rufl_code rufl_substitution_table_init(void)
}
/**
- * Destroy the substitution table and clean up its resources
+ * Construct the font substitution table.
*/
-void rufl_substitution_table_fini(void)
+rufl_code rufl_substitution_table_init(void)
{
- free(rufl_substitution_table->table);
- free(rufl_substitution_table);
- rufl_substitution_table = NULL;
+ unsigned int plane;
+ rufl_code rc;
+
+ for (plane = 0; plane < 17; plane++) {
+ rc = create_substitution_table_for_plane(plane);
+ if (rc != rufl_OK) {
+ while (plane > 0) {
+ plane--;
+ if (!rufl_substitution_table[plane])
+ continue;
+ rufl_substitution_table[plane]->free(
+ rufl_substitution_table[plane]);
+ }
+ return rc;
+ }
+ }
+
+ return rufl_OK;
}
/**
- * Look up a Unicode codepoint in the substitution table
+ * Destroy the substitution table and clean up its resources
*/
-unsigned int rufl_substitution_table_lookup(uint32_t u)
+void rufl_substitution_table_fini(void)
{
- uint32_t displacement = 0;
- uint32_t f, g = hash1(u & 0x1ffffff) &
- (rufl_substitution_table->num_buckets - 1);
- uint32_t bits_to_read = rufl_substitution_table->bits_per_entry;
- uint32_t offset_bits = g * bits_to_read;
- const uint8_t *pread =
- &rufl_substitution_table->displacement_map[offset_bits >> 3];
-
- offset_bits &= 7;
+ unsigned int plane;
- while (bits_to_read > 0) {
- uint32_t space_available = (8 - offset_bits);
- if (space_available > bits_to_read)
- space_available = bits_to_read;
-
- displacement <<= space_available;
- displacement |= (*pread & (0xff >> offset_bits)) >>
- (8 - space_available - offset_bits);
-
- offset_bits += space_available;
- if (offset_bits >= 8) {
- pread++;
- offset_bits = 0;
- }
- bits_to_read -= space_available;
+ for (plane = 0; plane < 17; plane++) {
+ if (rufl_substitution_table[plane] != NULL)
+ rufl_substitution_table[plane]->free(
+ rufl_substitution_table[plane]);
+ rufl_substitution_table[plane] = NULL;
}
-
- f = hash2((u & 0x1fffff), displacement) &
- (rufl_substitution_table->num_slots - 1);
-
- if ((rufl_substitution_table->table[f] & 0xffff) != NOT_AVAILABLE &&
- ((rufl_substitution_table->table[f] >> 32) & 0x1fffff) == u)
- return rufl_substitution_table->table[f] & 0xffff;
-
- return NOT_AVAILABLE;
}
-static int table_dump_cmp(const void *a, const void *b)
+/**
+ * Look up a Unicode codepoint in the substitution table
+ */
+
+unsigned int rufl_substitution_table_lookup(uint32_t u)
{
- const uint64_t aa = (*(const uint64_t *) a) & 0x001fffff00000000llu;
- const uint64_t bb = (*(const uint64_t *) b) & 0x001fffff00000000llu;
+ unsigned int plane = (u >> 16) & 0x1f;
- if (aa > bb)
- return 1;
- else if (aa < bb)
- return -1;
- return 0;
+ if (17 <= plane || !rufl_substitution_table[plane])
+ return NOT_AVAILABLE;
+
+ return rufl_substitution_table[plane]->lookup(
+ rufl_substitution_table[plane], u);
}
/**
@@ -673,36 +1072,18 @@ static int table_dump_cmp(const void *a, const void *b)
void rufl_substitution_table_dump(void)
{
- unsigned int font;
- unsigned int u, t;
- uint64_t *table;
-
- table = malloc(rufl_substitution_table->num_slots * sizeof(*table));
- if (table == NULL)
- return;
-
- memcpy(table, rufl_substitution_table->table,
- rufl_substitution_table->num_slots * sizeof(*table));
+ unsigned int plane;
+ size_t size = 0;
- qsort(table, rufl_substitution_table->num_slots, sizeof(*table),
- table_dump_cmp);
-
- u = 0;
- while (u < rufl_substitution_table->num_slots) {
- t = u;
- font = table[t] & 0xffff;
- while (u < rufl_substitution_table->num_slots &&
- font == (table[u] & 0xffff) &&
- ((u == t) ||
- (((table[u - 1] >> 32) & 0x1fffff) ==
- (((table[u] >> 32) & 0x1fffff) - 1))))
- u++;
- if (font != NOT_AVAILABLE)
- printf(" %llx-%llx => %u \"%s\"\n",
- (table[t] >> 32) & 0x1fffff,
- (table[u - 1] >> 32) & 0x1fffff,
- font, rufl_font_list[font].identifier);
+ for (plane = 0; plane < 17; plane++) {
+ if (!rufl_substitution_table[plane])
+ continue;
+ rufl_substitution_table[plane]->dump(
+ rufl_substitution_table[plane], plane);
+ size += rufl_substitution_table[plane]->size(
+ rufl_substitution_table[plane]);
}
- free(table);
+ printf(" Total substitution table storage: %zu bytes\n",
+ size + sizeof(rufl_substitution_table));
}
-----------------------------------------------------------------------
Summary of changes:
src/rufl_substitution_table.c | 759 +++++++++++++++++++++++++++++++----------
1 file changed, 570 insertions(+), 189 deletions(-)
diff --git a/src/rufl_substitution_table.c b/src/rufl_substitution_table.c
index 51c5b7a..0b201fa 100644
--- a/src/rufl_substitution_table.c
+++ b/src/rufl_substitution_table.c
@@ -14,6 +14,54 @@
#undef RUFL_SUBSTITUTION_TABLE_DEBUG
/**
+ * Base type for a substitution table.
+ */
+struct rufl_substitution_table {
+ /** Look up a Unicode codepoint. */
+ unsigned int (*lookup)(const struct rufl_substitution_table *t,
+ uint32_t u);
+ /** Free the resources used by this table */
+ void (*free)(struct rufl_substitution_table *t);
+ /** Dump the contents of this table to stdout */
+ void (*dump)(const struct rufl_substitution_table *t,
+ unsigned int plane);
+ /** Compute the storage size of this table */
+ size_t (*size)(const struct rufl_substitution_table *t);
+};
+
+/**
+ * Implementation of a substitution table using direct lookup.
+ */
+struct rufl_substitution_table_direct {
+ struct rufl_substitution_table base;
+
+ /** Table index.
+ *
+ * Each entry represents a block of 256 codepoints, so i[k] refers
+ * to codepoints [256*k, 256*(k+1)). The value is an offset into
+ * the block table.
+ */
+ uint8_t index[256];
+
+ /** Bits per block table entry. Will be 8 or 16. */
+ uint8_t bits_per_entry;
+
+ /** Substitution table.
+ *
+ * Entries are the index into rufl_font_list of a font providing a
+ * substitution glyph for this codepoint or NOT_AVAILABLE.
+ *
+ * Note that, although this is defined as a 16bit type,
+ * the actual field width is indicated by bits_per_entry (and,
+ * if bits_per_entry is 8, then (NOT_AVAILABLE & 0xff) represents
+ * a missing glyph).
+ */
+ uint16_t *table;
+};
+
+/**
+ * Implementation of a substitution table using a perfect hash.
+ *
* A perfect hash constructed at library initialisation time using the
* CHD algorithm. Hash entries are found via a two-step process:
*
@@ -23,7 +71,9 @@
* displacement value for the bucket to find the index
* into the substitution table.
*/
-struct rufl_substitution_table {
+struct rufl_substitution_table_chd {
+ struct rufl_substitution_table base;
+
uint32_t num_buckets; /**< Number of buckets in the hash */
uint32_t num_slots; /**< Number of slots in the table */
/** Substitution table.
@@ -33,18 +83,13 @@ struct rufl_substitution_table {
* 3 2 1 0
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Reserved | Unicode codepoint |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Reserved | Font identifier |
+ * | Unicode codepoint | Font identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* where:
*
- * reserved: 11 bits/16 bits
- * These bits are currently unused and must be set to 0.
- *
- * unicode codepoint: 21 bits
- * The Unicode codepoint value.
+ * unicode codepoint: 16 bits
+ * The low 16 bits of the Unicode codepoint value.
*
* font identifier: 16 bits
* The index into rufl_font_list of a font providing a
@@ -57,7 +102,7 @@ struct rufl_substitution_table {
* fail, no font provides a suitable glyph and the not available
* path should be taken.
*/
- uint64_t *table;
+ uint32_t *table;
uint8_t bits_per_entry; /**< Bits per displacement bitmap entry */
/** Displacement bitmap.
*
@@ -67,8 +112,8 @@ struct rufl_substitution_table {
*/
uint8_t displacement_map[];
};
-/** Font substitution table */
-static struct rufl_substitution_table *rufl_substitution_table;
+/** Font substitution tables -- one per plane */
+static struct rufl_substitution_table *rufl_substitution_table[17];
/**
* Round an unsigned 32bit value up to the next power of 2
@@ -170,8 +215,8 @@ static int table_chd_cmp(const void *a, const void *b)
{
/* We're only interested in the CHD metadata here.
* (i.e. the computed value of g(x) and the bucket size) */
- const uint64_t aa = (*(const uint64_t *) a) & 0x3fe00000ffff0000llu;
- const uint64_t bb = (*(const uint64_t *) b) & 0x3fe00000ffff0000llu;
+ const uint64_t aa = (*(const uint64_t *) a) & 0x000fffff00000000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x000fffff00000000llu;
if (aa > bb)
return -1;
@@ -214,6 +259,114 @@ static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
return result;
}
+static void rufl_substitution_table_free_chd(
+ struct rufl_substitution_table *t)
+{
+ free(((struct rufl_substitution_table_chd *)t)->table);
+ free(t);
+}
+
+
+static unsigned int rufl_substitution_table_lookup_chd(
+ const struct rufl_substitution_table *ts, uint32_t u)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ uint32_t displacement = 0;
+ uint32_t f, g = hash1(u & 0xffff) & (t->num_buckets - 1);
+ uint32_t bits_to_read = t->bits_per_entry;
+ uint32_t offset_bits = g * bits_to_read;
+ const uint8_t *pread = &t->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_read > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ if (space_available > bits_to_read)
+ space_available = bits_to_read;
+
+ displacement <<= space_available;
+ displacement |= (*pread & (0xff >> offset_bits)) >>
+ (8 - space_available - offset_bits);
+
+ offset_bits += space_available;
+ if (offset_bits >= 8) {
+ pread++;
+ offset_bits = 0;
+ }
+ bits_to_read -= space_available;
+ }
+
+ f = hash2((u & 0xffff), displacement) & (t->num_slots - 1);
+
+ if ((t->table[f] & 0xffff) != NOT_AVAILABLE &&
+ ((t->table[f] >> 16) & 0xffff) == (u & 0xffff))
+ return t->table[f] & 0xffff;
+
+ return NOT_AVAILABLE;
+}
+
+static int table_dump_cmp(const void *a, const void *b)
+{
+ const uint32_t aa = (*(const uint32_t *) a);
+ const uint32_t bb = (*(const uint32_t *) b);
+
+ if (aa > bb)
+ return 1;
+ else if (aa < bb)
+ return -1;
+ return 0;
+}
+
+static void rufl_substitution_table_dump_chd(
+ const struct rufl_substitution_table *ts, unsigned int plane)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ unsigned int font;
+ unsigned int u, prev;
+ uint32_t *table;
+
+ table = malloc(t->num_slots * sizeof(*table));
+ if (table == NULL)
+ return;
+
+ memcpy(table, t->table, t->num_slots * sizeof(*table));
+
+ qsort(table, t->num_slots, sizeof(*table), table_dump_cmp);
+
+ u = 0;
+ while (u < t->num_slots) {
+ prev = u;
+ font = table[prev] & 0xffff;
+ while (u < t->num_slots && font == (table[u] & 0xffff) &&
+ ((u == prev) ||
+ ((table[u - 1] >> 16) ==
+ ((table[u] >> 16) - 1))))
+ u++;
+ if (font != NOT_AVAILABLE)
+ printf(" %x-%x => %u \"%s\"\n",
+ (plane << 16) | (table[prev] >> 16),
+ (plane << 16) | (table[u - 1] >> 16),
+ font, rufl_font_list[font].identifier);
+ }
+
+ free(table);
+}
+
+static size_t rufl_substitution_table_size_chd(
+ const struct rufl_substitution_table *ts)
+{
+ const struct rufl_substitution_table_chd *t = (const void *) ts;
+ size_t size = sizeof(*t);
+
+ /* Add on displacement map size */
+ size += (t->num_buckets * t->bits_per_entry + 7) >> 3;
+
+ /* Add on table size */
+ size += t->num_slots * sizeof(*t->table);
+
+ return size;
+}
+
/**
* Create the final substitution table from the intermediate parts
*
@@ -225,12 +378,13 @@ static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
* \param displacements Table of displacement values. One per bucket.
* \param substitution_table Location to receive result.
*/
-static rufl_code create_substitution_table(uint64_t *table,
+static rufl_code create_substitution_table_chd(uint64_t *table,
size_t table_entries, uint32_t buckets, uint32_t range,
uint32_t max_displacement, uint32_t *displacements,
struct rufl_substitution_table **substitution_table)
{
- struct rufl_substitution_table *subst_table;
+ struct rufl_substitution_table_chd *subst_table;
+ uint64_t *t64;
size_t subst_table_size;
unsigned int i;
@@ -239,7 +393,7 @@ static rufl_code create_substitution_table(uint64_t *table,
max_displacement, bits_needed(max_displacement));
#endif
- subst_table_size = offsetof(struct rufl_substitution_table,
+ subst_table_size = offsetof(struct rufl_substitution_table_chd,
displacement_map) +
((buckets * bits_needed(max_displacement) + 7) >> 3);
@@ -248,17 +402,23 @@ static rufl_code create_substitution_table(uint64_t *table,
return rufl_OUT_OF_MEMORY;
/* We know there are at least table_entries in the table, but
- * we should now resize it to the size of the target hashtable */
+ * we should now resize it to the size of the target hashtable.
+ * We still want each entry to be 64bits wide at this point. */
subst_table->table = realloc(table, range * sizeof(*table));
if (!subst_table->table) {
free(subst_table);
return rufl_OUT_OF_MEMORY;
}
+ t64 = (uint64_t *) subst_table->table;
/* Initialise unused slots */
for (i = table_entries; i < range; i++) {
- subst_table->table[i] = NOT_AVAILABLE;
+ t64[i] = NOT_AVAILABLE;
}
+ subst_table->base.lookup = rufl_substitution_table_lookup_chd;
+ subst_table->base.free = rufl_substitution_table_free_chd;
+ subst_table->base.dump = rufl_substitution_table_dump_chd;
+ subst_table->base.size = rufl_substitution_table_size_chd;
subst_table->num_buckets = buckets;
subst_table->num_slots = range;
subst_table->bits_per_entry = bits_needed(max_displacement);
@@ -300,32 +460,52 @@ static rufl_code create_substitution_table(uint64_t *table,
uint32_t f, g;
uint64_t tmp;
- if (subst_table->table[i] == NOT_AVAILABLE) {
+ if (t64[i] == NOT_AVAILABLE) {
i++;
continue;
}
- g = ((subst_table->table[i] >> 53) & 0x1f0000) |
- ((subst_table->table[i] >> 16) & 0xffff);
- f = hash2((subst_table->table[i] >> 32) & 0x1fffff,
+ g = ((t64[i] >> 32) & 0xffff);
+ f = hash2((t64[i] >> 16) & 0xffff,
displacements[g]) & (range - 1);
/* Exchange this entry with the one in the slot at f.*/
if (f != i) {
- tmp = subst_table->table[f];
- subst_table->table[f] = subst_table->table[i];
- subst_table->table[i] = tmp;
+ tmp = t64[f];
+ t64[f] = t64[i];
+ t64[i] = tmp;
} else {
/* Reconsider this slot unless it already
* had the correct entry */
i++;
}
}
- /* Strip all the CHD metadata out of the final table */
- for (i = 0; i < range; i++)
- subst_table->table[i] &= 0x001fffff0000ffffllu;
+ /* Strip all the CHD metadata out of the final table.
+ * We can simply drop the top 32bits of each entry by
+ * compacting the entries. */
+ for (i = 0; i < range; i++) {
+ subst_table->table[i] = t64[i] & 0xffffffffu;
+ }
+
+ /* Shrink the table to its final size. If this fails, leave
+ * the existing data intact as it's correct -- we just have
+ * twice the storage usage we need. */
+ table = realloc(subst_table->table,
+ range * sizeof(*subst_table->table));
+ if (table)
+ subst_table->table = (uint32_t *) table;
- *substitution_table = subst_table;
+ *substitution_table = &subst_table->base;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
+ subst_table->num_slots * sizeof(*subst_table->table),
+ table_entries,
+ subst_table->num_buckets,
+ subst_table->bits_per_entry,
+ (subst_table->num_buckets *
+ subst_table->bits_per_entry + 7) >> 3);
+#endif
return rufl_OK;
}
@@ -349,8 +529,8 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
{
/** Number of buckets assuming an average bucket size of 4 */
const uint32_t buckets = ceil2((table_entries + 3) & ~3);
- /** Number of output hash slots assuming a load factor of 0.95 */
- const uint32_t range = ceil2((table_entries * 100)/95);
+ /** Number of output hash slots assuming a load factor of 1 */
+ const uint32_t range = ceil2(table_entries);
uint32_t bucket_size, max_displacement = 0;
unsigned int i;
uint8_t *entries_per_bucket, *bitmap;
@@ -381,21 +561,18 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
/* Compute g(x) for each entry, placing them into buckets */
for (i = 0; i < table_entries; i++) {
- uint32_t g = hash1((table[i] >> 32) & 0x1fffff) & (buckets - 1);
+ uint64_t g = hash1((table[i] >> 16) & 0xffff) & (buckets - 1);
- /* Insert hash into entry (it's 21 bits at most, so
- * needs splitting between bits 16-31 and 53-57 of
- * the entry) */
- table[i] |= ((g & 0xffff) << 16);
- table[i] |= ((uint64_t)(g & 0x1f0000) << 53);
+ /* Insert hash into entry (it's 16 bits at most,
+ * so use bits 32-47) */
+ table[i] |= ((g & 0xffff) << 32);
entries_per_bucket[g]++;
}
/* Inject bucket size into entries */
for (i = 0; i < table_entries; i++) {
- uint32_t g = ((table[i] >> 53) & 0x1f0000) |
- ((table[i] >> 16) & 0xffff);
+ uint32_t g = ((table[i] >> 32) & 0xffff);
/* With a target bucket size of 4, do not expect
* >= twice that number of entries in the largest
@@ -406,11 +583,11 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
LOG("unexpectedly large bucket %u",
entries_per_bucket[g]);
- /* Stash bucket size into bits 58-61 of the entry */
- table[i] |= ((uint64_t)entries_per_bucket[g] << 58);
+ /* Stash bucket size into bits 48-51 of the entry */
+ table[i] |= ((uint64_t)entries_per_bucket[g] << 48);
}
- /* Bits 62-63 of table entries are currently unused */
+ /* Bits 52-63 of table entries are currently unused */
free(entries_per_bucket);
@@ -419,12 +596,11 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
/* Compute f(x) for each bucket, finding a unique mapping */
for (i = 0; i < table_entries; i += bucket_size) {
- const uint32_t g = ((table[i] >> 53) & 0x1f0000) |
- ((table[i] >> 16) & 0xffff);
+ const uint32_t g = ((table[i] >> 32) & 0xffff);
uint32_t hashes[8], num_hashes;
uint32_t d = 0;
- bucket_size = ((table[i] >> 58) & 0xf);
+ bucket_size = ((table[i] >> 48) & 0xf);
do {
uint32_t j, k;
@@ -434,7 +610,7 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
for (j = 0; j != bucket_size; j++) {
uint32_t f = hash2(
- (table[i+j] >> 32) & 0x1fffff, d) &
+ (table[i+j] >> 16) & 0xffff, d) &
(range - 1);
for (k = 0; k < num_hashes; k++) {
if (f == hashes[k])
@@ -455,7 +631,7 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
free(bitmap);
- result = create_substitution_table(table, table_entries,
+ result = create_substitution_table_chd(table, table_entries,
buckets, range, max_displacement, displacements,
substitution_table);
free(displacements);
@@ -463,6 +639,203 @@ static rufl_code chd(uint64_t *table, size_t table_entries,
return result;
}
+static size_t rufl_substitution_table_estimate_size_chd(size_t table_entries,
+ size_t blocks_used)
+{
+ size_t size = sizeof(struct rufl_substitution_table_chd);
+
+ (void) blocks_used;
+
+ /** Number of buckets assuming an average bucket size of 4 */
+ const uint32_t buckets = ceil2((table_entries + 3) & ~3);
+ /** Number of output hash slots assuming a load factor of 1 */
+ const uint32_t range = ceil2(table_entries);
+
+ /* Conservatively assume 6 bits per displacement map entry */
+ size += (buckets * 6 + 7) >> 3;
+
+ /* Add on table size */
+ size += range * 4;
+
+ return size;
+}
+
+/****************************************************************************/
+
+static void rufl_substitution_table_free_direct(
+ struct rufl_substitution_table *t)
+{
+ free(((struct rufl_substitution_table_direct *)t)->table);
+ free(t);
+}
+
+
+static unsigned int rufl_substitution_table_lookup_direct(
+ const struct rufl_substitution_table *ts, uint32_t u)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ uint32_t block = (u >> 8) & 0xff;
+ uint32_t slot = (u & 0xff);
+ unsigned int font;
+
+ if (t->bits_per_entry == 8) {
+ font = ((uint8_t *) t->table)[t->index[block] * 256 + slot];
+ if (font == (NOT_AVAILABLE & 0xff))
+ font = NOT_AVAILABLE;
+ } else
+ font = t->table[t->index[block] * 256 + slot];
+
+ return font;
+}
+
+static void rufl_substitution_table_dump_direct(
+ const struct rufl_substitution_table *ts, unsigned int plane)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ unsigned int font, na;
+ unsigned int u, prev;
+ uint8_t *t8 = (uint8_t *) t->table;
+
+ na = NOT_AVAILABLE & ((t->bits_per_entry == 8) ? 0xff : 0xffff);
+
+#define LOOKUP(u) (t->bits_per_entry == 8 \
+ ? t8[t->index[(u >> 8) & 0xff] * 256 + (u & 0xff)] \
+ : t->table[t->index[(u >> 8) & 0xff] * 256 + (u & 0xff)])
+
+ u = 0;
+ while (u < 0x10000) {
+ prev = u;
+ font = LOOKUP(u);
+ while (u < 0x10000 && font == LOOKUP(u))
+ u++;
+ if (font != na)
+ printf(" %x-%x => %u \"%s\"\n",
+ (plane << 16) | prev,
+ (plane << 16) | (u - 1),
+ font, rufl_font_list[font].identifier);
+ }
+
+#undef LOOKUP
+}
+
+static size_t rufl_substitution_table_size_direct(
+ const struct rufl_substitution_table *ts)
+{
+ const struct rufl_substitution_table_direct *t = (const void *) ts;
+ size_t size = sizeof(*t);
+ unsigned int i, block_idx = 0;
+
+ /* Find the largest block index (blocks are contiguous) */
+ for (i = 0; i < 256; i++)
+ if (t->index[i] > block_idx)
+ block_idx = t->index[i];
+
+ /* Add on table size */
+ size += (t->bits_per_entry * (block_idx + 1) * 256) >> 3;
+
+ return size;
+}
+
+/**
+ * Construct a direct-mapped substitution table
+ */
+static rufl_code direct(uint64_t *table, size_t table_entries,
+ size_t blocks_used, const uint8_t block_histogram[256],
+ struct rufl_substitution_table **substitution_table)
+{
+ struct rufl_substitution_table_direct *subst_table;
+ size_t blocks_needed, table_size;
+ unsigned int i, block;
+
+ subst_table = calloc(sizeof(*subst_table), 1);
+ if (!subst_table)
+ return rufl_OUT_OF_MEMORY;
+
+ subst_table->base.lookup = rufl_substitution_table_lookup_direct;
+ subst_table->base.free = rufl_substitution_table_free_direct;
+ subst_table->base.dump = rufl_substitution_table_dump_direct;
+ subst_table->base.size = rufl_substitution_table_size_direct;
+ /* We can use 8bits per entry if there are fewer than 255 fonts */
+ subst_table->bits_per_entry = rufl_font_list_entries < 255 ? 8 : 16;
+
+ /* Need one extra block if there's at least one free */
+ blocks_needed = (blocks_used < 256) ?
+ (blocks_used + 1) : blocks_used;
+
+ table_size = (256 * blocks_needed * subst_table->bits_per_entry) >> 3;
+
+ /* Populate block index */
+ for (i = 0, block = 0; i != 256; i++) {
+ if (block_histogram[i] == 0) {
+ subst_table->index[i] = blocks_used;
+ } else {
+ subst_table->index[i] = block;
+ block++;
+ }
+ }
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("blocks-used = %zu blocks-needed = %zu"
+ " bits-per-entry = %u size = %zu",
+ blocks_used, blocks_needed, subst_table->bits_per_entry,
+ table_size);
+#endif
+
+ /* Allocate table */
+ //XXX: can we just rearrange the existing one in-place?
+ subst_table->table = malloc(table_size);
+ if (!subst_table->table) {
+ free(subst_table);
+ return rufl_OUT_OF_MEMORY;
+ }
+ /* Fill it with NOT_AVAILABLE */
+ if (subst_table->bits_per_entry == 8) {
+ memset(subst_table->table, (NOT_AVAILABLE & 0xff), table_size);
+ } else {
+ for (i = 0; i < table_size; i++)
+ subst_table->table[i] = NOT_AVAILABLE;
+ }
+
+ /* Populate the table */
+ for (i = 0; i < table_entries; i++) {
+ uint64_t val = table[i];
+ uint32_t slot = (val >> 16) & 0xff;
+ block = subst_table->index[(val >> 24) & 0xff];
+
+ if (subst_table->bits_per_entry == 8) {
+ uint8_t *t8 = (uint8_t *) subst_table->table;
+ t8[256 * block + slot] = (val & 0xff);
+ } else {
+ subst_table->table[256 * block + slot] = (val & 0xffff);
+ }
+ }
+
+ free(table);
+
+ *substitution_table = &subst_table->base;
+
+ return rufl_OK;
+}
+
+static size_t rufl_substitution_table_estimate_size_direct(size_t table_entries,
+ size_t blocks_used)
+{
+ size_t size = sizeof(struct rufl_substitution_table_direct);
+
+ (void) table_entries;
+
+ /* Add one for empty block */
+ if (blocks_used < 256)
+ blocks_used += 1;
+
+ /* We can use 8bits per entry if there are fewer than 255 fonts */
+ size += blocks_used * 256 * (rufl_font_list_entries < 255 ? 1 : 2);
+
+ return size;
+}
+
+/****************************************************************************/
+
/**
* Populate the substitution map for a given block
*/
@@ -492,20 +865,23 @@ static void fill_map_for_block(const struct rufl_character_set **charsets,
}
}
-
/**
- * Construct the font substitution table.
+ * Create a substitution table for the plane specified
*/
-
-rufl_code rufl_substitution_table_init(void)
+static rufl_code create_substitution_table_for_plane(unsigned int plane)
{
unsigned int i;
- unsigned int plane, block;
+ unsigned int block;
unsigned int u;
const struct rufl_character_set **charsets;
+ const struct rufl_character_set *charset;
+ unsigned int num_charsets;
uint64_t *table;
size_t table_size;
size_t table_entries;
+ uint8_t block_histogram[256];
+ size_t blocks_used;
+ size_t direct_size, chd_size;
rufl_code result;
charsets = malloc(rufl_font_list_entries * sizeof(*charsets));
@@ -515,6 +891,34 @@ rufl_code rufl_substitution_table_init(void)
return rufl_OUT_OF_MEMORY;
}
+ /* Find fonts that have charsets for this plane */
+ num_charsets = 0;
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ charset = rufl_font_list[i].charset;
+ if (!charset) {
+ charsets[i] = NULL;
+ continue;
+ }
+
+ while (PLANE_ID(charset->metadata) != plane &&
+ EXTENSION_FOLLOWS(charset->metadata)) {
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ if (PLANE_ID(charset->metadata) != plane)
+ charset = NULL;
+ charsets[i] = charset;
+ num_charsets++;
+ }
+ if (num_charsets == 0) {
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("no charsets for plane %u", plane);
+#endif
+ rufl_substitution_table[plane] = NULL;
+ free(charsets);
+ return rufl_OK;
+ }
+
table = malloc(1024 * sizeof(*table));
if (!table) {
LOG("malloc(%zu) failed", 1024 * sizeof(*table));
@@ -524,76 +928,80 @@ rufl_code rufl_substitution_table_init(void)
table_size = 1024;
table_entries = 0;
- for (plane = 0; plane < 17; plane++) {
- const struct rufl_character_set *charset;
- unsigned int num_charsets = 0;
-
- /* Find fonts that have charsets for this plane */
- for (i = 0; i != rufl_font_list_entries; i++) {
- charset = rufl_font_list[i].charset;
- if (!charset) {
- charsets[i] = NULL;
- continue;
- }
+ /* Process each block, finding fonts that have glyphs */
+ blocks_used = 0;
+ memset(block_histogram, 0, 256);
+ for (block = 0; block != 256; block++) {
+ size_t prev_table_entries = table_entries;
+ uint16_t map_for_block[256];
+ for (i = 0; i != 256; i++)
+ map_for_block[i] = NOT_AVAILABLE;
- while (PLANE_ID(charset->metadata) != plane &&
- EXTENSION_FOLLOWS(charset->metadata)) {
- charset = (void *)(((uint8_t *)charset) +
- PLANE_SIZE(charset->metadata));
- }
- if (PLANE_ID(charset->metadata) != plane)
- charset = NULL;
- charsets[i] = charset;
- num_charsets++;
- }
- if (num_charsets == 0)
- continue;
-
- /* Process each block, finding fonts that have glyphs */
- for (block = 0; block != 256; block++) {
- uint16_t map_for_block[256];
- memset(map_for_block, 0xff, 512);
+ fill_map_for_block(charsets, block, map_for_block);
- fill_map_for_block(charsets, block, map_for_block);
-
- /* Merge block map into table */
- for (i = 0; i != 256; i++) {
- if (map_for_block[i] == NOT_AVAILABLE)
- continue;
+ /* Merge block map into table */
+ for (i = 0; i != 256; i++) {
+ if (map_for_block[i] == NOT_AVAILABLE)
+ continue;
- u = (plane << 16) | (block << 8) | i;
- table[table_entries] = ((uint64_t) u << 32) |
- map_for_block[i];
- if (++table_entries == table_size) {
- uint64_t *tmp = realloc(table,
- 2 * table_size *
+ u = (block << 8) | i;
+ table[table_entries] = (u << 16) | map_for_block[i];
+ if (++table_entries == table_size) {
+ uint64_t *tmp = realloc(table,
+ 2 * table_size *
+ sizeof(*table));
+ if (!tmp) {
+ LOG("realloc(%zu) failed",
+ 2 * table_size *
sizeof(*table));
- if (!tmp) {
- LOG("realloc(%zu) failed",
- 2 * table_size *
- sizeof(*table));
- free(table);
- return rufl_OUT_OF_MEMORY;
- }
-
- table = tmp;
- table_size *= 2;
+ free(table);
+ return rufl_OUT_OF_MEMORY;
}
+
+ table = tmp;
+ table_size *= 2;
}
}
+
+ block_histogram[block] = (table_entries != prev_table_entries);
+ if (block_histogram[block] != 0)
+ blocks_used++;
}
- /* Build hash from table */
- result = chd(table, table_entries, &rufl_substitution_table);
+ if (table_entries == 0) {
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("no glyphs for plane %u", plane);
+#endif
+ rufl_substitution_table[plane] = NULL;
+ free(table);
+ free(charsets);
+ return rufl_OK;
+ }
+
+ /* Build final substitution table using whichever implementation
+ * estimates the smallest storage requirements. */
+ direct_size = rufl_substitution_table_estimate_size_direct(
+ table_entries, blocks_used);
+ chd_size = rufl_substitution_table_estimate_size_chd(
+ table_entries, blocks_used);
+ if (direct_size <= chd_size) {
+ result = direct(table, table_entries, blocks_used,
+ block_histogram,
+ &rufl_substitution_table[plane]);
+ } else {
+ result = chd(table, table_entries,
+ &rufl_substitution_table[plane]);
+ }
#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
- LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
- rufl_substitution_table->num_slots * sizeof(*table),
- table_entries,
- rufl_substitution_table->num_buckets,
- rufl_substitution_table->bits_per_entry,
- (rufl_substitution_table->num_buckets *
- rufl_substitution_table->bits_per_entry + 7) >> 3);
+ LOG("plane %u: table-entries = %zu blocks-used = %zu"
+ " estimated-direct-size = %zu estimated-chd-size = %zu"
+ " actual-size = %zu",
+ plane, table_entries, blocks_used,
+ direct_size, chd_size,
+ rufl_substitution_table[plane] ?
+ rufl_substitution_table[plane]->size(
+ rufl_substitution_table[plane]) : 0);
#endif
free(charsets);
@@ -602,69 +1010,60 @@ rufl_code rufl_substitution_table_init(void)
}
/**
- * Destroy the substitution table and clean up its resources
+ * Construct the font substitution table.
*/
-void rufl_substitution_table_fini(void)
+rufl_code rufl_substitution_table_init(void)
{
- free(rufl_substitution_table->table);
- free(rufl_substitution_table);
- rufl_substitution_table = NULL;
+ unsigned int plane;
+ rufl_code rc;
+
+ for (plane = 0; plane < 17; plane++) {
+ rc = create_substitution_table_for_plane(plane);
+ if (rc != rufl_OK) {
+ while (plane > 0) {
+ plane--;
+ if (!rufl_substitution_table[plane])
+ continue;
+ rufl_substitution_table[plane]->free(
+ rufl_substitution_table[plane]);
+ }
+ return rc;
+ }
+ }
+
+ return rufl_OK;
}
/**
- * Look up a Unicode codepoint in the substitution table
+ * Destroy the substitution table and clean up its resources
*/
-unsigned int rufl_substitution_table_lookup(uint32_t u)
+void rufl_substitution_table_fini(void)
{
- uint32_t displacement = 0;
- uint32_t f, g = hash1(u & 0x1ffffff) &
- (rufl_substitution_table->num_buckets - 1);
- uint32_t bits_to_read = rufl_substitution_table->bits_per_entry;
- uint32_t offset_bits = g * bits_to_read;
- const uint8_t *pread =
- &rufl_substitution_table->displacement_map[offset_bits >> 3];
-
- offset_bits &= 7;
+ unsigned int plane;
- while (bits_to_read > 0) {
- uint32_t space_available = (8 - offset_bits);
- if (space_available > bits_to_read)
- space_available = bits_to_read;
-
- displacement <<= space_available;
- displacement |= (*pread & (0xff >> offset_bits)) >>
- (8 - space_available - offset_bits);
-
- offset_bits += space_available;
- if (offset_bits >= 8) {
- pread++;
- offset_bits = 0;
- }
- bits_to_read -= space_available;
+ for (plane = 0; plane < 17; plane++) {
+ if (rufl_substitution_table[plane] != NULL)
+ rufl_substitution_table[plane]->free(
+ rufl_substitution_table[plane]);
+ rufl_substitution_table[plane] = NULL;
}
-
- f = hash2((u & 0x1fffff), displacement) &
- (rufl_substitution_table->num_slots - 1);
-
- if ((rufl_substitution_table->table[f] & 0xffff) != NOT_AVAILABLE &&
- ((rufl_substitution_table->table[f] >> 32) & 0x1fffff) == u)
- return rufl_substitution_table->table[f] & 0xffff;
-
- return NOT_AVAILABLE;
}
-static int table_dump_cmp(const void *a, const void *b)
+/**
+ * Look up a Unicode codepoint in the substitution table
+ */
+
+unsigned int rufl_substitution_table_lookup(uint32_t u)
{
- const uint64_t aa = (*(const uint64_t *) a) & 0x001fffff00000000llu;
- const uint64_t bb = (*(const uint64_t *) b) & 0x001fffff00000000llu;
+ unsigned int plane = (u >> 16) & 0x1f;
- if (aa > bb)
- return 1;
- else if (aa < bb)
- return -1;
- return 0;
+ if (17 <= plane || !rufl_substitution_table[plane])
+ return NOT_AVAILABLE;
+
+ return rufl_substitution_table[plane]->lookup(
+ rufl_substitution_table[plane], u);
}
/**
@@ -673,36 +1072,18 @@ static int table_dump_cmp(const void *a, const void *b)
void rufl_substitution_table_dump(void)
{
- unsigned int font;
- unsigned int u, t;
- uint64_t *table;
-
- table = malloc(rufl_substitution_table->num_slots * sizeof(*table));
- if (table == NULL)
- return;
-
- memcpy(table, rufl_substitution_table->table,
- rufl_substitution_table->num_slots * sizeof(*table));
+ unsigned int plane;
+ size_t size = 0;
- qsort(table, rufl_substitution_table->num_slots, sizeof(*table),
- table_dump_cmp);
-
- u = 0;
- while (u < rufl_substitution_table->num_slots) {
- t = u;
- font = table[t] & 0xffff;
- while (u < rufl_substitution_table->num_slots &&
- font == (table[u] & 0xffff) &&
- ((u == t) ||
- (((table[u - 1] >> 32) & 0x1fffff) ==
- (((table[u] >> 32) & 0x1fffff) - 1))))
- u++;
- if (font != NOT_AVAILABLE)
- printf(" %llx-%llx => %u \"%s\"\n",
- (table[t] >> 32) & 0x1fffff,
- (table[u - 1] >> 32) & 0x1fffff,
- font, rufl_font_list[font].identifier);
+ for (plane = 0; plane < 17; plane++) {
+ if (!rufl_substitution_table[plane])
+ continue;
+ rufl_substitution_table[plane]->dump(
+ rufl_substitution_table[plane], plane);
+ size += rufl_substitution_table[plane]->size(
+ rufl_substitution_table[plane]);
}
- free(table);
+ printf(" Total substitution table storage: %zu bytes\n",
+ size + sizeof(rufl_substitution_table));
}
--
RISC OS Unicode Font Library
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-15-ga520ed2
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/a520ed23f23e77b8c91b3...
...commit http://git.netsurf-browser.org/librufl.git/commit/a520ed23f23e77b8c91b318...
...tree http://git.netsurf-browser.org/librufl.git/tree/a520ed23f23e77b8c91b31814...
The branch, jmb/ac has been updated
via a520ed23f23e77b8c91b31814d9bbc2246df18a5 (commit)
via bb8eab8b112ef6eae8af7d0869f0e1d2b416f61c (commit)
via 3c116337d2cad81fa27df86b1d9f995d8906fcd8 (commit)
via 5be9bd8e833c84dbd55511046657e2fcf678d03c (commit)
via 6f212ee62e6cc19cb686208dd5b510d01217d0af (commit)
via a0bad0bd03988b9b77969f8b00cc9a512856f7f0 (commit)
via fbec3fe20c30e4597110967f05f8416ba7769db4 (commit)
via c4db3cb6963278e377083e556b4a74341c446a27 (commit)
via 247a8f1c34b8ffcf3d6072dbb621ea2a19052874 (commit)
via 9bd774ec26a7a97019210b6779105f58cb29788b (commit)
from 282b342fe51a2e9856b5448c30679ea8b49f18c5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a520ed23f23e77b8c91...
commit a520ed23f23e77b8c91b31814d9bbc2246df18a5
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Teach rufl_chars about other planes.
Selectable via the menu, like everything else.
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index 14a0fb6..1df86e3 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -18,13 +18,13 @@
unsigned int font = 0;
unsigned int weight = rufl_WEIGHT_400;
bool italic = false;
+unsigned int plane = 0;
static rufl_code redraw(int x, int y, int y0, int y1);
static void try(rufl_code code, const char *context);
static void die(const char *error);
-
int main(void)
{
unsigned int i;
@@ -73,7 +73,7 @@ int main(void)
try(rufl_init(), "rufl_init");
- menu = malloc(wimp_SIZEOF_MENU(10 + rufl_family_list_entries));
+ menu = malloc(wimp_SIZEOF_MENU(27 + rufl_family_list_entries));
if (!menu)
die("Out of memory");
strcpy(menu->title_data.text, "Fonts");
@@ -99,23 +99,37 @@ int main(void)
(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT);
strcpy(menu->entries[9].data.text, "Italic");
- for (i = 0; i != rufl_family_list_entries; i++) {
- menu->entries[10 + i].menu_flags = 0;
+ for (i = 0; i != 17; i++) {
+ menu->entries[10 + i].menu_flags =
+ (i == 16 ? wimp_MENU_SEPARATE :0);
menu->entries[10 + i].sub_menu = wimp_NO_SUB_MENU;
menu->entries[10 + 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[10 + i].data.text, "Plane 1");
+ menu->entries[10 + i].data.text[6] = '0' + (i+1)/10;
+ if (menu->entries[10 + i].data.text[6] == '0')
+ menu->entries[10 + i].data.text[6] = ' ';
+ menu->entries[10 + i].data.text[7] = '0' + (i+1)%10;
+ }
+ for (i = 0; i != rufl_family_list_entries; i++) {
+ menu->entries[27 + i].menu_flags = 0;
+ menu->entries[27 + i].sub_menu = wimp_NO_SUB_MENU;
+ menu->entries[27 + 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[10 + i].data.indirected_text.text =
+ menu->entries[27 + i].data.indirected_text.text =
(char *) rufl_family_list[i];
- menu->entries[10 + i].data.indirected_text.validation =
+ menu->entries[27 + i].data.indirected_text.validation =
(char *) -1;
- menu->entries[10 + i].data.indirected_text.size =
+ menu->entries[27 + i].data.indirected_text.size =
strlen(rufl_family_list[i]);
}
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;
+ menu->entries[27].menu_flags |= wimp_MENU_TICKED;
+ menu->entries[i + 26].menu_flags |= wimp_MENU_LAST;
error = xwimp_create_window((wimp_window *) &window, &w);
if (error)
@@ -194,11 +208,17 @@ int main(void)
} else if (block.selection.items[0] == 9) {
italic = !italic;
menu->entries[9].menu_flags ^= wimp_MENU_TICKED;
+ } else if (block.selection.items[0] <= 26) {
+ menu->entries[10 + plane].menu_flags ^=
+ wimp_MENU_TICKED;
+ plane = block.selection.items[0] - 10;
+ menu->entries[10 + plane].menu_flags ^=
+ wimp_MENU_TICKED;
} else {
- menu->entries[10 + font].menu_flags ^=
+ menu->entries[27 + font].menu_flags ^=
wimp_MENU_TICKED;
- font = block.selection.items[0] - 10;
- menu->entries[10 + font].menu_flags ^=
+ font = block.selection.items[0] - 27;
+ menu->entries[27 + font].menu_flags ^=
wimp_MENU_TICKED;
}
error = xwimp_force_redraw(w,
@@ -249,15 +269,21 @@ rufl_code redraw(int x, int y, int y0, int y1)
rufl_style style = weight | (italic ? rufl_SLANTED : 0);
for (u = y0 / 40 * 32; (int) u != (y1 / 40 + 1) * 32; u++) {
- if (u <= 0x7f)
- s[0] = u, l = 1;
- else if (u <= 0x7ff)
- s[0] = 0xc0 | (u >> 6),
- s[1] = 0x80 | (u & 0x3f), l = 2;
- else if (u <= 0xffff)
- s[0] = 0xe0 | (u >> 12),
- s[1] = 0x80 | ((u >> 6) & 0x3f),
- s[2] = 0x80 | (u & 0x3f), l = 3;
+ unsigned int c = (plane << 16) | u;
+ if (c <= 0x7f)
+ s[0] = c, l = 1;
+ else if (c <= 0x7ff)
+ s[0] = 0xc0 | (c >> 6),
+ s[1] = 0x80 | (c & 0x3f), l = 2;
+ else if (c <= 0xffff)
+ s[0] = 0xe0 | (c >> 12),
+ s[1] = 0x80 | ((c >> 6) & 0x3f),
+ s[2] = 0x80 | (c & 0x3f), l = 3;
+ else if (c <= 0x10ffff)
+ s[0] = 0xf0 | (c >> 18),
+ s[1] = 0x80 | ((c >> 12) & 0x3f),
+ s[2] = 0x80 | ((c >> 6) & 0x3f),
+ s[3] = 0x80 | (c & 0x3f), l = 4;
else
break;
s[l] = 0;
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=bb8eab8b112ef6eae8a...
commit bb8eab8b112ef6eae8af7d0869f0e1d2b416f61c
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Make rufl_test render an astral character
diff --git a/test/rufl_test.c b/test/rufl_test.c
index 45af5b6..d939467 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -25,7 +25,8 @@ static void callback(void *context,
int main(void)
{
char utf8_test[] = "Hello, world! ����������� "
- "Uhersk�� Hradi��t��. ����";
+ "Uhersk�� Hradi��t��. ����"
+ "\xf0\xa0\x80\xa1";
int width;
size_t char_offset;
int x;
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=3c116337d2cad81fa27...
commit 3c116337d2cad81fa27df86b1d9f995d8906fcd8
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Perform font substitution for astral characters, too.
This significantly reworks the construction of the substitution
table (and hides its implementation from the rest of the library).
It is no longer practical to use a directly-indexed array so,
instead, we front it with a perfect hash function. The storage
required for the (unoptimised) hash data is currently about 6 bits
per entry. Implementing compression would reduce this to the order
of ~2 bits per entry.
As the resulting data structure is sparse, we must store the
original Unicode codepoint value along with the identity of the
font providing a suitable glyph. This has necessitated expanding
the size of substitution table entries from 16 to 64 bits (of
which 27 bits are currently unused).
With the 55757 codepoint coverage I have been testing with, this
results in an increase in the substitution table storage
requirements from the original 128kB directly-indexed array
(covering the Basic Multilingual Plane only) to a rather fatter
512kB (for the codepoint+font id array) + ~41kB of hash metadata.
This is still ~25% the size of a linear array, however, so is not
completely outrageous.
diff --git a/src/Makefile b/src/Makefile
index 7592083..22df8df 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,8 @@
# Sources
DIR_SOURCES := rufl_character_set_test.c rufl_decompose.c rufl_dump_state.c \
rufl_find.c rufl_init.c rufl_invalidate_cache.c \
- rufl_metrics.c rufl_paint.c rufl_quit.c
+ rufl_metrics.c rufl_paint.c rufl_substitution_table.c \
+ rufl_quit.c
ifeq ($(toolchain),norcroft)
DIR_SOURCES := $(DIR_SOURCES) strfuncs.c
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index b03109c..13a1564 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -12,7 +12,6 @@
static void rufl_dump_character_set_list(
const struct rufl_character_set *charset);
static void rufl_dump_unicode_map(struct rufl_unicode_map *umap);
-static void rufl_dump_substitution_table(void);
/**
@@ -66,7 +65,7 @@ void rufl_dump_state(void)
}
printf("rufl_substitution_table:\n");
- rufl_dump_substitution_table();
+ rufl_substitution_table_dump();
}
@@ -132,25 +131,3 @@ void rufl_dump_unicode_map(struct rufl_unicode_map *umap)
for (i = 0; i != umap->entries; i++)
printf("%x:%x ", umap->map[i].u, umap->map[i].c);
}
-
-
-/**
- * Dump a representation of the substitution table to stdout.
- */
-
-void rufl_dump_substitution_table(void)
-{
- unsigned int font;
- unsigned int u, t;
-
- u = 0;
- while (u != 0x10000) {
- t = u;
- font = rufl_substitution_table[t];
- while (u != 0x10000 && font == rufl_substitution_table[u])
- u++;
- if (font != NOT_AVAILABLE)
- printf(" %x-%x => %u \"%s\"\n", t, u - 1,
- font, rufl_font_list[font].identifier);
- }
-}
diff --git a/src/rufl_init.c b/src/rufl_init.c
index d12fac0..25753d6 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -31,7 +31,6 @@ unsigned int rufl_family_list_entries = 0;
struct rufl_family_map_entry *rufl_family_map = 0;
os_error *rufl_fm_error = 0;
void *rufl_family_menu = 0;
-unsigned short *rufl_substitution_table = 0;
struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
int rufl_cache_time = 0;
bool rufl_old_font_manager = false;
@@ -87,7 +86,6 @@ static rufl_code rufl_init_read_encoding(font_f font,
void *pw);
static int rufl_glyph_map_cmp(const void *keyval, const void *datum);
static int rufl_unicode_map_cmp(const void *z1, const void *z2);
-static rufl_code rufl_init_substitution_table(void);
static rufl_code rufl_save_cache(void);
static rufl_code rufl_load_cache(void);
static int rufl_font_list_cmp(const void *keyval, const void *datum);
@@ -214,9 +212,9 @@ rufl_code rufl_init(void)
xhourglass_leds(2, 0, 0);
xhourglass_colours(0x0000ff, 0x00ffff, &old_sand, &old_glass);
- code = rufl_init_substitution_table();
+ code = rufl_substitution_table_init();
if (code != rufl_OK) {
- LOG("rufl_init_substitution_table: 0x%x", code);
+ LOG("rufl_substitution_table_init: 0x%x", code);
rufl_quit();
xhourglass_off();
return code;
@@ -1332,66 +1330,6 @@ int rufl_unicode_map_cmp(const void *z1, const void *z2)
/**
- * Construct the font substitution table.
- */
-
-rufl_code rufl_init_substitution_table(void)
-{
- unsigned char z;
- unsigned int i;
- unsigned int block, byte, bit;
- unsigned int u;
- unsigned int index;
- const struct rufl_character_set *charset;
-
- rufl_substitution_table = malloc(65536 *
- sizeof rufl_substitution_table[0]);
- if (!rufl_substitution_table) {
- LOG("malloc(%zu) failed", 65536 *
- sizeof rufl_substitution_table[0]);
- return rufl_OUT_OF_MEMORY;
- }
-
- for (u = 0; u != 0x10000; u++)
- rufl_substitution_table[u] = NOT_AVAILABLE;
-
- for (i = 0; i != rufl_font_list_entries; i++) {
- charset = rufl_font_list[i].charset;
- if (!charset)
- continue;
- for (block = 0; block != 256; block++) {
- if (charset->index[block] == BLOCK_EMPTY)
- continue;
- if (charset->index[block] == BLOCK_FULL) {
- for (u = block << 8; u != (block << 8) + 256;
- u++) {
- if (rufl_substitution_table[u] ==
- NOT_AVAILABLE)
- rufl_substitution_table[u] = i;
- }
- continue;
- }
- index = charset->index[block];
- for (byte = 0; byte != 32; byte++) {
- z = charset->block[index][byte];
- if (z == 0)
- continue;
- u = (block << 8) | (byte << 3);
- for (bit = 0; bit != 8; bit++, u++) {
- if (rufl_substitution_table[u] ==
- NOT_AVAILABLE &&
- z & (1 << bit))
- rufl_substitution_table[u] = i;
- }
- }
- }
- }
-
- return rufl_OK;
-}
-
-
-/**
* Save character sets to cache.
*/
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 139e114..6cf6b14 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -158,10 +158,7 @@ extern struct rufl_family_map_entry *rufl_family_map;
/** No font contains this character. */
-#define NOT_AVAILABLE 65535
-/** Font substitution table. */
-extern unsigned short *rufl_substitution_table;
-
+#define NOT_AVAILABLE 0xffff
/** Number of slots in recent-use cache. This is the maximum number of RISC OS
* font handles that will be used at any time by the library. */
@@ -203,6 +200,10 @@ rufl_code rufl_find_font(unsigned int font, unsigned int font_size,
bool rufl_character_set_test(const struct rufl_character_set *charset,
uint32_t u);
+rufl_code rufl_substitution_table_init(void);
+void rufl_substitution_table_fini(void);
+unsigned int rufl_substitution_table_lookup(uint32_t u);
+void rufl_substitution_table_dump(void);
#define rufl_utf8_read(s, l, u) \
if (4 <= l && ((s[0] & 0xf8) == 0xf0) && ((s[1] & 0xc0) == 0x80) && \
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index f05b696..0637ddb 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -139,10 +139,11 @@ rufl_code rufl_glyph_metrics(const char *font_family,
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;
+ else {
+ font1 = rufl_substitution_table_lookup(u);
+ if (font1 == NOT_AVAILABLE)
+ font1 = rufl_CACHE_CORPUS;
+ }
/* Old font managers need the font encoding, too */
if (rufl_old_font_manager && font1 != rufl_CACHE_CORPUS) {
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index 251e7e4..360baec 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -225,10 +225,8 @@ rufl_code rufl_process(rufl_action action,
font1 = NOT_AVAILABLE;
else if (charset && rufl_character_set_test(charset, u))
font1 = font;
- else if (u < 0x10000)
- font1 = rufl_substitution_table[u];
else
- font1 = NOT_AVAILABLE;
+ font1 = rufl_substitution_table_lookup(u);
do {
s[0] = u;
offset_map[0] = offset_u;
@@ -244,10 +242,8 @@ rufl_code rufl_process(rufl_action action,
font1 = NOT_AVAILABLE;
else if (charset && rufl_character_set_test(charset, u))
font1 = font;
- else if (u < 0x10000)
- font1 = rufl_substitution_table[u];
else
- font1 = NOT_AVAILABLE;
+ font1 = rufl_substitution_table_lookup(u);
if (font1 == font0)
n++;
}
diff --git a/src/rufl_quit.c b/src/rufl_quit.c
index cacc9c5..ed03128 100644
--- a/src/rufl_quit.c
+++ b/src/rufl_quit.c
@@ -44,6 +44,5 @@ void rufl_quit(void)
free(rufl_family_menu);
rufl_family_menu = 0;
- free(rufl_substitution_table);
- rufl_substitution_table = 0;
+ rufl_substitution_table_fini();
}
diff --git a/src/rufl_substitution_table.c b/src/rufl_substitution_table.c
new file mode 100644
index 0000000..51c5b7a
--- /dev/null
+++ b/src/rufl_substitution_table.c
@@ -0,0 +1,708 @@
+/*
+ * This file is part of RUfl
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ * Copyright 2006 James Bursa <james(a)semichrome.net>
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include "rufl_internal.h"
+
+#undef RUFL_SUBSTITUTION_TABLE_DEBUG
+
+/**
+ * A perfect hash constructed at library initialisation time using the
+ * CHD algorithm. Hash entries are found via a two-step process:
+ *
+ * 1. apply a first-stage hash to the key to find the bucket
+ * in which the corresponding entry should be found.
+ * 2. apply a second-stage hash to the key and the stored
+ * displacement value for the bucket to find the index
+ * into the substitution table.
+ */
+struct rufl_substitution_table {
+ uint32_t num_buckets; /**< Number of buckets in the hash */
+ uint32_t num_slots; /**< Number of slots in the table */
+ /** Substitution table.
+ *
+ * Fields in the substitution table have the following format:
+ *
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Unicode codepoint |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Font identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * where:
+ *
+ * reserved: 11 bits/16 bits
+ * These bits are currently unused and must be set to 0.
+ *
+ * unicode codepoint: 21 bits
+ * The Unicode codepoint value.
+ *
+ * font identifier: 16 bits
+ * The index into rufl_font_list of a font providing a
+ * substitution glyph for this codepoint or NOT_AVAILABLE.
+ *
+ * Note that, as the substitution table is sparse and may not be
+ * fully populated, it is necessary to verify that the Unicode
+ * codepoint matches the key being hashed and that the font
+ * identifier is not NOT_AVAILABLE. If either of these tests
+ * fail, no font provides a suitable glyph and the not available
+ * path should be taken.
+ */
+ uint64_t *table;
+ uint8_t bits_per_entry; /**< Bits per displacement bitmap entry */
+ /** Displacement bitmap.
+ *
+ * The displacement values are stored in a bitmap of num_buckets
+ * fields each being bits_per_entry wide. Both values are computed
+ * at runtime.
+ */
+ uint8_t displacement_map[];
+};
+/** Font substitution table */
+static struct rufl_substitution_table *rufl_substitution_table;
+
+/**
+ * Round an unsigned 32bit value up to the next power of 2
+ */
+static uint32_t ceil2(uint32_t val)
+{
+ val--;
+ val |= (val >> 1);
+ val |= (val >> 2);
+ val |= (val >> 4);
+ val |= (val >> 8);
+ val |= (val >> 16);
+ val++;
+ val += (val == 0);
+ return val;
+}
+
+/**
+ * Compute the number of bits needed to store a value
+ */
+static uint32_t bits_needed(uint32_t val)
+{
+ int32_t result = 0;
+
+ if (val == 0)
+ return 1;
+
+ if ((val & (val - 1))) {
+ /* Not a power of 2: round up */
+ val = ceil2(val);
+ /* Will need one fewer bit than we're about to count */
+ result = -1;
+ }
+
+ while (val > 0) {
+ result += 1;
+ val >>= 1;
+ }
+
+ return (uint32_t) result;
+}
+
+/**
+ * Perform one round of MurmurHash2
+ */
+static uint32_t mround(uint32_t val, uint32_t s)
+{
+ val *= 0x5db1e995;
+ val ^= (val >> 24);
+ val *= 0x5db1e995;
+ val ^= (s * 0x5db1e995);
+
+ return val;
+}
+
+/**
+ * Perform the MurmurHash2 mixing step
+ */
+static uint32_t mmix(uint32_t val)
+{
+ val ^= (val >> 13);
+ val *= 0x5db1e995;
+ val ^= (val >> 15);
+
+ return val;
+}
+
+/**
+ * First-stage hash (i.e. g(x)) for substitution table.
+ *
+ * As we know that the input values are Unicode codepoints,
+ * do some trivial bit manipulation, which has reasonable
+ * distribution properties.
+ */
+static uint32_t hash1(uint32_t val)
+{
+ val ^= (val >> 7);
+ val ^= (val << 3);
+ val ^= (val >> 4);
+ return val;
+}
+
+/**
+ * Second-stage hash (i.e. f(d, x)) for substitution table.
+ *
+ * Apply MurmurHash2 to the value and displacement
+ */
+static uint32_t hash2(uint32_t val, uint32_t d)
+{
+ return mmix(mround(val, mround(d, 4)));
+}
+
+/**
+ * Comparison function for table entries.
+ *
+ * We use this when sorting the intermediate table for CHD.
+ */
+static int table_chd_cmp(const void *a, const void *b)
+{
+ /* We're only interested in the CHD metadata here.
+ * (i.e. the computed value of g(x) and the bucket size) */
+ const uint64_t aa = (*(const uint64_t *) a) & 0x3fe00000ffff0000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x3fe00000ffff0000llu;
+
+ if (aa > bb)
+ return -1;
+ else if (aa < bb)
+ return 1;
+ return 0;
+}
+
+/**
+ * Test that all specified bits in a bit map are clear and set them if so.
+ *
+ * \param bitmap Bit map to inspect
+ * \param idx Table of indices to inspect
+ * \param len Number of entries in index table
+ * \return True if all bits were clear. False otherwise.
+ */
+static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
+{
+ unsigned int i;
+ bool result = true;
+
+ /* Test if all specified bits are clear */
+ for (i = 0; i != len; i++) {
+ const uint32_t byte = (idx[i] >> 3);
+ const uint32_t bit = (idx[i] & 0x7);
+
+ result &= ((bitmap[byte] & (1 << bit)) == 0);
+ }
+
+ if (result) {
+ /* They are, so set them */
+ for (i = 0; i != len; i++) {
+ const uint32_t byte = (idx[i] >> 3);
+ const uint32_t bit = (idx[i] & 0x7);
+
+ bitmap[byte] |= (1 << bit);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Create the final substitution table from the intermediate parts
+ *
+ * \param table Substitution table
+ * \param table_entries Number of entries in table
+ * \param buckets Number of CHD buckets
+ * \param range Number of slots in final table
+ * \param max_displacement max(displacements)
+ * \param displacements Table of displacement values. One per bucket.
+ * \param substitution_table Location to receive result.
+ */
+static rufl_code create_substitution_table(uint64_t *table,
+ size_t table_entries, uint32_t buckets, uint32_t range,
+ uint32_t max_displacement, uint32_t *displacements,
+ struct rufl_substitution_table **substitution_table)
+{
+ struct rufl_substitution_table *subst_table;
+ size_t subst_table_size;
+ unsigned int i;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("max displacement of %u requires %u bits",
+ max_displacement, bits_needed(max_displacement));
+#endif
+
+ subst_table_size = offsetof(struct rufl_substitution_table,
+ displacement_map) +
+ ((buckets * bits_needed(max_displacement) + 7) >> 3);
+
+ subst_table = calloc(subst_table_size, 1);
+ if (!subst_table)
+ return rufl_OUT_OF_MEMORY;
+
+ /* We know there are at least table_entries in the table, but
+ * we should now resize it to the size of the target hashtable */
+ subst_table->table = realloc(table, range * sizeof(*table));
+ if (!subst_table->table) {
+ free(subst_table);
+ return rufl_OUT_OF_MEMORY;
+ }
+ /* Initialise unused slots */
+ for (i = table_entries; i < range; i++) {
+ subst_table->table[i] = NOT_AVAILABLE;
+ }
+
+ subst_table->num_buckets = buckets;
+ subst_table->num_slots = range;
+ subst_table->bits_per_entry = bits_needed(max_displacement);
+
+ /* Fill in displacement map */
+ //XXX: compress map using Fredriksson-Nikitin encoding?
+ for (i = 0; i < buckets; i++) {
+ uint32_t offset_bits = i * subst_table->bits_per_entry;
+ uint32_t bits_to_write = subst_table->bits_per_entry;
+ uint8_t *pwrite =
+ &subst_table->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_write > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ uint32_t mask = 0, mask_idx;
+
+ if (space_available > bits_to_write)
+ space_available = bits_to_write;
+
+ for (mask_idx = 0; mask_idx != space_available;
+ mask_idx++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+
+ *pwrite |= ((displacements[i] >>
+ (bits_to_write - space_available)) & mask) <<
+ (8 - offset_bits - space_available);
+ pwrite++;
+ offset_bits = 0;
+ bits_to_write -= space_available;
+ }
+ }
+
+ /* Shuffle table data so the indices match the hash values */
+ for (i = 0; i < table_entries; ) {
+ uint32_t f, g;
+ uint64_t tmp;
+
+ if (subst_table->table[i] == NOT_AVAILABLE) {
+ i++;
+ continue;
+ }
+
+ g = ((subst_table->table[i] >> 53) & 0x1f0000) |
+ ((subst_table->table[i] >> 16) & 0xffff);
+ f = hash2((subst_table->table[i] >> 32) & 0x1fffff,
+ displacements[g]) & (range - 1);
+
+ /* Exchange this entry with the one in the slot at f.*/
+ if (f != i) {
+ tmp = subst_table->table[f];
+ subst_table->table[f] = subst_table->table[i];
+ subst_table->table[i] = tmp;
+ } else {
+ /* Reconsider this slot unless it already
+ * had the correct entry */
+ i++;
+ }
+ }
+ /* Strip all the CHD metadata out of the final table */
+ for (i = 0; i < range; i++)
+ subst_table->table[i] &= 0x001fffff0000ffffllu;
+
+ *substitution_table = subst_table;
+
+ return rufl_OK;
+}
+
+/**
+ * Compute a perfect hash to address the substitution table.
+ *
+ * We use the CHD algorithm to do this.
+ * (https://doi.org/10.1007/978-3-642-04128-0_61 ;
+ * http://cmph.sourceforge.net/papers/esa09.pdf)
+ *
+ * A more recent alternative might be RecSplit
+ * (https://arxiv.org/abs/1910.06416v2).
+ *
+ * \param table Pre-filled table of raw substitution data
+ * \param table_entries Number of entries in the table
+ * \param substitution_table Location to receive result
+ */
+static rufl_code chd(uint64_t *table, size_t table_entries,
+ struct rufl_substitution_table **substitution_table)
+{
+ /** Number of buckets assuming an average bucket size of 4 */
+ const uint32_t buckets = ceil2((table_entries + 3) & ~3);
+ /** Number of output hash slots assuming a load factor of 0.95 */
+ const uint32_t range = ceil2((table_entries * 100)/95);
+ uint32_t bucket_size, max_displacement = 0;
+ unsigned int i;
+ uint8_t *entries_per_bucket, *bitmap;
+ uint32_t *displacements;
+ rufl_code result = rufl_OK;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("hashing %zu entries into %u buckets with range %u",
+ table_entries, buckets, range);
+#endif
+
+ entries_per_bucket = calloc(buckets, sizeof(*entries_per_bucket));
+ if (!entries_per_bucket)
+ return rufl_OUT_OF_MEMORY;
+
+ bitmap = calloc(range >> 3, 1);
+ if (!bitmap) {
+ free(entries_per_bucket);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ displacements = calloc(buckets, sizeof(*displacements));
+ if (!displacements) {
+ free(bitmap);
+ free(entries_per_bucket);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ /* Compute g(x) for each entry, placing them into buckets */
+ for (i = 0; i < table_entries; i++) {
+ uint32_t g = hash1((table[i] >> 32) & 0x1fffff) & (buckets - 1);
+
+ /* Insert hash into entry (it's 21 bits at most, so
+ * needs splitting between bits 16-31 and 53-57 of
+ * the entry) */
+ table[i] |= ((g & 0xffff) << 16);
+ table[i] |= ((uint64_t)(g & 0x1f0000) << 53);
+
+ entries_per_bucket[g]++;
+ }
+
+ /* Inject bucket size into entries */
+ for (i = 0; i < table_entries; i++) {
+ uint32_t g = ((table[i] >> 53) & 0x1f0000) |
+ ((table[i] >> 16) & 0xffff);
+
+ /* With a target bucket size of 4, do not expect
+ * >= twice that number of entries in the largest
+ * bucket. If there are, the hash function needs
+ * work (we allocate 4 bits for the bucket size,
+ * so should have sufficient headroom). */
+ if (entries_per_bucket[g] >= 8)
+ LOG("unexpectedly large bucket %u",
+ entries_per_bucket[g]);
+
+ /* Stash bucket size into bits 58-61 of the entry */
+ table[i] |= ((uint64_t)entries_per_bucket[g] << 58);
+ }
+
+ /* Bits 62-63 of table entries are currently unused */
+
+ free(entries_per_bucket);
+
+ /* Sort entries in descending bucket size order */
+ qsort(table, table_entries, sizeof(*table), table_chd_cmp);
+
+ /* Compute f(x) for each bucket, finding a unique mapping */
+ for (i = 0; i < table_entries; i += bucket_size) {
+ const uint32_t g = ((table[i] >> 53) & 0x1f0000) |
+ ((table[i] >> 16) & 0xffff);
+ uint32_t hashes[8], num_hashes;
+ uint32_t d = 0;
+
+ bucket_size = ((table[i] >> 58) & 0xf);
+
+ do {
+ uint32_t j, k;
+
+ d++;
+ num_hashes = 0;
+
+ for (j = 0; j != bucket_size; j++) {
+ uint32_t f = hash2(
+ (table[i+j] >> 32) & 0x1fffff, d) &
+ (range - 1);
+ for (k = 0; k < num_hashes; k++) {
+ if (f == hashes[k])
+ break;
+ }
+ if (k == num_hashes) {
+ hashes[num_hashes] = f;
+ num_hashes++;
+ }
+ }
+ } while (num_hashes != bucket_size || !test_and_set_bits(
+ bitmap, hashes, num_hashes));
+
+ displacements[g] = d;
+ if (d > max_displacement)
+ max_displacement = d;
+ }
+
+ free(bitmap);
+
+ result = create_substitution_table(table, table_entries,
+ buckets, range, max_displacement, displacements,
+ substitution_table);
+ free(displacements);
+
+ return result;
+}
+
+/**
+ * Populate the substitution map for a given block
+ */
+static void fill_map_for_block(const struct rufl_character_set **charsets,
+ uint32_t block, uint16_t map_for_block[256])
+{
+ unsigned int i, u;
+
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ if (!charsets[i])
+ continue;
+
+ if (charsets[i]->index[block] == BLOCK_FULL) {
+ for (u = 0; u != 256; u++)
+ if (map_for_block[u] == NOT_AVAILABLE)
+ map_for_block[u] = i;
+ } else if (charsets[i]->index[block] != BLOCK_EMPTY) {
+ const uint8_t *blk = charsets[i]->block[
+ charsets[i]->index[block]];
+ for (u = 0; u != 256; u++) {
+ if (map_for_block[u] == NOT_AVAILABLE &&
+ (blk[(u>>3)] & (1 << (u&7)))) {
+ map_for_block[u] = i;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Construct the font substitution table.
+ */
+
+rufl_code rufl_substitution_table_init(void)
+{
+ unsigned int i;
+ unsigned int plane, block;
+ unsigned int u;
+ const struct rufl_character_set **charsets;
+ uint64_t *table;
+ size_t table_size;
+ size_t table_entries;
+ rufl_code result;
+
+ charsets = malloc(rufl_font_list_entries * sizeof(*charsets));
+ if (!charsets) {
+ LOG("malloc(%zu) failed",
+ rufl_font_list_entries * sizeof(*charsets));
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ table = malloc(1024 * sizeof(*table));
+ if (!table) {
+ LOG("malloc(%zu) failed", 1024 * sizeof(*table));
+ free(charsets);
+ return rufl_OUT_OF_MEMORY;
+ }
+ table_size = 1024;
+ table_entries = 0;
+
+ for (plane = 0; plane < 17; plane++) {
+ const struct rufl_character_set *charset;
+ unsigned int num_charsets = 0;
+
+ /* Find fonts that have charsets for this plane */
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ charset = rufl_font_list[i].charset;
+ if (!charset) {
+ charsets[i] = NULL;
+ continue;
+ }
+
+ while (PLANE_ID(charset->metadata) != plane &&
+ EXTENSION_FOLLOWS(charset->metadata)) {
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ if (PLANE_ID(charset->metadata) != plane)
+ charset = NULL;
+ charsets[i] = charset;
+ num_charsets++;
+ }
+ if (num_charsets == 0)
+ continue;
+
+ /* Process each block, finding fonts that have glyphs */
+ for (block = 0; block != 256; block++) {
+ uint16_t map_for_block[256];
+ memset(map_for_block, 0xff, 512);
+
+ fill_map_for_block(charsets, block, map_for_block);
+
+ /* Merge block map into table */
+ for (i = 0; i != 256; i++) {
+ if (map_for_block[i] == NOT_AVAILABLE)
+ continue;
+
+ u = (plane << 16) | (block << 8) | i;
+ table[table_entries] = ((uint64_t) u << 32) |
+ map_for_block[i];
+ if (++table_entries == table_size) {
+ uint64_t *tmp = realloc(table,
+ 2 * table_size *
+ sizeof(*table));
+ if (!tmp) {
+ LOG("realloc(%zu) failed",
+ 2 * table_size *
+ sizeof(*table));
+ free(table);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ table = tmp;
+ table_size *= 2;
+ }
+ }
+ }
+ }
+
+ /* Build hash from table */
+ result = chd(table, table_entries, &rufl_substitution_table);
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
+ rufl_substitution_table->num_slots * sizeof(*table),
+ table_entries,
+ rufl_substitution_table->num_buckets,
+ rufl_substitution_table->bits_per_entry,
+ (rufl_substitution_table->num_buckets *
+ rufl_substitution_table->bits_per_entry + 7) >> 3);
+#endif
+
+ free(charsets);
+
+ return result;
+}
+
+/**
+ * Destroy the substitution table and clean up its resources
+ */
+
+void rufl_substitution_table_fini(void)
+{
+ free(rufl_substitution_table->table);
+ free(rufl_substitution_table);
+ rufl_substitution_table = NULL;
+}
+
+/**
+ * Look up a Unicode codepoint in the substitution table
+ */
+
+unsigned int rufl_substitution_table_lookup(uint32_t u)
+{
+ uint32_t displacement = 0;
+ uint32_t f, g = hash1(u & 0x1ffffff) &
+ (rufl_substitution_table->num_buckets - 1);
+ uint32_t bits_to_read = rufl_substitution_table->bits_per_entry;
+ uint32_t offset_bits = g * bits_to_read;
+ const uint8_t *pread =
+ &rufl_substitution_table->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_read > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ if (space_available > bits_to_read)
+ space_available = bits_to_read;
+
+ displacement <<= space_available;
+ displacement |= (*pread & (0xff >> offset_bits)) >>
+ (8 - space_available - offset_bits);
+
+ offset_bits += space_available;
+ if (offset_bits >= 8) {
+ pread++;
+ offset_bits = 0;
+ }
+ bits_to_read -= space_available;
+ }
+
+ f = hash2((u & 0x1fffff), displacement) &
+ (rufl_substitution_table->num_slots - 1);
+
+ if ((rufl_substitution_table->table[f] & 0xffff) != NOT_AVAILABLE &&
+ ((rufl_substitution_table->table[f] >> 32) & 0x1fffff) == u)
+ return rufl_substitution_table->table[f] & 0xffff;
+
+ return NOT_AVAILABLE;
+}
+
+static int table_dump_cmp(const void *a, const void *b)
+{
+ const uint64_t aa = (*(const uint64_t *) a) & 0x001fffff00000000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x001fffff00000000llu;
+
+ if (aa > bb)
+ return 1;
+ else if (aa < bb)
+ return -1;
+ return 0;
+}
+
+/**
+ * Dump a representation of the substitution table to stdout.
+ */
+
+void rufl_substitution_table_dump(void)
+{
+ unsigned int font;
+ unsigned int u, t;
+ uint64_t *table;
+
+ table = malloc(rufl_substitution_table->num_slots * sizeof(*table));
+ if (table == NULL)
+ return;
+
+ memcpy(table, rufl_substitution_table->table,
+ rufl_substitution_table->num_slots * sizeof(*table));
+
+ qsort(table, rufl_substitution_table->num_slots, sizeof(*table),
+ table_dump_cmp);
+
+ u = 0;
+ while (u < rufl_substitution_table->num_slots) {
+ t = u;
+ font = table[t] & 0xffff;
+ while (u < rufl_substitution_table->num_slots &&
+ font == (table[u] & 0xffff) &&
+ ((u == t) ||
+ (((table[u - 1] >> 32) & 0x1fffff) ==
+ (((table[u] >> 32) & 0x1fffff) - 1))))
+ u++;
+ if (font != NOT_AVAILABLE)
+ printf(" %llx-%llx => %u \"%s\"\n",
+ (table[t] >> 32) & 0x1fffff,
+ (table[u - 1] >> 32) & 0x1fffff,
+ font, rufl_font_list[font].identifier);
+ }
+
+ free(table);
+}
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=5be9bd8e833c84dbd55...
commit 5be9bd8e833c84dbd55511046657e2fcf678d03c
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Include extension plane data in RUfl_cache
This requires us to bump the cache version, as it is a breaking
change.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 7f6a2ac..d12fac0 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1424,7 +1424,10 @@ rufl_code rufl_save_cache(void)
}
for (i = 0; i != rufl_font_list_entries; i++) {
- if (!rufl_font_list[i].charset)
+ const struct rufl_character_set *charset =
+ rufl_font_list[i].charset;
+
+ if (!charset)
continue;
/* length of font identifier */
@@ -1442,9 +1445,26 @@ rufl_code rufl_save_cache(void)
return rufl_OK;
}
- /* character set */
- if (fwrite(rufl_font_list[i].charset,
- PLANE_SIZE(rufl_font_list[i].charset->metadata),
+ /* character set (all planes) */
+ LOG("writing character sets for %s",
+ rufl_font_list[i].identifier);
+ while (EXTENSION_FOLLOWS(charset->metadata)) {
+ LOG("writing plane %d (%u)",
+ PLANE_ID(charset->metadata),
+ PLANE_SIZE(charset->metadata));
+ if (fwrite(charset, PLANE_SIZE(charset->metadata),
+ 1, fp) != 1) {
+ LOG("fwrite: 0x%x: %s", errno, strerror(errno));
+ fclose(fp);
+ return rufl_OK;
+ }
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ LOG("writing plane %d (%u)",
+ PLANE_ID(charset->metadata),
+ PLANE_SIZE(charset->metadata));
+ if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
fclose(fp);
@@ -1528,10 +1548,11 @@ rufl_code rufl_load_cache(void)
unsigned int i = 0;
bool old_font_manager;
char *identifier;
- size_t len, size;
+ size_t len, size = 0;
+ uint32_t metadata;
FILE *fp;
struct rufl_font_list_entry *entry;
- struct rufl_character_set *charset;
+ struct rufl_character_set *charset = NULL, *cur_charset;
struct rufl_unicode_map *umap = NULL;
unsigned int num_umaps = 0;
@@ -1603,33 +1624,56 @@ rufl_code rufl_load_cache(void)
identifier[len] = 0;
/* character set */
- if (fread(&size, sizeof size, 1, fp) != 1) {
- if (feof(fp))
- LOG("fread: %s", "unexpected eof");
- else
- LOG("fread: 0x%x: %s", errno, strerror(errno));
- free(identifier);
- break;
- }
+ LOG("reading character sets for %s", identifier);
+ do {
+ if (fread(&metadata, sizeof metadata, 1, fp) != 1) {
+ if (feof(fp))
+ LOG("fread: %s", "unexpected eof");
+ else
+ LOG("fread: 0x%x: %s",
+ errno, strerror(errno));
+ free(identifier);
+ break;
+ }
- charset = malloc(size);
- if (!charset) {
- LOG("malloc(%zu) failed", size);
- free(identifier);
- fclose(fp);
- return rufl_OUT_OF_MEMORY;
- }
+ LOG("reading plane %d (%u)",
+ PLANE_ID(metadata),
+ PLANE_SIZE(metadata));
+ if (!charset) {
+ charset = cur_charset = malloc(
+ PLANE_SIZE(metadata));
+ } else {
+ struct rufl_character_set *c2 = realloc(charset,
+ size + PLANE_SIZE(metadata));
+ if (!c2) {
+ free(charset);
+ }
+ charset = c2;
+ cur_charset = (void *)(((uint8_t *) charset) +
+ size);
+ }
+ if (!charset) {
+ LOG("malloc(%zu) failed", size);
+ free(identifier);
+ fclose(fp);
+ return rufl_OUT_OF_MEMORY;
+ }
- charset->metadata = size;
- if (fread(charset->index, size - sizeof size, 1, fp) != 1) {
- if (feof(fp))
- LOG("fread: %s", "unexpected eof");
- else
- LOG("fread: 0x%x: %s", errno, strerror(errno));
- free(charset);
- free(identifier);
- break;
- }
+ size += PLANE_SIZE(metadata);
+ cur_charset->metadata = metadata;
+ if (fread(cur_charset->index,
+ PLANE_SIZE(metadata) - sizeof metadata,
+ 1, fp) != 1) {
+ if (feof(fp))
+ LOG("fread: %s", "unexpected eof");
+ else
+ LOG("fread: 0x%x: %s",
+ errno, strerror(errno));
+ free(charset);
+ free(identifier);
+ break;
+ }
+ } while(EXTENSION_FOLLOWS(cur_charset->metadata));
/* unicode map */
if (rufl_old_font_manager) {
@@ -1761,6 +1805,9 @@ rufl_code rufl_load_cache(void)
free(charset);
}
+ charset = NULL;
+ size = 0;
+
free(identifier);
}
fclose(fp);
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 9c7d46e..139e114 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -235,7 +235,7 @@ bool rufl_character_set_test(const struct rufl_character_set *charset,
}
#define rufl_CACHE "<Wimp$ScrapDir>.RUfl_cache"
-#define rufl_CACHE_VERSION 3
+#define rufl_CACHE_VERSION 4
struct rufl_glyph_map_entry {
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=6f212ee62e6cc19cb68...
commit 6f212ee62e6cc19cb686208dd5b510d01217d0af
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Merge UCS font scan implementations
The only meaningful difference is how we enumerate the codepoints
represented by a font. Factor this out so that we can share almost
all of the implementation.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 523158d..7f6a2ac 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -35,6 +35,7 @@ unsigned short *rufl_substitution_table = 0;
struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
int rufl_cache_time = 0;
bool rufl_old_font_manager = false;
+static bool rufl_broken_font_enumerate_characters = false;
wimp_w rufl_status_w = 0;
char rufl_status_buffer[80];
@@ -73,7 +74,6 @@ static rufl_code rufl_init_add_font(const char *identifier,
const char *local_name);
static int rufl_weight_table_cmp(const void *keyval, const void *datum);
static rufl_code rufl_init_scan_font(unsigned int font);
-static rufl_code rufl_init_scan_font_no_enumerate(unsigned int font);
static bool rufl_is_space(unsigned int u);
static rufl_code rufl_init_scan_font_old(unsigned int font_index);
static rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
@@ -105,7 +105,6 @@ static void rufl_init_status_close(void);
rufl_code rufl_init(void)
{
- bool rufl_broken_font_enumerate_characters = false;
unsigned int changes = 0;
unsigned int i;
int fm_version;
@@ -202,8 +201,6 @@ rufl_code rufl_init(void)
(float) i / rufl_font_list_entries);
if (rufl_old_font_manager)
code = rufl_init_scan_font_old(i);
- else if (rufl_broken_font_enumerate_characters)
- code = rufl_init_scan_font_no_enumerate(i);
else
code = rufl_init_scan_font(i);
if (code != rufl_OK) {
@@ -548,37 +545,17 @@ static struct rufl_character_set *rufl_init_shrinkwrap_planes(
return charset;
}
-/**
- * Scan a font for available characters.
- */
-
-rufl_code rufl_init_scan_font(unsigned int font_index)
+static rufl_code rufl_init_enumerate_characters(const char *font_name,
+ font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
{
- char font_name[80];
- int x_out, y_out;
- unsigned int byte, bit;
- unsigned int string[2] = { 0, 0 };
unsigned int u, next;
- struct rufl_character_set *planes[17];
- struct rufl_character_set *charset;
- font_f font;
- font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
-
- /*LOG("font %u \"%s\"", font_index,
- rufl_font_list[font_index].identifier);*/
-
- for (u = 0; u < 17; u++)
- planes[u] = NULL;
-
- snprintf(font_name, sizeof font_name, "%s\\EUTF8",
- rufl_font_list[font_index].identifier);
+ rufl_code result;
- rufl_fm_error = xfont_find_font(font_name, 160, 160, 0, 0, &font, 0, 0);
- if (rufl_fm_error) {
- LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
- return rufl_OK;
- }
+ if (rufl_broken_font_enumerate_characters)
+ return rufl_init_read_encoding(font, callback, pw);
/* Scan through mapped characters */
for (u = 0; u != (unsigned int) -1; u = next) {
@@ -592,110 +569,20 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
font_name, u,
rufl_fm_error->errnum,
rufl_fm_error->errmess);
- xfont_lose_font(font);
- for (u = 0; u < 17; u++)
- free(planes[u]);
- return rufl_OK;
+ break;
}
- /* Skip DELETE and C0/C1 controls */
- if (u < 0x0020 || (0x007f <= u && u <= 0x009f))
- continue;
-
/* Skip unmapped characters */
if (internal == (unsigned int) -1)
continue;
- if (u % 0x200 == 0)
- rufl_init_status(0, 0);
-
- /* Character is mapped, let's see if it's really there */
- string[0] = u;
- rufl_fm_error = xfont_scan_string(font, (char *) string,
- font_RETURN_BBOX | font_GIVEN32_BIT |
- font_GIVEN_FONT | font_GIVEN_LENGTH |
- font_GIVEN_BLOCK,
- 0x7fffffff, 0x7fffffff,
- &block, 0, 4,
- 0, &x_out, &y_out, 0);
- if (rufl_fm_error)
+ /* Character is mapped, emit it */
+ result = callback(pw, internal, u);
+ if (result != rufl_OK)
break;
-
- 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 (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 */
- const unsigned int plane = (u >> 16) & 0x1f;
- const unsigned int block = (u >> 8) & 0xff;
-
- /* Ensure plane exists */
- if (!planes[plane]) {
- planes[plane] = rufl_init_alloc_plane(plane);
- if (!planes[plane]) {
- for (u = 0; u < 17; u++)
- free(planes[u]);
- xfont_lose_font(font);
- return rufl_OUT_OF_MEMORY;
- }
- }
-
- /* Allocate block, if it's currently empty */
- if (planes[plane]->index[block] == BLOCK_EMPTY) {
- unsigned int last_used =
- PLANE_SIZE(planes[plane]->metadata);
- if (last_used < BLOCK_EMPTY) {
- planes[plane]->index[block] = last_used;
- planes[plane]->metadata =
- (planes[plane]->metadata &
- 0xffff0000) |
- (last_used + 1);
- }
- }
-
- /* Set bit for codepoint in bitmap, if bitmap exists */
- if (planes[plane]->index[block] < BLOCK_EMPTY) {
- byte = (u >> 3) & 31;
- bit = u & 7;
- planes[plane]->block[
- planes[plane]->index[block]
- ][byte] |= 1 << bit;
- }
- }
- }
-
- xfont_lose_font(font);
-
- if (rufl_fm_error) {
- LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
- font_name, u,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
- for (u = 0; u < 17; u++)
- free(planes[u]);
- return rufl_FONT_MANAGER_ERROR;
- }
-
- charset = rufl_init_shrinkwrap_planes(planes);
- if (!charset) {
- for (u = 0; u < 17; u++)
- free(planes[u]);
- return rufl_OUT_OF_MEMORY;
}
- for (u = 0; u < 17; u++)
- free(planes[u]);
-
- rufl_font_list[font_index].charset = charset;
-
- return rufl_OK;
+ return result;
}
static rufl_code find_plane_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
@@ -704,7 +591,9 @@ static rufl_code find_plane_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
(void) glyph_idx;
- planes[(ucs4 >> 16) & 0x1f] = (struct rufl_character_set *) 1;
+ /* Skip DELETE and C0/C1 controls */
+ if (ucs4 > 0x0020 && (ucs4 < 0x007f || 0x009f < ucs4))
+ planes[(ucs4 >> 16) & 0x1f] = (struct rufl_character_set *) 1;
return rufl_OK;
}
@@ -724,6 +613,10 @@ static rufl_code find_glyph_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
(void) glyph_idx;
+ /* Skip DELETE and C0/C1 controls */
+ if (ucs4 < 0x0020 || (0x007f <= ucs4 && ucs4 <= 0x009f))
+ return rufl_OK;
+
if (ucs4 % 0x200 == 0)
rufl_init_status(0, 0);
@@ -785,10 +678,10 @@ static rufl_code find_glyph_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
}
/**
- * Scan a font for available characters (version without character enumeration)
+ * Scan a font for available characters
*/
-rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
+rufl_code rufl_init_scan_font(unsigned int font_index)
{
char font_name[80];
struct rufl_character_set *planes[17];
@@ -815,7 +708,8 @@ rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
}
/* First pass: find the planes we need */
- rc = rufl_init_read_encoding(font, find_plane_cb, planes);
+ rc = rufl_init_enumerate_characters(font_name, font,
+ find_plane_cb, planes);
if (rc != rufl_OK)
return rc;
@@ -838,7 +732,8 @@ rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
ctx.font = font;
ctx.planes = planes;
- rc = rufl_init_read_encoding(font, find_glyph_cb, &ctx);
+ rc = rufl_init_enumerate_characters(font_name, font,
+ find_glyph_cb, &ctx);
if (rc != rufl_OK) {
for (plane = 0; plane < 17; plane++)
free(planes[plane]);
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=a0bad0bd03988b9b779...
commit a0bad0bd03988b9b77969f8b00cc9a512856f7f0
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Include astral characters in font scan
We now construct extension plane data if astral characters are
present. Systems with a non-UCS Font Manager are still restricted
to using the Basic Multilingual Plane (as there is no mechanism
for encoding astral characters in the font or encoding data).
Rewrite the UCS Font Manager 3.41-3.63 support to scan the font
encoding itself (as Font_EnumerateCharacters is broken on these
Font Manager versions).
This also fixes the post-scan shrink-wrapping for Font Manager 3.64
or later -- previously it would not coalesce block bitmaps when
determining that a block was full.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index b7821c4..523158d 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -440,6 +440,114 @@ int rufl_weight_table_cmp(const void *keyval, const void *datum)
return strcasecmp(key, entry->name);
}
+static struct rufl_character_set *rufl_init_alloc_plane(uint8_t index)
+{
+ struct rufl_character_set *charset;
+ unsigned int u;
+
+ charset = calloc(1, sizeof *charset);
+ if (charset != NULL) {
+ /* Set plane ID. Extension/size must be filled in by caller */
+ charset->metadata |= ((index & 0x1f) << 26);
+ for (u = 0; u != 256; u++)
+ charset->index[u] = BLOCK_EMPTY;
+ }
+
+ return charset;
+}
+
+static void rufl_init_shrinkwrap_plane(struct rufl_character_set *charset)
+{
+ unsigned int last_used = PLANE_SIZE(charset->metadata);
+ unsigned int u, bit, byte;
+
+ /* Determine which blocks are full, and mark them as such */
+ for (u = 0; u != 256; u++) {
+ const unsigned int block = charset->index[u];
+
+ if (block == BLOCK_EMPTY)
+ continue;
+
+ bit = 0xff;
+
+ for (byte = 0; byte != 32; byte++)
+ bit &= charset->block[block][byte];
+
+ if (bit == 0xff) {
+ /* Block is full */
+
+ /* Find a block whose index is after this one.
+ * If such a block exists, move its data into
+ * this block, as this block's bitmap is now free
+ */
+ for (byte = 0; byte != 256; byte++) {
+ if (charset->index[byte] < BLOCK_EMPTY &&
+ charset->index[byte] > block) {
+ break;
+ }
+ }
+ if (byte != 256) {
+ memcpy(charset->block[block],
+ charset->block[
+ charset->index[byte]],
+ 32);
+ charset->index[byte] = block;
+ }
+
+ /* Now mark this block as full */
+ charset->index[u] = BLOCK_FULL;
+ last_used--;
+ }
+ }
+
+ /* Fill in this plane's size now we know it */
+ charset->metadata = (charset->metadata & 0xffff0000) |
+ (offsetof(struct rufl_character_set, block) +
+ 32 * last_used);
+}
+
+static struct rufl_character_set *rufl_init_shrinkwrap_planes(
+ struct rufl_character_set *planes[17])
+{
+ struct rufl_character_set *charset;
+ unsigned int size = 0, pos, u;
+
+ /* Shrink-wrap each plane, accumulating total required size as we go */
+ for (u = 0; u < 17; u++) {
+ if (planes[u]) {
+ LOG("shrink-wrapping plane %d", u);
+ rufl_init_shrinkwrap_plane(planes[u]);
+ size += PLANE_SIZE(planes[u]->metadata);
+ }
+ }
+
+ LOG("shrink-wrapped size: %u", size);
+
+ charset = malloc(size);
+ if (!charset)
+ return NULL;
+
+ /* Copy planes into output, backwards, setting the extension bit for
+ * all but the last plane present */
+ pos = size;
+ for (u = 17; u > 0; u--) {
+ if (!planes[u-1])
+ continue;
+
+ LOG("merging plane %d", u);
+
+ /* Set E bit if not the last plane */
+ if (pos != size)
+ planes[u-1]->metadata |= (1u<<31);
+
+ pos -= PLANE_SIZE(planes[u-1]->metadata);
+ memcpy(((uint8_t *)charset) + pos, planes[u-1],
+ PLANE_SIZE(planes[u-1]->metadata));
+ }
+
+ return charset;
+}
+
/**
* Scan a font for available characters.
*/
@@ -449,22 +557,18 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
char font_name[80];
int x_out, y_out;
unsigned int byte, bit;
- unsigned int last_used = 0;
unsigned int string[2] = { 0, 0 };
unsigned int u, next;
+ struct rufl_character_set *planes[17];
struct rufl_character_set *charset;
- struct rufl_character_set *charset2;
font_f font;
font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
/*LOG("font %u \"%s\"", font_index,
rufl_font_list[font_index].identifier);*/
- charset = calloc(1, sizeof *charset);
- if (!charset)
- return rufl_OUT_OF_MEMORY;
- for (u = 0; u != 256; u++)
- charset->index[u] = BLOCK_EMPTY;
+ for (u = 0; u < 17; u++)
+ planes[u] = NULL;
snprintf(font_name, sizeof font_name, "%s\\EUTF8",
rufl_font_list[font_index].identifier);
@@ -473,7 +577,6 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
if (rufl_fm_error) {
LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name,
rufl_fm_error->errnum, rufl_fm_error->errmess);
- free(charset);
return rufl_OK;
}
@@ -490,7 +593,8 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
rufl_fm_error->errnum,
rufl_fm_error->errmess);
xfont_lose_font(font);
- free(charset);
+ for (u = 0; u < 17; u++)
+ free(planes[u]);
return rufl_OK;
}
@@ -498,10 +602,6 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
if (u < 0x0020 || (0x007f <= u && u <= 0x009f))
continue;
- /* Skip astral characters */
- if (u > 0xffff)
- continue;
-
/* Skip unmapped characters */
if (internal == (unsigned int) -1)
continue;
@@ -534,60 +634,152 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
* fonts do this) */
} else {
/* present */
- if (charset->index[u >> 8] == BLOCK_EMPTY) {
- charset->index[u >> 8] = last_used;
- last_used++;
- if (last_used == 254)
- /* too many characters */
- break;
+ const unsigned int plane = (u >> 16) & 0x1f;
+ const unsigned int block = (u >> 8) & 0xff;
+
+ /* Ensure plane exists */
+ if (!planes[plane]) {
+ planes[plane] = rufl_init_alloc_plane(plane);
+ if (!planes[plane]) {
+ for (u = 0; u < 17; u++)
+ free(planes[u]);
+ xfont_lose_font(font);
+ return rufl_OUT_OF_MEMORY;
+ }
}
- byte = (u >> 3) & 31;
- bit = u & 7;
- charset->block[charset->index[u >> 8]][byte] |=
- 1 << bit;
+ /* Allocate block, if it's currently empty */
+ if (planes[plane]->index[block] == BLOCK_EMPTY) {
+ unsigned int last_used =
+ PLANE_SIZE(planes[plane]->metadata);
+ if (last_used < BLOCK_EMPTY) {
+ planes[plane]->index[block] = last_used;
+ planes[plane]->metadata =
+ (planes[plane]->metadata &
+ 0xffff0000) |
+ (last_used + 1);
+ }
+ }
+
+ /* Set bit for codepoint in bitmap, if bitmap exists */
+ if (planes[plane]->index[block] < BLOCK_EMPTY) {
+ byte = (u >> 3) & 31;
+ bit = u & 7;
+ planes[plane]->block[
+ planes[plane]->index[block]
+ ][byte] |= 1 << bit;
+ }
}
}
xfont_lose_font(font);
if (rufl_fm_error) {
- free(charset);
LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
font_name, u,
rufl_fm_error->errnum, rufl_fm_error->errmess);
+ for (u = 0; u < 17; u++)
+ free(planes[u]);
return rufl_FONT_MANAGER_ERROR;
}
- /* Determine which blocks are full, and mark them as such */
- for (u = 0; u != 256; u++) {
- if (charset->index[u] == BLOCK_EMPTY)
- continue;
+ charset = rufl_init_shrinkwrap_planes(planes);
+ if (!charset) {
+ for (u = 0; u < 17; u++)
+ free(planes[u]);
+ return rufl_OUT_OF_MEMORY;
+ }
- bit = 0xff;
+ for (u = 0; u < 17; u++)
+ free(planes[u]);
- for (byte = 0; byte != 32; byte++)
- bit &= charset->block[u][byte];
+ rufl_font_list[font_index].charset = charset;
- if (bit == 0xff) {
- /* Block is full */
- charset->index[u] = BLOCK_FULL;
+ return rufl_OK;
+}
- for (byte = 0; byte != 32; byte++)
- charset->block[u][byte] = 0;
- }
- }
+static rufl_code find_plane_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct rufl_character_set **planes = pw;
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
- charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
- if (!charset2) {
- free(charset);
- return rufl_OUT_OF_MEMORY;
+ (void) glyph_idx;
+
+ planes[(ucs4 >> 16) & 0x1f] = (struct rufl_character_set *) 1;
+
+ return rufl_OK;
+}
+
+struct find_glyph_ctx {
+ const char *font_name;
+ font_f font;
+ struct rufl_character_set **planes;
+};
+
+static rufl_code find_glyph_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct find_glyph_ctx *ctx = pw;
+ int x_out, y_out;
+ unsigned int string[2] = { 0, 0 };
+ font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
+
+ (void) glyph_idx;
+
+ if (ucs4 % 0x200 == 0)
+ rufl_init_status(0, 0);
+
+ string[0] = ucs4;
+ rufl_fm_error = xfont_scan_string(ctx->font, (char *) string,
+ font_RETURN_BBOX | font_GIVEN32_BIT |
+ font_GIVEN_FONT | font_GIVEN_LENGTH |
+ font_GIVEN_BLOCK,
+ 0x7fffffff, 0x7fffffff,
+ &block, 0, 4,
+ 0, &x_out, &y_out, 0);
+ if (rufl_fm_error) {
+ LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
+ ctx->font_name, ucs4,
+ rufl_fm_error->errnum, rufl_fm_error->errmess);
+ return rufl_FONT_MANAGER_ERROR;
}
- rufl_font_list[font_index].charset = charset;
+ 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 (empty) */
+ } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 &&
+ block.bbox.x1 == 0 && block.bbox.y1 == 0 &&
+ !rufl_is_space(ucs4)) {
+ /* absent (space but not a space character - some
+ * fonts do this) */
+ } else {
+ /* present */
+ const unsigned int plane = (ucs4 >> 16) & 0x1f;
+ const unsigned int blk = (ucs4 >> 8) & 0xff;
+ const unsigned int byte = (ucs4 >> 3) & 31;
+ const unsigned int bit = ucs4 & 7;
+
+ /* Allocate block, if it's currently empty */
+ if (ctx->planes[plane]->index[blk] == BLOCK_EMPTY) {
+ unsigned int last_used =
+ PLANE_SIZE(ctx->planes[plane]->metadata);
+ if (last_used < BLOCK_EMPTY) {
+ ctx->planes[plane]->index[blk] = last_used;
+ ctx->planes[plane]->metadata =
+ (ctx->planes[plane]->metadata &
+ 0xffff0000) |
+ (last_used + 1);
+ }
+ }
+
+ /* Set bit for codepoint in bitmap, if bitmap exists */
+ if (ctx->planes[plane]->index[blk] < BLOCK_EMPTY) {
+ ctx->planes[plane]->block[
+ ctx->planes[plane]->index[blk]
+ ][byte] |= 1 << bit;
+ }
+ }
return rufl_OK;
}
@@ -599,23 +791,18 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
{
char font_name[80];
- int x_out, y_out;
- unsigned int byte, bit;
- unsigned int block_count = 0;
- unsigned int last_used = 0;
- unsigned int string[2] = { 0, 0 };
- unsigned int u;
+ struct rufl_character_set *planes[17];
struct rufl_character_set *charset;
- struct rufl_character_set *charset2;
font_f font;
- font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
+ unsigned int plane;
+ struct find_glyph_ctx ctx;
+ rufl_code rc;
/*LOG("font %u \"%s\"", font_index,
rufl_font_list[font_index].identifier);*/
- charset = calloc(1, sizeof *charset);
- if (!charset)
- return rufl_OUT_OF_MEMORY;
+ for (plane = 0; plane < 17; plane++)
+ planes[plane] = NULL;
snprintf(font_name, sizeof font_name, "%s\\EUTF8",
rufl_font_list[font_index].identifier);
@@ -624,90 +811,53 @@ rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
if (rufl_fm_error) {
LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name,
rufl_fm_error->errnum, rufl_fm_error->errmess);
- free(charset);
return rufl_OK;
}
- /* scan through all characters */
- for (u = 0x0020; u != 0x10000; u++) {
- if (u == 0x007f) {
- /* skip DELETE and C1 controls */
- u = 0x009f;
- continue;
- }
-
- if (u % 0x200 == 0)
- rufl_init_status(0, 0);
-
- string[0] = u;
- rufl_fm_error = xfont_scan_string(font, (char *) string,
- font_RETURN_BBOX | font_GIVEN32_BIT |
- font_GIVEN_FONT | font_GIVEN_LENGTH |
- font_GIVEN_BLOCK,
- 0x7fffffff, 0x7fffffff,
- &block, 0, 4,
- 0, &x_out, &y_out, 0);
- if (rufl_fm_error)
- break;
-
- 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 (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;
- bit = u & 7;
- charset->block[last_used][byte] |= 1 << bit;
+ /* First pass: find the planes we need */
+ rc = rufl_init_read_encoding(font, find_plane_cb, planes);
+ if (rc != rufl_OK)
+ return rc;
- block_count++;
- }
+ /* Allocate the planes */
+ for (plane = 0; plane < 17; plane++) {
+ if (!planes[plane])
+ continue;
- if ((u + 1) % 256 == 0) {
- /* end of block */
- if (block_count == 0)
- charset->index[u >> 8] = BLOCK_EMPTY;
- else if (block_count == 256) {
- charset->index[u >> 8] = BLOCK_FULL;
- for (byte = 0; byte != 32; byte++)
- charset->block[last_used][byte] = 0;
- } else {
- charset->index[u >> 8] = last_used;
- last_used++;
- if (last_used == 254)
- /* too many characters */
- break;
- }
- block_count = 0;
+ planes[plane] = rufl_init_alloc_plane(plane);
+ if (!planes[plane]) {
+ while (plane > 0)
+ free(planes[plane-1]);
+ xfont_lose_font(font);
+ return rufl_OUT_OF_MEMORY;
}
}
- xfont_lose_font(font);
+ /* Second pass: populate the planes */
+ ctx.font_name = font_name;
+ ctx.font = font;
+ ctx.planes = planes;
- if (rufl_fm_error) {
- free(charset);
- LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
- font_name, u,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
- return rufl_FONT_MANAGER_ERROR;
+ rc = rufl_init_read_encoding(font, find_glyph_cb, &ctx);
+ if (rc != rufl_OK) {
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
+ xfont_lose_font(font);
+ return rc;
}
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
- charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
- if (!charset2) {
- free(charset);
+ xfont_lose_font(font);
+
+ charset = rufl_init_shrinkwrap_planes(planes);
+ if (!charset) {
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
return rufl_OUT_OF_MEMORY;
}
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
+
rufl_font_list[font_index].charset = charset;
return rufl_OK;
@@ -727,6 +877,9 @@ bool rufl_is_space(unsigned int u)
/**
* Scan a font for available characters (old font manager version).
+ * By definition, no astral characters are supported when using a non-UCS
+ * Font Manager (font encodings are defined using PostScript glyph names
+ * which, per the Glyph list, can only fall in the Basic Multilingual Plane)
*/
rufl_code rufl_init_scan_font_old(unsigned int font_index)
@@ -888,9 +1041,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
return rufl_OK;
}
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
+ /* Shrink-wrap. We only have the one plane so fill in last_used
+ * as expected by the shrinkwrapping helper and then resize the
+ * resulting charset manually. */
+ charset->metadata = (charset->metadata & 0xffff0000) | last_used;
+ rufl_init_shrinkwrap_plane(charset);
charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
if (!charset2) {
for (i = 0; i < num_umaps; i++)
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=fbec3fe20c30e459711...
commit fbec3fe20c30e4597110967f05f8416ba7769db4
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Parse UCS-aware Encoding files
1. Comprehend the /uniXXXX and /uXXXX - /uXXXXXXXX glyph names
2. Comprehend the sparse Encoding file format that explicitly
specifies the glyph index rather than inferring it
Support for both of these is conditional on the Font Manager being
UCS-aware (thus ensuring that we continue to parse Encoding files
in the same way as before on systems with no UCS Font Manager).
diff --git a/src/rufl_init.c b/src/rufl_init.c
index b345b75..b7821c4 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -1044,6 +1044,114 @@ rufl_code rufl_init_populate_unicode_map(font_f f,
return result;
}
+static int fromhex(char val, bool permit_lc)
+{
+ if ('0' <= val && val <= '9')
+ return val - '0';
+ else if ('A' <= val && val <= 'F')
+ return val - 'A' + 10;
+ else if (permit_lc && 'a' <= val && val <= 'f')
+ return val - 'a' + 10;
+ return -1;
+}
+
+static rufl_code emit_codepoint(char s[200], unsigned int i,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
+{
+ struct rufl_glyph_map_entry *entry;
+ rufl_code result = rufl_OK;
+
+ if (s[0] != '/') {
+ /* Sparse encoding entry: [XX;]XXXX;NNN..;.... */
+ uint32_t val = 0;
+ int digits;
+
+ if (s[2] == ';' && fromhex(s[0], true) != -1 &&
+ fromhex(s[1], true) != -1) {
+ /* Skip leading "XX;" */
+ s += 3;
+ }
+
+ for (digits = 0; digits < 4; digits++) {
+ int nibble = fromhex(s[digits], true);
+ if (nibble == -1)
+ break;
+ val = (val << 4) | nibble;
+ }
+
+ /* Bail out if the data is not what we expect */
+ if (digits != 4 || s[digits] != ';')
+ return result;
+
+ /* Set the glyph index to the value we found */
+ i = val;
+ /* Advance s to the start of the glyph name */
+ s += digits + 1;
+ /* Terminate the glyph name */
+ for (digits = 0; s[digits] != '\0'; digits++) {
+ if (s[digits] == ';') {
+ s[digits] = '\0';
+ break;
+ }
+ }
+ /* Fall through to the glyph name search */
+ } else {
+ /* Skip the leading / */
+ s += 1;
+
+ if (!rufl_old_font_manager && s[0] == 'u') {
+ /* Handle /uniXXXX and /uXXXX - /uXXXXXXXX.
+ * In the case of /uXXXXX - /uXXXXXXXX, no
+ * leading zeroes are permitted. */
+ int max_digits = 8, off = 1, digits = 0;
+ bool leading_zero = false;
+ uint32_t val = 0;
+
+ if (s[1] == 'n' && s[2] == 'i') {
+ max_digits = 4;
+ off = 3;
+ }
+
+ while (digits < max_digits) {
+ int nibble = fromhex(s[off], false);
+ if (nibble == -1)
+ break;
+ leading_zero = (digits == 0 && nibble == 0);
+ val = (val << 4) | nibble;
+ off++;
+ digits++;
+ }
+ if ((digits == 4 && s[off] == '\0') ||
+ (digits > 4 && s[off] == '\0' &&
+ !leading_zero)) {
+ return callback(pw, i, val);
+ }
+
+ /* Otherwise, let the glyph name search decide */
+ }
+ }
+
+ entry = bsearch(s, rufl_glyph_map,
+ rufl_glyph_map_size,
+ sizeof rufl_glyph_map[0],
+ rufl_glyph_map_cmp);
+ if (entry) {
+ /* may be more than one unicode for the glyph
+ * sentinels stop overshooting array */
+ while (strcmp(s, (entry - 1)->glyph_name) == 0)
+ entry--;
+ for (; strcmp(s, entry->glyph_name) == 0; entry++) {
+ result = callback(pw, i, entry->u);
+ if (result != rufl_OK)
+ break;
+ }
+ }
+
+ return result;
+}
+
/**
* Parse an encoding file
*/
@@ -1064,7 +1172,6 @@ rufl_code rufl_init_read_encoding(font_f font,
int c;
char filename[200];
char s[200];
- struct rufl_glyph_map_entry *entry;
FILE *fp;
rufl_fm_error = xfont_read_encoding_filename(font, filename,
@@ -1076,9 +1183,14 @@ rufl_code rufl_init_read_encoding(font_f font,
}
fp = fopen(filename, "r");
- if (!fp)
- /* many "symbol" fonts have no encoding file: assume Latin 1 */
- fp = fopen("Resources:$.Fonts.Encodings.Latin1", "r");
+ if (!fp) {
+ /* many "symbol" fonts have no encoding file */
+ const char *default_path =
+ "Resources:$.Fonts.Encodings./Default";
+ if (rufl_old_font_manager)
+ default_path = "Resources:$.Fonts.Encodings.Latin1";
+ fp = fopen(default_path, "r");
+ }
if (!fp)
return rufl_IO_ERROR;
@@ -1087,7 +1199,16 @@ rufl_code rufl_init_read_encoding(font_f font,
if (state == STATE_START) {
if (c == '/') {
- n = 0;
+ s[0] = c;
+ n = 1;
+ state = STATE_COLLECT;
+ } else if (!rufl_old_font_manager &&
+ (('0' <= c && c <= '9') ||
+ ('A' <= c && c <= 'F') ||
+ ('a' <= c && c <= 'f'))) {
+ /* New-style sparse encoding file */
+ s[0] = c;
+ n = 1;
state = STATE_COLLECT;
} else if (c <= 0x20) {
/* Consume C0 and space */
@@ -1104,7 +1225,8 @@ rufl_code rufl_init_read_encoding(font_f font,
if ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
- (c == '.') || (c == '_')) {
+ (c == '.') || (c == '_') ||
+ (c == ';')) {
/* Printable: append */
s[n++] = c;
if (n >= sizeof(s)) {
@@ -1126,24 +1248,8 @@ rufl_code rufl_init_read_encoding(font_f font,
if (emit) {
emit = false;
- entry = bsearch(s, rufl_glyph_map,
- rufl_glyph_map_size,
- sizeof rufl_glyph_map[0],
- rufl_glyph_map_cmp);
- if (entry) {
- /* may be more than one unicode for the glyph
- * sentinels stop overshooting array */
- while (strcmp(s, (entry - 1)->glyph_name) == 0)
- entry--;
- for (; strcmp(s, entry->glyph_name) == 0;
- entry++) {
- if (callback(pw, i,
- entry->u) != rufl_OK) {
- done = true;
- break;
- }
- }
- }
+ if (emit_codepoint(s, i, callback, pw) != rufl_OK)
+ done = true;
i++;
}
}
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=c4db3cb6963278e3770...
commit c4db3cb6963278e377083e556b4a74341c446a27
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Refactor Encoding file parsing
Change this into a callback-driven approach so that the logic for
dealing with each individual (glyph index, ucs4) pair is hoisted
out of the parsing code itself. This will allow us to use the same
parser implementation in different scenarios.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index a9d2719..b345b75 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -79,8 +79,12 @@ static rufl_code rufl_init_scan_font_old(unsigned int font_index);
static rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
const char *encoding, struct rufl_character_set *charset,
struct rufl_unicode_map *umap, unsigned int *last);
-static rufl_code rufl_init_read_encoding(font_f font,
+static rufl_code rufl_init_populate_unicode_map(font_f f,
struct rufl_unicode_map *umap);
+static rufl_code rufl_init_read_encoding(font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw);
static int rufl_glyph_map_cmp(const void *keyval, const void *datum);
static int rufl_unicode_map_cmp(const void *z1, const void *z2);
static rufl_code rufl_init_substitution_table(void);
@@ -935,7 +939,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
return rufl_FONT_MANAGER_ERROR;
}
- code = rufl_init_read_encoding(font, umap);
+ code = rufl_init_populate_unicode_map(font, umap);
if (code != rufl_OK) {
LOG("rufl_init_read_encoding(\"%s\", ...): 0x%x",
buf, code);
@@ -1003,21 +1007,58 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
return rufl_OK;
}
+static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct rufl_unicode_map *umap = pw;
+ rufl_code result = rufl_OK;
+
+ /* Ignore first 32 character codes (these are control chars) */
+ if (glyph_idx > 31 && glyph_idx < 256 && umap->entries < 256) {
+ umap->map[umap->entries].u = ucs4;
+ umap->map[umap->entries].c = glyph_idx;
+ umap->entries++;
+ if (umap->entries == 256)
+ result = rufl_IO_EOF;
+ }
+
+ return result;
+}
/**
- * Parse an encoding file and fill in a rufl_unicode_map.
+ * Populate a unicode map by parsing the font's encoding file
*/
-rufl_code rufl_init_read_encoding(font_f font,
+rufl_code rufl_init_populate_unicode_map(font_f f,
struct rufl_unicode_map *umap)
{
+ rufl_code result;
+
+ umap->entries = 0;
+
+ result = rufl_init_read_encoding(f, rufl_init_umap_cb, &umap);
+ if (result == rufl_OK) {
+ /* sort by unicode */
+ qsort(umap->map, umap->entries, sizeof umap->map[0],
+ rufl_unicode_map_cmp);
+ }
+ return result;
+}
+
+/**
+ * Parse an encoding file
+ */
+
+rufl_code rufl_init_read_encoding(font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
+{
enum {
STATE_START,
STATE_COMMENT,
STATE_COLLECT,
} state = STATE_START;
- bool emit = false;
- unsigned int u = 0;
+ bool emit = false, done = false;
unsigned int i = 0;
unsigned int n = 0;
int c;
@@ -1041,7 +1082,7 @@ rufl_code rufl_init_read_encoding(font_f font,
if (!fp)
return rufl_IO_ERROR;
- while (!feof(fp) && i < 256 && u < 256) {
+ while (!feof(fp) && !done) {
c = fgetc(fp);
if (state == STATE_START) {
@@ -1083,8 +1124,8 @@ rufl_code rufl_init_read_encoding(font_f font,
}
}
- /* Ignore first 32 character codes (these are control chars) */
- if (emit && i > 31 && i < 256 && u < 256) {
+ if (emit) {
+ emit = false;
entry = bsearch(s, rufl_glyph_map,
rufl_glyph_map_size,
sizeof rufl_glyph_map[0],
@@ -1096,28 +1137,20 @@ rufl_code rufl_init_read_encoding(font_f font,
entry--;
for (; strcmp(s, entry->glyph_name) == 0;
entry++) {
- umap->map[u].u = entry->u;
- umap->map[u].c = i;
- u++;
- if (u == 256)
+ if (callback(pw, i,
+ entry->u) != rufl_OK) {
+ done = true;
break;
+ }
}
}
- }
-
- if (emit) {
i++;
- emit = false;
}
}
if (fclose(fp) == EOF)
return rufl_IO_ERROR;
- /* sort by unicode */
- qsort(umap->map, u, sizeof umap->map[0], rufl_unicode_map_cmp);
- umap->entries = u;
-
return rufl_OK;
}
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=247a8f1c34b8ffcf3d6...
commit 247a8f1c34b8ffcf3d6072dbb621ea2a19052874
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Use UCS-4 for rendering and display 6-digit replacement characters.
As we introduce support for discovering and rendering astral
characters, ensure that we pass UCS-4 to the relevant Font Manager
APIs and extend our replacement hex code generation to emit
6 digits for codepoints outside the Basic Multilingual Plane.
This has necessitated a change to the API of the callback function
provided to rufl_paint_callback(). Where, previously, a 16 bit
UCS-2 string was exposed, we now expose UCS-4.
diff --git a/include/rufl.h b/include/rufl.h
index 767022e..0164df8 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -124,7 +124,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
/** Type of callback function for rufl_paint_callback(). */
typedef void (*rufl_callback_t)(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned short *s16, unsigned int n,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y);
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index 468f671..f05b696 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -121,7 +121,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
{
const char *font_encoding = NULL;
unsigned int font, font1, u;
- unsigned short u1[2];
+ uint32_t u1[2];
struct rufl_character_set *charset;
struct rufl_unicode_map_entry *umap_entry = NULL;
font_f f;
@@ -235,7 +235,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
flags = font_GIVEN_BLOCK | font_GIVEN_LENGTH | font_GIVEN_FONT |
font_RETURN_BBOX;
- u1[0] = (unsigned short)u;
+ u1[0] = u;
u1[1] = 0;
if (font1 == rufl_CACHE_CORPUS) {
@@ -266,8 +266,8 @@ rufl_code rufl_glyph_metrics(const char *font_family,
} else {
/* UCS Font Manager */
rufl_fm_error = xfont_scan_string(f, (const char *)u1,
- flags | font_GIVEN16_BIT,
- 0x7fffffff, 0x7fffffff, &block, 0, 2,
+ flags | font_GIVEN32_BIT,
+ 0x7fffffff, 0x7fffffff, &block, 0, 4,
0, &xa, &ya, 0);
if (rufl_fm_error) {
LOG("xfont_scan_string: 0x%x: %s",
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index b49a158..251e7e4 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -32,20 +32,20 @@ static rufl_code rufl_process(rufl_action action,
int *width, int click_x, size_t *char_offset, int *actual_x,
rufl_callback_t callback, void *context);
static rufl_code rufl_process_span(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
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,
+ uint32_t *s, unsigned int n,
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,
+ uint32_t *s, unsigned int n,
unsigned int font_size, int *x, int y,
unsigned int flags,
int click_x, size_t *offset,
@@ -159,7 +159,7 @@ rufl_code rufl_process(rufl_action action,
int *width, int click_x, size_t *char_offset, int *actual_x,
rufl_callback_t callback, void *context)
{
- unsigned short s[rufl_PROCESS_CHUNK];
+ uint32_t s[rufl_PROCESS_CHUNK];
unsigned int font;
unsigned int font0, font1;
unsigned int n;
@@ -295,13 +295,13 @@ rufl_code rufl_process(rufl_action action,
*/
rufl_code rufl_process_span(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
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)
{
- unsigned short *split_point;
+ uint32_t *split_point;
int x_out, y_out;
unsigned int i;
char font_name[80];
@@ -327,10 +327,10 @@ rufl_code rufl_process_span(rufl_action action,
(oblique ? font_GIVEN_TRFM : 0) |
font_GIVEN_LENGTH |
font_GIVEN_FONT | font_KERN |
- font_GIVEN16_BIT |
+ font_GIVEN32_BIT |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, y, 0, &trfm_oblique, n * 2);
+ *x, y, 0, &trfm_oblique, n * 4);
if (rufl_fm_error) {
LOG("xfont_paint: 0x%x: %s",
rufl_fm_error->errnum,
@@ -350,19 +350,19 @@ rufl_code rufl_process_span(rufl_action action,
if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) {
rufl_fm_error = xfont_scan_string(f, (const char *) s,
font_GIVEN_LENGTH | font_GIVEN_FONT |
- font_KERN | font_GIVEN16_BIT |
+ font_KERN | font_GIVEN32_BIT |
((action == rufl_X_TO_OFFSET) ?
font_RETURN_CARET_POS : 0),
(click_x - *x) * 400, 0x7fffffff, 0, 0,
- n * 2,
+ n * 4,
(char **)(void *)&split_point,
&x_out, &y_out, 0);
*offset = split_point - s;
} else {
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,
+ font_KERN | font_GIVEN32_BIT,
+ 0x7fffffff, 0x7fffffff, 0, 0, n * 4,
0, &x_out, &y_out, 0);
}
if (rufl_fm_error) {
@@ -383,7 +383,7 @@ rufl_code rufl_process_span(rufl_action action,
*/
rufl_code rufl_process_span_old(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
unsigned int font, unsigned int font_size, unsigned int slant,
int *x, int y, unsigned int flags,
int click_x, size_t *offset,
@@ -546,28 +546,33 @@ 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,
+ uint32_t *s, unsigned int n,
unsigned int font_size, int *x, int y,
unsigned int flags,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char missing[] = "0000";
- int dx = 7 * font_size / 64;
+ char missing[] = "000000";
+ const int dx = 7 * font_size / 64;
+ const int dx3 = 10.5 * font_size / 64;
int top_y = y + 5 * font_size / 64;
unsigned int i;
font_f f;
rufl_code code;
if (action == rufl_WIDTH) {
- *x += n * dx;
+ for (i = 0; i != n; i++)
+ *x += (s[i] < 0x10000) ? dx : dx3;
return rufl_OK;
} else if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) {
- if (click_x - *x < (int) (n * dx))
- *offset = (click_x - *x) / dx;
- else
- *offset = n;
- *x += *offset * dx;
+ int width = 0;
+ for (i = 0; i != n; i++) {
+ if (click_x - *x <= width)
+ break;
+ width += (s[i] < 0x10000) ? dx : dx3;
+ }
+ *offset = i;
+ *x += width;
return rufl_OK;
}
@@ -576,45 +581,50 @@ rufl_code rufl_process_not_available(rufl_action action,
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];
+ int offset = (s[i] < 0x10000) ? 2 : 0;
+ int step = (s[i] < 0x10000) ? 2 : 3;
+
+ missing[0] = "0123456789abcdef"[(s[i] >> 20) & 0xf];
+ missing[1] = "0123456789abcdef"[(s[i] >> 16) & 0xf];
+ missing[2] = "0123456789abcdef"[(s[i] >> 12) & 0xf];
+ missing[3] = "0123456789abcdef"[(s[i] >> 8) & 0xf];
+ missing[4] = "0123456789abcdef"[(s[i] >> 4) & 0xf];
+ missing[5] = "0123456789abcdef"[(s[i] >> 0) & 0xf];
/* first two characters in top row */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing, font_OS_UNITS |
- font_GIVEN_LENGTH | font_GIVEN_FONT |
- font_KERN |
+ rufl_fm_error = xfont_paint(f, missing + offset,
+ font_OS_UNITS | font_GIVEN_LENGTH |
+ font_GIVEN_FONT | font_KERN |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, top_y, 0, 0, 2);
+ *x, top_y, 0, 0, step);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
} else {
callback(context, "Corpus.Medium\\ELatin1",
- font_size / 2, missing, 0, 2,
- *x, top_y);
+ font_size / 2, missing + offset, 0,
+ step, *x, top_y);
}
/* last two characters underneath */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing + 2,
+ rufl_fm_error = xfont_paint(f, missing + offset + step,
font_OS_UNITS |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, y, 0, 0, 2);
+ *x, y, 0, 0, step);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
} else {
callback(context, "Corpus.Medium\\ELatin1",
- font_size / 2, missing + 2, 0, 2,
- *x, y);
+ font_size / 2, missing + offset + step,
+ 0, step, *x, y);
}
- *x += dx;
+ *x += (s[i] < 0x10000) ? dx : dx3;
}
return rufl_OK;
diff --git a/test/rufl_test.c b/test/rufl_test.c
index 51a29d6..45af5b6 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -18,7 +18,7 @@ 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,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y);
@@ -131,7 +131,7 @@ int cubic_to(os_coord *control1, os_coord *control2, os_coord *to,
void callback(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned short *s16, unsigned int n,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y)
{
(void) context;
@@ -142,7 +142,7 @@ void callback(void *context,
else {
printf("s16 \"");
for (unsigned int i = 0; i != n; i++)
- printf("%x ", (unsigned int) s16[i]);
+ printf("%x ", (unsigned int) s32[i]);
printf("\" ");
}
printf("%i %i\n", x, y);
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=9bd774ec26a7a970192...
commit 9bd774ec26a7a97019210b6779105f58cb29788b
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Fix use after free
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 3ae4ffa..a9d2719 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -896,7 +896,7 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
return rufl_OUT_OF_MEMORY;
}
- rufl_font_list[font_index].charset = charset;
+ rufl_font_list[font_index].charset = charset2;
rufl_font_list[font_index].umap = umap;
rufl_font_list[font_index].num_umaps = num_umaps;
-----------------------------------------------------------------------
Summary of changes:
include/rufl.h | 2 +-
src/Makefile | 3 +-
src/rufl_dump_state.c | 25 +-
src/rufl_init.c | 838 +++++++++++++++++++++++++----------------
src/rufl_internal.h | 11 +-
src/rufl_metrics.c | 17 +-
src/rufl_paint.c | 92 ++---
src/rufl_quit.c | 3 +-
src/rufl_substitution_table.c | 708 ++++++++++++++++++++++++++++++++++
test/rufl_chars.c | 66 +++-
test/rufl_test.c | 9 +-
11 files changed, 1334 insertions(+), 440 deletions(-)
create mode 100644 src/rufl_substitution_table.c
diff --git a/include/rufl.h b/include/rufl.h
index 767022e..0164df8 100644
--- a/include/rufl.h
+++ b/include/rufl.h
@@ -124,7 +124,7 @@ rufl_code rufl_split(const char *font_family, rufl_style font_style,
/** Type of callback function for rufl_paint_callback(). */
typedef void (*rufl_callback_t)(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned short *s16, unsigned int n,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y);
diff --git a/src/Makefile b/src/Makefile
index 7592083..22df8df 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,8 @@
# Sources
DIR_SOURCES := rufl_character_set_test.c rufl_decompose.c rufl_dump_state.c \
rufl_find.c rufl_init.c rufl_invalidate_cache.c \
- rufl_metrics.c rufl_paint.c rufl_quit.c
+ rufl_metrics.c rufl_paint.c rufl_substitution_table.c \
+ rufl_quit.c
ifeq ($(toolchain),norcroft)
DIR_SOURCES := $(DIR_SOURCES) strfuncs.c
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index b03109c..13a1564 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -12,7 +12,6 @@
static void rufl_dump_character_set_list(
const struct rufl_character_set *charset);
static void rufl_dump_unicode_map(struct rufl_unicode_map *umap);
-static void rufl_dump_substitution_table(void);
/**
@@ -66,7 +65,7 @@ void rufl_dump_state(void)
}
printf("rufl_substitution_table:\n");
- rufl_dump_substitution_table();
+ rufl_substitution_table_dump();
}
@@ -132,25 +131,3 @@ void rufl_dump_unicode_map(struct rufl_unicode_map *umap)
for (i = 0; i != umap->entries; i++)
printf("%x:%x ", umap->map[i].u, umap->map[i].c);
}
-
-
-/**
- * Dump a representation of the substitution table to stdout.
- */
-
-void rufl_dump_substitution_table(void)
-{
- unsigned int font;
- unsigned int u, t;
-
- u = 0;
- while (u != 0x10000) {
- t = u;
- font = rufl_substitution_table[t];
- while (u != 0x10000 && font == rufl_substitution_table[u])
- u++;
- if (font != NOT_AVAILABLE)
- printf(" %x-%x => %u \"%s\"\n", t, u - 1,
- font, rufl_font_list[font].identifier);
- }
-}
diff --git a/src/rufl_init.c b/src/rufl_init.c
index 3ae4ffa..25753d6 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -31,10 +31,10 @@ unsigned int rufl_family_list_entries = 0;
struct rufl_family_map_entry *rufl_family_map = 0;
os_error *rufl_fm_error = 0;
void *rufl_family_menu = 0;
-unsigned short *rufl_substitution_table = 0;
struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE];
int rufl_cache_time = 0;
bool rufl_old_font_manager = false;
+static bool rufl_broken_font_enumerate_characters = false;
wimp_w rufl_status_w = 0;
char rufl_status_buffer[80];
@@ -73,17 +73,19 @@ static rufl_code rufl_init_add_font(const char *identifier,
const char *local_name);
static int rufl_weight_table_cmp(const void *keyval, const void *datum);
static rufl_code rufl_init_scan_font(unsigned int font);
-static rufl_code rufl_init_scan_font_no_enumerate(unsigned int font);
static bool rufl_is_space(unsigned int u);
static rufl_code rufl_init_scan_font_old(unsigned int font_index);
static rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
const char *encoding, struct rufl_character_set *charset,
struct rufl_unicode_map *umap, unsigned int *last);
-static rufl_code rufl_init_read_encoding(font_f font,
+static rufl_code rufl_init_populate_unicode_map(font_f f,
struct rufl_unicode_map *umap);
+static rufl_code rufl_init_read_encoding(font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw);
static int rufl_glyph_map_cmp(const void *keyval, const void *datum);
static int rufl_unicode_map_cmp(const void *z1, const void *z2);
-static rufl_code rufl_init_substitution_table(void);
static rufl_code rufl_save_cache(void);
static rufl_code rufl_load_cache(void);
static int rufl_font_list_cmp(const void *keyval, const void *datum);
@@ -101,7 +103,6 @@ static void rufl_init_status_close(void);
rufl_code rufl_init(void)
{
- bool rufl_broken_font_enumerate_characters = false;
unsigned int changes = 0;
unsigned int i;
int fm_version;
@@ -198,8 +199,6 @@ rufl_code rufl_init(void)
(float) i / rufl_font_list_entries);
if (rufl_old_font_manager)
code = rufl_init_scan_font_old(i);
- else if (rufl_broken_font_enumerate_characters)
- code = rufl_init_scan_font_no_enumerate(i);
else
code = rufl_init_scan_font(i);
if (code != rufl_OK) {
@@ -213,9 +212,9 @@ rufl_code rufl_init(void)
xhourglass_leds(2, 0, 0);
xhourglass_colours(0x0000ff, 0x00ffff, &old_sand, &old_glass);
- code = rufl_init_substitution_table();
+ code = rufl_substitution_table_init();
if (code != rufl_OK) {
- LOG("rufl_init_substitution_table: 0x%x", code);
+ LOG("rufl_substitution_table_init: 0x%x", code);
rufl_quit();
xhourglass_off();
return code;
@@ -436,43 +435,126 @@ int rufl_weight_table_cmp(const void *keyval, const void *datum)
return strcasecmp(key, entry->name);
}
-/**
- * Scan a font for available characters.
- */
+static struct rufl_character_set *rufl_init_alloc_plane(uint8_t index)
+{
+ struct rufl_character_set *charset;
+ unsigned int u;
-rufl_code rufl_init_scan_font(unsigned int font_index)
+ charset = calloc(1, sizeof *charset);
+ if (charset != NULL) {
+ /* Set plane ID. Extension/size must be filled in by caller */
+ charset->metadata |= ((index & 0x1f) << 26);
+ for (u = 0; u != 256; u++)
+ charset->index[u] = BLOCK_EMPTY;
+ }
+
+ return charset;
+}
+
+static void rufl_init_shrinkwrap_plane(struct rufl_character_set *charset)
+{
+ unsigned int last_used = PLANE_SIZE(charset->metadata);
+ unsigned int u, bit, byte;
+
+ /* Determine which blocks are full, and mark them as such */
+ for (u = 0; u != 256; u++) {
+ const unsigned int block = charset->index[u];
+
+ if (block == BLOCK_EMPTY)
+ continue;
+
+ bit = 0xff;
+
+ for (byte = 0; byte != 32; byte++)
+ bit &= charset->block[block][byte];
+
+ if (bit == 0xff) {
+ /* Block is full */
+
+ /* Find a block whose index is after this one.
+ * If such a block exists, move its data into
+ * this block, as this block's bitmap is now free
+ */
+ for (byte = 0; byte != 256; byte++) {
+ if (charset->index[byte] < BLOCK_EMPTY &&
+ charset->index[byte] > block) {
+ break;
+ }
+ }
+ if (byte != 256) {
+ memcpy(charset->block[block],
+ charset->block[
+ charset->index[byte]],
+ 32);
+ charset->index[byte] = block;
+ }
+
+ /* Now mark this block as full */
+ charset->index[u] = BLOCK_FULL;
+ last_used--;
+ }
+ }
+
+ /* Fill in this plane's size now we know it */
+ charset->metadata = (charset->metadata & 0xffff0000) |
+ (offsetof(struct rufl_character_set, block) +
+ 32 * last_used);
+}
+
+static struct rufl_character_set *rufl_init_shrinkwrap_planes(
+ struct rufl_character_set *planes[17])
{
- char font_name[80];
- int x_out, y_out;
- unsigned int byte, bit;
- unsigned int last_used = 0;
- unsigned int string[2] = { 0, 0 };
- unsigned int u, next;
struct rufl_character_set *charset;
- struct rufl_character_set *charset2;
- font_f font;
- font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
+ unsigned int size = 0, pos, u;
+
+ /* Shrink-wrap each plane, accumulating total required size as we go */
+ for (u = 0; u < 17; u++) {
+ if (planes[u]) {
+ LOG("shrink-wrapping plane %d", u);
+ rufl_init_shrinkwrap_plane(planes[u]);
+ size += PLANE_SIZE(planes[u]->metadata);
+ }
+ }
- /*LOG("font %u \"%s\"", font_index,
- rufl_font_list[font_index].identifier);*/
+ LOG("shrink-wrapped size: %u", size);
- charset = calloc(1, sizeof *charset);
+ charset = malloc(size);
if (!charset)
- return rufl_OUT_OF_MEMORY;
- for (u = 0; u != 256; u++)
- charset->index[u] = BLOCK_EMPTY;
+ return NULL;
- snprintf(font_name, sizeof font_name, "%s\\EUTF8",
- rufl_font_list[font_index].identifier);
+ /* Copy planes into output, backwards, setting the extension bit for
+ * all but the last plane present */
+ pos = size;
+ for (u = 17; u > 0; u--) {
+ if (!planes[u-1])
+ continue;
- rufl_fm_error = xfont_find_font(font_name, 160, 160, 0, 0, &font, 0, 0);
- if (rufl_fm_error) {
- LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
- free(charset);
- return rufl_OK;
+ LOG("merging plane %d", u);
+
+ /* Set E bit if not the last plane */
+ if (pos != size)
+ planes[u-1]->metadata |= (1u<<31);
+
+ pos -= PLANE_SIZE(planes[u-1]->metadata);
+ memcpy(((uint8_t *)charset) + pos, planes[u-1],
+ PLANE_SIZE(planes[u-1]->metadata));
}
+ return charset;
+}
+
+static rufl_code rufl_init_enumerate_characters(const char *font_name,
+ font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
+{
+ unsigned int u, next;
+ rufl_code result;
+
+ if (rufl_broken_font_enumerate_characters)
+ return rufl_init_read_encoding(font, callback, pw);
+
/* Scan through mapped characters */
for (u = 0; u != (unsigned int) -1; u = next) {
unsigned int internal;
@@ -485,133 +567,133 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
font_name, u,
rufl_fm_error->errnum,
rufl_fm_error->errmess);
- xfont_lose_font(font);
- free(charset);
- return rufl_OK;
+ break;
}
- /* Skip DELETE and C0/C1 controls */
- if (u < 0x0020 || (0x007f <= u && u <= 0x009f))
- continue;
-
- /* Skip astral characters */
- if (u > 0xffff)
- continue;
-
/* Skip unmapped characters */
if (internal == (unsigned int) -1)
continue;
- if (u % 0x200 == 0)
- rufl_init_status(0, 0);
-
- /* Character is mapped, let's see if it's really there */
- string[0] = u;
- rufl_fm_error = xfont_scan_string(font, (char *) string,
- font_RETURN_BBOX | font_GIVEN32_BIT |
- font_GIVEN_FONT | font_GIVEN_LENGTH |
- font_GIVEN_BLOCK,
- 0x7fffffff, 0x7fffffff,
- &block, 0, 4,
- 0, &x_out, &y_out, 0);
- if (rufl_fm_error)
+ /* Character is mapped, emit it */
+ result = callback(pw, internal, u);
+ if (result != rufl_OK)
break;
+ }
- 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 (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) {
- charset->index[u >> 8] = last_used;
- last_used++;
- if (last_used == 254)
- /* too many characters */
- break;
- }
+ return result;
+}
- byte = (u >> 3) & 31;
- bit = u & 7;
- charset->block[charset->index[u >> 8]][byte] |=
- 1 << bit;
- }
- }
+static rufl_code find_plane_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct rufl_character_set **planes = pw;
- xfont_lose_font(font);
+ (void) glyph_idx;
+
+ /* Skip DELETE and C0/C1 controls */
+ if (ucs4 > 0x0020 && (ucs4 < 0x007f || 0x009f < ucs4))
+ planes[(ucs4 >> 16) & 0x1f] = (struct rufl_character_set *) 1;
+
+ return rufl_OK;
+}
+struct find_glyph_ctx {
+ const char *font_name;
+ font_f font;
+ struct rufl_character_set **planes;
+};
+
+static rufl_code find_glyph_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct find_glyph_ctx *ctx = pw;
+ int x_out, y_out;
+ unsigned int string[2] = { 0, 0 };
+ font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
+
+ (void) glyph_idx;
+
+ /* Skip DELETE and C0/C1 controls */
+ if (ucs4 < 0x0020 || (0x007f <= ucs4 && ucs4 <= 0x009f))
+ return rufl_OK;
+
+ if (ucs4 % 0x200 == 0)
+ rufl_init_status(0, 0);
+
+ string[0] = ucs4;
+ rufl_fm_error = xfont_scan_string(ctx->font, (char *) string,
+ font_RETURN_BBOX | font_GIVEN32_BIT |
+ font_GIVEN_FONT | font_GIVEN_LENGTH |
+ font_GIVEN_BLOCK,
+ 0x7fffffff, 0x7fffffff,
+ &block, 0, 4,
+ 0, &x_out, &y_out, 0);
if (rufl_fm_error) {
- free(charset);
LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
- font_name, u,
+ ctx->font_name, ucs4,
rufl_fm_error->errnum, rufl_fm_error->errmess);
return rufl_FONT_MANAGER_ERROR;
}
- /* Determine which blocks are full, and mark them as such */
- for (u = 0; u != 256; u++) {
- if (charset->index[u] == BLOCK_EMPTY)
- continue;
-
- bit = 0xff;
-
- for (byte = 0; byte != 32; byte++)
- bit &= charset->block[u][byte];
-
- if (bit == 0xff) {
- /* Block is full */
- charset->index[u] = BLOCK_FULL;
-
- for (byte = 0; byte != 32; byte++)
- charset->block[u][byte] = 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 (empty) */
+ } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 &&
+ block.bbox.x1 == 0 && block.bbox.y1 == 0 &&
+ !rufl_is_space(ucs4)) {
+ /* absent (space but not a space character - some
+ * fonts do this) */
+ } else {
+ /* present */
+ const unsigned int plane = (ucs4 >> 16) & 0x1f;
+ const unsigned int blk = (ucs4 >> 8) & 0xff;
+ const unsigned int byte = (ucs4 >> 3) & 31;
+ const unsigned int bit = ucs4 & 7;
+
+ /* Allocate block, if it's currently empty */
+ if (ctx->planes[plane]->index[blk] == BLOCK_EMPTY) {
+ unsigned int last_used =
+ PLANE_SIZE(ctx->planes[plane]->metadata);
+ if (last_used < BLOCK_EMPTY) {
+ ctx->planes[plane]->index[blk] = last_used;
+ ctx->planes[plane]->metadata =
+ (ctx->planes[plane]->metadata &
+ 0xffff0000) |
+ (last_used + 1);
+ }
}
- }
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
- charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
- if (!charset2) {
- free(charset);
- return rufl_OUT_OF_MEMORY;
+ /* Set bit for codepoint in bitmap, if bitmap exists */
+ if (ctx->planes[plane]->index[blk] < BLOCK_EMPTY) {
+ ctx->planes[plane]->block[
+ ctx->planes[plane]->index[blk]
+ ][byte] |= 1 << bit;
+ }
}
- rufl_font_list[font_index].charset = charset;
-
return rufl_OK;
}
/**
- * Scan a font for available characters (version without character enumeration)
+ * Scan a font for available characters
*/
-rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
+rufl_code rufl_init_scan_font(unsigned int font_index)
{
char font_name[80];
- int x_out, y_out;
- unsigned int byte, bit;
- unsigned int block_count = 0;
- unsigned int last_used = 0;
- unsigned int string[2] = { 0, 0 };
- unsigned int u;
+ struct rufl_character_set *planes[17];
struct rufl_character_set *charset;
- struct rufl_character_set *charset2;
font_f font;
- font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } };
+ unsigned int plane;
+ struct find_glyph_ctx ctx;
+ rufl_code rc;
/*LOG("font %u \"%s\"", font_index,
rufl_font_list[font_index].identifier);*/
- charset = calloc(1, sizeof *charset);
- if (!charset)
- return rufl_OUT_OF_MEMORY;
+ for (plane = 0; plane < 17; plane++)
+ planes[plane] = NULL;
snprintf(font_name, sizeof font_name, "%s\\EUTF8",
rufl_font_list[font_index].identifier);
@@ -620,90 +702,55 @@ rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
if (rufl_fm_error) {
LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name,
rufl_fm_error->errnum, rufl_fm_error->errmess);
- free(charset);
return rufl_OK;
}
- /* scan through all characters */
- for (u = 0x0020; u != 0x10000; u++) {
- if (u == 0x007f) {
- /* skip DELETE and C1 controls */
- u = 0x009f;
- continue;
- }
-
- if (u % 0x200 == 0)
- rufl_init_status(0, 0);
-
- string[0] = u;
- rufl_fm_error = xfont_scan_string(font, (char *) string,
- font_RETURN_BBOX | font_GIVEN32_BIT |
- font_GIVEN_FONT | font_GIVEN_LENGTH |
- font_GIVEN_BLOCK,
- 0x7fffffff, 0x7fffffff,
- &block, 0, 4,
- 0, &x_out, &y_out, 0);
- if (rufl_fm_error)
- break;
-
- 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 (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;
- bit = u & 7;
- charset->block[last_used][byte] |= 1 << bit;
+ /* First pass: find the planes we need */
+ rc = rufl_init_enumerate_characters(font_name, font,
+ find_plane_cb, planes);
+ if (rc != rufl_OK)
+ return rc;
- block_count++;
- }
+ /* Allocate the planes */
+ for (plane = 0; plane < 17; plane++) {
+ if (!planes[plane])
+ continue;
- if ((u + 1) % 256 == 0) {
- /* end of block */
- if (block_count == 0)
- charset->index[u >> 8] = BLOCK_EMPTY;
- else if (block_count == 256) {
- charset->index[u >> 8] = BLOCK_FULL;
- for (byte = 0; byte != 32; byte++)
- charset->block[last_used][byte] = 0;
- } else {
- charset->index[u >> 8] = last_used;
- last_used++;
- if (last_used == 254)
- /* too many characters */
- break;
- }
- block_count = 0;
+ planes[plane] = rufl_init_alloc_plane(plane);
+ if (!planes[plane]) {
+ while (plane > 0)
+ free(planes[plane-1]);
+ xfont_lose_font(font);
+ return rufl_OUT_OF_MEMORY;
}
}
- xfont_lose_font(font);
+ /* Second pass: populate the planes */
+ ctx.font_name = font_name;
+ ctx.font = font;
+ ctx.planes = planes;
- if (rufl_fm_error) {
- free(charset);
- LOG("xfont_scan_string(\"%s\", U+%x, ...): 0x%x: %s",
- font_name, u,
- rufl_fm_error->errnum, rufl_fm_error->errmess);
- return rufl_FONT_MANAGER_ERROR;
+ rc = rufl_init_enumerate_characters(font_name, font,
+ find_glyph_cb, &ctx);
+ if (rc != rufl_OK) {
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
+ xfont_lose_font(font);
+ return rc;
}
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
- charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
- if (!charset2) {
- free(charset);
+ xfont_lose_font(font);
+
+ charset = rufl_init_shrinkwrap_planes(planes);
+ if (!charset) {
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
return rufl_OUT_OF_MEMORY;
}
+ for (plane = 0; plane < 17; plane++)
+ free(planes[plane]);
+
rufl_font_list[font_index].charset = charset;
return rufl_OK;
@@ -723,6 +770,9 @@ bool rufl_is_space(unsigned int u)
/**
* Scan a font for available characters (old font manager version).
+ * By definition, no astral characters are supported when using a non-UCS
+ * Font Manager (font encodings are defined using PostScript glyph names
+ * which, per the Glyph list, can only fall in the Basic Multilingual Plane)
*/
rufl_code rufl_init_scan_font_old(unsigned int font_index)
@@ -884,9 +934,11 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
return rufl_OK;
}
- /* shrink-wrap */
- charset->metadata = offsetof(struct rufl_character_set, block) +
- 32 * last_used;
+ /* Shrink-wrap. We only have the one plane so fill in last_used
+ * as expected by the shrinkwrapping helper and then resize the
+ * resulting charset manually. */
+ charset->metadata = (charset->metadata & 0xffff0000) | last_used;
+ rufl_init_shrinkwrap_plane(charset);
charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
if (!charset2) {
for (i = 0; i < num_umaps; i++)
@@ -896,7 +948,7 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
return rufl_OUT_OF_MEMORY;
}
- rufl_font_list[font_index].charset = charset;
+ rufl_font_list[font_index].charset = charset2;
rufl_font_list[font_index].umap = umap;
rufl_font_list[font_index].num_umaps = num_umaps;
@@ -935,7 +987,7 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
return rufl_FONT_MANAGER_ERROR;
}
- code = rufl_init_read_encoding(font, umap);
+ code = rufl_init_populate_unicode_map(font, umap);
if (code != rufl_OK) {
LOG("rufl_init_read_encoding(\"%s\", ...): 0x%x",
buf, code);
@@ -1003,27 +1055,171 @@ rufl_code rufl_init_scan_font_in_encoding(const char *font_name,
return rufl_OK;
}
+static rufl_code rufl_init_umap_cb(void *pw, uint32_t glyph_idx, uint32_t ucs4)
+{
+ struct rufl_unicode_map *umap = pw;
+ rufl_code result = rufl_OK;
+
+ /* Ignore first 32 character codes (these are control chars) */
+ if (glyph_idx > 31 && glyph_idx < 256 && umap->entries < 256) {
+ umap->map[umap->entries].u = ucs4;
+ umap->map[umap->entries].c = glyph_idx;
+ umap->entries++;
+ if (umap->entries == 256)
+ result = rufl_IO_EOF;
+ }
+
+ return result;
+}
/**
- * Parse an encoding file and fill in a rufl_unicode_map.
+ * Populate a unicode map by parsing the font's encoding file
*/
-rufl_code rufl_init_read_encoding(font_f font,
+rufl_code rufl_init_populate_unicode_map(font_f f,
struct rufl_unicode_map *umap)
{
+ rufl_code result;
+
+ umap->entries = 0;
+
+ result = rufl_init_read_encoding(f, rufl_init_umap_cb, &umap);
+ if (result == rufl_OK) {
+ /* sort by unicode */
+ qsort(umap->map, umap->entries, sizeof umap->map[0],
+ rufl_unicode_map_cmp);
+ }
+ return result;
+}
+
+static int fromhex(char val, bool permit_lc)
+{
+ if ('0' <= val && val <= '9')
+ return val - '0';
+ else if ('A' <= val && val <= 'F')
+ return val - 'A' + 10;
+ else if (permit_lc && 'a' <= val && val <= 'f')
+ return val - 'a' + 10;
+ return -1;
+}
+
+static rufl_code emit_codepoint(char s[200], unsigned int i,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
+{
+ struct rufl_glyph_map_entry *entry;
+ rufl_code result = rufl_OK;
+
+ if (s[0] != '/') {
+ /* Sparse encoding entry: [XX;]XXXX;NNN..;.... */
+ uint32_t val = 0;
+ int digits;
+
+ if (s[2] == ';' && fromhex(s[0], true) != -1 &&
+ fromhex(s[1], true) != -1) {
+ /* Skip leading "XX;" */
+ s += 3;
+ }
+
+ for (digits = 0; digits < 4; digits++) {
+ int nibble = fromhex(s[digits], true);
+ if (nibble == -1)
+ break;
+ val = (val << 4) | nibble;
+ }
+
+ /* Bail out if the data is not what we expect */
+ if (digits != 4 || s[digits] != ';')
+ return result;
+
+ /* Set the glyph index to the value we found */
+ i = val;
+ /* Advance s to the start of the glyph name */
+ s += digits + 1;
+ /* Terminate the glyph name */
+ for (digits = 0; s[digits] != '\0'; digits++) {
+ if (s[digits] == ';') {
+ s[digits] = '\0';
+ break;
+ }
+ }
+ /* Fall through to the glyph name search */
+ } else {
+ /* Skip the leading / */
+ s += 1;
+
+ if (!rufl_old_font_manager && s[0] == 'u') {
+ /* Handle /uniXXXX and /uXXXX - /uXXXXXXXX.
+ * In the case of /uXXXXX - /uXXXXXXXX, no
+ * leading zeroes are permitted. */
+ int max_digits = 8, off = 1, digits = 0;
+ bool leading_zero = false;
+ uint32_t val = 0;
+
+ if (s[1] == 'n' && s[2] == 'i') {
+ max_digits = 4;
+ off = 3;
+ }
+
+ while (digits < max_digits) {
+ int nibble = fromhex(s[off], false);
+ if (nibble == -1)
+ break;
+ leading_zero = (digits == 0 && nibble == 0);
+ val = (val << 4) | nibble;
+ off++;
+ digits++;
+ }
+ if ((digits == 4 && s[off] == '\0') ||
+ (digits > 4 && s[off] == '\0' &&
+ !leading_zero)) {
+ return callback(pw, i, val);
+ }
+
+ /* Otherwise, let the glyph name search decide */
+ }
+ }
+
+ entry = bsearch(s, rufl_glyph_map,
+ rufl_glyph_map_size,
+ sizeof rufl_glyph_map[0],
+ rufl_glyph_map_cmp);
+ if (entry) {
+ /* may be more than one unicode for the glyph
+ * sentinels stop overshooting array */
+ while (strcmp(s, (entry - 1)->glyph_name) == 0)
+ entry--;
+ for (; strcmp(s, entry->glyph_name) == 0; entry++) {
+ result = callback(pw, i, entry->u);
+ if (result != rufl_OK)
+ break;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Parse an encoding file
+ */
+
+rufl_code rufl_init_read_encoding(font_f font,
+ rufl_code (*callback)(void *pw,
+ uint32_t glyph_idx, uint32_t ucs4),
+ void *pw)
+{
enum {
STATE_START,
STATE_COMMENT,
STATE_COLLECT,
} state = STATE_START;
- bool emit = false;
- unsigned int u = 0;
+ bool emit = false, done = false;
unsigned int i = 0;
unsigned int n = 0;
int c;
char filename[200];
char s[200];
- struct rufl_glyph_map_entry *entry;
FILE *fp;
rufl_fm_error = xfont_read_encoding_filename(font, filename,
@@ -1035,18 +1231,32 @@ rufl_code rufl_init_read_encoding(font_f font,
}
fp = fopen(filename, "r");
- if (!fp)
- /* many "symbol" fonts have no encoding file: assume Latin 1 */
- fp = fopen("Resources:$.Fonts.Encodings.Latin1", "r");
+ if (!fp) {
+ /* many "symbol" fonts have no encoding file */
+ const char *default_path =
+ "Resources:$.Fonts.Encodings./Default";
+ if (rufl_old_font_manager)
+ default_path = "Resources:$.Fonts.Encodings.Latin1";
+ fp = fopen(default_path, "r");
+ }
if (!fp)
return rufl_IO_ERROR;
- while (!feof(fp) && i < 256 && u < 256) {
+ while (!feof(fp) && !done) {
c = fgetc(fp);
if (state == STATE_START) {
if (c == '/') {
- n = 0;
+ s[0] = c;
+ n = 1;
+ state = STATE_COLLECT;
+ } else if (!rufl_old_font_manager &&
+ (('0' <= c && c <= '9') ||
+ ('A' <= c && c <= 'F') ||
+ ('a' <= c && c <= 'f'))) {
+ /* New-style sparse encoding file */
+ s[0] = c;
+ n = 1;
state = STATE_COLLECT;
} else if (c <= 0x20) {
/* Consume C0 and space */
@@ -1063,7 +1273,8 @@ rufl_code rufl_init_read_encoding(font_f font,
if ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
- (c == '.') || (c == '_')) {
+ (c == '.') || (c == '_') ||
+ (c == ';')) {
/* Printable: append */
s[n++] = c;
if (n >= sizeof(s)) {
@@ -1083,41 +1294,17 @@ rufl_code rufl_init_read_encoding(font_f font,
}
}
- /* Ignore first 32 character codes (these are control chars) */
- if (emit && i > 31 && i < 256 && u < 256) {
- entry = bsearch(s, rufl_glyph_map,
- rufl_glyph_map_size,
- sizeof rufl_glyph_map[0],
- rufl_glyph_map_cmp);
- if (entry) {
- /* may be more than one unicode for the glyph
- * sentinels stop overshooting array */
- while (strcmp(s, (entry - 1)->glyph_name) == 0)
- entry--;
- for (; strcmp(s, entry->glyph_name) == 0;
- entry++) {
- umap->map[u].u = entry->u;
- umap->map[u].c = i;
- u++;
- if (u == 256)
- break;
- }
- }
- }
-
if (emit) {
- i++;
emit = false;
+ if (emit_codepoint(s, i, callback, pw) != rufl_OK)
+ done = true;
+ i++;
}
}
if (fclose(fp) == EOF)
return rufl_IO_ERROR;
- /* sort by unicode */
- qsort(umap->map, u, sizeof umap->map[0], rufl_unicode_map_cmp);
- umap->entries = u;
-
return rufl_OK;
}
@@ -1143,66 +1330,6 @@ int rufl_unicode_map_cmp(const void *z1, const void *z2)
/**
- * Construct the font substitution table.
- */
-
-rufl_code rufl_init_substitution_table(void)
-{
- unsigned char z;
- unsigned int i;
- unsigned int block, byte, bit;
- unsigned int u;
- unsigned int index;
- const struct rufl_character_set *charset;
-
- rufl_substitution_table = malloc(65536 *
- sizeof rufl_substitution_table[0]);
- if (!rufl_substitution_table) {
- LOG("malloc(%zu) failed", 65536 *
- sizeof rufl_substitution_table[0]);
- return rufl_OUT_OF_MEMORY;
- }
-
- for (u = 0; u != 0x10000; u++)
- rufl_substitution_table[u] = NOT_AVAILABLE;
-
- for (i = 0; i != rufl_font_list_entries; i++) {
- charset = rufl_font_list[i].charset;
- if (!charset)
- continue;
- for (block = 0; block != 256; block++) {
- if (charset->index[block] == BLOCK_EMPTY)
- continue;
- if (charset->index[block] == BLOCK_FULL) {
- for (u = block << 8; u != (block << 8) + 256;
- u++) {
- if (rufl_substitution_table[u] ==
- NOT_AVAILABLE)
- rufl_substitution_table[u] = i;
- }
- continue;
- }
- index = charset->index[block];
- for (byte = 0; byte != 32; byte++) {
- z = charset->block[index][byte];
- if (z == 0)
- continue;
- u = (block << 8) | (byte << 3);
- for (bit = 0; bit != 8; bit++, u++) {
- if (rufl_substitution_table[u] ==
- NOT_AVAILABLE &&
- z & (1 << bit))
- rufl_substitution_table[u] = i;
- }
- }
- }
- }
-
- return rufl_OK;
-}
-
-
-/**
* Save character sets to cache.
*/
@@ -1235,7 +1362,10 @@ rufl_code rufl_save_cache(void)
}
for (i = 0; i != rufl_font_list_entries; i++) {
- if (!rufl_font_list[i].charset)
+ const struct rufl_character_set *charset =
+ rufl_font_list[i].charset;
+
+ if (!charset)
continue;
/* length of font identifier */
@@ -1253,9 +1383,26 @@ rufl_code rufl_save_cache(void)
return rufl_OK;
}
- /* character set */
- if (fwrite(rufl_font_list[i].charset,
- PLANE_SIZE(rufl_font_list[i].charset->metadata),
+ /* character set (all planes) */
+ LOG("writing character sets for %s",
+ rufl_font_list[i].identifier);
+ while (EXTENSION_FOLLOWS(charset->metadata)) {
+ LOG("writing plane %d (%u)",
+ PLANE_ID(charset->metadata),
+ PLANE_SIZE(charset->metadata));
+ if (fwrite(charset, PLANE_SIZE(charset->metadata),
+ 1, fp) != 1) {
+ LOG("fwrite: 0x%x: %s", errno, strerror(errno));
+ fclose(fp);
+ return rufl_OK;
+ }
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ LOG("writing plane %d (%u)",
+ PLANE_ID(charset->metadata),
+ PLANE_SIZE(charset->metadata));
+ if (fwrite(charset, PLANE_SIZE(charset->metadata),
1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
fclose(fp);
@@ -1339,10 +1486,11 @@ rufl_code rufl_load_cache(void)
unsigned int i = 0;
bool old_font_manager;
char *identifier;
- size_t len, size;
+ size_t len, size = 0;
+ uint32_t metadata;
FILE *fp;
struct rufl_font_list_entry *entry;
- struct rufl_character_set *charset;
+ struct rufl_character_set *charset = NULL, *cur_charset;
struct rufl_unicode_map *umap = NULL;
unsigned int num_umaps = 0;
@@ -1414,33 +1562,56 @@ rufl_code rufl_load_cache(void)
identifier[len] = 0;
/* character set */
- if (fread(&size, sizeof size, 1, fp) != 1) {
- if (feof(fp))
- LOG("fread: %s", "unexpected eof");
- else
- LOG("fread: 0x%x: %s", errno, strerror(errno));
- free(identifier);
- break;
- }
+ LOG("reading character sets for %s", identifier);
+ do {
+ if (fread(&metadata, sizeof metadata, 1, fp) != 1) {
+ if (feof(fp))
+ LOG("fread: %s", "unexpected eof");
+ else
+ LOG("fread: 0x%x: %s",
+ errno, strerror(errno));
+ free(identifier);
+ break;
+ }
- charset = malloc(size);
- if (!charset) {
- LOG("malloc(%zu) failed", size);
- free(identifier);
- fclose(fp);
- return rufl_OUT_OF_MEMORY;
- }
+ LOG("reading plane %d (%u)",
+ PLANE_ID(metadata),
+ PLANE_SIZE(metadata));
+ if (!charset) {
+ charset = cur_charset = malloc(
+ PLANE_SIZE(metadata));
+ } else {
+ struct rufl_character_set *c2 = realloc(charset,
+ size + PLANE_SIZE(metadata));
+ if (!c2) {
+ free(charset);
+ }
+ charset = c2;
+ cur_charset = (void *)(((uint8_t *) charset) +
+ size);
+ }
+ if (!charset) {
+ LOG("malloc(%zu) failed", size);
+ free(identifier);
+ fclose(fp);
+ return rufl_OUT_OF_MEMORY;
+ }
- charset->metadata = size;
- if (fread(charset->index, size - sizeof size, 1, fp) != 1) {
- if (feof(fp))
- LOG("fread: %s", "unexpected eof");
- else
- LOG("fread: 0x%x: %s", errno, strerror(errno));
- free(charset);
- free(identifier);
- break;
- }
+ size += PLANE_SIZE(metadata);
+ cur_charset->metadata = metadata;
+ if (fread(cur_charset->index,
+ PLANE_SIZE(metadata) - sizeof metadata,
+ 1, fp) != 1) {
+ if (feof(fp))
+ LOG("fread: %s", "unexpected eof");
+ else
+ LOG("fread: 0x%x: %s",
+ errno, strerror(errno));
+ free(charset);
+ free(identifier);
+ break;
+ }
+ } while(EXTENSION_FOLLOWS(cur_charset->metadata));
/* unicode map */
if (rufl_old_font_manager) {
@@ -1572,6 +1743,9 @@ rufl_code rufl_load_cache(void)
free(charset);
}
+ charset = NULL;
+ size = 0;
+
free(identifier);
}
fclose(fp);
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 9c7d46e..6cf6b14 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -158,10 +158,7 @@ extern struct rufl_family_map_entry *rufl_family_map;
/** No font contains this character. */
-#define NOT_AVAILABLE 65535
-/** Font substitution table. */
-extern unsigned short *rufl_substitution_table;
-
+#define NOT_AVAILABLE 0xffff
/** Number of slots in recent-use cache. This is the maximum number of RISC OS
* font handles that will be used at any time by the library. */
@@ -203,6 +200,10 @@ rufl_code rufl_find_font(unsigned int font, unsigned int font_size,
bool rufl_character_set_test(const struct rufl_character_set *charset,
uint32_t u);
+rufl_code rufl_substitution_table_init(void);
+void rufl_substitution_table_fini(void);
+unsigned int rufl_substitution_table_lookup(uint32_t u);
+void rufl_substitution_table_dump(void);
#define rufl_utf8_read(s, l, u) \
if (4 <= l && ((s[0] & 0xf8) == 0xf0) && ((s[1] & 0xc0) == 0x80) && \
@@ -235,7 +236,7 @@ bool rufl_character_set_test(const struct rufl_character_set *charset,
}
#define rufl_CACHE "<Wimp$ScrapDir>.RUfl_cache"
-#define rufl_CACHE_VERSION 3
+#define rufl_CACHE_VERSION 4
struct rufl_glyph_map_entry {
diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c
index 468f671..0637ddb 100644
--- a/src/rufl_metrics.c
+++ b/src/rufl_metrics.c
@@ -121,7 +121,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
{
const char *font_encoding = NULL;
unsigned int font, font1, u;
- unsigned short u1[2];
+ uint32_t u1[2];
struct rufl_character_set *charset;
struct rufl_unicode_map_entry *umap_entry = NULL;
font_f f;
@@ -139,10 +139,11 @@ rufl_code rufl_glyph_metrics(const char *font_family,
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;
+ else {
+ font1 = rufl_substitution_table_lookup(u);
+ if (font1 == NOT_AVAILABLE)
+ font1 = rufl_CACHE_CORPUS;
+ }
/* Old font managers need the font encoding, too */
if (rufl_old_font_manager && font1 != rufl_CACHE_CORPUS) {
@@ -235,7 +236,7 @@ rufl_code rufl_glyph_metrics(const char *font_family,
flags = font_GIVEN_BLOCK | font_GIVEN_LENGTH | font_GIVEN_FONT |
font_RETURN_BBOX;
- u1[0] = (unsigned short)u;
+ u1[0] = u;
u1[1] = 0;
if (font1 == rufl_CACHE_CORPUS) {
@@ -266,8 +267,8 @@ rufl_code rufl_glyph_metrics(const char *font_family,
} else {
/* UCS Font Manager */
rufl_fm_error = xfont_scan_string(f, (const char *)u1,
- flags | font_GIVEN16_BIT,
- 0x7fffffff, 0x7fffffff, &block, 0, 2,
+ flags | font_GIVEN32_BIT,
+ 0x7fffffff, 0x7fffffff, &block, 0, 4,
0, &xa, &ya, 0);
if (rufl_fm_error) {
LOG("xfont_scan_string: 0x%x: %s",
diff --git a/src/rufl_paint.c b/src/rufl_paint.c
index b49a158..360baec 100644
--- a/src/rufl_paint.c
+++ b/src/rufl_paint.c
@@ -32,20 +32,20 @@ static rufl_code rufl_process(rufl_action action,
int *width, int click_x, size_t *char_offset, int *actual_x,
rufl_callback_t callback, void *context);
static rufl_code rufl_process_span(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
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,
+ uint32_t *s, unsigned int n,
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,
+ uint32_t *s, unsigned int n,
unsigned int font_size, int *x, int y,
unsigned int flags,
int click_x, size_t *offset,
@@ -159,7 +159,7 @@ rufl_code rufl_process(rufl_action action,
int *width, int click_x, size_t *char_offset, int *actual_x,
rufl_callback_t callback, void *context)
{
- unsigned short s[rufl_PROCESS_CHUNK];
+ uint32_t s[rufl_PROCESS_CHUNK];
unsigned int font;
unsigned int font0, font1;
unsigned int n;
@@ -225,10 +225,8 @@ rufl_code rufl_process(rufl_action action,
font1 = NOT_AVAILABLE;
else if (charset && rufl_character_set_test(charset, u))
font1 = font;
- else if (u < 0x10000)
- font1 = rufl_substitution_table[u];
else
- font1 = NOT_AVAILABLE;
+ font1 = rufl_substitution_table_lookup(u);
do {
s[0] = u;
offset_map[0] = offset_u;
@@ -244,10 +242,8 @@ rufl_code rufl_process(rufl_action action,
font1 = NOT_AVAILABLE;
else if (charset && rufl_character_set_test(charset, u))
font1 = font;
- else if (u < 0x10000)
- font1 = rufl_substitution_table[u];
else
- font1 = NOT_AVAILABLE;
+ font1 = rufl_substitution_table_lookup(u);
if (font1 == font0)
n++;
}
@@ -295,13 +291,13 @@ rufl_code rufl_process(rufl_action action,
*/
rufl_code rufl_process_span(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
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)
{
- unsigned short *split_point;
+ uint32_t *split_point;
int x_out, y_out;
unsigned int i;
char font_name[80];
@@ -327,10 +323,10 @@ rufl_code rufl_process_span(rufl_action action,
(oblique ? font_GIVEN_TRFM : 0) |
font_GIVEN_LENGTH |
font_GIVEN_FONT | font_KERN |
- font_GIVEN16_BIT |
+ font_GIVEN32_BIT |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, y, 0, &trfm_oblique, n * 2);
+ *x, y, 0, &trfm_oblique, n * 4);
if (rufl_fm_error) {
LOG("xfont_paint: 0x%x: %s",
rufl_fm_error->errnum,
@@ -350,19 +346,19 @@ rufl_code rufl_process_span(rufl_action action,
if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) {
rufl_fm_error = xfont_scan_string(f, (const char *) s,
font_GIVEN_LENGTH | font_GIVEN_FONT |
- font_KERN | font_GIVEN16_BIT |
+ font_KERN | font_GIVEN32_BIT |
((action == rufl_X_TO_OFFSET) ?
font_RETURN_CARET_POS : 0),
(click_x - *x) * 400, 0x7fffffff, 0, 0,
- n * 2,
+ n * 4,
(char **)(void *)&split_point,
&x_out, &y_out, 0);
*offset = split_point - s;
} else {
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,
+ font_KERN | font_GIVEN32_BIT,
+ 0x7fffffff, 0x7fffffff, 0, 0, n * 4,
0, &x_out, &y_out, 0);
}
if (rufl_fm_error) {
@@ -383,7 +379,7 @@ rufl_code rufl_process_span(rufl_action action,
*/
rufl_code rufl_process_span_old(rufl_action action,
- unsigned short *s, unsigned int n,
+ uint32_t *s, unsigned int n,
unsigned int font, unsigned int font_size, unsigned int slant,
int *x, int y, unsigned int flags,
int click_x, size_t *offset,
@@ -546,28 +542,33 @@ 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,
+ uint32_t *s, unsigned int n,
unsigned int font_size, int *x, int y,
unsigned int flags,
int click_x, size_t *offset,
rufl_callback_t callback, void *context)
{
- char missing[] = "0000";
- int dx = 7 * font_size / 64;
+ char missing[] = "000000";
+ const int dx = 7 * font_size / 64;
+ const int dx3 = 10.5 * font_size / 64;
int top_y = y + 5 * font_size / 64;
unsigned int i;
font_f f;
rufl_code code;
if (action == rufl_WIDTH) {
- *x += n * dx;
+ for (i = 0; i != n; i++)
+ *x += (s[i] < 0x10000) ? dx : dx3;
return rufl_OK;
} else if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) {
- if (click_x - *x < (int) (n * dx))
- *offset = (click_x - *x) / dx;
- else
- *offset = n;
- *x += *offset * dx;
+ int width = 0;
+ for (i = 0; i != n; i++) {
+ if (click_x - *x <= width)
+ break;
+ width += (s[i] < 0x10000) ? dx : dx3;
+ }
+ *offset = i;
+ *x += width;
return rufl_OK;
}
@@ -576,45 +577,50 @@ rufl_code rufl_process_not_available(rufl_action action,
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];
+ int offset = (s[i] < 0x10000) ? 2 : 0;
+ int step = (s[i] < 0x10000) ? 2 : 3;
+
+ missing[0] = "0123456789abcdef"[(s[i] >> 20) & 0xf];
+ missing[1] = "0123456789abcdef"[(s[i] >> 16) & 0xf];
+ missing[2] = "0123456789abcdef"[(s[i] >> 12) & 0xf];
+ missing[3] = "0123456789abcdef"[(s[i] >> 8) & 0xf];
+ missing[4] = "0123456789abcdef"[(s[i] >> 4) & 0xf];
+ missing[5] = "0123456789abcdef"[(s[i] >> 0) & 0xf];
/* first two characters in top row */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing, font_OS_UNITS |
- font_GIVEN_LENGTH | font_GIVEN_FONT |
- font_KERN |
+ rufl_fm_error = xfont_paint(f, missing + offset,
+ font_OS_UNITS | font_GIVEN_LENGTH |
+ font_GIVEN_FONT | font_KERN |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, top_y, 0, 0, 2);
+ *x, top_y, 0, 0, step);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
} else {
callback(context, "Corpus.Medium\\ELatin1",
- font_size / 2, missing, 0, 2,
- *x, top_y);
+ font_size / 2, missing + offset, 0,
+ step, *x, top_y);
}
/* last two characters underneath */
if (action == rufl_PAINT) {
- rufl_fm_error = xfont_paint(f, missing + 2,
+ rufl_fm_error = xfont_paint(f, missing + offset + step,
font_OS_UNITS |
font_GIVEN_LENGTH | font_GIVEN_FONT |
font_KERN |
((flags & rufl_BLEND_FONT) ?
font_BLEND_FONT : 0),
- *x, y, 0, 0, 2);
+ *x, y, 0, 0, step);
if (rufl_fm_error)
return rufl_FONT_MANAGER_ERROR;
} else {
callback(context, "Corpus.Medium\\ELatin1",
- font_size / 2, missing + 2, 0, 2,
- *x, y);
+ font_size / 2, missing + offset + step,
+ 0, step, *x, y);
}
- *x += dx;
+ *x += (s[i] < 0x10000) ? dx : dx3;
}
return rufl_OK;
diff --git a/src/rufl_quit.c b/src/rufl_quit.c
index cacc9c5..ed03128 100644
--- a/src/rufl_quit.c
+++ b/src/rufl_quit.c
@@ -44,6 +44,5 @@ void rufl_quit(void)
free(rufl_family_menu);
rufl_family_menu = 0;
- free(rufl_substitution_table);
- rufl_substitution_table = 0;
+ rufl_substitution_table_fini();
}
diff --git a/src/rufl_substitution_table.c b/src/rufl_substitution_table.c
new file mode 100644
index 0000000..51c5b7a
--- /dev/null
+++ b/src/rufl_substitution_table.c
@@ -0,0 +1,708 @@
+/*
+ * This file is part of RUfl
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ * Copyright 2006 James Bursa <james(a)semichrome.net>
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include "rufl_internal.h"
+
+#undef RUFL_SUBSTITUTION_TABLE_DEBUG
+
+/**
+ * A perfect hash constructed at library initialisation time using the
+ * CHD algorithm. Hash entries are found via a two-step process:
+ *
+ * 1. apply a first-stage hash to the key to find the bucket
+ * in which the corresponding entry should be found.
+ * 2. apply a second-stage hash to the key and the stored
+ * displacement value for the bucket to find the index
+ * into the substitution table.
+ */
+struct rufl_substitution_table {
+ uint32_t num_buckets; /**< Number of buckets in the hash */
+ uint32_t num_slots; /**< Number of slots in the table */
+ /** Substitution table.
+ *
+ * Fields in the substitution table have the following format:
+ *
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Unicode codepoint |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Font identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * where:
+ *
+ * reserved: 11 bits/16 bits
+ * These bits are currently unused and must be set to 0.
+ *
+ * unicode codepoint: 21 bits
+ * The Unicode codepoint value.
+ *
+ * font identifier: 16 bits
+ * The index into rufl_font_list of a font providing a
+ * substitution glyph for this codepoint or NOT_AVAILABLE.
+ *
+ * Note that, as the substitution table is sparse and may not be
+ * fully populated, it is necessary to verify that the Unicode
+ * codepoint matches the key being hashed and that the font
+ * identifier is not NOT_AVAILABLE. If either of these tests
+ * fail, no font provides a suitable glyph and the not available
+ * path should be taken.
+ */
+ uint64_t *table;
+ uint8_t bits_per_entry; /**< Bits per displacement bitmap entry */
+ /** Displacement bitmap.
+ *
+ * The displacement values are stored in a bitmap of num_buckets
+ * fields each being bits_per_entry wide. Both values are computed
+ * at runtime.
+ */
+ uint8_t displacement_map[];
+};
+/** Font substitution table */
+static struct rufl_substitution_table *rufl_substitution_table;
+
+/**
+ * Round an unsigned 32bit value up to the next power of 2
+ */
+static uint32_t ceil2(uint32_t val)
+{
+ val--;
+ val |= (val >> 1);
+ val |= (val >> 2);
+ val |= (val >> 4);
+ val |= (val >> 8);
+ val |= (val >> 16);
+ val++;
+ val += (val == 0);
+ return val;
+}
+
+/**
+ * Compute the number of bits needed to store a value
+ */
+static uint32_t bits_needed(uint32_t val)
+{
+ int32_t result = 0;
+
+ if (val == 0)
+ return 1;
+
+ if ((val & (val - 1))) {
+ /* Not a power of 2: round up */
+ val = ceil2(val);
+ /* Will need one fewer bit than we're about to count */
+ result = -1;
+ }
+
+ while (val > 0) {
+ result += 1;
+ val >>= 1;
+ }
+
+ return (uint32_t) result;
+}
+
+/**
+ * Perform one round of MurmurHash2
+ */
+static uint32_t mround(uint32_t val, uint32_t s)
+{
+ val *= 0x5db1e995;
+ val ^= (val >> 24);
+ val *= 0x5db1e995;
+ val ^= (s * 0x5db1e995);
+
+ return val;
+}
+
+/**
+ * Perform the MurmurHash2 mixing step
+ */
+static uint32_t mmix(uint32_t val)
+{
+ val ^= (val >> 13);
+ val *= 0x5db1e995;
+ val ^= (val >> 15);
+
+ return val;
+}
+
+/**
+ * First-stage hash (i.e. g(x)) for substitution table.
+ *
+ * As we know that the input values are Unicode codepoints,
+ * do some trivial bit manipulation, which has reasonable
+ * distribution properties.
+ */
+static uint32_t hash1(uint32_t val)
+{
+ val ^= (val >> 7);
+ val ^= (val << 3);
+ val ^= (val >> 4);
+ return val;
+}
+
+/**
+ * Second-stage hash (i.e. f(d, x)) for substitution table.
+ *
+ * Apply MurmurHash2 to the value and displacement
+ */
+static uint32_t hash2(uint32_t val, uint32_t d)
+{
+ return mmix(mround(val, mround(d, 4)));
+}
+
+/**
+ * Comparison function for table entries.
+ *
+ * We use this when sorting the intermediate table for CHD.
+ */
+static int table_chd_cmp(const void *a, const void *b)
+{
+ /* We're only interested in the CHD metadata here.
+ * (i.e. the computed value of g(x) and the bucket size) */
+ const uint64_t aa = (*(const uint64_t *) a) & 0x3fe00000ffff0000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x3fe00000ffff0000llu;
+
+ if (aa > bb)
+ return -1;
+ else if (aa < bb)
+ return 1;
+ return 0;
+}
+
+/**
+ * Test that all specified bits in a bit map are clear and set them if so.
+ *
+ * \param bitmap Bit map to inspect
+ * \param idx Table of indices to inspect
+ * \param len Number of entries in index table
+ * \return True if all bits were clear. False otherwise.
+ */
+static bool test_and_set_bits(uint8_t *bitmap, const uint32_t *idx, size_t len)
+{
+ unsigned int i;
+ bool result = true;
+
+ /* Test if all specified bits are clear */
+ for (i = 0; i != len; i++) {
+ const uint32_t byte = (idx[i] >> 3);
+ const uint32_t bit = (idx[i] & 0x7);
+
+ result &= ((bitmap[byte] & (1 << bit)) == 0);
+ }
+
+ if (result) {
+ /* They are, so set them */
+ for (i = 0; i != len; i++) {
+ const uint32_t byte = (idx[i] >> 3);
+ const uint32_t bit = (idx[i] & 0x7);
+
+ bitmap[byte] |= (1 << bit);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Create the final substitution table from the intermediate parts
+ *
+ * \param table Substitution table
+ * \param table_entries Number of entries in table
+ * \param buckets Number of CHD buckets
+ * \param range Number of slots in final table
+ * \param max_displacement max(displacements)
+ * \param displacements Table of displacement values. One per bucket.
+ * \param substitution_table Location to receive result.
+ */
+static rufl_code create_substitution_table(uint64_t *table,
+ size_t table_entries, uint32_t buckets, uint32_t range,
+ uint32_t max_displacement, uint32_t *displacements,
+ struct rufl_substitution_table **substitution_table)
+{
+ struct rufl_substitution_table *subst_table;
+ size_t subst_table_size;
+ unsigned int i;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("max displacement of %u requires %u bits",
+ max_displacement, bits_needed(max_displacement));
+#endif
+
+ subst_table_size = offsetof(struct rufl_substitution_table,
+ displacement_map) +
+ ((buckets * bits_needed(max_displacement) + 7) >> 3);
+
+ subst_table = calloc(subst_table_size, 1);
+ if (!subst_table)
+ return rufl_OUT_OF_MEMORY;
+
+ /* We know there are at least table_entries in the table, but
+ * we should now resize it to the size of the target hashtable */
+ subst_table->table = realloc(table, range * sizeof(*table));
+ if (!subst_table->table) {
+ free(subst_table);
+ return rufl_OUT_OF_MEMORY;
+ }
+ /* Initialise unused slots */
+ for (i = table_entries; i < range; i++) {
+ subst_table->table[i] = NOT_AVAILABLE;
+ }
+
+ subst_table->num_buckets = buckets;
+ subst_table->num_slots = range;
+ subst_table->bits_per_entry = bits_needed(max_displacement);
+
+ /* Fill in displacement map */
+ //XXX: compress map using Fredriksson-Nikitin encoding?
+ for (i = 0; i < buckets; i++) {
+ uint32_t offset_bits = i * subst_table->bits_per_entry;
+ uint32_t bits_to_write = subst_table->bits_per_entry;
+ uint8_t *pwrite =
+ &subst_table->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_write > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ uint32_t mask = 0, mask_idx;
+
+ if (space_available > bits_to_write)
+ space_available = bits_to_write;
+
+ for (mask_idx = 0; mask_idx != space_available;
+ mask_idx++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+
+ *pwrite |= ((displacements[i] >>
+ (bits_to_write - space_available)) & mask) <<
+ (8 - offset_bits - space_available);
+ pwrite++;
+ offset_bits = 0;
+ bits_to_write -= space_available;
+ }
+ }
+
+ /* Shuffle table data so the indices match the hash values */
+ for (i = 0; i < table_entries; ) {
+ uint32_t f, g;
+ uint64_t tmp;
+
+ if (subst_table->table[i] == NOT_AVAILABLE) {
+ i++;
+ continue;
+ }
+
+ g = ((subst_table->table[i] >> 53) & 0x1f0000) |
+ ((subst_table->table[i] >> 16) & 0xffff);
+ f = hash2((subst_table->table[i] >> 32) & 0x1fffff,
+ displacements[g]) & (range - 1);
+
+ /* Exchange this entry with the one in the slot at f.*/
+ if (f != i) {
+ tmp = subst_table->table[f];
+ subst_table->table[f] = subst_table->table[i];
+ subst_table->table[i] = tmp;
+ } else {
+ /* Reconsider this slot unless it already
+ * had the correct entry */
+ i++;
+ }
+ }
+ /* Strip all the CHD metadata out of the final table */
+ for (i = 0; i < range; i++)
+ subst_table->table[i] &= 0x001fffff0000ffffllu;
+
+ *substitution_table = subst_table;
+
+ return rufl_OK;
+}
+
+/**
+ * Compute a perfect hash to address the substitution table.
+ *
+ * We use the CHD algorithm to do this.
+ * (https://doi.org/10.1007/978-3-642-04128-0_61 ;
+ * http://cmph.sourceforge.net/papers/esa09.pdf)
+ *
+ * A more recent alternative might be RecSplit
+ * (https://arxiv.org/abs/1910.06416v2).
+ *
+ * \param table Pre-filled table of raw substitution data
+ * \param table_entries Number of entries in the table
+ * \param substitution_table Location to receive result
+ */
+static rufl_code chd(uint64_t *table, size_t table_entries,
+ struct rufl_substitution_table **substitution_table)
+{
+ /** Number of buckets assuming an average bucket size of 4 */
+ const uint32_t buckets = ceil2((table_entries + 3) & ~3);
+ /** Number of output hash slots assuming a load factor of 0.95 */
+ const uint32_t range = ceil2((table_entries * 100)/95);
+ uint32_t bucket_size, max_displacement = 0;
+ unsigned int i;
+ uint8_t *entries_per_bucket, *bitmap;
+ uint32_t *displacements;
+ rufl_code result = rufl_OK;
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("hashing %zu entries into %u buckets with range %u",
+ table_entries, buckets, range);
+#endif
+
+ entries_per_bucket = calloc(buckets, sizeof(*entries_per_bucket));
+ if (!entries_per_bucket)
+ return rufl_OUT_OF_MEMORY;
+
+ bitmap = calloc(range >> 3, 1);
+ if (!bitmap) {
+ free(entries_per_bucket);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ displacements = calloc(buckets, sizeof(*displacements));
+ if (!displacements) {
+ free(bitmap);
+ free(entries_per_bucket);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ /* Compute g(x) for each entry, placing them into buckets */
+ for (i = 0; i < table_entries; i++) {
+ uint32_t g = hash1((table[i] >> 32) & 0x1fffff) & (buckets - 1);
+
+ /* Insert hash into entry (it's 21 bits at most, so
+ * needs splitting between bits 16-31 and 53-57 of
+ * the entry) */
+ table[i] |= ((g & 0xffff) << 16);
+ table[i] |= ((uint64_t)(g & 0x1f0000) << 53);
+
+ entries_per_bucket[g]++;
+ }
+
+ /* Inject bucket size into entries */
+ for (i = 0; i < table_entries; i++) {
+ uint32_t g = ((table[i] >> 53) & 0x1f0000) |
+ ((table[i] >> 16) & 0xffff);
+
+ /* With a target bucket size of 4, do not expect
+ * >= twice that number of entries in the largest
+ * bucket. If there are, the hash function needs
+ * work (we allocate 4 bits for the bucket size,
+ * so should have sufficient headroom). */
+ if (entries_per_bucket[g] >= 8)
+ LOG("unexpectedly large bucket %u",
+ entries_per_bucket[g]);
+
+ /* Stash bucket size into bits 58-61 of the entry */
+ table[i] |= ((uint64_t)entries_per_bucket[g] << 58);
+ }
+
+ /* Bits 62-63 of table entries are currently unused */
+
+ free(entries_per_bucket);
+
+ /* Sort entries in descending bucket size order */
+ qsort(table, table_entries, sizeof(*table), table_chd_cmp);
+
+ /* Compute f(x) for each bucket, finding a unique mapping */
+ for (i = 0; i < table_entries; i += bucket_size) {
+ const uint32_t g = ((table[i] >> 53) & 0x1f0000) |
+ ((table[i] >> 16) & 0xffff);
+ uint32_t hashes[8], num_hashes;
+ uint32_t d = 0;
+
+ bucket_size = ((table[i] >> 58) & 0xf);
+
+ do {
+ uint32_t j, k;
+
+ d++;
+ num_hashes = 0;
+
+ for (j = 0; j != bucket_size; j++) {
+ uint32_t f = hash2(
+ (table[i+j] >> 32) & 0x1fffff, d) &
+ (range - 1);
+ for (k = 0; k < num_hashes; k++) {
+ if (f == hashes[k])
+ break;
+ }
+ if (k == num_hashes) {
+ hashes[num_hashes] = f;
+ num_hashes++;
+ }
+ }
+ } while (num_hashes != bucket_size || !test_and_set_bits(
+ bitmap, hashes, num_hashes));
+
+ displacements[g] = d;
+ if (d > max_displacement)
+ max_displacement = d;
+ }
+
+ free(bitmap);
+
+ result = create_substitution_table(table, table_entries,
+ buckets, range, max_displacement, displacements,
+ substitution_table);
+ free(displacements);
+
+ return result;
+}
+
+/**
+ * Populate the substitution map for a given block
+ */
+static void fill_map_for_block(const struct rufl_character_set **charsets,
+ uint32_t block, uint16_t map_for_block[256])
+{
+ unsigned int i, u;
+
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ if (!charsets[i])
+ continue;
+
+ if (charsets[i]->index[block] == BLOCK_FULL) {
+ for (u = 0; u != 256; u++)
+ if (map_for_block[u] == NOT_AVAILABLE)
+ map_for_block[u] = i;
+ } else if (charsets[i]->index[block] != BLOCK_EMPTY) {
+ const uint8_t *blk = charsets[i]->block[
+ charsets[i]->index[block]];
+ for (u = 0; u != 256; u++) {
+ if (map_for_block[u] == NOT_AVAILABLE &&
+ (blk[(u>>3)] & (1 << (u&7)))) {
+ map_for_block[u] = i;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Construct the font substitution table.
+ */
+
+rufl_code rufl_substitution_table_init(void)
+{
+ unsigned int i;
+ unsigned int plane, block;
+ unsigned int u;
+ const struct rufl_character_set **charsets;
+ uint64_t *table;
+ size_t table_size;
+ size_t table_entries;
+ rufl_code result;
+
+ charsets = malloc(rufl_font_list_entries * sizeof(*charsets));
+ if (!charsets) {
+ LOG("malloc(%zu) failed",
+ rufl_font_list_entries * sizeof(*charsets));
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ table = malloc(1024 * sizeof(*table));
+ if (!table) {
+ LOG("malloc(%zu) failed", 1024 * sizeof(*table));
+ free(charsets);
+ return rufl_OUT_OF_MEMORY;
+ }
+ table_size = 1024;
+ table_entries = 0;
+
+ for (plane = 0; plane < 17; plane++) {
+ const struct rufl_character_set *charset;
+ unsigned int num_charsets = 0;
+
+ /* Find fonts that have charsets for this plane */
+ for (i = 0; i != rufl_font_list_entries; i++) {
+ charset = rufl_font_list[i].charset;
+ if (!charset) {
+ charsets[i] = NULL;
+ continue;
+ }
+
+ while (PLANE_ID(charset->metadata) != plane &&
+ EXTENSION_FOLLOWS(charset->metadata)) {
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ if (PLANE_ID(charset->metadata) != plane)
+ charset = NULL;
+ charsets[i] = charset;
+ num_charsets++;
+ }
+ if (num_charsets == 0)
+ continue;
+
+ /* Process each block, finding fonts that have glyphs */
+ for (block = 0; block != 256; block++) {
+ uint16_t map_for_block[256];
+ memset(map_for_block, 0xff, 512);
+
+ fill_map_for_block(charsets, block, map_for_block);
+
+ /* Merge block map into table */
+ for (i = 0; i != 256; i++) {
+ if (map_for_block[i] == NOT_AVAILABLE)
+ continue;
+
+ u = (plane << 16) | (block << 8) | i;
+ table[table_entries] = ((uint64_t) u << 32) |
+ map_for_block[i];
+ if (++table_entries == table_size) {
+ uint64_t *tmp = realloc(table,
+ 2 * table_size *
+ sizeof(*table));
+ if (!tmp) {
+ LOG("realloc(%zu) failed",
+ 2 * table_size *
+ sizeof(*table));
+ free(table);
+ return rufl_OUT_OF_MEMORY;
+ }
+
+ table = tmp;
+ table_size *= 2;
+ }
+ }
+ }
+ }
+
+ /* Build hash from table */
+ result = chd(table, table_entries, &rufl_substitution_table);
+
+#ifdef RUFL_SUBSTITUTION_TABLE_DEBUG
+ LOG("table size(%zu) entries %zu buckets(%u@%ubpe => %u)",
+ rufl_substitution_table->num_slots * sizeof(*table),
+ table_entries,
+ rufl_substitution_table->num_buckets,
+ rufl_substitution_table->bits_per_entry,
+ (rufl_substitution_table->num_buckets *
+ rufl_substitution_table->bits_per_entry + 7) >> 3);
+#endif
+
+ free(charsets);
+
+ return result;
+}
+
+/**
+ * Destroy the substitution table and clean up its resources
+ */
+
+void rufl_substitution_table_fini(void)
+{
+ free(rufl_substitution_table->table);
+ free(rufl_substitution_table);
+ rufl_substitution_table = NULL;
+}
+
+/**
+ * Look up a Unicode codepoint in the substitution table
+ */
+
+unsigned int rufl_substitution_table_lookup(uint32_t u)
+{
+ uint32_t displacement = 0;
+ uint32_t f, g = hash1(u & 0x1ffffff) &
+ (rufl_substitution_table->num_buckets - 1);
+ uint32_t bits_to_read = rufl_substitution_table->bits_per_entry;
+ uint32_t offset_bits = g * bits_to_read;
+ const uint8_t *pread =
+ &rufl_substitution_table->displacement_map[offset_bits >> 3];
+
+ offset_bits &= 7;
+
+ while (bits_to_read > 0) {
+ uint32_t space_available = (8 - offset_bits);
+ if (space_available > bits_to_read)
+ space_available = bits_to_read;
+
+ displacement <<= space_available;
+ displacement |= (*pread & (0xff >> offset_bits)) >>
+ (8 - space_available - offset_bits);
+
+ offset_bits += space_available;
+ if (offset_bits >= 8) {
+ pread++;
+ offset_bits = 0;
+ }
+ bits_to_read -= space_available;
+ }
+
+ f = hash2((u & 0x1fffff), displacement) &
+ (rufl_substitution_table->num_slots - 1);
+
+ if ((rufl_substitution_table->table[f] & 0xffff) != NOT_AVAILABLE &&
+ ((rufl_substitution_table->table[f] >> 32) & 0x1fffff) == u)
+ return rufl_substitution_table->table[f] & 0xffff;
+
+ return NOT_AVAILABLE;
+}
+
+static int table_dump_cmp(const void *a, const void *b)
+{
+ const uint64_t aa = (*(const uint64_t *) a) & 0x001fffff00000000llu;
+ const uint64_t bb = (*(const uint64_t *) b) & 0x001fffff00000000llu;
+
+ if (aa > bb)
+ return 1;
+ else if (aa < bb)
+ return -1;
+ return 0;
+}
+
+/**
+ * Dump a representation of the substitution table to stdout.
+ */
+
+void rufl_substitution_table_dump(void)
+{
+ unsigned int font;
+ unsigned int u, t;
+ uint64_t *table;
+
+ table = malloc(rufl_substitution_table->num_slots * sizeof(*table));
+ if (table == NULL)
+ return;
+
+ memcpy(table, rufl_substitution_table->table,
+ rufl_substitution_table->num_slots * sizeof(*table));
+
+ qsort(table, rufl_substitution_table->num_slots, sizeof(*table),
+ table_dump_cmp);
+
+ u = 0;
+ while (u < rufl_substitution_table->num_slots) {
+ t = u;
+ font = table[t] & 0xffff;
+ while (u < rufl_substitution_table->num_slots &&
+ font == (table[u] & 0xffff) &&
+ ((u == t) ||
+ (((table[u - 1] >> 32) & 0x1fffff) ==
+ (((table[u] >> 32) & 0x1fffff) - 1))))
+ u++;
+ if (font != NOT_AVAILABLE)
+ printf(" %llx-%llx => %u \"%s\"\n",
+ (table[t] >> 32) & 0x1fffff,
+ (table[u - 1] >> 32) & 0x1fffff,
+ font, rufl_font_list[font].identifier);
+ }
+
+ free(table);
+}
diff --git a/test/rufl_chars.c b/test/rufl_chars.c
index 14a0fb6..1df86e3 100644
--- a/test/rufl_chars.c
+++ b/test/rufl_chars.c
@@ -18,13 +18,13 @@
unsigned int font = 0;
unsigned int weight = rufl_WEIGHT_400;
bool italic = false;
+unsigned int plane = 0;
static rufl_code redraw(int x, int y, int y0, int y1);
static void try(rufl_code code, const char *context);
static void die(const char *error);
-
int main(void)
{
unsigned int i;
@@ -73,7 +73,7 @@ int main(void)
try(rufl_init(), "rufl_init");
- menu = malloc(wimp_SIZEOF_MENU(10 + rufl_family_list_entries));
+ menu = malloc(wimp_SIZEOF_MENU(27 + rufl_family_list_entries));
if (!menu)
die("Out of memory");
strcpy(menu->title_data.text, "Fonts");
@@ -99,23 +99,37 @@ int main(void)
(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT);
strcpy(menu->entries[9].data.text, "Italic");
- for (i = 0; i != rufl_family_list_entries; i++) {
- menu->entries[10 + i].menu_flags = 0;
+ for (i = 0; i != 17; i++) {
+ menu->entries[10 + i].menu_flags =
+ (i == 16 ? wimp_MENU_SEPARATE :0);
menu->entries[10 + i].sub_menu = wimp_NO_SUB_MENU;
menu->entries[10 + 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[10 + i].data.text, "Plane 1");
+ menu->entries[10 + i].data.text[6] = '0' + (i+1)/10;
+ if (menu->entries[10 + i].data.text[6] == '0')
+ menu->entries[10 + i].data.text[6] = ' ';
+ menu->entries[10 + i].data.text[7] = '0' + (i+1)%10;
+ }
+ for (i = 0; i != rufl_family_list_entries; i++) {
+ menu->entries[27 + i].menu_flags = 0;
+ menu->entries[27 + i].sub_menu = wimp_NO_SUB_MENU;
+ menu->entries[27 + 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[10 + i].data.indirected_text.text =
+ menu->entries[27 + i].data.indirected_text.text =
(char *) rufl_family_list[i];
- menu->entries[10 + i].data.indirected_text.validation =
+ menu->entries[27 + i].data.indirected_text.validation =
(char *) -1;
- menu->entries[10 + i].data.indirected_text.size =
+ menu->entries[27 + i].data.indirected_text.size =
strlen(rufl_family_list[i]);
}
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;
+ menu->entries[27].menu_flags |= wimp_MENU_TICKED;
+ menu->entries[i + 26].menu_flags |= wimp_MENU_LAST;
error = xwimp_create_window((wimp_window *) &window, &w);
if (error)
@@ -194,11 +208,17 @@ int main(void)
} else if (block.selection.items[0] == 9) {
italic = !italic;
menu->entries[9].menu_flags ^= wimp_MENU_TICKED;
+ } else if (block.selection.items[0] <= 26) {
+ menu->entries[10 + plane].menu_flags ^=
+ wimp_MENU_TICKED;
+ plane = block.selection.items[0] - 10;
+ menu->entries[10 + plane].menu_flags ^=
+ wimp_MENU_TICKED;
} else {
- menu->entries[10 + font].menu_flags ^=
+ menu->entries[27 + font].menu_flags ^=
wimp_MENU_TICKED;
- font = block.selection.items[0] - 10;
- menu->entries[10 + font].menu_flags ^=
+ font = block.selection.items[0] - 27;
+ menu->entries[27 + font].menu_flags ^=
wimp_MENU_TICKED;
}
error = xwimp_force_redraw(w,
@@ -249,15 +269,21 @@ rufl_code redraw(int x, int y, int y0, int y1)
rufl_style style = weight | (italic ? rufl_SLANTED : 0);
for (u = y0 / 40 * 32; (int) u != (y1 / 40 + 1) * 32; u++) {
- if (u <= 0x7f)
- s[0] = u, l = 1;
- else if (u <= 0x7ff)
- s[0] = 0xc0 | (u >> 6),
- s[1] = 0x80 | (u & 0x3f), l = 2;
- else if (u <= 0xffff)
- s[0] = 0xe0 | (u >> 12),
- s[1] = 0x80 | ((u >> 6) & 0x3f),
- s[2] = 0x80 | (u & 0x3f), l = 3;
+ unsigned int c = (plane << 16) | u;
+ if (c <= 0x7f)
+ s[0] = c, l = 1;
+ else if (c <= 0x7ff)
+ s[0] = 0xc0 | (c >> 6),
+ s[1] = 0x80 | (c & 0x3f), l = 2;
+ else if (c <= 0xffff)
+ s[0] = 0xe0 | (c >> 12),
+ s[1] = 0x80 | ((c >> 6) & 0x3f),
+ s[2] = 0x80 | (c & 0x3f), l = 3;
+ else if (c <= 0x10ffff)
+ s[0] = 0xf0 | (c >> 18),
+ s[1] = 0x80 | ((c >> 12) & 0x3f),
+ s[2] = 0x80 | ((c >> 6) & 0x3f),
+ s[3] = 0x80 | (c & 0x3f), l = 4;
else
break;
s[l] = 0;
diff --git a/test/rufl_test.c b/test/rufl_test.c
index 51a29d6..d939467 100644
--- a/test/rufl_test.c
+++ b/test/rufl_test.c
@@ -18,14 +18,15 @@ 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,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y);
int main(void)
{
char utf8_test[] = "Hello, world! ����������� "
- "Uhersk�� Hradi��t��. ����";
+ "Uhersk�� Hradi��t��. ����"
+ "\xf0\xa0\x80\xa1";
int width;
size_t char_offset;
int x;
@@ -131,7 +132,7 @@ int cubic_to(os_coord *control1, os_coord *control2, os_coord *to,
void callback(void *context,
const char *font_name, unsigned int font_size,
- const char *s8, unsigned short *s16, unsigned int n,
+ const char *s8, unsigned int *s32, unsigned int n,
int x, int y)
{
(void) context;
@@ -142,7 +143,7 @@ void callback(void *context,
else {
printf("s16 \"");
for (unsigned int i = 0; i != n; i++)
- printf("%x ", (unsigned int) s16[i]);
+ printf("%x ", (unsigned int) s32[i]);
printf("\" ");
}
printf("%i %i\n", x, y);
--
RISC OS Unicode Font Library
2 years, 1 month
libdom: branch master updated. release/0.4.1-18-gade633d
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libdom.git/shortlog/ade633dd4a93360cb25fba...
...commit http://git.netsurf-browser.org/libdom.git/commit/ade633dd4a93360cb25fbabc...
...tree http://git.netsurf-browser.org/libdom.git/tree/ade633dd4a93360cb25fbabc05...
The branch, master has been updated
via ade633dd4a93360cb25fbabc05c749a45950b8b9 (commit)
from 631f016a9ccff344f4dcb0b57e8ef1cf275e175c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/libdom.git/commit/?id=ade633dd4a93360cb25f...
commit ade633dd4a93360cb25fbabc05c749a45950b8b9
Author: Michael Drake <michael.drake(a)codethink.co.uk>
Commit: Michael Drake <michael.drake(a)codethink.co.uk>
DOM Walker: Rename client private word parameter.
diff --git a/examples/dom-structure-dump.c b/examples/dom-structure-dump.c
index 2cdc7c5..189292d 100644
--- a/examples/dom-structure-dump.c
+++ b/examples/dom-structure-dump.c
@@ -259,9 +259,9 @@ enum dom_walk_cmd dump_dom_structure__cb(
enum dom_walk_stage stage,
dom_node_type type,
dom_node *node,
- void *ctx)
+ void *pw)
{
- int *depth = ctx;
+ int *depth = pw;
switch (type) {
case DOM_ELEMENT_NODE:
diff --git a/include/dom/walk.h b/include/dom/walk.h
index 0cd3fd0..5de3546 100644
--- a/include/dom/walk.h
+++ b/include/dom/walk.h
@@ -37,14 +37,14 @@ enum dom_walk_cmd {
* \param[in] stage Whether the \ref node is being entered or left.
* \param[in] node The node being walked. Client must take ref itself.
* \param[in] type The node type.
- * \param[in] ctx Client private data.
+ * \param[in] pw Client private data.
* \return Tree walking client command.
*/
typedef enum dom_walk_cmd (*dom_walk_cb)(
enum dom_walk_stage stage,
dom_node_type type,
dom_node *node,
- void *ctx);
+ void *pw);
/**
@@ -53,13 +53,13 @@ typedef enum dom_walk_cmd (*dom_walk_cb)(
* \param[in] mask Mask of stages to enable callback for.
* \param[in] cb The client callback function.
* \param[in] root Node to start walk from.
- * \param[in] ctx The client's private data.
+ * \param[in] pw The client's private data.
* \return false for early termination of walk, true otherwise.
*/
dom_exception libdom_treewalk(
enum dom_walk_enable mask,
dom_walk_cb cb,
dom_node *root,
- void *ctx);
+ void *pw);
#endif
diff --git a/src/utils/walk.c b/src/utils/walk.c
index 20314f3..f103908 100644
--- a/src/utils/walk.c
+++ b/src/utils/walk.c
@@ -19,7 +19,7 @@
* \param[in] stage Whether the \ref node is being entered or left.
* \param[in] node The node being walked.
* \param[in] cb The client callback function.
- * \param[in] ctx The client's private data.
+ * \param[in] pw The client's private data.
* \param[out] cmd_out Walk instruction from client.
* \return false for early termination of walk, true otherwise.
*/
@@ -28,7 +28,7 @@ static inline dom_exception dom_walk__cb(
enum dom_walk_stage stage,
dom_node *node,
dom_walk_cb cb,
- void *ctx,
+ void *pw,
enum dom_walk_cmd *cmd_out)
{
if ((1 << stage) & mask) {
@@ -40,7 +40,7 @@ static inline dom_exception dom_walk__cb(
return exc;
}
- *cmd_out = cb(stage, type, node, ctx);
+ *cmd_out = cb(stage, type, node, pw);
}
return DOM_NO_ERR;
@@ -51,7 +51,7 @@ dom_exception libdom_treewalk(
enum dom_walk_enable mask,
dom_walk_cb cb,
dom_node *root,
- void *ctx)
+ void *pw)
{
dom_node *node;
dom_exception exc;
@@ -77,7 +77,7 @@ dom_exception libdom_treewalk(
/* No children; siblings & ancestor's siblings */
while (node != root) {
exc = dom_walk__cb(mask, DOM_WALK_STAGE_LEAVE,
- node, cb, ctx, &cmd);
+ node, cb, pw, &cmd);
if (exc != DOM_NO_ERR ||
cmd == DOM_WALK_CMD_ABORT) {
dom_node_unref(node);
@@ -118,7 +118,7 @@ dom_exception libdom_treewalk(
assert(node != root);
exc = dom_walk__cb(mask, DOM_WALK_STAGE_ENTER, node,
- cb, ctx, &cmd);
+ cb, pw, &cmd);
if (exc != DOM_NO_ERR) {
return exc;
}
-----------------------------------------------------------------------
Summary of changes:
examples/dom-structure-dump.c | 4 ++--
include/dom/walk.h | 8 ++++----
src/utils/walk.c | 12 ++++++------
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/examples/dom-structure-dump.c b/examples/dom-structure-dump.c
index 2cdc7c5..189292d 100644
--- a/examples/dom-structure-dump.c
+++ b/examples/dom-structure-dump.c
@@ -259,9 +259,9 @@ enum dom_walk_cmd dump_dom_structure__cb(
enum dom_walk_stage stage,
dom_node_type type,
dom_node *node,
- void *ctx)
+ void *pw)
{
- int *depth = ctx;
+ int *depth = pw;
switch (type) {
case DOM_ELEMENT_NODE:
diff --git a/include/dom/walk.h b/include/dom/walk.h
index 0cd3fd0..5de3546 100644
--- a/include/dom/walk.h
+++ b/include/dom/walk.h
@@ -37,14 +37,14 @@ enum dom_walk_cmd {
* \param[in] stage Whether the \ref node is being entered or left.
* \param[in] node The node being walked. Client must take ref itself.
* \param[in] type The node type.
- * \param[in] ctx Client private data.
+ * \param[in] pw Client private data.
* \return Tree walking client command.
*/
typedef enum dom_walk_cmd (*dom_walk_cb)(
enum dom_walk_stage stage,
dom_node_type type,
dom_node *node,
- void *ctx);
+ void *pw);
/**
@@ -53,13 +53,13 @@ typedef enum dom_walk_cmd (*dom_walk_cb)(
* \param[in] mask Mask of stages to enable callback for.
* \param[in] cb The client callback function.
* \param[in] root Node to start walk from.
- * \param[in] ctx The client's private data.
+ * \param[in] pw The client's private data.
* \return false for early termination of walk, true otherwise.
*/
dom_exception libdom_treewalk(
enum dom_walk_enable mask,
dom_walk_cb cb,
dom_node *root,
- void *ctx);
+ void *pw);
#endif
diff --git a/src/utils/walk.c b/src/utils/walk.c
index 20314f3..f103908 100644
--- a/src/utils/walk.c
+++ b/src/utils/walk.c
@@ -19,7 +19,7 @@
* \param[in] stage Whether the \ref node is being entered or left.
* \param[in] node The node being walked.
* \param[in] cb The client callback function.
- * \param[in] ctx The client's private data.
+ * \param[in] pw The client's private data.
* \param[out] cmd_out Walk instruction from client.
* \return false for early termination of walk, true otherwise.
*/
@@ -28,7 +28,7 @@ static inline dom_exception dom_walk__cb(
enum dom_walk_stage stage,
dom_node *node,
dom_walk_cb cb,
- void *ctx,
+ void *pw,
enum dom_walk_cmd *cmd_out)
{
if ((1 << stage) & mask) {
@@ -40,7 +40,7 @@ static inline dom_exception dom_walk__cb(
return exc;
}
- *cmd_out = cb(stage, type, node, ctx);
+ *cmd_out = cb(stage, type, node, pw);
}
return DOM_NO_ERR;
@@ -51,7 +51,7 @@ dom_exception libdom_treewalk(
enum dom_walk_enable mask,
dom_walk_cb cb,
dom_node *root,
- void *ctx)
+ void *pw)
{
dom_node *node;
dom_exception exc;
@@ -77,7 +77,7 @@ dom_exception libdom_treewalk(
/* No children; siblings & ancestor's siblings */
while (node != root) {
exc = dom_walk__cb(mask, DOM_WALK_STAGE_LEAVE,
- node, cb, ctx, &cmd);
+ node, cb, pw, &cmd);
if (exc != DOM_NO_ERR ||
cmd == DOM_WALK_CMD_ABORT) {
dom_node_unref(node);
@@ -118,7 +118,7 @@ dom_exception libdom_treewalk(
assert(node != root);
exc = dom_walk__cb(mask, DOM_WALK_STAGE_ENTER, node,
- cb, ctx, &cmd);
+ cb, pw, &cmd);
if (exc != DOM_NO_ERR) {
return exc;
}
--
Document Object Model library
2 years, 1 month
librufl: branch jmb/ac updated. release/0.0.5-5-g282b342
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/librufl.git/shortlog/282b342fe51a2e9856b54...
...commit http://git.netsurf-browser.org/librufl.git/commit/282b342fe51a2e9856b5448...
...tree http://git.netsurf-browser.org/librufl.git/tree/282b342fe51a2e9856b5448c3...
The branch, jmb/ac has been updated
discards 9699d2175ca7c5492f156d9683356822bf43650a (commit)
via 282b342fe51a2e9856b5448c30679ea8b49f18c5 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (9699d2175ca7c5492f156d9683356822bf43650a)
\
N -- N -- N (282b342fe51a2e9856b5448c30679ea8b49f18c5)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/librufl.git/commit/?id=282b342fe51a2e9856b...
commit 282b342fe51a2e9856b5448c30679ea8b49f18c5
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Pave the way for astral character support.
No functional change, but redefine the meaning of the old "size"
member of the rufl_character_set structure to allow for the
addition of extension structures in future. This change is
backwards compatible as it is reusing previously unused bits in
the size field (which will be set to zero in all existing
RUfl_caches). Rename the "size" field to "metadata" which better
reflects its new usage.
Update rufl_character_set_test and rufl_dump_state to follow this
change (and fix up their parameter types while we're here).
diff --git a/src/rufl_character_set_test.c b/src/rufl_character_set_test.c
index 45fbcaf..2e97894 100644
--- a/src/rufl_character_set_test.c
+++ b/src/rufl_character_set_test.c
@@ -12,18 +12,28 @@
* Test if a character set contains a character.
*
* \param charset character set
- * \param c character code
+ * \param u Unicode codepoint
* \return true if present, false if absent
*/
-bool rufl_character_set_test(struct rufl_character_set *charset,
- unsigned int c)
+bool rufl_character_set_test(const struct rufl_character_set *charset,
+ uint32_t u)
{
- unsigned int block = c >> 8;
- unsigned int byte = (c >> 3) & 31;
- unsigned int bit = c & 7;
+ unsigned int plane = u >> 16;
+ unsigned int block = (u >> 8) & 0xff;
+ unsigned int byte = (u >> 3) & 31;
+ unsigned int bit = u & 7;
- if (256 <= block)
+ if (17 <= plane)
+ return false;
+
+ /* Look for the plane we want */
+ while (PLANE_ID(charset->metadata) != plane &&
+ EXTENSION_FOLLOWS(charset->metadata)) {
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ if (PLANE_ID(charset->metadata) != plane)
return false;
if (charset->index[block] == BLOCK_EMPTY)
@@ -31,7 +41,7 @@ bool rufl_character_set_test(struct rufl_character_set *charset,
else if (charset->index[block] == BLOCK_FULL)
return true;
else {
- unsigned char z = charset->block[charset->index[block]][byte];
+ uint8_t z = charset->block[charset->index[block]][byte];
return z & (1 << bit);
}
}
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index 06a1f22..b03109c 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -9,7 +9,8 @@
#include "rufl_internal.h"
-static void rufl_dump_character_set(struct rufl_character_set *charset);
+static void rufl_dump_character_set_list(
+ const struct rufl_character_set *charset);
static void rufl_dump_unicode_map(struct rufl_unicode_map *umap);
static void rufl_dump_substitution_table(void);
@@ -27,7 +28,7 @@ void rufl_dump_state(void)
printf(" %u \"%s\"\n", i, rufl_font_list[i].identifier);
if (rufl_font_list[i].charset) {
printf(" ");
- rufl_dump_character_set(rufl_font_list[i].charset);
+ rufl_dump_character_set_list(rufl_font_list[i].charset);
printf("\n");
} else {
printf(" (no charset table)\n");
@@ -75,28 +76,45 @@ void rufl_dump_state(void)
* \param charset character set to print
*/
-void rufl_dump_character_set(struct rufl_character_set *charset)
+static void rufl_dump_character_set(const struct rufl_character_set *charset)
{
- unsigned int u, t;
+ unsigned int u, t, plane = PLANE_ID(charset->metadata) << 16;
u = 0;
while (u != 0x10000) {
- while (u != 0x10000 && !rufl_character_set_test(charset, u))
+ while (u != 0x10000 &&
+ !rufl_character_set_test(charset, plane + u))
u++;
if (u != 0x10000) {
- if (!rufl_character_set_test(charset, u + 1)) {
- printf("%x ", u);
+ if (!rufl_character_set_test(charset, plane + u + 1)) {
+ printf("%x ", plane + u);
u++;
} else {
t = u;
- while (rufl_character_set_test(charset, u))
+ while (rufl_character_set_test(
+ charset, plane + u))
u++;
- printf("%x-%x ", t, u - 1);
+ printf("%x-%x ", plane + t, plane + u - 1);
}
}
}
}
+/**
+ * Dump a representation of a character set list to stdout.
+ *
+ * \param charset character set to print
+ */
+
+void rufl_dump_character_set_list(const struct rufl_character_set *charset)
+{
+ while (EXTENSION_FOLLOWS(charset->metadata)) {
+ rufl_dump_character_set(charset);
+ charset = (void *)(((uint8_t *)charset) +
+ PLANE_SIZE(charset->metadata));
+ }
+ rufl_dump_character_set(charset);
+}
/**
* Dump a representation of a unicode map to stdout.
diff --git a/src/rufl_init.c b/src/rufl_init.c
index b441edc..3ae4ffa 100644
--- a/src/rufl_init.c
+++ b/src/rufl_init.c
@@ -575,9 +575,9 @@ rufl_code rufl_init_scan_font(unsigned int font_index)
}
/* shrink-wrap */
- charset->size = offsetof(struct rufl_character_set, block) +
+ charset->metadata = offsetof(struct rufl_character_set, block) +
32 * last_used;
- charset2 = realloc(charset, charset->size);
+ charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
if (!charset2) {
free(charset);
return rufl_OUT_OF_MEMORY;
@@ -696,9 +696,9 @@ rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index)
}
/* shrink-wrap */
- charset->size = offsetof(struct rufl_character_set, block) +
+ charset->metadata = offsetof(struct rufl_character_set, block) +
32 * last_used;
- charset2 = realloc(charset, charset->size);
+ charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
if (!charset2) {
free(charset);
return rufl_OUT_OF_MEMORY;
@@ -885,9 +885,9 @@ rufl_code rufl_init_scan_font_old(unsigned int font_index)
}
/* shrink-wrap */
- charset->size = offsetof(struct rufl_character_set, block) +
+ charset->metadata = offsetof(struct rufl_character_set, block) +
32 * last_used;
- charset2 = realloc(charset, charset->size);
+ charset2 = realloc(charset, PLANE_SIZE(charset->metadata));
if (!charset2) {
for (i = 0; i < num_umaps; i++)
free((umap + i)->encoding);
@@ -1255,7 +1255,8 @@ rufl_code rufl_save_cache(void)
/* character set */
if (fwrite(rufl_font_list[i].charset,
- rufl_font_list[i].charset->size, 1, fp) != 1) {
+ PLANE_SIZE(rufl_font_list[i].charset->metadata),
+ 1, fp) != 1) {
LOG("fwrite: 0x%x: %s", errno, strerror(errno));
fclose(fp);
return rufl_OK;
@@ -1430,7 +1431,7 @@ rufl_code rufl_load_cache(void)
return rufl_OUT_OF_MEMORY;
}
- charset->size = size;
+ charset->metadata = size;
if (fread(charset->index, size - sizeof size, 1, fp) != 1) {
if (feof(fp))
LOG("fread: %s", "unexpected eof");
diff --git a/src/rufl_internal.h b/src/rufl_internal.h
index 7d793a1..9c7d46e 100644
--- a/src/rufl_internal.h
+++ b/src/rufl_internal.h
@@ -14,20 +14,78 @@
#endif
-/** The available characters in a font. The range which can be represented is
- * 0x0000 to 0xffff. The size of the structure is 4 + 256 + 32 * blocks. A
- * typical * 200 glyph font might have characters in 10 blocks, giving 580
- * bytes. The maximum possible size of the structure is 8388 bytes. Note that
- * since two index values are reserved, fonts with 65280-65024 glyphs may be
- * unrepresentable, if there are no full blocks. This is unlikely. The primary
- * aim of this structure is to make lookup fast. */
+/**
+ * The available Unicode codepoints represented by a font. The entire Unicode
+ * range (U+0000 - U+10FFFF) may be covered by the font, but only codepoints
+ * in the Basic Multilingual Plane (i.e. U+0000 - U+FFFF) can be represented
+ * without the need for extension structures.
+ *
+ * Fonts which provide glyphs for astral characters will set the extension
+ * bit in the structure size field. If set, this indicates that an additional
+ * character set structure follows immediately after this one. The plane id
+ * field in the structure metadata indicates which plane the structure relates
+ * to. Planes are specified in ascending order (as the most commonly used
+ * codepoints occur in earlier planes). Planes for which the font has no
+ * glyphs are omitted entirely.
+ *
+ * Each plane is subdivided into 256 codepoint blocks (each block representing
+ * 256 contiguous codepoints). Note, however, that two index values are
+ * reserved (to indicate full or empty blocks) so only 254 partial blocks may
+ * be represented. As of Unicode 13, all planes have at least two blocks
+ * unused (or, in the case of the surrogate ranges in the Basic Multilingual
+ * Plane, defined as containing no characters), so all valid codepoints should
+ * be representable using this scheme.
+ *
+ * The size of the structure is 4 + 256 + 32 * blocks. A typical 200 glyph
+ * font might represent codepoints in 10 blocks, using 580 bytes of storage.
+ * A plane with glyphs in every block (but no block fully populated) requires
+ * the maximum possible structure size of (4 + 256 + 32 * 254 =) 8388 bytes.
+ * The maximum storage required for (the unlikely scenario of) a font
+ * providing glyphs in every block in each of the 17 Unicode planes is
+ * 17 * 8388 = 142596 bytes.
+ *
+ * The primary aim of this structure is to make lookup fast.
+ */
struct rufl_character_set {
- /** Size of structure / bytes. */
- size_t size;
+ /** Structure metadata.
+ *
+ * This field contains metadata about the structure in the form:
+ *
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |E| PID | Reserved | Size |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * where:
+ *
+ * extension (E): 1 bit
+ * If set, another character set covering a different plane
+ * follows.
+ *
+ * plane id (PID): 5 bits
+ * The 0-based index of the Unicode plane this structure relates
+ * to. Valid values are in the range [0, 16], where 0 represents
+ * the Basic Multilingual Plane, and 16 represents the
+ * Supplementary Private Use Area - B.
+ *
+ * reserved: 10 bits
+ * These bits are currently unused and must be set to 0.
+ *
+ * size: 16 bits
+ * The total size of this structure, in bytes.
+ */
+ uint32_t metadata;
+# define EXTENSION_FOLLOWS(x) ((x) & (1u<<31))
+# define PLANE_ID(x) (((x) >> 26) & 0x1f)
+# define PLANE_SIZE(x) ((x) & 0xffff)
- /** Index table. Each entry represents a block of 256 characters, so
- * i[k] refers to characters [256*k, 256*(k+1)). The value is either
- * BLOCK_EMPTY, BLOCK_FULL, or an offset into the block table. */
+ /** Index table.
+ *
+ * Each entry represents a block of 256 codepoints, so i[k] refers
+ * to codepoints [256*k, 256*(k+1)). The value is either BLOCK_EMPTY,
+ * BLOCK_FULL, or an offset into the block table.
+ * */
uint8_t index[256];
/** The block has no characters present. */
# define BLOCK_EMPTY 254
@@ -142,8 +200,8 @@ rufl_code rufl_find_font_family(const char *family, rufl_style font_style,
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);
+bool rufl_character_set_test(const struct rufl_character_set *charset,
+ uint32_t u);
#define rufl_utf8_read(s, l, u) \
-----------------------------------------------------------------------
Summary of changes:
src/rufl_dump_state.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c
index 5ba13dc..b03109c 100644
--- a/src/rufl_dump_state.c
+++ b/src/rufl_dump_state.c
@@ -82,15 +82,17 @@ static void rufl_dump_character_set(const struct rufl_character_set *charset)
u = 0;
while (u != 0x10000) {
- while (u != 0x10000 && !rufl_character_set_test(charset, u))
+ while (u != 0x10000 &&
+ !rufl_character_set_test(charset, plane + u))
u++;
if (u != 0x10000) {
- if (!rufl_character_set_test(charset, u + 1)) {
+ if (!rufl_character_set_test(charset, plane + u + 1)) {
printf("%x ", plane + u);
u++;
} else {
t = u;
- while (rufl_character_set_test(charset, u))
+ while (rufl_character_set_test(
+ charset, plane + u))
u++;
printf("%x-%x ", plane + t, plane + u - 1);
}
--
RISC OS Unicode Font Library
2 years, 1 month