GCC Code Coverage Report


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