diff options
Diffstat (limited to 'modules/text_server_fb')
-rw-r--r-- | modules/text_server_fb/SCsub | 1 | ||||
-rw-r--r-- | modules/text_server_fb/bitmap_font_fb.cpp | 1 | ||||
-rw-r--r-- | modules/text_server_fb/dynamic_font_fb.cpp | 62 | ||||
-rw-r--r-- | modules/text_server_fb/dynamic_font_fb.h | 5 | ||||
-rw-r--r-- | modules/text_server_fb/text_server_fb.cpp | 113 |
5 files changed, 77 insertions, 105 deletions
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub index 7650e27063..03eccbe7bd 100644 --- a/modules/text_server_fb/SCsub +++ b/modules/text_server_fb/SCsub @@ -9,4 +9,5 @@ env_text_server_fb.Append( "#thirdparty/freetype/include", ] ) + env_text_server_fb.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp index 5ab8edbd71..99cbccb69a 100644 --- a/modules/text_server_fb/bitmap_font_fb.cpp +++ b/modules/text_server_fb/bitmap_font_fb.cpp @@ -198,7 +198,6 @@ Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_s chr.rect.position.y = c[2]; chr.rect.size.x = c[3]; chr.rect.size.y = c[4]; - chr.texture_idx = 0; if (c[7] < 0) { chr.advance.x = c[3]; } else { diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 6feeaec102..6731870e8f 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -33,8 +33,6 @@ #include FT_STROKER_H #include FT_ADVANCES_H -HashMap<String, Vector<uint8_t>> DynamicFontDataFallback::font_mem_cache; - DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(int p_size, int p_outline_size) { ERR_FAIL_COND_V(!valid, nullptr); ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr); @@ -55,11 +53,10 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( if (E != nullptr) { fds = E->get(); } else { - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) { - if (font_mem_cache.has(font_path)) { - font_mem = font_mem_cache[font_path].ptr(); - font_mem_size = font_mem_cache[font_path].size(); + if (font_mem == nullptr && font_path != String()) { + if (!font_mem_cache.empty()) { + font_mem = font_mem_cache.ptr(); + font_mem_size = font_mem_cache.size(); } else { FileAccess *f = FileAccess::open(font_path, FileAccess::READ); if (!f) { @@ -67,11 +64,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( } size_t len = f->get_len(); - font_mem_cache[font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = font_mem_cache[font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font_mem = fontdata.ptr(); + font_mem_cache.resize(len); + f->get_buffer(font_mem_cache.ptrw(), len); + font_mem = font_mem_cache.ptr(); font_mem_size = len; f->close(); } @@ -79,27 +74,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( int error = 0; fds = memnew(DataAtSize); - if (font_mem == nullptr && font_path != String()) { - FileAccess *f = FileAccess::open(font_path, FileAccess::READ); - if (!f) { - memdelete(fds); - ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); - } - - memset(&fds->stream, 0, sizeof(FT_StreamRec)); - fds->stream.base = nullptr; - fds->stream.size = f->get_len(); - fds->stream.pos = 0; - fds->stream.descriptor.pointer = f; - fds->stream.read = _ft_stream_io; - fds->stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &fds->stream; - error = FT_Open_Face(library, &fargs, 0, &fds->face); - } else if (font_mem) { + if (font_mem) { memset(&fds->stream, 0, sizeof(FT_StreamRec)); fds->stream.base = (unsigned char *)font_mem; fds->stream.size = font_mem_size; @@ -161,30 +136,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( return fds; } -unsigned long DynamicFontDataFallback::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); - } - if (count == 0) { - return 0; - } - - return f->get_buffer(buffer, count); -} - -void DynamicFontDataFallback::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); -} - DynamicFontDataFallback::TexturePosition DynamicFontDataFallback::find_texture_pos_for_glyph(DynamicFontDataFallback::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) { TexturePosition ret; ret.index = -1; - ret.x = 0; - ret.y = 0; int mw = p_width; int mh = p_height; diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h index 060b8cfbf9..6ac8cb52a8 100644 --- a/modules/text_server_fb/dynamic_font_fb.h +++ b/modules/text_server_fb/dynamic_font_fb.h @@ -107,7 +107,7 @@ private: const uint8_t *font_mem = nullptr; int font_mem_size = 0; String font_path; - static HashMap<String, Vector<uint8_t>> font_mem_cache; + Vector<uint8_t> font_mem_cache; float rect_margin = 1.f; int base_size = 16; @@ -119,9 +119,6 @@ private: Map<CacheID, DataAtSize *> size_cache; Map<CacheID, DataAtSize *> size_cache_outline; - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0); TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index e74a1d9ef9..675d0e5d4d 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -45,6 +45,10 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029); } +_FORCE_INLINE_ bool is_punct(char32_t p_char) { + return (p_char >= 0x0020 && p_char <= 0x002F) || (p_char >= 0x003A && p_char <= 0x0040) || (p_char >= 0x005B && p_char <= 0x0060) || (p_char >= 0x007B && p_char <= 0x007E) || (p_char >= 0x2000 && p_char <= 0x206F) || (p_char >= 0x3000 && p_char <= 0x303F); +} + /*************************************************************************/ String TextServerFallback::interface_name = "Fallback"; @@ -625,7 +629,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->width = 0; sd->upos = 0; sd->uthk = 0; - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + const FontDataFallback *fd = nullptr; + RID prev_rid = RID(); + + for (int i = 0; i < sd_size; i++) { Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { @@ -645,8 +653,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); @@ -661,8 +669,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); @@ -671,25 +679,28 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->glyphs.write[i].advance = sd->objects[key].rect.size.y; } } else { - const FontDataFallback *fd = font_owner.getornull(gl.font_rid); + if (prev_rid != gl.font_rid) { + fd = font_owner.getornull(gl.font_rid); + prev_rid = gl.font_rid; + } if (fd != nullptr) { if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size)); sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance * gl.repeat; @@ -760,21 +771,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (p_length > 0) { new_sd->text = sd->text.substr(p_start, p_length); + int sd_size = sd->glyphs.size(); + const Glyph *sd_glyphs = sd->glyphs.ptr(); - for (int i = 0; i < sd->glyphs.size(); i++) { - if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) { - Glyph gl = sd->glyphs[i]; + for (int i = 0; i < sd_size; i++) { + if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) { + Glyph gl = sd_glyphs[i]; Variant key; + bool find_embedded = false; if (gl.count == 1) { for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (E->get().pos == gl.start) { + find_embedded = true; key = E->key(); new_sd->objects[key] = E->get(); break; } } } - if (key != Variant()) { + if (find_embedded) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; @@ -783,8 +798,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); @@ -798,8 +813,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); @@ -813,17 +828,17 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size)); new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size)); } else { - new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } new_sd->width += gl.advance * gl.repeat; @@ -943,7 +958,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; - gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size)); sd->width += (gl.advance - old_adv); } } @@ -978,8 +993,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float delta = -1; } + Glyph *gl = sd->glyphs.ptrw(); + for (int i = start; i != end; i += delta) { - if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { + if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; @@ -988,13 +1005,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float tab_index = 0; } } - float old_adv = sd->glyphs.write[i].advance; - sd->glyphs.write[i].advance = (tab_off - off); - sd->width += sd->glyphs.write[i].advance - old_adv; + float old_adv = gl[i].advance; + gl[i].advance = tab_off - off; + sd->width += gl[i].advance - old_adv; off = 0; continue; } - off += sd->glyphs[i].advance * sd->glyphs[i].repeat; + off += gl[i].advance * gl[i].repeat; } return 0.f; @@ -1012,9 +1029,13 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { return true; // Noting to do. } - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + for (int i = 0; i < sd_size; i++) { if (sd->glyphs[i].count > 0) { char32_t c = sd->text[sd->glyphs[i].start]; + if (is_punct(c)) { + sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION; + } if (is_whitespace(c) && !is_linebreak(c)) { sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; @@ -1086,8 +1107,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); @@ -1101,8 +1122,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); @@ -1157,14 +1178,14 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { gl.advance = fd->get_advance(gl.index, gl.font_size).y; - gl.x_off = -fd->get_advance(gl.index, gl.font_size).x * 0.5; + gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5); gl.y_off = fd->get_ascent(gl.font_size); - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size)); + sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size)); // Add kerning to previous glyph. if (sd->glyphs.size() > 0) { @@ -1181,12 +1202,12 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance; |