diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/INDEX | 8 | ||||
-rw-r--r-- | test/Makefile | 14 | ||||
-rw-r--r-- | test/data/oldfminit/Allerta (renamed from test/data/Encoding) | 0 | ||||
-rw-r--r-- | test/data/oldfminit/INDEX | 10 | ||||
-rw-r--r-- | test/data/oldfminit/Latin1 | 270 | ||||
-rw-r--r-- | test/data/oldfminit/brokenencoding.cfg | 28 | ||||
-rw-r--r-- | test/data/oldfminit/latin1.cfg | 28 | ||||
-rw-r--r-- | test/data/oldfminit/mergeumap.cfg | 40 | ||||
-rw-r--r-- | test/data/oldfminit/nomapping.cfg | 19 | ||||
-rw-r--r-- | test/data/oldfminit/symbol.cfg | 28 | ||||
-rw-r--r-- | test/harness-priv.h | 45 | ||||
-rw-r--r-- | test/harness.c | 139 | ||||
-rw-r--r-- | test/harness.h | 10 | ||||
-rw-r--r-- | test/manyfonts.c | 100 | ||||
-rw-r--r-- | test/mocks.c | 671 | ||||
-rw-r--r-- | test/nofonts.c | 20 | ||||
-rw-r--r-- | test/oldfminit.c | 353 | ||||
-rw-r--r-- | test/olducsinit.c | 140 | ||||
-rw-r--r-- | test/rufl_chars.c | 68 | ||||
-rw-r--r-- | test/rufl_test.c | 21 | ||||
-rw-r--r-- | test/testutils.h | 123 | ||||
-rw-r--r-- | test/ucsinit.c | 140 |
22 files changed, 2243 insertions, 32 deletions
diff --git a/test/INDEX b/test/INDEX new file mode 100644 index 0000000..417b032 --- /dev/null +++ b/test/INDEX @@ -0,0 +1,8 @@ +# Index for testcases +# +# Test Description DataDir +nofonts Ensure a lack of fonts "works" +ucsinit Ensure that UCS FM initialisation works +olducsinit Ensure that UCS FM (pre 3.64) initialisation works +oldfminit Ensure that non-UCS FM initialisation works oldfminit +manyfonts Ensure that more than 256 fonts works diff --git a/test/Makefile b/test/Makefile index 2bfa58b..65c3170 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,16 @@ # Tests -DIR_TEST_ITEMS := rufl_test:rufl_test.c rufl_chars:rufl_chars.c +ifeq ($(findstring -riscos,$(HOST)),-riscos) + DIR_TEST_ITEMS := $(DIR_TEST_ITEMS) \ + rufl_test:rufl_test.c \ + rufl_chars:rufl_chars.c + # We do not want to run tests if building for RISC OS + TESTRUNNER := echo +else + DIR_TEST_ITEMS := nofonts:nofonts.c;harness.c;mocks.c \ + oldfminit:oldfminit.c;harness.c;mocks.c \ + olducsinit:olducsinit.c;harness.c;mocks.c \ + ucsinit:ucsinit.c;harness.c;mocks.c \ + manyfonts:manyfonts.c;harness.c;mocks.c +endif include $(NSBUILD)/Makefile.subdir diff --git a/test/data/Encoding b/test/data/oldfminit/Allerta index e5b633e..e5b633e 100644 --- a/test/data/Encoding +++ b/test/data/oldfminit/Allerta diff --git a/test/data/oldfminit/INDEX b/test/data/oldfminit/INDEX new file mode 100644 index 0000000..c2d250f --- /dev/null +++ b/test/data/oldfminit/INDEX @@ -0,0 +1,10 @@ +# Index file for non-UCS FM initialisation tests +# +# Test Description + +latin1.cfg Simple Latin1 Encoding +mergeumap.cfg Merge identical umaps +nomapping.cfg Fonts with no mapping +symbol.cfg Simple symbol fonts + +brokenencoding.cfg Garbage encoding file diff --git a/test/data/oldfminit/Latin1 b/test/data/oldfminit/Latin1 new file mode 100644 index 0000000..6821aa8 --- /dev/null +++ b/test/data/oldfminit/Latin1 @@ -0,0 +1,270 @@ +% Acorn_Latin1Encoding 1.00 0 + +%%RISCOS_BasedOn 0 +%%RISCOS_Alphabet 101 + +% These first characters are for use by PostScript printer driver ONLY, +% they are not accessible using the RISC OS font manager. +/ring +/circumflex +/tilde +/dotlessi +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef +/.notdef + +/space +/exclam +/quotedbl +/numbersign +/dollar +/percent +/ampersand +/quotesingle +/parenleft +/parenright +/asterisk +/plus +/comma +/hyphen +/period +/slash +/zero +/one +/two +/three +/four +/five +/six +/seven +/eight +/nine +/colon +/semicolon +/less +/equal +/greater +/question + +/at +/A +/B +/C +/D +/E +/F +/G +/H +/I +/J +/K +/L +/M +/N +/O +/P +/Q +/R +/S +/T +/U +/V +/W +/X +/Y +/Z +/bracketleft +/backslash +/bracketright +/asciicircum +/underscore + +/grave +/a +/b +/c +/d +/e +/f +/g +/h +/i +/j +/k +/l +/m +/n +/o +/p +/q +/r +/s +/t +/u +/v +/w +/x +/y +/z +/braceleft +/bar +/braceright +/asciitilde +/.notdef + +/Euro +/Wcircumflex +/wcircumflex +/.notdef +/.notdef +/Ycircumflex +/ycircumflex +/special1 +/special2 +/special3 +/special4 +/special5 +/ellipsis +/trademark +/perthousand +/bullet +/quoteleft +/quoteright +/guilsinglleft +/guilsinglright +/quotedblleft +/quotedblright +/quotedblbase +/endash +/emdash +/minus +/OE +/oe +/dagger +/daggerdbl +/fi +/fl + +/space +/exclamdown +/cent +/sterling +/currency +/yen +/brokenbar +/section +/dieresis +/copyright +/ordfeminine +/guillemotleft +/logicalnot +/hyphen +/registered +/macron +/degree +/plusminus +/twosuperior +/threesuperior +/acute +/mu +/paragraph +/periodcentered +/cedilla +/onesuperior +/ordmasculine +/guillemotright +/onequarter +/onehalf +/threequarters +/questiondown + +/Agrave +/Aacute +/Acircumflex +/Atilde +/Adieresis +/Aring +/AE +/Ccedilla +/Egrave +/Eacute +/Ecircumflex +/Edieresis +/Igrave +/Iacute +/Icircumflex +/Idieresis +/Eth +/Ntilde +/Ograve +/Oacute +/Ocircumflex +/Otilde +/Odieresis +/multiply +/Oslash +/Ugrave +/Uacute +/Ucircumflex +/Udieresis +/Yacute +/Thorn +/germandbls + +/agrave +/aacute +/acircumflex +/atilde +/adieresis +/aring +/ae +/ccedilla +/egrave +/eacute +/ecircumflex +/edieresis +/igrave +/iacute +/icircumflex +/idieresis +/eth +/ntilde +/ograve +/oacute +/ocircumflex +/otilde +/odieresis +/divide +/oslash +/ugrave +/uacute +/ucircumflex +/udieresis +/yacute +/thorn +/ydieresis diff --git a/test/data/oldfminit/brokenencoding.cfg b/test/data/oldfminit/brokenencoding.cfg new file mode 100644 index 0000000..b5e12c1 --- /dev/null +++ b/test/data/oldfminit/brokenencoding.cfg @@ -0,0 +1,28 @@ +# Configuration for broken encoding file + +%expumaps Corpus.Bold 0 +%expumaps Corpus.Bold.Oblique 0 +%expumaps Corpus.Medium 1 +%expumaps Corpus.Medium.Oblique 0 +%expumaps Homerton.Bold 0 +%expumaps Homerton.Bold.Oblique 0 +%expumaps Homerton.Medium 1 +%expumaps Homerton.Medium.Oblique 0 +%expumaps Trinity.Bold 0 +%expumaps Trinity.Bold.Italic 0 +%expumaps Trinity.Medium 1 +%expumaps Trinity.Medium.Italic 0 + +# Font name Encoding name Filename +Corpus.Bold Latin1 Allerta +Corpus.Bold.Oblique Latin1 Allerta +Corpus.Medium Latin1 Latin1 +Corpus.Medium.Oblique Latin1 Allerta +Homerton.Bold Latin1 Allerta +Homerton.Bold.Oblique Latin1 Allerta +Homerton.Medium Latin1 Latin1 +Homerton.Medium.Oblique Latin1 Allerta +Trinity.Bold Latin1 Allerta +Trinity.Bold.Italic Latin1 Allerta +Trinity.Medium Latin1 Latin1 +Trinity.Medium.Italic Latin1 Allerta diff --git a/test/data/oldfminit/latin1.cfg b/test/data/oldfminit/latin1.cfg new file mode 100644 index 0000000..646582a --- /dev/null +++ b/test/data/oldfminit/latin1.cfg @@ -0,0 +1,28 @@ +# Configuration for Latin1 language fonts + +%expumaps Corpus.Bold 1 +%expumaps Corpus.Bold.Oblique 1 +%expumaps Corpus.Medium 1 +%expumaps Corpus.Medium.Oblique 1 +%expumaps Homerton.Bold 1 +%expumaps Homerton.Bold.Oblique 1 +%expumaps Homerton.Medium 1 +%expumaps Homerton.Medium.Oblique 1 +%expumaps Trinity.Bold 1 +%expumaps Trinity.Bold.Italic 1 +%expumaps Trinity.Medium 1 +%expumaps Trinity.Medium.Italic 1 + +# Font name Encoding name Filename +Corpus.Bold Latin1 Latin1 +Corpus.Bold.Oblique Latin1 Latin1 +Corpus.Medium Latin1 Latin1 +Corpus.Medium.Oblique Latin1 Latin1 +Homerton.Bold Latin1 Latin1 +Homerton.Bold.Oblique Latin1 Latin1 +Homerton.Medium Latin1 Latin1 +Homerton.Medium.Oblique Latin1 Latin1 +Trinity.Bold Latin1 Latin1 +Trinity.Bold.Italic Latin1 Latin1 +Trinity.Medium Latin1 Latin1 +Trinity.Medium.Italic Latin1 Latin1 diff --git a/test/data/oldfminit/mergeumap.cfg b/test/data/oldfminit/mergeumap.cfg new file mode 100644 index 0000000..654a0bf --- /dev/null +++ b/test/data/oldfminit/mergeumap.cfg @@ -0,0 +1,40 @@ +# Configuration for merging duplicate umaps + +%expumaps Corpus.Bold 1 +%expumaps Corpus.Bold.Oblique 1 +%expumaps Corpus.Medium 1 +%expumaps Corpus.Medium.Oblique 1 +%expumaps Homerton.Bold 1 +%expumaps Homerton.Bold.Oblique 1 +%expumaps Homerton.Medium 1 +%expumaps Homerton.Medium.Oblique 1 +%expumaps Trinity.Bold 1 +%expumaps Trinity.Bold.Italic 1 +%expumaps Trinity.Medium 1 +%expumaps Trinity.Medium.Italic 1 + +# Font name Encoding name Filename +Corpus.Bold Latin1 Latin1 +Corpus.Bold.Oblique Latin1 Latin1 +Corpus.Medium Latin1 Latin1 +Corpus.Medium.Oblique Latin1 Latin1 +Corpus.Bold Latin2 Latin1 +Corpus.Bold.Oblique Latin2 Latin1 +Corpus.Medium Latin2 Latin1 +Corpus.Medium.Oblique Latin2 Latin1 +Homerton.Bold Latin1 Latin1 +Homerton.Bold.Oblique Latin1 Latin1 +Homerton.Medium Latin1 Latin1 +Homerton.Medium.Oblique Latin1 Latin1 +Homerton.Bold Latin2 Latin1 +Homerton.Bold.Oblique Latin2 Latin1 +Homerton.Medium Latin2 Latin1 +Homerton.Medium.Oblique Latin2 Latin1 +Trinity.Bold Latin1 Latin1 +Trinity.Bold.Italic Latin1 Latin1 +Trinity.Medium Latin1 Latin1 +Trinity.Medium.Italic Latin1 Latin1 +Trinity.Bold Latin2 Latin1 +Trinity.Bold.Italic Latin2 Latin1 +Trinity.Medium Latin2 Latin1 +Trinity.Medium.Italic Latin2 Latin1 diff --git a/test/data/oldfminit/nomapping.cfg b/test/data/oldfminit/nomapping.cfg new file mode 100644 index 0000000..18de2fb --- /dev/null +++ b/test/data/oldfminit/nomapping.cfg @@ -0,0 +1,19 @@ +# Configuration for fonts with no mapping + +%expumaps Corpus.Bold 0 +%expumaps Corpus.Bold.Oblique 0 +%expumaps Corpus.Medium 1 +%expumaps Corpus.Medium.Oblique 0 +%expumaps Homerton.Bold 0 +%expumaps Homerton.Bold.Oblique 0 +%expumaps Homerton.Medium 1 +%expumaps Homerton.Medium.Oblique 0 +%expumaps Trinity.Bold 0 +%expumaps Trinity.Bold.Italic 0 +%expumaps Trinity.Medium 1 +%expumaps Trinity.Medium.Italic 0 + +# Font name Encoding name Filename +Corpus.Medium Latin1 Latin1 +Homerton.Medium Latin1 Latin1 +Trinity.Medium Latin1 Latin1 diff --git a/test/data/oldfminit/symbol.cfg b/test/data/oldfminit/symbol.cfg new file mode 100644 index 0000000..ca7c760 --- /dev/null +++ b/test/data/oldfminit/symbol.cfg @@ -0,0 +1,28 @@ +# Configuration for symbol fonts + +%expumaps Corpus.Bold 1 +%expumaps Corpus.Bold.Oblique 1 +%expumaps Corpus.Medium 1 +%expumaps Corpus.Medium.Oblique 1 +%expumaps Homerton.Bold 1 +%expumaps Homerton.Bold.Oblique 1 +%expumaps Homerton.Medium 1 +%expumaps Homerton.Medium.Oblique 1 +%expumaps Trinity.Bold 1 +%expumaps Trinity.Bold.Italic 1 +%expumaps Trinity.Medium 1 +%expumaps Trinity.Medium.Italic 1 + +# Font name Encoding name Filename +Corpus.Bold Symbol Latin1 +Corpus.Bold.Oblique Symbol Latin1 +Corpus.Medium Symbol Latin1 +Corpus.Medium.Oblique Symbol Latin1 +Homerton.Bold Symbol Latin1 +Homerton.Bold.Oblique Symbol Latin1 +Homerton.Medium Symbol Latin1 +Homerton.Medium.Oblique Symbol Latin1 +Trinity.Bold Symbol Latin1 +Trinity.Bold.Italic Symbol Latin1 +Trinity.Medium Symbol Latin1 +Trinity.Medium.Italic Symbol Latin1 diff --git a/test/harness-priv.h b/test/harness-priv.h new file mode 100644 index 0000000..60d5135 --- /dev/null +++ b/test/harness-priv.h @@ -0,0 +1,45 @@ +#ifndef rufl_test_harness_priv_h_ +#define rufl_test_harness_priv_h_ + +#include <stdbool.h> +#include <stddef.h> +#include <inttypes.h> + +#include "harness.h" + +typedef struct { + unsigned int refcnt; + size_t name; /* Index of name in names array */ +#define FONT_ENCODING_SYMBOL ((size_t) -1) /* Symbol, not language, font */ + size_t encoding; /* Index of encoding in encodings array */ + int xsize; /* XSize of this font */ + int ysize; /* YSize if this font */ + int xres; /* XResolution of this font */ + int yres; /* YResolution of this font */ +} rufl_test_harness_sized_font; + +typedef struct { + int fm_version; + bool fm_ucs; + bool fm_broken_fec; + + const char **font_names; + size_t n_font_names; + + const char **encodings; + size_t n_encodings; + + /* n_font_names * (n_encodings + 1) entries */ + char **encoding_filenames; + + /* At most 256 active font handles */ + rufl_test_harness_sized_font fonts[256]; + int current_font; + + char *buffer; + int buffer_flags; +} rufl_test_harness_t; + +extern rufl_test_harness_t *h; + +#endif diff --git a/test/harness.c b/test/harness.c new file mode 100644 index 0000000..8f8ea9a --- /dev/null +++ b/test/harness.c @@ -0,0 +1,139 @@ +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "harness-priv.h" + +rufl_test_harness_t *h = NULL; + +static void rufl_test_harness_free(void) +{ + size_t ni, ei; + + free(h->font_names); + free(h->encodings); + if (h->encoding_filenames != NULL) { + for (ni = 0; ni != h->n_font_names; ni++) { + for (ei = 0; ei != h->n_encodings + 1; ei++) { + free(h->encoding_filenames[ + (ni * (h->n_encodings + 1)) + ei]); + } + } + } + free(h->encoding_filenames); + free(h); +} + +void rufl_test_harness_init(int fm_version, bool fm_ucs, bool preload) +{ + h = calloc(1, sizeof(*h)); + assert(h != NULL); + + h->fm_version = fm_version; + h->fm_ucs = fm_ucs; + h->fm_broken_fec = fm_version < 364; + + if (preload) { + /* Register ROM fonts as a convenience */ + rufl_test_harness_register_font("Corpus.Bold"); + rufl_test_harness_register_font("Corpus.Bold.Oblique"); + rufl_test_harness_register_font("Corpus.Medium"); + rufl_test_harness_register_font("Corpus.Medium.Oblique"); + rufl_test_harness_register_font("Homerton.Bold"); + rufl_test_harness_register_font("Homerton.Bold.Oblique"); + rufl_test_harness_register_font("Homerton.Medium"); + rufl_test_harness_register_font("Homerton.Medium.Oblique"); + rufl_test_harness_register_font("Trinity.Bold"); + rufl_test_harness_register_font("Trinity.Bold.Italic"); + rufl_test_harness_register_font("Trinity.Medium"); + rufl_test_harness_register_font("Trinity.Medium.Italic"); + + /* Register encodings as a convenience */ + rufl_test_harness_register_encoding("Cyrillic"); + rufl_test_harness_register_encoding("Greek"); + rufl_test_harness_register_encoding("Hebrew"); + rufl_test_harness_register_encoding("Latin1"); + rufl_test_harness_register_encoding("Latin2"); + rufl_test_harness_register_encoding("Latin3"); + rufl_test_harness_register_encoding("Latin4"); + rufl_test_harness_register_encoding("Latin5"); + rufl_test_harness_register_encoding("Latin6"); + rufl_test_harness_register_encoding("Latin7"); + rufl_test_harness_register_encoding("Latin8"); + rufl_test_harness_register_encoding("Latin9"); + rufl_test_harness_register_encoding("Latin10"); + if (fm_ucs) + rufl_test_harness_register_encoding("UTF8"); + rufl_test_harness_register_encoding("Welsh"); + } + + atexit(rufl_test_harness_free); +} + +void rufl_test_harness_register_font(const char *name) +{ + const char **names; + + /* Encoding paths must be registered last */ + assert(h->encoding_filenames == NULL); + + names = realloc(h->font_names, + (h->n_font_names + 1) * sizeof(*names)); + assert(names != NULL); + + h->font_names = names; + + h->font_names[h->n_font_names++] = name; +} + +void rufl_test_harness_register_encoding(const char *encoding) +{ + const char **encodings; + + /* Encoding paths must be registered last */ + assert(h->encoding_filenames == NULL); + + encodings = realloc(h->encodings, + (h->n_encodings + 1) * sizeof(*encodings)); + assert(encodings != NULL); + + h->encodings = encodings; + + h->encodings[h->n_encodings++] = encoding; +} + +void rufl_test_harness_set_font_encoding(const char *fontname, + const char *encoding, const char *path) +{ + size_t ni, ei; + + if (h->encoding_filenames == NULL) { + h->encoding_filenames = calloc( + h->n_font_names * (h->n_encodings + 1), + sizeof(*h->encoding_filenames)); + assert(h->encoding_filenames != NULL); + } + + /* Find font index */ + for (ni = 0; ni < h->n_font_names; ni++) { + if (strcmp(h->font_names[ni], fontname) == 0) + break; + } + assert(ni != h->n_font_names); + + /* Find encoding index */ + if (strcmp("Symbol", encoding) == 0) { + ei = h->n_encodings; + } else { + for (ei = 0; ei < h->n_encodings; ei++) { + if (strcmp(h->encodings[ei], encoding) == 0) + break; + } + assert(ei != h->n_encodings); + } + + if (h->encoding_filenames[(ni * (h->n_encodings + 1)) + ei] != NULL) + free(h->encoding_filenames[(ni * (h->n_encodings + 1)) + ei]); + h->encoding_filenames[(ni * (h->n_encodings + 1)) + ei] = strdup(path); + assert(h->encoding_filenames[(ni * (h->n_encodings + 1)) + ei] != NULL); +} diff --git a/test/harness.h b/test/harness.h new file mode 100644 index 0000000..b62617f --- /dev/null +++ b/test/harness.h @@ -0,0 +1,10 @@ +#ifndef rufl_test_harness_h_ +#define rufl_test_harness_h_ + +void rufl_test_harness_init(int fm_version, bool fm_ucs, bool preload); +void rufl_test_harness_register_font(const char *name); +void rufl_test_harness_register_encoding(const char *encoding); +void rufl_test_harness_set_font_encoding(const char *fontname, + const char *encoding, const char *path); + +#endif diff --git a/test/manyfonts.c b/test/manyfonts.c new file mode 100644 index 0000000..bc4b01e --- /dev/null +++ b/test/manyfonts.c @@ -0,0 +1,100 @@ +/* + * XXX: This test currently needs the following patch to be valid. + * We need a way of ensuring the library chooses the direct substitution + * table format (which basically means we need to flood a plane with glyphs) + * + * diff --git a/src/rufl_substitution_table.c b/src/rufl_substitution_table.c + * index f5de7d8..2b58b72 100644 + * --- a/src/rufl_substitution_table.c + * +++ b/src/rufl_substitution_table.c + * @@ -1019,7 +1019,7 @@ static rufl_code create_substitution_table_for_plane(unsigned int plane) + * table_entries, blocks_used); + * chd_size = rufl_substitution_table_estimate_size_chd( + * table_entries, blocks_used); + * - if (direct_size <= chd_size) { + * + if (1 || direct_size <= chd_size) { + * result = direct(table, table_entries, blocks_used, + * block_histogram, + * &rufl_substitution_table[plane]); + */ + +#include <ftw.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "rufl.h" + +#include "harness.h" +#include "testutils.h" + +static char template[] = "/tmp/manyfontsXXXXXX"; +static const char *ptmp = NULL; + +static int ftw_cb(const char *path, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) +{ + (void) sb; + (void) typeflag; + (void) ftwbuf; + + remove(path); + + return 0; +} + +static void cleanup(void) +{ + if (ptmp == NULL) + return; + + nftw(ptmp, ftw_cb, FOPEN_MAX, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); +} + +int main(int argc, const char **argv) +{ + char *names[300]; + int x; + + UNUSED(argc); + UNUSED(argv); + + ptmp = mkdtemp(template); + assert(NULL != ptmp); + atexit(cleanup); + chdir(ptmp); + + rufl_test_harness_init(380, true, true); + + for (x = 0; x < 300; x++) { + char buf[64]; + sprintf(buf, "Font%03d", x); + names[x] = strdup(buf); + rufl_test_harness_register_font(names[x]); + } + + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(303 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + + rufl_dump_state(true); + + rufl_quit(); + + /* Reinit -- should load cache */ + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(303 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + /* Done for real this time */ + rufl_quit(); + + for (x = 0; x < 300; x++) { + free(names[x]); + } + + printf("PASS\n"); + + return 0; +} diff --git a/test/mocks.c b/test/mocks.c new file mode 100644 index 0000000..734211b --- /dev/null +++ b/test/mocks.c @@ -0,0 +1,671 @@ +#include <assert.h> +#include <string.h> + +#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> + +#include "harness-priv.h" + +static os_error font_no_font = { error_FONT_NO_FONT, "Undefined font handle" }; +static os_error font_bad_font_number = { + error_FONT_BAD_FONT_NUMBER, + "Font handle out of range" +}; +static os_error font_not_found = { error_FONT_NOT_FOUND, "Font not found" }; +static os_error font_encoding_not_found = { + error_FONT_ENCODING_NOT_FOUND, + "Encoding not found" +}; +static os_error font_no_handles = { + error_FONT_NO_HANDLES, + "No more font handles" +}; +static os_error font_reserved = { + error_FONT_RESERVED, + "Reserved fields must be zero" +}; +static os_error buff_overflow = { error_BUFF_OVERFLOW, "Buffer overflow" }; +static os_error bad_parameters = { error_BAD_PARAMETERS, "Bad parameters" }; +static os_error no_such_swi = { error_NO_SUCH_SWI, "SWI not known" }; +static os_error unimplemented = { error_UNIMPLEMENTED, "Not implemented" }; + +/****************************************************************************/ + +os_error *xfont_cache_addr (int *version, int *cache_size, int *cache_used) +{ + if (version != NULL) + *version = h->fm_version; + if (cache_size != NULL) + *cache_size = 512 * 1024; + if (cache_used != NULL) + *cache_used = 0; + + return NULL; +} + +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) +{ + char name[80], encoding[80]; + const char *slash; + size_t ni, ei; + int fh; + + /* Default xres and yres */ + if (xres <= 0) + xres = 90; + if (yres <= 0) + yres = 90; + + /* Parse font name */ + slash = strchr(font_name, '\\'); + if (slash == NULL) { + /* Bare name: symbol font */ + strncpy(name, font_name, sizeof(name)); + name[sizeof(name)-1] = '\0'; + strcpy(encoding, "Symbol"); + } else { + /* Identifier: extract encoding */ + strncpy(name, font_name, slash - font_name); + name[slash-font_name] = '\0'; + assert(slash[1] == 'E'); + strncpy(encoding, slash + 2, sizeof(encoding)); + encoding[sizeof(encoding)-1] = '\0'; + } + + /* Determine if we know about this font name */ + for (ni = 0; ni < h->n_font_names; ni++) { + if (strcmp(h->font_names[ni], name) == 0) + break; + } + if (ni == h->n_font_names) { + return &font_not_found; + } + + /* Determine if we know about this encoding */ + if (strcmp("Symbol", encoding) == 0) { + ei = FONT_ENCODING_SYMBOL; + } else { + for (ei = 0; ei < h->n_encodings; ei++) { + if (strcmp(h->encodings[ei], encoding) == 0) + break; + } + if (ei == h->n_encodings) { + return &font_encoding_not_found; + } + } + + /* Find existing font handle (0 is forbidden) */ + for (fh = 1; fh < 256; fh++) { + if (h->fonts[fh].refcnt > 0 && h->fonts[fh].name == ni && + h->fonts[fh].encoding == ei && + h->fonts[fh].xsize == xsize && + h->fonts[fh].ysize == ysize && + h->fonts[fh].xres == xres && + h->fonts[fh].yres == yres) + break; + } + if (fh == 256) { + /* No existing font found: allocate new one */ + for (fh = 1; fh < 256; fh++) { + if (h->fonts[fh].refcnt == 0) + break; + } + if (fh == 256) { + return &font_no_handles; + } + + h->fonts[fh].name = ni; + h->fonts[fh].encoding = ei; + h->fonts[fh].xsize = xsize; + h->fonts[fh].ysize = ysize; + h->fonts[fh].xres = xres; + h->fonts[fh].yres = yres; + } + + /* Bump refcnt */ + h->fonts[fh].refcnt++; + + /* Set current font */ + h->current_font = fh; + + if (font != NULL) + *font = (font_f) fh; + if (xres_out != NULL) + *xres_out = xres; + if (yres_out != NULL) + *yres_out = yres; + + return NULL; +} + +os_error *xfont_lose_font (font_f font) +{ + if (font != 0 && h->fonts[font].refcnt > 0) + h->fonts[font].refcnt--; + + return NULL; +} + +os_error *xfont_read_info (font_f font, int *x0, int *y0, int *x1, int *y1) +{ + if (font == 0) + return &font_bad_font_number; + if (h->fonts[font].refcnt == 0) + return &font_no_font; + + /* Cheat: just scale point size to OS units */ + if (x0 != NULL) + *x0 = 0; + if (y0 != NULL) + *y0 = 0; + if (x1 != NULL) + *x1 = (h->fonts[font].xsize * 180) / (72 * 16); + if (y1 != NULL) + *y1 = (h->fonts[font].ysize * 180) / (72 * 16); + + return NULL; +} + +os_error *xfont_read_font_metrics (font_f font, font_bbox_info *bbox_info, + font_width_info *xwidth_info, font_width_info *ywidth_info, + font_metrics_misc_info *misc_info, font_kern_info *kern_info, + font_metric_flags *flags, int *bbox_info_size, + int *xwidth_info_size, int *ywidth_info_size, + int *misc_info_size, int *kern_info_size) +{ + if (font == 0) + return &font_bad_font_number; + if (h->fonts[font].refcnt == 0) + return &font_no_font; + if (bbox_info != NULL || xwidth_info != NULL || ywidth_info != NULL || + kern_info != NULL || flags != NULL) + return &unimplemented; + + if (misc_info != NULL) { + os_error *err = xfont_read_info(font, + &misc_info->x0, &misc_info->y0, + &misc_info->x1, &misc_info->y1); + if (err != NULL) + return err; + misc_info->xkern = misc_info->ykern = 0; + misc_info->italic_correction = 0; + misc_info->underline_position = 0; + misc_info->underline_thickness = 0; + misc_info->cap_height = misc_info->y1 - misc_info->y0; + misc_info->xheight = misc_info->cap_height >> 1; + misc_info->descender = misc_info->ascender = 0; + } + + if (bbox_info_size != NULL) + *bbox_info_size = 0; + if (xwidth_info_size != NULL) + *xwidth_info_size = 0; + if (ywidth_info_size != NULL) + *ywidth_info_size = 0; + if (misc_info_size != NULL) + *misc_info_size = sizeof(font_metrics_misc_info); + if (kern_info_size != NULL) + *kern_info_size = 0; + + return NULL; +} + +os_error *xfont_read_encoding_filename (font_f font, char *buffer, int size, + char **end) +{ + const char *filename = NULL; + size_t ei; + + if (font == 0) + return &font_bad_font_number; + if (h->fonts[font].refcnt == 0) + return &font_no_font; + if (h->encoding_filenames == NULL) + return &font_encoding_not_found; + if (h->fonts[font].encoding != FONT_ENCODING_SYMBOL) { + ei = h->fonts[font].encoding; + } else { + ei = h->n_encodings; + } + filename = h->encoding_filenames[ + (h->fonts[font].name * (h->n_encodings + 1)) + ei]; + if (filename == NULL) + return &font_encoding_not_found; + if (buffer == NULL || (size_t) size < strlen(filename) + 1) + return &bad_parameters; + + strcpy(buffer, filename); + + if (end != NULL) + *end = buffer + strlen(filename) + 1; + + return NULL; +} + +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) +{ + const char **values; + size_t n_values; + size_t index = (context & 0xffff); + + if ((context & font_RETURN_FONT_MENU) && + (context & ~(font_USE_LINEFEED | + font_RETURN_FONT_MENU | + font_ALLOW_SYSTEM_FONT | + font_GIVEN_TICK | 0x400000)) >> 16) + return &bad_parameters; + if (!(context & font_RETURN_FONT_MENU) && + (context & ~(font_RETURN_FONT_NAME | + font_RETURN_LOCAL_FONT_NAME | + font_USE_LINEFEED | 0x400000)) >> 16) + return &bad_parameters; + if (context & font_RETURN_FONT_MENU) + return &unimplemented; + + if (context & 0x400000) { + values = h->encodings; + n_values = h->n_encodings; + } else { + values = h->font_names; + n_values = h->n_font_names; + } + + if (index < n_values) { + int len = (int) strlen(values[index]) + 1; + if (context & font_RETURN_FONT_NAME) { + if (buffer1 != NULL && size1 < len) + return &buff_overflow; + if (buffer1 != NULL) + strcpy((char *) buffer1, values[index]); + if (used1 != NULL) + *used1 = len; + } + if (context & font_RETURN_LOCAL_FONT_NAME) { + if (buffer2 != NULL && size2 < len) + return &buff_overflow; + if (buffer2 != NULL) + strcpy((char *) buffer2, values[index]); + if (used2 != NULL) + *used2 = len; + } + index++; + } else { + index = -1; + } + + if (context_out != NULL) + *context_out = (font_list_context) index; + + (void) tick_font; + + return NULL; +} + +os_error *xfont_set_font (font_f font) +{ + if (font == 0) + return &font_bad_font_number; + if (h->fonts[font].refcnt == 0) + return &font_no_font; + + h->current_font = font; + + return NULL; +} + +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) +{ + if (!(flags & font_GIVEN_FONT) || font == 0) + font = h->current_font; + if (font == 0 || h->fonts[font].refcnt == 0) + return &font_no_font; + + if (flags & font_GIVEN_FONT) + h->current_font = font; + + //XXX: + //XXX: also, pay attention to redirection to buffer + (void) string; + (void) xpos; + (void) ypos; + (void) block; + (void) trfm; + (void) length; + + return NULL; +} + +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) +{ + size_t advance = 1; + int width = 0; + + if (!(flags & font_GIVEN_FONT) || font == 0) + font = h->current_font; + if (font == 0 || h->fonts[font].refcnt == 0) + return &font_no_font; + + if ((flags & font_GIVEN_BLOCK) && block == NULL) + return &bad_parameters; + if ((flags & font_RETURN_BBOX) && !(flags & font_GIVEN_BLOCK)) + return &bad_parameters; + if ((flags & font_GIVEN_BLOCK) && (block->space.x != 0 || + block->space.y != 0 || + block->letter.x != 0 || + block->letter.y != 0 || + block->split_char != -1)) + return &unimplemented; + + if ((flags & font_GIVEN32_BIT) && (flags & font_GIVEN16_BIT)) + return &bad_parameters; + + if (!(flags & font_GIVEN_LENGTH)) + length = 0x7ffffffc; + + if (flags & font_GIVEN32_BIT) + advance = 4; + else if (flags & font_GIVEN16_BIT) + advance = 2; + + /* Consume up to length bytes of input */ + while (length > 0) { + uint32_t c = 0, i; + int cwidth; + for (i = 0; i < advance; i++) { + c |= s[i] << (advance - i - 1); + } + s += advance; + length -= advance; + + /* Regardless of length, stop on terminator */ + if (c == 0 || c == 10 || c == 13) + break; + + /* Just scale font size to millipoints and add on the width */ + cwidth = ((h->fonts[font].xsize * 1000) >> 4); + if ((flags & font_RETURN_CARET_POS) && x > 0 && + (width + cwidth/2) > x) { + /* Split point is less than half way through + * this character: exclude it */ + s -= advance; + length += advance; + break; + } + width += cwidth; + //XXX: how is negative x meant to work? + if (x > 0 && width > x) + break; + } + + if (flags & font_RETURN_BBOX) { + block->bbox.x0 = 0; + block->bbox.y0 = 0; + block->bbox.x1 = width; + block->bbox.y1 = (h->fonts[font].ysize * 1000) >> 4; + } + + if (x_out != NULL) + *x_out = width; + if (y_out != NULL) + *y_out = (h->fonts[font].ysize * 1000) >> 4; + if (split_point != NULL) + *split_point = (char *) s; + + (void) y; + (void) trfm; + (void) num_split_chars; + + return NULL; +} + +os_error *xfont_switch_output_to_buffer (font_output_flags flags, + byte *buffer, char **end) +{ + if ((intptr_t) buffer <= 0 && flags != 0) + return &font_reserved; + if (flags & ~(font_NO_OUTPUT | font_ADD_HINTS | font_ERROR_IF_BITMAP)) + return &font_reserved; + + if (end) + *end = h->buffer; + + if ((intptr_t) buffer != -1) { + h->buffer = (char *) buffer; + h->buffer_flags = flags; + } + + return NULL; +} + +os_error *xfont_enumerate_characters (font_f font, int character, + int *next_character, int *internal_character_code) +{ + static int extchars[] = { 0x20, 0x21, 0x30, 0x31, 0x32, 0xa0, 0x10ac0, 0x20021, 0x30000, -1 }; + static int intchars[] = { 1, 2, 3, 4, -1, 5, 6, 7, 8 }; + size_t index = 0; + int next = -1, internal = -1; + + if (!h->fm_ucs) + return &no_such_swi; + + if (font == 0) + font = h->current_font; + if (font == 0) + return &font_bad_font_number; + if (h->fonts[font].refcnt == 0) + return &font_no_font; + + /* Broken FEC: skip first chunk unless code is valid. + * (only 0x20 and 0x21 are valid in the first chunk here, + * so we simply need to skip over these if the code is + * less than 0x20 -- any other codes in the first chunk + * will just fall out of the usual "next code" logic) + */ + if (h->fm_broken_fec && character < extchars[0]) + index = 2; + + for (; index < (sizeof(intchars)/sizeof(intchars[0])); index++) { + if (extchars[index] == character) { + /* Found: return it and compute next */ + next = extchars[index+1]; + internal = intchars[index]; + break; + } else if (extchars[index] > character) { + /* Not found and won't be: compute next */ + next = extchars[index]; + internal = -1; + break; + } + } + + if (next_character != NULL) + *next_character = next; + if (internal_character_code != NULL) + *internal_character_code = internal; + + return NULL; +} + +/****************************************************************************/ + +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) +{ + const char *prefix = "Resources:$.Fonts."; + size_t len = strlen(path_name) + strlen(prefix) + 1; + + if (strcmp(var, "Font$Path") != 0 || path != NULL) + return &unimplemented; + + if (buffer == NULL && size != 0) + return &bad_parameters; + + if (buffer != NULL && size < (int) len) + return &buff_overflow; + + if (buffer != NULL) { + strcpy(buffer, prefix); + strcpy(buffer + strlen(prefix), path_name); + } + + if (spare != NULL) + *spare = size - len; + + return NULL; +} + +/****************************************************************************/ + +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/nofonts.c b/test/nofonts.c new file mode 100644 index 0000000..557d764 --- /dev/null +++ b/test/nofonts.c @@ -0,0 +1,20 @@ +#include <stdio.h> + +#include "rufl.h" + +#include "harness.h" +#include "testutils.h" + +int main(int argc, const char **argv) +{ + UNUSED(argc); + UNUSED(argv); + + rufl_test_harness_init(380, true, false); + + assert(rufl_FONT_MANAGER_ERROR == rufl_init()); + + printf("PASS\n"); + + return 0; +} diff --git a/test/oldfminit.c b/test/oldfminit.c new file mode 100644 index 0000000..c554499 --- /dev/null +++ b/test/oldfminit.c @@ -0,0 +1,353 @@ +#include <ftw.h> +#include <libgen.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "rufl.h" + +/* dirty! */ +#include "../src/rufl_internal.h" + +#include "harness.h" +#include "testutils.h" + +struct expumap { + char *fontname; + size_t num_umaps; +}; + +struct cfg { + const char *datadir; + + struct expumap *expumaps; + size_t n_expumaps; +}; + +static char template[] = "/tmp/oldfminitXXXXXX"; +static const char *ptmp = NULL; +static struct cfg cfg; + +static int ftw_cb(const char *path, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) +{ + (void) sb; + (void) typeflag; + (void) ftwbuf; + + remove(path); + + return 0; +} + +static void cleanup(void) +{ + if (cfg.expumaps != NULL) { + size_t i; + + for (i = 0; i < cfg.n_expumaps; i++) { + free(cfg.expumaps[i].fontname); + } + free(cfg.expumaps); + } + + if (ptmp == NULL) + return; + + nftw(ptmp, ftw_cb, FOPEN_MAX, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); +} + +static void parse_cfg(const char *path, struct cfg *cfg, + void (*cb)(struct cfg *cfg, const char *line, size_t len)) +{ + FILE *fp; + char wbuf[4096]; + size_t nleft = 0; + + fp = fopen(path, "r"); + assert(fp != NULL); + + while (!feof(fp)) { + char buf[2048]; + size_t nread; + const char *p, *s; + + nread = fread(buf, 1, sizeof(buf), fp); + if (nread != sizeof(buf)) { + assert(ferror(fp) == 0); + } + + memcpy(wbuf + nleft, buf, nread); + nleft += nread; + + for (p = s = wbuf; p < wbuf + nleft; p++) { + if (*p == '\n') { + cb(cfg, s, p - s); + s = p+1; + } + } + if (s != wbuf + nleft) { + memmove(wbuf, s, p - s); + nleft = p - s; + } else { + nleft = 0; + } + assert(nleft < sizeof(buf)); + } + assert(nleft == 0); + + fclose(fp); +} + +static void parse_expumaps(struct cfg *cfg, char *data, size_t len) +{ + char *p, *s; + const char *font = NULL, *count = NULL; + struct expumap *e; + size_t num_umaps; + + for (p = s = data; p < data+len; p++) { + if (*p == ' ' || *p == '\t') { + *p = '\0'; + if (s != p) { + if (font == NULL) + font = s; + else if (count == NULL) + count = s; + } + s = p+1; + } + } + if (count == NULL) + count = s; + + num_umaps = strtoul(count, &p, 10); + assert((size_t)(p-count) == strlen(count)); + + e = realloc(cfg->expumaps, (cfg->n_expumaps + 1) * sizeof(*e)); + assert(e != NULL); + + cfg->expumaps = e; + cfg->expumaps[cfg->n_expumaps].fontname = strdup(font); + assert(cfg->expumaps[cfg->n_expumaps].fontname != NULL); + cfg->expumaps[cfg->n_expumaps].num_umaps = num_umaps; + cfg->n_expumaps++; +} + +static void parse_directive(struct cfg *cfg, char *linecpy, size_t len) +{ + char *p, *s; + const char *directive = NULL; + + for (p = s = linecpy; p < linecpy+len; p++) { + if (*p == ' ' || *p == '\t') { + *p = '\0'; + if (s != p && directive == NULL) { + directive = s; + s = p+1; + break; + } + s = p+1; + } + } + if (directive == NULL) + directive = s; + + if (strcmp("\%expumaps", directive) == 0) { + parse_expumaps(cfg, s, len - (s - linecpy)); + } +} + +static void parse_encoding(struct cfg *cfg, char *linecpy, size_t len) +{ + char *p, *s; + const char *font = NULL, *encoding = NULL, *file = NULL; + char *path; + + for (p = s = linecpy; p < linecpy+len; p++) { + if (*p == ' ' || *p == '\t') { + *p = '\0'; + if (s != p) { + if (font == NULL) + font = s; + else if (encoding == NULL) + encoding = s; + else if (file == NULL) + file = s; + } + s = p+1; + } + } + if (file == NULL) + file = s; + + assert(font != NULL); + assert(encoding != NULL); + assert(file != NULL); + + path = malloc(strlen(cfg->datadir) + strlen(file) + 2); + assert(path != NULL); + strcpy(path, cfg->datadir); + path[strlen(cfg->datadir)] = '/'; //XXX: platform-agnostic dirsep? + strcpy(path+strlen(cfg->datadir)+1, file); + + rufl_test_harness_set_font_encoding(font, encoding, path); + + free(path); +} + +static void line_cb(struct cfg *cfg, const char *line, size_t len) +{ + char *linecpy; + + if (len == 0 || line[0] == '#') + return; + + linecpy = malloc(len + 1); + assert(linecpy != NULL); + memcpy(linecpy, line, len); + linecpy[len] = '\0'; + + if (line[0] == '%') + parse_directive(cfg, linecpy, len); + else + parse_encoding(cfg, linecpy, len); + + free(linecpy); +} + +static void read_config(const char *path, struct cfg *cfg) +{ + char *pathcpy; + + pathcpy = strdup(path); + assert(pathcpy != NULL); + + cfg->datadir = dirname(pathcpy); + + parse_cfg(path, cfg, line_cb); + + free(pathcpy); + cfg->datadir = NULL; +} + +int main(int argc, const char **argv) +{ + int width, x; + size_t offset; + int32_t xkern, ykern, italic, ascent, descent, xheight, cap_height; + int32_t x_bearing, y_bearing, mwidth, mheight, x_advance, y_advance; + int8_t uline_position; + uint8_t uline_thickness; + os_box bbox; + + assert(2 == argc); + + ptmp = mkdtemp(template); + assert(NULL != ptmp); + atexit(cleanup); + chdir(ptmp); + + rufl_test_harness_init(339, false, true); + + read_config(argv[1], &cfg); + + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + + if (cfg.expumaps != NULL) { + size_t i, j; + for (i = 0; i != cfg.n_expumaps; i++) { + for (j = 0; j != rufl_font_list_entries; j++) { + if (strcmp(cfg.expumaps[i].fontname, rufl_font_list[j].identifier) == 0) { + assert(cfg.expumaps[i].num_umaps == rufl_font_list[j].num_umaps); + } + } + } + } + + assert(rufl_OK == rufl_font_metrics("Corpus", rufl_WEIGHT_500, + &bbox, &xkern, &ykern, &italic, + &ascent, &descent, &xheight, &cap_height, + &uline_position, &uline_thickness)); + assert(0 == bbox.x0); + assert(2 == bbox.x1); + assert(0 == bbox.y0); + assert(2 == bbox.y1); + assert(0 == xkern); + assert(0 == ykern); + assert(0 == italic); + assert(0 == ascent); + assert(0 == descent); + assert((bbox.y1 - bbox.y0) == cap_height); + assert((cap_height / 2) == xheight); + assert(0 == uline_position); + assert(0 == uline_thickness); + + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, &width)); + assert(50 == width); + + /* Place caret after first character */ + assert(rufl_OK == rufl_x_to_offset("Homerton", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(1 == offset); + assert(25 == x); + + /* Attempt to split after first character. As the split point is + * coincident with the start of the second character, however, + * the split point is placed after it. */ + assert(rufl_OK == rufl_split("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(3 == offset); + assert(50 == x); + + /* Compute width of replacement character */ + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xef\xbf\xbd", 3, &width)); + assert(17 == width); + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xf0\xa0\x80\xa5", 4, &width)); + assert(26 == width); + + /* Measure font bounding box */ + assert(rufl_OK == rufl_font_bbox("Corpus", rufl_WEIGHT_500, 160, + &bbox)); + assert(0 == bbox.x0); + assert(25 == bbox.x1); + assert(0 == bbox.y0); + assert(25 == bbox.y1); + + /* Trivial render */ + assert(rufl_OK == rufl_paint("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 0, 0, 0)); + + rufl_dump_state(true); + + /* Obtain metrics for a glyph */ + assert(rufl_OK == rufl_glyph_metrics("Homerton", rufl_WEIGHT_500, 160, + "!", 1, &x_bearing, &y_bearing, + &mwidth, &mheight, &x_advance, &y_advance)); + assert(0 == x_bearing); + assert(10000 == y_bearing); + assert(10000 == mwidth); + assert(10000 == mheight); + assert(10000 == x_advance); + assert(10000 == y_advance); + + rufl_quit(); + + /* Reinit -- should load cache */ + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + /* Done for real this time */ + rufl_quit(); + + printf("PASS\n"); + + return 0; +} diff --git a/test/olducsinit.c b/test/olducsinit.c new file mode 100644 index 0000000..ed3d846 --- /dev/null +++ b/test/olducsinit.c @@ -0,0 +1,140 @@ +#include <ftw.h> +#include <stdio.h> +#include <unistd.h> + +#include "rufl.h" + +#include "harness.h" +#include "testutils.h" + +static char template[] = "/tmp/olducsinitXXXXXX"; +static const char *ptmp = NULL; + +static int ftw_cb(const char *path, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) +{ + (void) sb; + (void) typeflag; + (void) ftwbuf; + + remove(path); + + return 0; +} + +static void cleanup(void) +{ + if (ptmp == NULL) + return; + + nftw(ptmp, ftw_cb, FOPEN_MAX, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); +} + +int main(int argc, const char **argv) +{ + int width, x; + size_t offset; + int32_t xkern, ykern, italic, ascent, descent, xheight, cap_height; + int32_t x_bearing, y_bearing, mwidth, mheight, x_advance, y_advance; + int8_t uline_position; + uint8_t uline_thickness; + os_box bbox; + + UNUSED(argc); + UNUSED(argv); + + ptmp = mkdtemp(template); + assert(NULL != ptmp); + atexit(cleanup); + chdir(ptmp); + + rufl_test_harness_init(361, true, true); + + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + + assert(rufl_OK == rufl_font_metrics("Corpus", rufl_WEIGHT_500, + &bbox, &xkern, &ykern, &italic, + &ascent, &descent, &xheight, &cap_height, + &uline_position, &uline_thickness)); + assert(0 == bbox.x0); + assert(2 == bbox.x1); + assert(0 == bbox.y0); + assert(2 == bbox.y1); + assert(0 == xkern); + assert(0 == ykern); + assert(0 == italic); + assert(0 == ascent); + assert(0 == descent); + assert((bbox.y1 - bbox.y0) == cap_height); + assert((cap_height / 2) == xheight); + assert(0 == uline_position); + assert(0 == uline_thickness); + + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, &width)); + assert(50 == width); + + /* Place caret after first character */ + assert(rufl_OK == rufl_x_to_offset("Homerton", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(1 == offset); + assert(25 == x); + + /* Attempt to split after first character. As the split point is + * coincident with the start of the second character, however, + * the split point is placed after it. */ + assert(rufl_OK == rufl_split("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(3 == offset); + assert(50 == x); + + /* Compute width of replacement character */ + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xef\xbf\xbd", 3, &width)); + assert(17 == width); + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xf0\xa0\x80\xa5", 4, &width)); + assert(26 == width); + + /* Measure font bounding box */ + assert(rufl_OK == rufl_font_bbox("Corpus", rufl_WEIGHT_500, 160, + &bbox)); + assert(0 == bbox.x0); + assert(25 == bbox.x1); + assert(0 == bbox.y0); + assert(25 == bbox.y1); + + /* Trivial render */ + assert(rufl_OK == rufl_paint("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 0, 0, 0)); + + /* Obtain metrics for a glyph */ + assert(rufl_OK == rufl_glyph_metrics("Homerton", rufl_WEIGHT_500, 160, + "!", 1, &x_bearing, &y_bearing, + &mwidth, &mheight, &x_advance, &y_advance)); + assert(0 == x_bearing); + assert(10000 == y_bearing); + assert(10000 == mwidth); + assert(10000 == mheight); + assert(10000 == x_advance); + assert(10000 == y_advance); + + rufl_dump_state(true); + + rufl_quit(); + + /* Reinit -- should load cache */ + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + /* Done for real this time */ + rufl_quit(); + + printf("PASS\n"); + + return 0; +} diff --git a/test/rufl_chars.c b/test/rufl_chars.c index 14a0fb6..64831ad 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; @@ -276,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/rufl_test.c b/test/rufl_test.c index 51a29d6..bc644f5 100644 --- a/test/rufl_test.c +++ b/test/rufl_test.c @@ -18,23 +18,24 @@ 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 uint8_t *s8, const uint32_t *s32, unsigned int n, int x, int y); int main(void) { - char utf8_test[] = "Hello, world! ὕαλον " - "Uherské Hradiště. 𐀀"; + const char utf8_test[] = "Hello, world! ὕαλον " + "Uherské Hradiště. 𐀀" + "\xf0\xa0\x80\xa1"; int width; size_t char_offset; 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(); + rufl_dump_state(false); try(rufl_paint("NewHall", rufl_WEIGHT_400, 240, utf8_test, sizeof utf8_test - 1, 1200, 1000, 0), "rufl_paint"); @@ -62,9 +63,9 @@ int main(void) 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; @@ -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 uint8_t *s8, const uint32_t *s32, unsigned int n, int x, int y) { (void) context; @@ -140,9 +141,9 @@ 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) s16[i]); + printf("%x ", (unsigned int) s32[i]); printf("\" "); } printf("%i %i\n", x, y); 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 diff --git a/test/ucsinit.c b/test/ucsinit.c new file mode 100644 index 0000000..25aea60 --- /dev/null +++ b/test/ucsinit.c @@ -0,0 +1,140 @@ +#include <ftw.h> +#include <stdio.h> +#include <unistd.h> + +#include "rufl.h" + +#include "harness.h" +#include "testutils.h" + +static char template[] = "/tmp/ucsinitXXXXXX"; +static const char *ptmp = NULL; + +static int ftw_cb(const char *path, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) +{ + (void) sb; + (void) typeflag; + (void) ftwbuf; + + remove(path); + + return 0; +} + +static void cleanup(void) +{ + if (ptmp == NULL) + return; + + nftw(ptmp, ftw_cb, FOPEN_MAX, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); +} + +int main(int argc, const char **argv) +{ + int width, x; + size_t offset; + int32_t xkern, ykern, italic, ascent, descent, xheight, cap_height; + int32_t x_bearing, y_bearing, mwidth, mheight, x_advance, y_advance; + int8_t uline_position; + uint8_t uline_thickness; + os_box bbox; + + UNUSED(argc); + UNUSED(argv); + + ptmp = mkdtemp(template); + assert(NULL != ptmp); + atexit(cleanup); + chdir(ptmp); + + rufl_test_harness_init(380, true, true); + + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + + assert(rufl_OK == rufl_font_metrics("Corpus", rufl_WEIGHT_500, + &bbox, &xkern, &ykern, &italic, + &ascent, &descent, &xheight, &cap_height, + &uline_position, &uline_thickness)); + assert(0 == bbox.x0); + assert(2 == bbox.x1); + assert(0 == bbox.y0); + assert(2 == bbox.y1); + assert(0 == xkern); + assert(0 == ykern); + assert(0 == italic); + assert(0 == ascent); + assert(0 == descent); + assert((bbox.y1 - bbox.y0) == cap_height); + assert((cap_height / 2) == xheight); + assert(0 == uline_position); + assert(0 == uline_thickness); + + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, &width)); + assert(50 == width); + + /* Place caret after first character */ + assert(rufl_OK == rufl_x_to_offset("Homerton", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(1 == offset); + assert(25 == x); + + /* Attempt to split after first character. As the split point is + * coincident with the start of the second character, however, + * the split point is placed after it. */ + assert(rufl_OK == rufl_split("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 25, &offset, &x)); + assert(3 == offset); + assert(50 == x); + + /* Compute width of replacement character */ + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xef\xbf\xbd", 3, &width)); + assert(17 == width); + assert(rufl_OK == rufl_width("Corpus", rufl_WEIGHT_500, 160, + "\xf0\xa0\x80\xa5", 4, &width)); + assert(26 == width); + + /* Measure font bounding box */ + assert(rufl_OK == rufl_font_bbox("Corpus", rufl_WEIGHT_500, 160, + &bbox)); + assert(0 == bbox.x0); + assert(25 == bbox.x1); + assert(0 == bbox.y0); + assert(25 == bbox.y1); + + /* Trivial render */ + assert(rufl_OK == rufl_paint("Trinity", rufl_WEIGHT_500, 160, + "!\xc2\xa0", 3, 0, 0, 0)); + + /* Obtain metrics for a glyph */ + assert(rufl_OK == rufl_glyph_metrics("Homerton", rufl_WEIGHT_500, 160, + "!", 1, &x_bearing, &y_bearing, + &mwidth, &mheight, &x_advance, &y_advance)); + assert(0 == x_bearing); + assert(10000 == y_bearing); + assert(10000 == mwidth); + assert(10000 == mheight); + assert(10000 == x_advance); + assert(10000 == y_advance); + + rufl_dump_state(true); + + rufl_quit(); + + /* Reinit -- should load cache */ + assert(rufl_OK == rufl_init()); + assert(NULL == rufl_fm_error); + assert(3 == rufl_family_list_entries); + assert(NULL != rufl_family_menu); + /* Done for real this time */ + rufl_quit(); + + printf("PASS\n"); + + return 0; +} |