./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 / 220
0.0%
Branches:
0 / 204
0.0%
Functions:
0 / 26
0.0%

libs/render/src/eu/render/font.cc
Line Branch Exec Source
1 #include "eu/render/font.h"
2
3
4 #include <memory>
5 #include <map>
6 #include <algorithm>
7 #include <iostream>
8
9 #include "eustb_rect_pack.h"
10
11 #include "eu/base/cint.h"
12 #include "eu/log/log.h"
13 // #include "eu/core/image_draw.h"
14 #include "eu/core/utf8.h"
15 #include "eu/assert/assert.h"
16 #include "eu/core/image.h"
17 // #include "eu/render/stdutils.h"
18 // #include "eu/base/stringmerger.h"
19
20 // #include "files/font.h"
21
22 #include "eu/render/texture.h"
23 // #include "eu/render/spriterender.h"
24 // #include "eu/render/texturecache.h"
25
26 #include "canvas.h"
27 #include "dependency_glad.h"
28 #include "eu/base/memorychunk.h"
29
30
31 // ====================================================================================================================
32 // Internal
33
34 namespace internal
35 {
36 namespace
37 {
38 using namespace eu;
39 using namespace eu::render;
40
41 std::pair<::eu::Rect, Rect>
42 ✗ construct_character_rects
43 (
44 const stbrp_rect& packed_rect,
45 const core::LoadedGlyph& glyph,
46 int image_width,
47 int image_height,
48 int half_margin
49 )
50 {
51 ✗ const int vert_left = glyph.bearing_x;
52 ✗ const int vert_right = vert_left + glyph.image.width;
53 ✗ const int vert_top = glyph.bearing_y;
54 ✗ const int vert_bottom = vert_top - std::max(1, glyph.image.height);
55
56 ✗ const stbrp_coord uv_left = packed_rect.x + half_margin;
57 ✗ const stbrp_coord uv_right = uv_left + packed_rect.w - half_margin * 2;
58 ✗ const stbrp_coord uv_bottom = packed_rect.y + half_margin;
59 ✗ const stbrp_coord uv_top = uv_bottom + std::max<int>(1, packed_rect.h - half_margin * 2);
60
61 // todo(Gustav): add ability to be a quad for tighter fit
62
0/12
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 20 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 85 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 54 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 52 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 60 not taken.
✗ ASSERTX(vert_top > vert_bottom, vert_top, vert_bottom, glyph.code_point);
63
0/12
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 36 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 85 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 70 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 68 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 76 not taken.
✗ ASSERTX(uv_top > uv_bottom, uv_top, uv_bottom, glyph.code_point);
64
65 ✗ const auto iw = float_from_int(image_width);
66 ✗ const auto ih = float_from_int(image_height);
67
68 const auto sprite = Rect::from_left_right_top_bottom
69
0/2
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 85 not taken.
✗ (
70 float_from_int(vert_left),
71 float_from_int(vert_right),
72 float_from_int(vert_top),
73 float_from_int(vert_bottom)
74 );
75 const auto texture = Rect::from_left_right_top_bottom
76
0/2
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 85 not taken.
✗ (
77 ✗ float_from_int(uv_left) / iw,
78 ✗ float_from_int(uv_right) / iw,
79 ✗ float_from_int(uv_top) / ih,
80 ✗ float_from_int(uv_bottom) / ih
81 );
82
83 // scale to make sure bake resolution is separate from rendering size
84 ✗ const float scale = 1.0f / glyph.size;
85
0/2
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 84 not taken.
✗ return std::make_pair(sprite.with_scale(scale, scale), texture);
86
0/20
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 61 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 61 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 61 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 77 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 77 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 77 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 65 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 65 not taken.
✗ Branch 77 → 78 not taken.
✗ Branch 77 → 81 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 81 not taken.
✗ }
87
88 v2
89 ✗ get_offset(Align alignment, const Rect& extent)
90 {
91 // todo(Gustav): test this more
92 ✗ const auto middle = -(extent.left + extent.right) / 2;
93 ✗ const auto right = -extent.right;
94 ✗ const auto top = extent.top;
95 ✗ const auto bottom = -extent.bottom;
96
97
0/10
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 12 not taken.
✗ Branch 2 → 15 not taken.
✗ Branch 2 → 18 not taken.
✗ Branch 2 → 21 not taken.
✗ Branch 2 → 24 not taken.
✗ Branch 2 → 27 not taken.
✗ Branch 2 → 30 not taken.
✗ switch (alignment)
98 {
99 ✗ case Align::top_left: return { 0.0f, top };
100 ✗ case Align::top_center: return { middle, top };
101 ✗ case Align::top_right: return { right, top };
102 ✗ case Align::baseline_left: return { 0.0f, 0.0f };
103 ✗ case Align::baseline_center: return { middle, 0.0f };
104 ✗ case Align::baseline_right: return { right, 0.0f };
105 ✗ case Align::bottom_left: return { 0.0f, bottom };
106 ✗ case Align::bottom_center: return { middle, bottom };
107 ✗ case Align::bottom_right: return { right, bottom };
108
0/2
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 37 not taken.
✗ default: DIE("Unhandled case"); return { 0.0f, 0.0f };
109 }
110 }
111 }
112 }
113
114 // ====================================================================================================================
115 // API
116
117 namespace eu::render
118 {
119 ✗ Glyph::Glyph
120 (
121 const Rect& sprite,
122 const Rect& texture,
123 int ch,
124 float ad
125 ✗ )
126 ✗ : sprite_rect(sprite)
127 ✗ , texture_rect(texture)
128 ✗ , code_point(ch)
129 ✗ , advance(ad)
130 {
131 ✗ }
132
133
134 ////////////////////////////////////////////////////////////////////////////////
135
136
137 ✗ DrawableFont::DrawableFont
138 (
139 const MemoryChunk& file_memory
140 ✗ )
141 {
142 // todo(Gustav): too long, break up
143 ✗ const int texture_width = 512;
144 ✗ const int texture_height = 512;
145
146 ✗ core::LoadedFont fontchars;
147
148 fontchars.load_characters_from_font
149
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 83 not taken.
✗ (
150 file_memory,
151 48,
152 // todo(Gustav): use a range instead
153
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 85 not taken.
✗ "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{}|;:'\",.<>/?`~ "
154 );
155
156
157 // const auto image_font = get_characters_from_single_image(fs, image);
158 // fontchars.combine_with(image_font);
159
160 // todo(Gustav): add more sources, built in image font or images
161
162 // the half margin between glyphs in the final texture
163 ✗ const int half_margin = 1;
164
165 // todo(Gustav): use core/pack.h instead
166
167 // pack char textures to a single texture
168 ✗ const int num_rects = int_from_sizet(fontchars.codepoint_to_glyph.size());
169
0/2
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 89 not taken.
✗ std::vector<stbrp_rect> packed_rects(num_rects);
170 ✗ std::map<int, int> id_to_codepoint;
171 {
172 ✗ int index = 0;
173
0/2
✗ Branch 29 → 22 not taken.
✗ Branch 29 → 30 not taken.
✗ for(const auto& [codepoint, glyph]: fontchars.codepoint_to_glyph)
174 {
175 ✗ stbrp_rect& r = packed_rects[index];
176 ✗ r.id = index;
177 ✗ r.w = glyph.image.width + half_margin * 2;
178 ✗ r.h = glyph.image.height + half_margin * 2;
179
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 92 not taken.
✗ id_to_codepoint[index] = codepoint;
180 ✗ index +=1;
181 }
182 }
183 ✗ stbrp_context context {};
184 ✗ const int num_nodes = texture_width;
185
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 94 not taken.
✗ std::vector<stbrp_node> nodes(num_nodes);
186
0/2
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 123 not taken.
✗ stbrp_init_target(&context, texture_width, texture_height, nodes.data(), num_nodes);
187
0/2
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 123 not taken.
✗ stbrp_pack_rects(&context, packed_rects.data(), num_rects);
188
189 ✗ CharToGlyphMap map;
190
0/2
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 121 not taken.
✗ core::Image image;
191
0/2
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 119 not taken.
✗ image.setup_with_alpha_support(texture_width, texture_height);
192
0/2
✗ Branch 68 → 42 not taken.
✗ Branch 68 → 69 not taken.
✗ for(int rect_index = 0; rect_index < num_rects; rect_index += 1)
193 {
194 ✗ const stbrp_rect& src_rect = packed_rects[rect_index];
195
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 49 not taken.
✗ if(src_rect.was_packed == 0)
196 {
197
0/6
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 111 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 99 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 97 not taken.
✗ LOG_ERR("Failed to pack");
198 ✗ continue;
199 }
200
0/4
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 111 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 111 not taken.
✗ const auto& src_char = fontchars.codepoint_to_glyph[id_to_codepoint[src_rect.id]];
201
0/4
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 111 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 58 not taken.
✗ if (src_char.image.is_valid() == false)
202 {
203
0/6
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 111 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 103 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 101 not taken.
✗ LOG_WARN("Glyph for code point {0} has an invalid image, skipping", src_char.code_point);
204 }
205 else
206 {
207 paste_image
208 ✗ (
209 &image,
210 ✗ src_rect.x + half_margin,
211 ✗ src_rect.y + half_margin,
212
0/2
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 111 not taken.
✗ src_char.image
213 );
214 }
215 const auto sprite_and_texture_rects = internal::construct_character_rects
216
0/2
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 111 not taken.
✗ (
217 src_rect,
218 src_char,
219 texture_width,
220 texture_height,
221 half_margin
222 );
223
224 const auto dest = std::make_shared<Glyph>
225 (
226 sprite_and_texture_rects.first,
227 sprite_and_texture_rects.second,
228 ✗ src_char.code_point,
229 ✗ static_cast<float>(src_char.advance) / src_char.size
230
0/2
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 105 not taken.
✗ );
231
0/2
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 106 not taken.
✗ map.insert(CharToGlyphMap::value_type(dest->code_point, dest));
232 ✗ }
233
234 // for debug
235 // fs->WriteFile("charmap.png", image.Write(ImageWriteFormat::PNG));
236
237 // load pixels into texture
238
0/2
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 119 not taken.
✗ private_use_aliases = fontchars.private_use_aliases;
239
0/2
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 119 not taken.
✗ kernings = fontchars.kerning;
240
0/2
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 119 not taken.
✗ char_to_glyph = map;
241
0/2
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 112 not taken.
✗ texture = std::make_unique<Texture2d>(SEND_DEBUG_LABEL_MANY("FONT TEXTURE") image.data.data(), GL_RGBA, texture_width, texture_height,
242 ✗ TextureEdge::clamp, TextureRenderStyle::linear, Transparency::include, ColorData::color_data);
243 ✗ ascent = fontchars.ascent;
244 ✗ descent = fontchars.descent;
245 ✗ line_gap = fontchars.line_gap;
246 ✗ }
247
248
249 void
250 ✗ DrawableFont::draw_background
251 (
252 SpriteBatch* renderer,
253 float alpha,
254 const Rect& where
255 ) const
256 {
257
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Quad{ .tint = Color{eu::colors::black, alpha} }.draw(renderer, where);
258 ✗ }
259
260
261 ✗ TextDrawCommand::TextDrawCommand
262 (
263 const Texture2d* atexture,
264 const Rect& asprite_rect,
265 const Rect& atexture_rect,
266 bool ahi
267 ✗ )
268 ✗ : texture(atexture)
269 ✗ , sprite_rect(asprite_rect)
270 ✗ , texture_rect(atexture_rect)
271 ✗ , hi(ahi)
272 {
273 ✗ }
274
275
276 void
277 ✗ ListOfTextDrawCommands::add
278 (
279 const Texture2d* texture,
280 const Rect& sprite_rect,
281 const Rect& texture_rect,
282 bool hi
283 )
284 {
285 ✗ commands.emplace_back(texture, sprite_rect, texture_rect, hi);
286 ✗ }
287
288
289 void
290 ✗ ListOfTextDrawCommands::draw
291 (
292 SpriteBatch* renderer,
293 const v2& start_position,
294 const Rgb& base_color,
295 const Rgb& hi_color
296 )
297 {
298
0/2
✗ Branch 24 → 4 not taken.
✗ Branch 24 → 25 not taken.
✗ for(const auto& cmd: commands)
299 {
300
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ const auto tint = cmd.hi ? hi_color : base_color;
301 ✗ Quad{
302 ✗ .texture = cmd.texture,
303 ✗ .texturecoord = cmd.texture_rect,
304 .tint = Color{tint}
305
0/4
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 26 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 26 not taken.
✗ }.draw(renderer, cmd.sprite_rect.with_translate(start_position));
306 }
307 ✗ }
308
309
310 struct UiTextCompileVisitor// : public textparser::Visitor
311 {
312 const DrawableFont* font;
313 float size;
314 bool apply_highlight = false;
315 v2 position = v2{0, 0}; // todo(Gustav): rename to offset
316 int last_char_index = 0;
317
318 // return value
319 ListOfTextDrawCommands* list;
320
321 ✗ UiTextCompileVisitor
322 (
323 const DrawableFont* f,
324 float s,
325 ListOfTextDrawCommands* li
326 )
327 ✗ : font{f}
328 ✗ , size{s}
329 ✗ , list{li}
330 {
331 ✗ }
332
333
334 void
335 ✗ on_text(const std::string& text)// override
336 {
337 core::calc_utf8_to_codepoints
338 ✗ (
339 text,
340 ✗ [this](int cp)
341 {
342 ✗ add_char_index(cp);
343 ✗ }
344 );
345 ✗ }
346
347 #ifdef TODO_IMAGE_GLYPH_HANDLING
348 void
349 on_image(const std::string& image) override
350 {
351 // todo(Gustav): handle invalid font alias
352 auto found = font.private_use_aliases.find(image);
353 if(found == font.private_use_aliases.end())
354 {
355 LOG_ERR
356 (
357 "Unable to find image {0}, could be {1}",
358 image,
359 string_mergers::english_or.merge(get_keys(font.private_use_aliases))
360 );
361 return;
362 }
363 add_char_index(found->second);
364 }
365 #endif
366
367
368 void
369 ✗ on_begin()// override
370 {
371 ✗ apply_highlight = true;
372 ✗ }
373
374
375 void
376 ✗ on_end()// override
377 {
378 ✗ apply_highlight = false;
379 ✗ }
380
381
382 void
383 ✗ add_char_index(int code_point)
384 {
385
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 5 not taken.
✗ if(code_point == '\n')
386 {
387 ✗ position.x = 0;
388 ✗ position.y -= size*font->get_line_height();
389 }
390 else
391 {
392
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 44 not taken.
✗ auto it = font->char_to_glyph.find(code_point);
393
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 14 not taken.
✗ if(it == font->char_to_glyph.end())
394 {
395
0/6
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 44 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 37 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 35 not taken.
✗ LOG_ERR("Failed to print '{0}'", code_point);
396 ✗ return;
397 }
398 ✗ const std::shared_ptr<Glyph> ch = it->second;
399
400 ✗ list->add
401
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 39 not taken.
✗ (
402 ✗ font->texture.get(),
403
0/4
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 39 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 39 not taken.
✗ ch->sprite_rect.with_scale(size, size).with_translate(position),
404 ✗ ch->texture_rect,
405 ✗ apply_highlight
406 );
407
408 ✗ const auto kerning = font->kernings.find
409
0/2
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 41 not taken.
✗ (
410 std::make_pair
411 ✗ (
412 ✗ last_char_index,
413 code_point
414 )
415 );
416 ✗ const float the_kerning = kerning == font->kernings.end()
417
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
✗ ? 0.0f
418 ✗ : kerning->second
419 ;
420 ✗ position.x += (ch->advance + the_kerning) * size;
421 ✗ }
422 ✗ last_char_index = code_point;
423 }
424 };
425
426
427 ListOfTextDrawCommands
428 ✗ DrawableFont::compile_list(const std::string& text, float size) const
429 {
430 ✗ ListOfTextDrawCommands list;
431
432 ✗ UiTextCompileVisitor vis {this, size, &list};
433 // text.accept(&vis);
434 ✗ vis.on_begin();
435
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
✗ vis.on_text(text);
436 ✗ vis.on_end();
437
438 ✗ return list;
439 ✗ }
440
441
442 Rect
443 ✗ ListOfTextDrawCommands::get_extents() const
444 {
445
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 21 not taken.
✗ Rect ret;
446
0/2
✗ Branch 17 → 5 not taken.
✗ Branch 17 → 18 not taken.
✗ for(const auto& cmd: commands)
447 {
448
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 20 not taken.
✗ ret.extend(cmd.sprite_rect);
449 }
450 ✗ return ret;
451 }
452
453
454 ✗ DrawableText::DrawableText(const DrawableFont* the_font)
455 ✗ : font(the_font)
456 {
457 ✗ }
458
459
460 ✗ DrawableText::~DrawableText() = default;
461
462
463 void
464 ✗ DrawableText::set_text(const std::string& new_text)
465 {
466 ✗ text = new_text;
467 ✗ is_dirty = true;
468 ✗ }
469
470
471 void
472 ✗ DrawableText::set_background(bool new_use_background, float new_alpha)
473 {
474 ✗ use_background = new_use_background;
475 ✗ background_alpha = new_alpha;
476 ✗ }
477
478
479 void
480 ✗ DrawableText::set_alignment(Align new_alignment)
481 {
482 ✗ alignment = new_alignment;
483 ✗ }
484
485
486 void
487 ✗ DrawableText::set_size(float new_size)
488 {
489
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if(size != new_size)
490 {
491 ✗ size = new_size;
492 ✗ is_dirty = true;
493 }
494 ✗ }
495
496
497 void
498 ✗ DrawableText::draw
499 (
500 SpriteBatch* renderer,
501 const v2& p,
502 const Rgb& base_hi_color
503 ) const
504 {
505 ✗ draw(renderer, p, base_hi_color, base_hi_color);
506 ✗ }
507
508
509 void
510 ✗ DrawableText::draw
511 (
512 SpriteBatch* renderer,
513 const v2& p,
514 const Rgb& base_color,
515 const Rgb& hi_color
516 ) const
517 {
518
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 33 not taken.
✗ compile();
519
0/8
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 10 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 33 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 10 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 25 not taken.
✗ ASSERT(!is_dirty);
520
521
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
✗ if(font == nullptr)
522 {
523 ✗ return;
524 }
525
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 33 not taken.
✗ const auto e = get_extents();
526
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 33 not taken.
✗ const auto off = internal::get_offset(alignment, e);
527
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 21 not taken.
✗ if(use_background)
528 {
529 ✗ font->draw_background
530 ✗ (
531 renderer,
532
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 28 not taken.
✗ background_alpha,
533
0/6
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 29 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 28 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 28 not taken.
✗ e.with_inset(Lrtb{ -5.0f }).with_offset(p + off)
534 );
535 }
536
537
0/4
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 32 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 32 not taken.
✗ commands.draw(renderer, p + off, base_color, hi_color);
538 }
539
540
541 void
542 ✗ DrawableText::compile() const
543 {
544
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ if(is_dirty)
545 {
546 ✗ is_dirty = false;
547
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 8 not taken.
✗ commands = font->compile_list(text, size);
548 }
549 ✗ }
550
551
552 Rect
553 ✗ DrawableText::get_extents() const
554 {
555 ✗ compile();
556
0/6
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 10 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 10 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 12 not taken.
✗ ASSERT(!is_dirty);
557 ✗ return commands.get_extents();
558 }
559 }
560