summaryrefslogtreecommitdiff
path: root/src/rufl_internal.h
blob: 42ed5c47cca5ad6cd69c27acc952c41e711d2da8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/*
 * This file is part of RUfl
 * Licensed under the MIT License,
 *                http://www.opensource.org/licenses/mit-license
 * Copyright 2006 James Bursa <james@semichrome.net>
 */

#include <inttypes.h>
#include <limits.h>
#include <oslib/font.h>
#include "rufl.h"
#ifdef __CC_NORCROFT
#include "strfuncs.h"
#endif


/**
 * 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 {
	/** 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 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
	/** All characters in the block are present. */
#	define BLOCK_FULL 255

	/** Block table. Each entry is a 256-bit bitmap indicating which
	 * characters in the block are present and absent. */
	uint8_t block[254][32];
};


/** Part of struct rufl_unicode_map. */
struct rufl_unicode_map_entry {
	/** Unicode value (must be in Basic Multilingual Plane). */
	uint16_t u;
	/** Corresponding character. */
	uint8_t c;
};


/** Old font manager: mapping from Unicode to character code. This is simply
 * an array sorted by Unicode value, suitable for bsearch(). If a font has
 * support for multiple encodings, then it will have multiple unicode maps.
 * The encoding field contains the name of the encoding to pass to the 
 * font manager. This will be NULL if the font is a Symbol font. */
struct rufl_unicode_map {
	/** Corresponding encoding name */
	char *encoding;
	/** Number of valid entries in map. */
	size_t entries;
	/** Map from Unicode to character code. */
	struct rufl_unicode_map_entry map[256];
};


/** An entry in rufl_font_list. */
struct rufl_font_list_entry {
	/** Font identifier (name). */
	char *identifier;
	/** Character set of font. */
	struct rufl_character_set *charset;
	/** Number of Unicode mapping tables */
	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). */
	uint32_t family;
	/** Font weight (0 to 8). */
	uint32_t weight;
	/** Font slant (0 or 1). */
	uint32_t slant;
};
/** List of all available fonts. */
extern struct rufl_font_list_entry *rufl_font_list;
/** Number of entries in rufl_font_list. */
extern size_t rufl_font_list_entries;


/** An entry in rufl_family_map. */
struct rufl_family_map_entry {
	/** This style does not exist in this family. */
#	define NO_FONT UINT_MAX
	/** Map from weight and slant to index in rufl_font_list, or NO_FONT. */
	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;


/** No font contains this character. */
#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. */
#define rufl_CACHE_SIZE 10

/** An entry in rufl_cache. */
struct rufl_cache_entry {
	/** Font number (index in rufl_font_list), or rufl_CACHE_*. */
	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. */
	uint32_t size;
	/** Font encoding */
	const char *encoding;
	/** Value of rufl_cache_time when 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 uint32_t rufl_cache_time;

/** Font manager does not support Unicode. */
extern bool rufl_old_font_manager;

/** Font manager supports background blending */
extern bool rufl_can_background_blend;

rufl_code rufl_find_font_family(const char *family, rufl_style font_style,
		unsigned int *font, unsigned int *slanted,
		struct rufl_character_set **charset);
rufl_code rufl_find_font(unsigned int font, unsigned int font_size,
		const char *encoding, font_f *fhandle);
bool rufl_character_set_test(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) &&    \
			((s[2] & 0xc0) == 0x80) && ((s[3] & 0xc0) == 0x80)) {  \
		u = ((s[0] & 0x7) << 18) | ((s[1] & 0x3f) << 12) |	       \
				((s[2] & 0x3f) << 6) | (s[3] & 0x3f);	       \
		s += 4; l -= 4;						       \
		if (u < 0x10000) u = 0xfffd;				       \
	} else if (3 <= l && ((s[0] & 0xf0) == 0xe0) &&			       \
			((s[1] & 0xc0) == 0x80) &&			       \
			((s[2] & 0xc0) == 0x80)) {			       \
		u = ((s[0] & 0xf) << 12) | ((s[1] & 0x3f) << 6) |	       \
				(s[2] & 0x3f);				       \
		s += 3; l -= 3;						       \
		if (u < 0x800) u = 0xfffd;				       \
	} else if (2 <= l && ((s[0] & 0xe0) == 0xc0) &&			       \
			((s[1] & 0xc0) == 0x80)) {			       \
		u = ((s[0] & 0x3f) << 6) | (s[1] & 0x3f);		       \
		s += 2; l -= 2;						       \
		if (u < 0x80) u = 0xfffd;				       \
	} else if ((s[0] & 0x80) == 0) {				       \
		u = s[0];						       \
		s++; l--;						       \
	} else {							       \
		u = 0xfffd;						       \
		s++; l--;						       \
	}								       \
	if ((u >= 0xd800 && u <= 0xdfff) || u == 0xfffe || u == 0xffff) {      \
		u = 0xfffd;						       \
	}

#define rufl_CACHE_TEMPLATE "<Wimp$ScrapDir>.RUfl.CacheNNNN"
#define rufl_CACHE_VERSION 4


struct rufl_glyph_map_entry {
	const char *glyph_name;
	/* The glyph map contains codepoints in the BMP only */
	uint16_t u;
};

extern const struct rufl_glyph_map_entry rufl_glyph_map[];
extern const size_t rufl_glyph_map_size;


#if 1 /*ndef NDEBUG*/
#include <time.h>
extern bool rufl_log_got_start_time;
extern time_t rufl_log_start_time;
#define LOG(format, ...)						\
	do {								\
		if (rufl_log_got_start_time == false) {			\
			rufl_log_start_time = time(NULL);		\
			rufl_log_got_start_time = true;			\
		}							\
									\
		fprintf(stderr,"(%.6fs) " __FILE__ " %s %i: ",		\
				difftime(time(NULL),			\
					rufl_log_start_time),		\
				__func__, __LINE__);			\
		fprintf(stderr, format, __VA_ARGS__);			\
		fprintf(stderr, "\n");					\
	} while (0)
#else
#define LOG(format, ...) ((void) 0)
#endif