GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/extensions/ttf_extensions.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 478 545 87.7%
Functions: 28 28 100.0%
Branches: 181 286 63.3%

Line Branch Exec Source
1 /*
2 Copyright 2025 Joel Svensson svenssonjoel@yahoo.se
3
4 LispBM is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 LispBM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <extensions/ttf_extensions.h>
19 #include <extensions.h>
20 #include <buffer.h>
21
22 #include "schrift.h"
23
24 #ifdef LBM_OPT_TTF_EXTENSIONS_SIZE
25 #pragma GCC optimize ("-Os")
26 #endif
27 #ifdef LBM_OPT_TTF_EXTENSIONS_SIZE_AGGRESSIVE
28 #pragma GCC optimize ("-Oz")
29 #endif
30
31 15 static bool mk_font_raw(SFT_Font *ft, lbm_value font_val) {
32 15 lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(font_val);
33
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (arr) {
34 15 ft->memory = (uint8_t*)arr->data;
35 15 ft->size = (uint_fast32_t)arr->size;
36 15 ft->unitsPerEm = 0;
37 15 ft->locaFormat = 0;
38 15 ft->numLongHmtx = 0;
39 15 return (init_font(ft) >= 0) ? true : false;
40 }
41 return false;
42 }
43
44 14 static SFT mk_sft(SFT_Font *ft, float x_scale, float y_scale) {
45 SFT sft;
46 14 sft.font = ft;
47 14 sft.xScale = x_scale;
48 14 sft.yScale = y_scale;
49 14 sft.xOffset = 0;
50 14 sft.yOffset = 0;
51 14 sft.flags = SFT_DOWNWARD_Y;
52
53 14 return sft;
54 }
55
56 // If we are not bin searching then sorting the UTF32 codes is not needed.
57
58 #define FONT_MAX_ID_STRING_LENGTH 10
59 #define FONT_VERSION 0
60 #define FONT_MAGIC_STRING "font"
61 #define FONT_LINE_METRICS_STRING "lmtx"
62 #define FONT_KERNING_STRING "kern"
63 #define FONT_GLYPHS_STRING "glyphs"
64
65 // sizeof when used on string literals include the the terminating 0
66 #define FONT_PREAMBLE_SIZE (sizeof(uint16_t) * 2 + sizeof(FONT_MAGIC_STRING))
67 #define FONT_LINE_METRICS_SIZE (sizeof(uint32_t) + (sizeof(float) * 3) + sizeof(FONT_LINE_METRICS_STRING))
68
69 // "header sizes" excluding data payload
70 #define FONT_KERN_PAIR_SIZE (uint32_t)(4 + 4 + 4)
71 #define FONT_KERN_ROW_SIZE (uint32_t)(4 + 4)
72 #define FONT_KERN_TABLE_SIZE (uint32_t)(sizeof(FONT_KERNING_STRING) + 4 + 4)
73 #define FONT_GLYPH_TABLE_SIZE (uint32_t)(sizeof(FONT_GLYPHS_STRING) + 4 + 4 + 4)
74 #define FONT_GLYPH_SIZE (uint32_t)(6*4)
75
76 295 static int num_kern_pairs_row(SFT *sft, uint32_t utf32, uint32_t *codes, uint32_t num_codes) {
77
78 295 int num = 0;
79
80 SFT_Glyph lgid;
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 295 times.
295 if (sft_lookup(sft, utf32, &lgid) < 0) {
82 return -1;
83 }
84
85
2/2
✓ Branch 0 taken 4405 times.
✓ Branch 1 taken 295 times.
4700 for (uint32_t i = 0; i < num_codes; i ++) {
86 4405 uint32_t right_utf32 = codes[i];
87 SFT_Kerning kern;
88 4405 kern.xShift = 0.0;
89 4405 kern.yShift = 0.0;
90
91 SFT_Glyph rgid;
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4405 times.
4405 if (sft_lookup(sft, right_utf32, &rgid) < 0) {
93 return -1;
94 }
95
96
1/2
✓ Branch 0 taken 4405 times.
✗ Branch 1 not taken.
4405 if (sft->font->pairAdjustOffset) {
97 4405 sft_gpos_kerning(sft, lgid, rgid, &kern); //TODO: can it fail?
98 }
99
2/4
✓ Branch 0 taken 4405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4405 times.
✗ Branch 3 not taken.
4405 if (kern.xShift == 0.0 && kern.yShift == 0.0) {
100 4405 sft_kerning(sft, lgid, rgid, &kern); //TODO: can it fail?
101 }
102
3/4
✓ Branch 0 taken 3991 times.
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3991 times.
4405 if (kern.xShift != 0.0 || kern.yShift != 0.0) {
103 414 num++;
104 }
105 }
106 295 return num;
107 }
108
109 26 static bool kern_table_dims(SFT *sft, uint32_t *codes, uint32_t num_codes, int *rows, int *tot_pairs) {
110
111 26 int num_rows = 0;
112 26 int tot_kern_pairs = 0;
113
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 26 times.
224 for (uint32_t i = 0; i < num_codes; i ++) {
114 198 int r = num_kern_pairs_row(sft, codes[i], codes, num_codes);
115
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 128 times.
198 if (r > 0) {
116 70 num_rows ++;
117 70 tot_kern_pairs += r;
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 } else if (r < 0) {
119 return false;
120 }
121 }
122 26 *rows = num_rows;
123 26 *tot_pairs = tot_kern_pairs;
124 26 return true;
125 }
126
127 14 static int kern_table_size_bytes(SFT *sft, uint32_t *codes, uint32_t num_codes) {
128 14 int rows = 0;
129 14 int tot_pairs = 0;
130
131 int size_bytes;
132
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (kern_table_dims(sft, codes, num_codes, &rows, &tot_pairs)) {
133 14 size_bytes =
134 14 (int)(FONT_KERN_PAIR_SIZE * (uint32_t)tot_pairs +
135 14 FONT_KERN_ROW_SIZE * (uint32_t)rows +
136 FONT_KERN_TABLE_SIZE);
137 } else {
138 return -1;
139 }
140 14 return size_bytes;
141 }
142
143
144 48 static void buffer_append_string(uint8_t *buffer, char *str, int32_t *index) {
145 48 size_t n = strlen(str);
146 48 memcpy(&buffer[*index], str, n + 1); // include the 0
147 48 *index = *index + (int32_t)n + 1;
148 48 }
149
150 12 static void buffer_append_font_preamble(uint8_t *buffer, int32_t *index) {
151 12 buffer_append_uint16(buffer, 0, index); // 2 leading zero bytes
152 12 buffer_append_uint16(buffer, 0, index); // version 0
153 12 buffer_append_string(buffer, FONT_MAGIC_STRING, index);
154 12 }
155
156 12 static void buffer_append_line_metrics(uint8_t *buffer, float ascender, float descender, float line_gap, int32_t *index) {
157 12 buffer_append_string(buffer, FONT_LINE_METRICS_STRING, index);
158 12 buffer_append_uint32(buffer, sizeof(float) * 3, index);
159 12 buffer_append_float32_auto(buffer, ascender, index);
160 12 buffer_append_float32_auto(buffer, descender, index);
161 12 buffer_append_float32_auto(buffer, line_gap, index);
162 12 }
163
164
165 12 static bool buffer_append_kerning_table(uint8_t *buffer, SFT *sft, uint32_t *codes, uint32_t num_codes, int32_t *index) {
166
167 12 int num_rows = 0;
168 12 int tot_pairs = 0;
169
170
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (kern_table_dims(sft, codes, num_codes, &num_rows, &tot_pairs)) {
171
172 // TODO: compute size of "payload" only
173 12 uint32_t size_bytes =
174 12 FONT_KERN_PAIR_SIZE * (uint32_t)tot_pairs +
175 12 FONT_KERN_ROW_SIZE * (uint32_t)num_rows +
176 + 4; // number of rows field
177
178 12 buffer_append_string(buffer, FONT_KERNING_STRING, index);
179 12 buffer_append_uint32(buffer, size_bytes, index); // distance to jump ahead from index if not interested in kerning.
180 12 buffer_append_uint32(buffer, (uint32_t)num_rows, index);
181
182
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 12 times.
109 for (uint32_t left_ix = 0; left_ix < num_codes; left_ix ++) { // loop over all codes
183 97 int32_t row_len = num_kern_pairs_row(sft, codes[left_ix], codes, num_codes);
184
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 62 times.
97 if ( row_len > 0) {
185 SFT_Glyph lgid;
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (sft_lookup(sft, codes[left_ix], &lgid) < 0) {
187 return false;
188 }
189
190 // format kerning table row
191 // - UTF32 : leftGlyph
192 // - uint32 : numKernPairs
193 // - KernPair[]
194
195 35 buffer_append_uint32(buffer, codes[left_ix],index);
196 35 buffer_append_uint32(buffer, (uint32_t)row_len, index);
197
198
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 35 times.
674 for (uint32_t right_ix = 0; right_ix < num_codes; right_ix ++) { // and all codes
199 639 uint32_t right_utf32 = codes[right_ix];
200 SFT_Kerning kern;
201 639 kern.xShift = 0.0;
202 639 kern.yShift = 0.0;
203
204 // format KernPair
205 // - UTF32 : rightGlyph
206 // - float : xShift
207 // - float : yShift
208
209 SFT_Glyph rgid;
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 639 times.
639 if (sft_lookup(sft, right_utf32, &rgid) < 0) {
211 return false;
212 }
213
214
1/2
✓ Branch 0 taken 639 times.
✗ Branch 1 not taken.
639 if (sft->font->pairAdjustOffset) {
215 639 sft_gpos_kerning(sft, lgid, rgid, &kern); //TODO: can it fail?
216 }
217
2/4
✓ Branch 0 taken 639 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 639 times.
✗ Branch 3 not taken.
639 if (kern.xShift == 0.0 && kern.yShift == 0.0) {
218 639 sft_kerning(sft, lgid, rgid, &kern); //TODO: can it fail?
219 }
220
3/4
✓ Branch 0 taken 501 times.
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 501 times.
639 if (kern.xShift != 0.0 || kern.yShift != 0.0) {
221 138 buffer_append_uint32(buffer, right_utf32, index);
222 138 buffer_append_float32_auto(buffer, kern.xShift, index);
223 138 buffer_append_float32_auto(buffer, kern.yShift, index);
224 }
225 }
226 }
227 }
228 }
229 12 return true;
230 }
231
232 26 int glyphs_img_data_size(SFT *sft, color_format_t fmt, uint32_t *codes, uint32_t num_codes) {
233 26 int total_size = 0;
234
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 26 times.
224 for (uint32_t i = 0; i < num_codes; i ++) {
235 SFT_Glyph gid;
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (sft_lookup(sft, codes[i], &gid) < 0) return -1;
237 SFT_GMetrics gmtx;
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (sft_gmetrics(sft, gid, &gmtx) < 0) return -1;
239 198 total_size += (int)image_dims_to_size_bytes(fmt, (uint16_t)gmtx.minWidth, (uint16_t)gmtx.minHeight);
240 }
241 26 return total_size;
242 }
243
244 97 static int buffer_append_glyph(uint8_t *buffer, SFT *sft, color_format_t fmt, uint32_t utf32, int32_t *index){
245 SFT_Glyph gid;
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (sft_lookup(sft, utf32, &gid) < 0) return -1;
247 SFT_GMetrics gmtx;
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (sft_gmetrics(sft, gid, &gmtx) < 0) return -1;
249
250 97 buffer_append_uint32(buffer, utf32, index);
251 97 buffer_append_float32_auto(buffer, gmtx.advanceWidth, index);
252 97 buffer_append_float32_auto(buffer, gmtx.leftSideBearing, index);
253 97 buffer_append_int32(buffer,gmtx.yOffset,index);
254 97 buffer_append_int32(buffer,gmtx.minWidth, index);
255 97 buffer_append_int32(buffer,gmtx.minHeight, index);
256
257 image_buffer_t img;
258 97 img.width = (uint16_t)gmtx.minWidth;
259 97 img.height = (uint16_t)gmtx.minHeight;
260 97 img.fmt = fmt;
261 97 img.mem_base = &buffer[*index];
262 97 img.data = &buffer[*index];
263
264 97 int r = sft_render(sft, gid, &img);
265 97 *index += (int32_t)image_dims_to_size_bytes(fmt, (uint16_t)gmtx.minWidth, (uint16_t)gmtx.minHeight);
266 97 return r;
267 }
268
269 12 static int buffer_append_glyph_table(uint8_t *buffer, SFT *sft, color_format_t fmt, uint32_t *codes, uint32_t num_codes, int32_t *index) {
270
271 12 uint32_t size_bytes =
272 4 + // number of glyphs
273 4 + // image format
274 24 num_codes * 24 + // glyph metrics
275 12 (uint32_t)glyphs_img_data_size(sft,fmt,codes,num_codes);
276
277 12 buffer_append_string(buffer, FONT_GLYPHS_STRING, index);
278 12 buffer_append_uint32(buffer, size_bytes, index); // distance to jump ahead from index if not interested in kerning.
279 12 buffer_append_uint32(buffer, num_codes, index);
280 12 buffer_append_uint32(buffer, (uint32_t)fmt, index);
281
282 12 int r = 0;
283
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 12 times.
109 for (uint32_t i = 0; i < num_codes; i ++) {
284 97 r = buffer_append_glyph(buffer,sft,fmt,codes[i], index);
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (r < 0) return r;
286 }
287 12 return r;
288 }
289
290 //returns the increment for n
291 106 static int insert_nub(uint32_t *arr, uint32_t n, uint32_t new_elt) {
292 uint32_t i;
293
2/2
✓ Branch 0 taken 487 times.
✓ Branch 1 taken 50 times.
537 for (i = 0; i < n; i ++) {
294
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 482 times.
487 if (arr[i] == new_elt) return 0;
295
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 431 times.
482 if (arr[i] > new_elt) {
296 51 memmove(&arr[i+1], &arr[i], (n - i) * 4);
297 51 arr[i] = new_elt;
298 51 return 1;
299 }
300 }
301 50 arr[i] = new_elt;
302 50 return 1;
303 }
304
305 // (ttf-prepare-bin font font-scale img-fmt chars-string)
306 16 lbm_value ext_ttf_prepare_bin(lbm_value *args, lbm_uint argn) {
307
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
31 if (argn == 4 &&
308
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 lbm_is_array_r(args[0]) && // font file data
309
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 lbm_is_number(args[1]) &&
310
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 lbm_is_symbol(args[2]) &&
311 15 lbm_is_array_r(args[3])) {
312
313 15 float x_scale = lbm_dec_as_float(args[1]);
314 15 float y_scale = x_scale;
315
316 15 color_format_t fmt = sym_to_color_format(args[2]);
317
318 15 lbm_value result_array_cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE);
319
320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (result_array_cell == ENC_SYM_MERROR) return result_array_cell;
321 15 lbm_array_header_t *result_array_header = (lbm_array_header_t *)lbm_malloc(sizeof(lbm_array_header_t));
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (!result_array_header) return ENC_SYM_MERROR;
323
324 15 lbm_array_header_t *utf8_array_header = (lbm_array_header_t*)(lbm_car(args[3]));
325
326 // Try to keep the utf8 array as nubbed as possible or there will be waste of mem.
327 // Unfortunate dynamic tmp storage...
328 15 uint32_t* unique_utf32 = lbm_malloc(utf8_array_header->size * sizeof(uint32_t));
329
330
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (unique_utf32) {
331
332 SFT_Font ft;
333
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
15 if (!mk_font_raw(&ft,args[0])) {
334 1 lbm_free(unique_utf32);
335 1 return ENC_SYM_EERROR;
336 }
337 14 SFT sft = mk_sft(&ft, x_scale, y_scale);
338
339 // We know which glyphs to prerender...
340 // So time to start collecting information to put into the binary prerender format
341 // and to figure out how much prerender space to allocate!
342
343 14 uint32_t i = 0;
344 14 uint32_t next_i = 0;
345 uint32_t utf32;
346 14 uint32_t n = 0;
347
348
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 14 times.
120 while (get_utf32((uint8_t*)utf8_array_header->data, &utf32, i, &next_i)) {
349 106 n += (uint32_t)insert_nub(unique_utf32, n, utf32);
350 106 i = next_i;
351 }
352
353 // There could be zero kerning pairs and then we dont
354 // need the kerning table at all.
355 // TODO: Fix this.
356 14 int kern_tab_bytes = kern_table_size_bytes(&sft, unique_utf32, n);
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (kern_tab_bytes <= 0) {
358 lbm_free(unique_utf32);
359 return ENC_SYM_EERROR;
360 }
361
362 14 int glyph_gfx_size = glyphs_img_data_size(&sft, fmt, unique_utf32, n);
363
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (glyph_gfx_size <= 0) {
364 2 lbm_free(unique_utf32);
365 2 return ENC_SYM_EERROR;
366 }
367
368 12 uint32_t bytes_required =
369 FONT_PREAMBLE_SIZE +
370 FONT_LINE_METRICS_SIZE +
371 12 (uint32_t)kern_tab_bytes +
372 12 FONT_GLYPH_TABLE_SIZE +
373 12 n * FONT_GLYPH_SIZE + // per glyph metrics
374 (uint32_t)glyph_gfx_size;
375
376 12 uint8_t *buffer = (uint8_t*)lbm_malloc(bytes_required);
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!buffer) {
378 lbm_free(unique_utf32);
379 return ENC_SYM_MERROR;
380 }
381 12 memset(buffer,0, bytes_required);
382
383 SFT_LMetrics lmtx;
384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (sft_lmetrics(&sft, &lmtx) < 0) {
385 lbm_free(unique_utf32);
386 return ENC_SYM_EERROR;
387 }
388 12 int32_t index = 0;
389
390 12 buffer_append_font_preamble(buffer, &index);
391 12 buffer_append_line_metrics(buffer,
392 lmtx.ascender,
393 lmtx.descender,
394 lmtx.lineGap,
395 &index);
396 12 buffer_append_kerning_table(buffer, &sft, unique_utf32, n, &index);
397
398 12 int r = buffer_append_glyph_table(buffer, &sft, fmt, unique_utf32, n, &index);
399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if ( r == SFT_MEM_ERROR) {
400 lbm_free(unique_utf32);
401 lbm_free(buffer);
402 lbm_set_car_and_cdr(result_array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
403 return ENC_SYM_MERROR;
404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 } else if (r < 0) {
405 lbm_free(unique_utf32);
406 lbm_free(buffer);
407 lbm_set_car_and_cdr(result_array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
408 return ENC_SYM_EERROR;
409 }
410
411 12 lbm_free(unique_utf32); // tmp data nolonger needed
412 12 result_array_header->size = (lbm_uint)index;
413 12 result_array_header->data = (lbm_uint*)buffer;
414 12 lbm_set_car(result_array_cell, (lbm_uint)result_array_header);
415 12 result_array_cell = lbm_set_ptr_type(result_array_cell, LBM_TYPE_ARRAY);
416 12 return result_array_cell;
417 } else {
418 return ENC_SYM_MERROR;
419 }
420 }
421 1 return ENC_SYM_TERROR;
422 }
423
424 39 bool buffer_get_font_preamble(uint8_t* buffer, uint16_t *version, int32_t *index) {
425
426 39 uint16_t zero = buffer_get_uint16(buffer, index);
427
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (zero == 0) {
428 39 *version = buffer_get_uint16(buffer, index);
429
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (strncmp((const char *)&buffer[*index], "font", 4) == 0) {
430 39 *index += (int32_t)sizeof("font"); // includes 0 for constant string
431 39 return true;
432 }
433 }
434 return false;
435 }
436
437 38 static bool font_get_line_metrics(uint8_t *buffer, int32_t buffer_size, float *ascender, float *descender, float *line_gap ,int32_t index) {
438
439
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 while(index < buffer_size) {
440 38 char *str = (char*)&buffer[index];
441
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (strncmp(str, "lmtx", 4) == 0) {
442 38 int32_t i = index + 5 + 4; // skip over string and size field;
443 38 *ascender = buffer_get_float32_auto(buffer, &i);
444 38 *descender = buffer_get_float32_auto(buffer, &i);
445 38 *line_gap = buffer_get_float32_auto(buffer, &i);
446 38 return true;
447 }
448 index += (int32_t)(strlen(str) + 1);
449 index += (int32_t)buffer_get_uint32(buffer,&index); // just to next position
450 }
451 return false;
452 }
453
454 34 static bool font_get_kerning_table_index(uint8_t *buffer, int32_t buffer_size, int32_t *res_index, int32_t index) {
455
456
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 while (index < buffer_size) {
457 68 char *str = (char*)&buffer[index];
458
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 34 times.
68 if (strncmp(str, "kern", 4) == 0) {
459 34 *res_index = index + 5 + 4;
460 34 return true;
461 }
462 34 index += (int32_t)(strlen(str) + 1);
463 34 index += (int32_t)buffer_get_uint32(buffer,&index); // jump to next position
464 }
465 return false;
466 }
467
468 35 static bool font_get_glyphs_table_index(uint8_t *buffer, int32_t buffer_size, int32_t *res_index, uint32_t *num_codes, uint32_t *fmt, int32_t index) {
469
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
105 while (index < buffer_size) {
470 105 char *str = (char*)&buffer[index];
471
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 70 times.
105 if (strncmp(str, "glyphs", 6) == 0) {
472 35 int32_t i = index + 7 + 4;
473 35 *num_codes = buffer_get_uint32(buffer,&i);
474 35 *fmt = buffer_get_uint32(buffer,&i);
475 35 *res_index = i;
476 35 return true;
477 }
478 70 index += (int32_t)(strlen(str) + 1);
479 70 index += (int32_t)buffer_get_uint32(buffer,&index);
480 }
481 return false;
482 }
483
484 268 static bool font_get_glyph(uint8_t *buffer,
485 float *advance_width,
486 float *left_side_bearing,
487 int32_t *y_offset,
488 int32_t *width,
489 int32_t *height,
490 uint8_t **gfx,
491 uint32_t utf32,
492 uint32_t num_codes,
493 color_format_t fmt,
494 int32_t index) {
495
496 268 uint32_t i = 0;
497
1/2
✓ Branch 0 taken 2640 times.
✗ Branch 1 not taken.
2640 while (i < num_codes) {
498 2640 uint32_t c = buffer_get_uint32(buffer, &index);
499
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 2372 times.
2640 if (c == utf32) {
500 268 *advance_width = buffer_get_float32_auto(buffer, &index);
501 268 *left_side_bearing = buffer_get_float32_auto(buffer, &index);
502 268 *y_offset = buffer_get_int32(buffer, &index);
503 268 *width = buffer_get_int32(buffer, &index);
504 268 *height = buffer_get_int32(buffer,&index);
505 268 *gfx = &buffer[index];
506 268 return true;
507 } else {
508 2372 index += 12;
509 2372 int32_t w = buffer_get_int32(buffer, &index);
510 2372 int32_t h = buffer_get_int32(buffer, &index);
511 2372 index += (int32_t)image_dims_to_size_bytes(fmt, (uint16_t)w, (uint16_t)h);
512 }
513 2372 i++;
514 }
515 return false;
516 }
517
518 236 bool font_get_kerning(uint8_t *buffer, uint32_t left, uint32_t right, float *x_shift, float *y_shift, int32_t index) {
519
520 236 uint32_t num_rows = buffer_get_uint32(buffer, &index);
521
522
2/2
✓ Branch 0 taken 2169 times.
✓ Branch 1 taken 195 times.
2364 for (uint32_t row = 0; row < num_rows; row ++) {
523
524 2169 uint32_t row_code = buffer_get_uint32(buffer, &index);
525 2169 uint32_t row_len = buffer_get_uint32(buffer, &index);
526
527
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 2001 times.
2169 if (row_code == left) {
528
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 127 times.
382 for (uint32_t col = 0; col < row_len; col ++) {
529 255 uint32_t col_code = buffer_get_uint32(buffer, &index);
530
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 214 times.
255 if (col_code == right) {
531 41 *x_shift = buffer_get_float32_auto(buffer, &index);
532 41 *y_shift = buffer_get_float32_auto(buffer, &index);
533 41 return true;
534 } else {
535 214 index += 8;
536 }
537 }
538 } else {
539 2001 index += (int32_t)(row_len * FONT_KERN_PAIR_SIZE);
540 }
541 }
542 195 return false;
543 }
544
545 36 lbm_value ttf_text_bin(lbm_value *args, lbm_uint argn) {
546 36 lbm_value res = ENC_SYM_TERROR;
547 lbm_array_header_t *img_arr;
548 lbm_value font;
549 char *utf8_str;
550 uint32_t colors[16];
551 36 uint32_t next_arg = 0;
552
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 2 times.
72 if (argn >= 6 &&
553
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
70 (img_arr = get_image_buffer(args[0])) &&
554
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
68 lbm_is_number(args[1]) && // x position
555
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
68 lbm_is_number(args[2]) && // y position
556
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
68 lbm_is_cons(args[3]) && // list of colors
557
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1 times.
68 lbm_is_array_r(args[4]) && // Binary font
558 34 lbm_is_array_r(args[5])) { // sequence of utf8 characters
559 33 lbm_value curr = args[3];
560 33 int i = 0;
561
3/4
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
165 while(lbm_is_cons(curr) && i < 16) {
562 132 colors[i] = lbm_dec_as_u32(lbm_car(curr));
563 132 curr = lbm_cdr(curr);
564 132 i ++;
565 }
566 33 font = args[4];
567 33 utf8_str = lbm_dec_str(args[5]);
568 33 next_arg = 6;
569 } else {
570 3 return res;
571 }
572
573 33 int x_pos = lbm_dec_as_i32(args[1]);
574 33 int y_pos = lbm_dec_as_i32(args[2]);
575
576 33 float line_spacing = 1.0f;
577 33 bool up = false;
578 33 bool down = false;
579
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 33 times.
58 for (uint32_t i = next_arg; i < argn; i ++) {
580
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
25 if (lbm_is_symbol(args[i])) {
581 24 up = display_is_symbol_up(args[i]);
582 24 down = display_is_symbol_down(args[i]);
583
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (lbm_is_number(args[i])) {
584 1 line_spacing = lbm_dec_as_float(args[i]);
585 }
586 }
587
588 33 lbm_array_header_t *font_arr = lbm_dec_array_r(font);
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (font_arr->size < 10) return ENC_SYM_EERROR;
590
591 33 int32_t index = 0;
592 uint16_t version;
593
594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
595 return ENC_SYM_EERROR;
596 }
597
598 float ascender;
599 float descender;
600 float line_gap;
601
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
603 return ENC_SYM_EERROR;
604 }
605
606 33 int32_t kern_index = 0;
607
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!font_get_kerning_table_index((uint8_t*)font_arr->data, (int32_t)font_arr->size, &kern_index, index)) {
609 return ENC_SYM_EERROR;
610 }
611
612 33 int32_t glyphs_index = 0;
613 uint32_t num_codes;
614 uint32_t color_fmt;
615
616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!font_get_glyphs_table_index((uint8_t*)font_arr->data, (int32_t)font_arr->size, &glyphs_index, &num_codes, &color_fmt, index)) {
617 return ENC_SYM_EERROR;
618 }
619
620 33 color_format_t fmt = (color_format_t)color_fmt;
621 33 float x = 0.0;
622 33 float y = 0.0;
623
624 image_buffer_t tgt;
625 33 tgt.width = image_buffer_width((uint8_t*)img_arr->data);
626 33 tgt.height = image_buffer_height((uint8_t*)img_arr->data);
627 33 tgt.fmt = image_buffer_format((uint8_t*)img_arr->data);
628 33 tgt.mem_base = (uint8_t*)img_arr->data;
629 33 tgt.data = image_buffer_data((uint8_t*)img_arr->data);
630
631 uint32_t utf32;
632 uint32_t prev;
633 33 bool has_prev = false;
634 33 uint32_t i = 0;
635 33 uint32_t next_i = 0;
636
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 33 times.
296 while (get_utf32((uint8_t*)utf8_str, &utf32, i, &next_i)) {
637
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (utf32 == '\n') {
638 1 x = 0.0;
639 1 y += line_spacing * (ascender - descender + line_gap);
640 1 i++;
641 1 continue; // next iteration
642 }
643
644 262 float x_n = x;
645 262 float y_n = y;
646
647 float advance_width;
648 float left_side_bearing;
649 int32_t y_offset;
650 int32_t width;
651 int32_t height;
652 uint8_t *gfx;
653
654
1/2
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
262 if (font_get_glyph((uint8_t*)font_arr->data,
655 &advance_width,
656 &left_side_bearing,
657 &y_offset,
658 &width,
659 &height,
660 &gfx,
661 utf32,
662 num_codes,
663 fmt,
664 glyphs_index)) {
665
666 262 float x_shift = 0;
667 262 float y_shift = 0;
668
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 30 times.
262 if (has_prev) {
669 232 font_get_kerning((uint8_t*)font_arr->data,
670 prev,
671 utf32,
672 &x_shift,
673 &y_shift,
674 kern_index);
675 }
676 262 x_n += x_shift;
677 262 y_n += y_shift;
678 262 y_n += (float)y_offset;
679
680 image_buffer_t src;
681 262 src.width = (uint16_t)width;
682 262 src.height = (uint16_t)height;
683 262 src.fmt = fmt;
684 //src.mem_base = gfx;
685 262 src.data = gfx;
686
687 262 uint32_t num_colors = 1 << src.fmt;
688
2/2
✓ Branch 0 taken 5406 times.
✓ Branch 1 taken 262 times.
5668 for (int j = 0; j < src.height; j++) {
689
2/2
✓ Branch 0 taken 90134 times.
✓ Branch 1 taken 5406 times.
95540 for (int k = 0; k < src.width; k ++) {
690 // the bearing should not be accumulated into the advances
691
692 90134 uint32_t p = getpixel(&src, k, j);
693
2/2
✓ Branch 0 taken 37931 times.
✓ Branch 1 taken 52203 times.
90134 if (p) { // only draw colored
694 37931 uint32_t c = colors[p & (num_colors-1)]; // ceiled
695
2/2
✓ Branch 0 taken 12256 times.
✓ Branch 1 taken 25675 times.
37931 if (up) {
696 12256 putpixel(&tgt, x_pos + (j + (int)y_n), y_pos - (k + (int)(x_n + left_side_bearing)), c);
697
2/2
✓ Branch 0 taken 15604 times.
✓ Branch 1 taken 10071 times.
25675 } else if (down) {
698 15604 putpixel(&tgt, x_pos - (j + (int)y_n), y_pos + (k + (int)(x_n + left_side_bearing)), c);
699 } else {
700 10071 putpixel(&tgt, x_pos + (k + (int)(x_n + left_side_bearing)), y_pos + (j + (int)y_n), c);
701 }
702 }
703 }
704 }
705 } else {
706 lbm_set_error_reason("Character is not one of those listed in ttf-prepare\n");
707 return ENC_SYM_EERROR;
708 }
709 262 x = x_n + advance_width;
710 262 i = next_i;
711 262 prev = utf32;
712 262 has_prev = true;
713 }
714 33 return ENC_SYM_TRUE;
715 }
716
717 2 lbm_value ext_ttf_wh(lbm_value *args, lbm_uint argn) {
718 2 lbm_value res = ENC_SYM_TERROR;
719 lbm_value font;
720 char *utf8_str;
721 2 uint32_t next_arg = 0;
722
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (argn >= 2 &&
723
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 lbm_is_array_r(args[0]) && // Binary font
724 2 lbm_is_array_r(args[1])) { // sequence of utf8 characters
725 2 font = args[0];
726 2 utf8_str = lbm_dec_str(args[1]);
727 2 next_arg = 2;
728 } else {
729 return res;
730 }
731
732 2 float line_spacing = 1.0f;
733 2 bool up = false;
734 2 bool down = false;
735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for (uint32_t i = next_arg; i < argn; i ++) {
736 if (lbm_is_symbol(args[i])) {
737 up = display_is_symbol_up(args[i]);
738 down = display_is_symbol_down(args[i]);
739 } else if (lbm_is_number(args[i])) {
740 line_spacing = lbm_dec_as_float(args[i]);
741 }
742 }
743
744 2 lbm_value r_list = lbm_heap_allocate_list(2);
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (lbm_is_symbol(r_list)) return r_list;
746
747 2 lbm_array_header_t *font_arr = lbm_dec_array_r(font);
748
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (font_arr->size < 10) return ENC_SYM_EERROR;
749
750 1 int32_t index = 0;
751 uint16_t version;
752
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
754 return ENC_SYM_EERROR;
755 }
756
757 float ascender;
758 float descender;
759 float line_gap;
760
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
762 return ENC_SYM_EERROR;
763 }
764
765 1 int32_t kern_index = 0;
766
767
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_get_kerning_table_index((uint8_t*)font_arr->data, (int32_t)font_arr->size, &kern_index, index)) {
768 return ENC_SYM_EERROR;
769 }
770
771 1 int32_t glyphs_index = 0;
772 uint32_t num_codes;
773 uint32_t color_fmt;
774
775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_get_glyphs_table_index((uint8_t*)font_arr->data, (int32_t)font_arr->size, &glyphs_index, &num_codes, &color_fmt, index)) {
776 return ENC_SYM_EERROR;
777 }
778
779 1 float x = 0.0;
780 1 float y = 0.0;
781 1 float max_x = 0.0;
782
783 uint32_t utf32;
784 uint32_t prev;
785 1 bool has_prev = false;
786 1 uint32_t i = 0;
787 1 uint32_t next_i = 0;
788
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 while (get_utf32((uint8_t*)utf8_str, &utf32, i, &next_i)) {
789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (utf32 == '\n') {
790 if (x > max_x) max_x = x;
791 x = 0.0;
792 y += line_spacing * (ascender - descender + line_gap);
793 i++;
794 continue; // next iteration
795 }
796
797 5 float x_n = x;
798
799 float advance_width;
800 float left_side_bearing;
801 int32_t y_offset;
802 int32_t width;
803 int32_t height;
804 uint8_t *gfx;
805
806
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (font_get_glyph((uint8_t*)font_arr->data,
807 &advance_width,
808 &left_side_bearing,
809 &y_offset,
810 &width,
811 &height,
812 &gfx,
813 utf32,
814 num_codes,
815 (color_format_t)color_fmt,
816 glyphs_index)) {
817
818 5 float x_shift = 0;
819 5 float y_shift = 0;
820
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (has_prev) {
821 4 font_get_kerning((uint8_t*)font_arr->data,
822 prev,
823 utf32,
824 &x_shift,
825 &y_shift,
826 kern_index);
827 }
828 5 x_n += x_shift;
829 } else {
830 return ENC_SYM_EERROR;
831 }
832 5 x = x_n + advance_width;
833 5 i = next_i;
834 5 prev = utf32;
835 5 has_prev = true;
836 }
837
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (max_x < x) max_x = x;
838 1 lbm_value rest = lbm_cdr(r_list);
839
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (up || down) {
840 lbm_set_car(r_list, lbm_enc_u((uint32_t)(y + line_spacing * (ascender - descender + line_gap))));
841 lbm_set_car(rest, lbm_enc_u((uint32_t)max_x));
842 } else {
843 1 lbm_set_car(r_list, lbm_enc_u((uint32_t)max_x));
844 1 lbm_set_car(rest, lbm_enc_u((uint32_t)(y + line_spacing * (ascender - descender + line_gap))));
845 }
846 1 return r_list;
847 }
848
849 1 lbm_value ext_ttf_glyph_dims(lbm_value *args, lbm_uint argn) {
850
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (argn == 2 &&
851
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 lbm_is_array_r(args[0]) &&
852 1 lbm_is_array_r(args[1])) { // string utf8,
853
854 1 lbm_array_header_t *font_arr = lbm_dec_array_r(args[0]);
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (!font_arr) return ENC_SYM_FATAL_ERROR;
856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (font_arr->size < 10) return ENC_SYM_EERROR;
857
858 1 int32_t index = 0;
859 uint16_t version;
860
861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
862 return ENC_SYM_EERROR;
863 }
864
865 1 int32_t glyphs_index = 0;
866 uint32_t num_codes;
867 uint32_t color_fmt;
868
869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_get_glyphs_table_index((uint8_t*)font_arr->data, (int32_t)font_arr->size, &glyphs_index, &num_codes, &color_fmt, index)) {
870 return ENC_SYM_EERROR;
871 }
872
873 1 lbm_array_header_t *utf8_array_header = (lbm_array_header_t*)(lbm_car(args[1]));
874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!utf8_array_header) return ENC_SYM_FATAL_ERROR;
875
876 1 uint32_t next_i = 0;
877 1 uint32_t utf32 = 0;
878 1 get_utf32((uint8_t*)utf8_array_header->data, &utf32, 0, &next_i);
879
880 float advance_width;
881 float left_side_bearing;
882 int32_t y_offset;
883 int32_t width;
884 int32_t height;
885 uint8_t *gfx;
886
887
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (font_get_glyph((uint8_t*)font_arr->data,
888 &advance_width,
889 &left_side_bearing,
890 &y_offset,
891 &width,
892 &height,
893 &gfx,
894 utf32,
895 num_codes,
896 (color_format_t)color_fmt,
897 glyphs_index)) {
898
899 1 return lbm_heap_allocate_list_init(2,
900 lbm_enc_u((uint32_t)(width)),
901 lbm_enc_u((uint32_t)height));
902 }
903 }
904 return ENC_SYM_TERROR;
905 }
906
907 2 lbm_value ext_ttf_line_height(lbm_value *args, lbm_uint argn) {
908 2 lbm_value res = ENC_SYM_TERROR;
909
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (argn == 1 &&
910 2 lbm_is_array_r(args[0])) {
911
912 2 lbm_array_header_t *font_arr = lbm_dec_array_r(args[0]);
913
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
3 if (!font_arr) return ENC_SYM_FATAL_ERROR;
914
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (font_arr->size < 10) return ENC_SYM_EERROR;
915
916 1 int32_t index = 0;
917 uint16_t version;
918
919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
920 return ENC_SYM_EERROR;
921 }
922
923 float ascender;
924 float descender;
925 float line_gap;
926
927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
928 return ENC_SYM_EERROR;
929 }
930
931 1 res = lbm_enc_float(ascender - descender + line_gap);
932 }
933 1 return res;
934 }
935
936 1 lbm_value ext_ttf_ascender(lbm_value *args, lbm_uint argn) {
937 1 lbm_value res = ENC_SYM_TERROR;
938
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (argn == 1 &&
939 1 lbm_is_array_r(args[0])) {
940
941 1 lbm_array_header_t *font_arr = lbm_dec_array_r(args[0]);
942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_arr) return ENC_SYM_FATAL_ERROR;
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (font_arr->size < 10) return ENC_SYM_EERROR;
944
945 1 int32_t index = 0;
946 uint16_t version;
947
948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
949 return ENC_SYM_EERROR;
950 }
951
952 float ascender;
953 float descender;
954 float line_gap;
955
956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
957 return ENC_SYM_EERROR;
958 }
959
960 1 res = lbm_enc_float(ascender);
961 }
962 1 return res;
963 }
964
965 1 lbm_value ext_ttf_descender(lbm_value *args, lbm_uint argn) {
966 1 lbm_value res = ENC_SYM_TERROR;
967
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (argn == 1 &&
968 1 lbm_is_array_r(args[0])) {
969
970 1 lbm_array_header_t *font_arr = lbm_dec_array_r(args[0]);
971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_arr) return ENC_SYM_FATAL_ERROR;
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (font_arr->size < 10) return ENC_SYM_EERROR;
973
974 1 int32_t index = 0;
975 uint16_t version;
976
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
978 return ENC_SYM_EERROR;
979 }
980
981 float ascender;
982 float descender;
983 float line_gap;
984
985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
986 return ENC_SYM_EERROR;
987 }
988
989 1 res = lbm_enc_float(descender);
990 }
991 1 return res;
992 }
993
994 1 lbm_value ext_ttf_line_gap(lbm_value *args, lbm_uint argn) {
995 1 lbm_value res = ENC_SYM_TERROR;
996
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (argn == 1 &&
997 1 lbm_is_array_r(args[0])) {
998
999 1 lbm_array_header_t *font_arr = lbm_dec_array_r(args[0]);
1000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!font_arr) return ENC_SYM_FATAL_ERROR;
1001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (font_arr->size < 10) return ENC_SYM_EERROR;
1002
1003 1 int32_t index = 0;
1004 uint16_t version;
1005
1006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buffer_get_font_preamble((uint8_t*)font_arr->data, &version, &index)) {
1007 return ENC_SYM_EERROR;
1008 }
1009
1010 float ascender;
1011 float descender;
1012 float line_gap;
1013
1014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!font_get_line_metrics((uint8_t*)font_arr->data, (int32_t)font_arr->size, &ascender, &descender, &line_gap , index)) {
1015 return ENC_SYM_EERROR;
1016 }
1017
1018 1 res = lbm_enc_float(line_gap);
1019 }
1020 1 return res;
1021 }
1022
1023 188 void lbm_ttf_extensions_init(void) {
1024
1025 // metrics
1026 188 lbm_add_extension("ttf-line-height", ext_ttf_line_height);
1027 188 lbm_add_extension("ttf-ascender", ext_ttf_ascender);
1028 188 lbm_add_extension("ttf-descender", ext_ttf_descender);
1029 188 lbm_add_extension("ttf-line-gap", ext_ttf_line_gap);
1030 188 lbm_add_extension("ttf-text-dims",ext_ttf_wh);
1031 188 lbm_add_extension("ttf-glyph-dims",ext_ttf_glyph_dims);
1032
1033 // Prepare
1034 188 lbm_add_extension("ttf-prepare", ext_ttf_prepare_bin);
1035
1036 // Draw text.
1037 188 lbm_add_extension("ttf-text", ttf_text_bin);
1038 188 }
1039