GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 102, 0 excluded
0.0%
Functions:
0 of 8, 0 excluded
0.0%
Branches:
0 of 98, 0 excluded
0.0%

libs/core/src/eu/core/loadedfont.cc
Line Branch Exec Source
1 #include "eu/core/loadedfont.h"
2
3 #include <set>
4 #include <optional>
5 #include <map>
6
7 #include "eustb_truetype.h"
8
9 #include "eu/log/log.h"
10
11 #include "eu/assert/assert.h"
12
13 #include "eu/base/cint.h"
14 #include "eu/base/memorychunk.h"
15
16 #include "eu/core/utf8.h"
17
18
19
20 namespace eu::core
21 {
22 struct FontData
23 {
24 stbtt_fontinfo font;
25 float size;
26 bool was_loaded;
27 float ascent_in_pixels = 0.0f;
28 float descent_in_pixels = 0.0f;
29 float line_gap_in_pixels = 0.0f;
30
31 std::vector<stbtt_kerningentry> kernings;
32 std::map<int, int> index_to_unicode;
33
34 ✗ FontData(const unsigned char* ttf_buffer, float s)
35 ✗ : font{}
36 ✗ , size{s}
37 ✗ , was_loaded{stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)) == 1}
38 {
39 ✗ if(was_loaded == false) {return;}
40
41 ✗ const int count = stbtt_GetKerningTableLength(&font);
42 ✗ kernings.reserve(count);
43 ✗ stbtt_GetKerningTable(&font, kernings.data(), count);
44
45 ✗ int ascent_in_points = 0;
46 ✗ int descent_in_points = 0;
47 ✗ int line_gap_in_points = 0;
48 ✗ stbtt_GetFontVMetrics(&font, &ascent_in_points, &descent_in_points, &line_gap_in_points);
49 ✗ const float points_to_pixels = stbtt_ScaleForPixelHeight(&font, size);
50 ✗ ascent_in_pixels = float_from_int(ascent_in_points) * points_to_pixels;
51 ✗ descent_in_pixels = float_from_int(descent_in_points) * points_to_pixels;
52 ✗ line_gap_in_pixels = float_from_int(line_gap_in_points) * points_to_pixels;
53 ✗ }
54
55 ✗ void define_codepoint(int cp)
56 {
57 ✗ const int index = stbtt_FindGlyphIndex(&font, cp);
58 ✗ index_to_unicode[index] = cp;
59 ✗ }
60
61 ✗ [[nodiscard]] std::optional<int> from_glyph_index_to_unicode(int glyph) const
62 {
63 ✗ auto found = index_to_unicode.find(glyph);
64 ✗ if(found == index_to_unicode.end())
65 {
66 ✗ return {};
67 }
68 else
69 {
70 ✗ return found->second;
71 }
72 }
73
74 [[nodiscard]] LoadedGlyph
75 ✗ load_glyph(int code_point) const
76 {
77 ✗ int width=0; int height=0;
78 ✗ int xoffset=0; int yoffset=0;
79 ✗ const auto scale = stbtt_ScaleForPixelHeight(&font, size);
80 unsigned char *bitmap = stbtt_GetCodepointBitmap
81 ✗ (
82 &font,
83 scale,
84 scale,
85 code_point,
86 &width,
87 &height,
88 &xoffset,
89 &yoffset
90 );
91
92 ✗ LoadedGlyph ch;
93 ✗ ch.code_point= code_point;
94 ✗ ch.size = size;
95 ✗ ch.bearing_x = xoffset;
96 ✗ ch.bearing_y = -yoffset;
97 ✗ ch.valid = true;
98 {
99 ✗ int advance_width = 0;
100 ✗ stbtt_GetCodepointHMetrics(&font, code_point, &advance_width, nullptr);
101 ✗ ch.advance = int_from_float(float_from_int(advance_width) * scale);
102 }
103 ✗ if(width == 0 && height == 0)
104 {
105 ✗ ch.image.make_invalid();
106 }
107 else
108 {
109 ✗ ch.image.setup_with_alpha_support(width, height);
110
111 ✗ for(int y = 0; y < ch.image.height; y += 1)
112 {
113 ✗ for(int x = 0; x < ch.image.width; x += 1)
114 {
115 ✗ const auto alpha = bitmap[ch.image.width * y + x];
116 ch.image.set_pixel
117 ✗ (
118 ✗ x, ch.image.height-y-1,
119 255, 255, 255,
120 alpha
121 );
122 }
123 }
124 }
125
126 ✗ if(bitmap != nullptr)
127 {
128 ✗ stbtt_FreeBitmap(bitmap, nullptr);
129 }
130
131 ✗ return ch;
132 ✗ }
133 };
134
135
136 int
137 ✗ LoadedFont::generate_new_index_from_private_use(const std::string& alias)
138 {
139 // detect existing private use alias!
140 ✗ const auto pu = next_private_use;
141 ✗ next_private_use += 1;
142 ✗ private_use_aliases[alias] = pu;
143 ✗ return pu;
144 }
145
146
147 ✗ bool LoadedFont::load_characters_from_font
148 (
149 const MemoryChunk& file_memory,
150 int font_size,
151 const std::string& chars
152 )
153 {
154 auto f = FontData
155 {
156 ✗ reinterpret_cast<const unsigned char*>(file_memory.bytes),
157 float_from_int(font_size)
158 ✗ };
159
160 ✗ if(f.was_loaded == false) { return false; }
161
162 ✗ std::vector<int> code_points;
163 calc_utf8_to_codepoints
164 ✗ (
165 chars,
166 ✗ [&](int cp){code_points.emplace_back(cp);}
167 );
168
169 ✗ for(int code_point: code_points)
170 {
171 ✗ const LoadedGlyph cc = f.load_glyph(code_point);
172 ✗ if(!cc.valid)
173 {
174 ✗ LOG_INFO("Invalid codepoint {0}", code_point);
175 ✗ continue;
176 }
177 ✗ this->codepoint_to_glyph[code_point] = cc;
178 ✗ }
179
180 ✗ const float pixels_to_units = 1 / static_cast<float>(font_size);
181
182 ✗ this->ascent = f.ascent_in_pixels * pixels_to_units;
183 ✗ this->descent= f.descent_in_pixels * pixels_to_units;
184 ✗ this->line_gap = f.line_gap_in_pixels * pixels_to_units;
185
186 ✗ for(const auto& cp: code_points)
187 {
188 ✗ f.define_codepoint(cp);
189 }
190
191 ✗ for(const auto& info: f.kernings)
192 {
193 ✗ const auto previous = f.from_glyph_index_to_unicode(info.glyph1);
194 ✗ const auto current = f.from_glyph_index_to_unicode(info.glyph2);
195 ✗ const int dx = info.advance;
196 ✗ if(previous && current)
197 {
198 this->kerning.insert
199 ✗ (
200 ✗ KerningMap::value_type
201 (
202 ✗ KerningMap::key_type(*previous, *current),
203 ✗ static_cast<float>(dx) * pixels_to_units
204 ✗ )
205 );
206 }
207 }
208
209 ✗ return true;
210 ✗ }
211
212 #if 0
213 LoadedFont
214 get_characters_from_single_image
215 (
216 io::FileSystem* fs,
217 const io::FilePath& image_file,
218 const std::string& image_alias,
219 float image_scale,
220 float image_bearing_x,
221 float image_bearing_y,
222 float image_advance
223 )
224 {
225 const auto loaded = load_image
226 (
227 fs,
228 image_file,
229 AlphaLoad::keep
230 );
231
232 if(loaded.error.empty() == false)
233 {
234 LOG_ERR("Failed to load font image {}", image_file);
235 return LoadedFont{};
236 }
237
238 return get_characters_from_single_image
239 (
240 loaded.image,
241 image_alias,
242 image_scale,
243 image_bearing_x,
244 image_bearing_y,
245 image_advance
246 );
247 }
248 #endif
249
250
251 LoadedFont
252 ✗ get_characters_from_single_image
253 (
254 const Image& image,
255 const std::string& image_alias,
256 float image_scale,
257 float image_bearing_x,
258 float image_bearing_y,
259 float image_advance
260 )
261 {
262 ✗ LoadedFont font;
263
264 ✗ const auto s = 1 / image_scale;
265 ✗ LoadedGlyph glyph;
266 ✗ glyph.size = s * static_cast<float>(image.height);
267 ✗ glyph.bearing_y = int_from_float(s * static_cast<float>(image.height) + image_bearing_y);
268 ✗ glyph.bearing_x = int_from_float(image_bearing_x);
269 ✗ glyph.advance = int_from_float(s * static_cast<float>(image.width) + image_advance);
270 ✗ glyph.code_point= font.generate_new_index_from_private_use(image_alias);
271 // todo(Gustav): add ability to clip image
272 ✗ glyph.image = image;
273 ✗ font.codepoint_to_glyph[glyph.code_point] = glyph;
274
275 ✗ return font;
276 ✗ }
277
278 }
279
280