summaryrefslogtreecommitdiffstats
path: root/modules/text_server_adv/text_server_adv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/text_server_adv/text_server_adv.cpp')
-rw-r--r--modules/text_server_adv/text_server_adv.cpp144
1 files changed, 99 insertions, 45 deletions
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index f5174d7d46..1ed335fe99 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -958,7 +958,7 @@ void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
}
}
-_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const {
+_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *p_outline, const Vector2 &p_advance) const {
msdfgen::Shape shape;
shape.contours.clear();
@@ -974,13 +974,13 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
ft_functions.shift = 0;
ft_functions.delta = 0;
- int error = FT_Outline_Decompose(outline, &ft_functions, &context);
+ int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);
ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");
if (!shape.contours.empty() && shape.contours.back().edges.empty()) {
shape.contours.pop_back();
}
- if (FT_Outline_Get_Orientation(outline) == 1) {
+ if (FT_Outline_Get_Orientation(p_outline) == 1) {
for (int i = 0; i < (int)shape.contours.size(); ++i) {
shape.contours[i].reverse();
}
@@ -993,12 +993,19 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
FontGlyph chr;
chr.found = true;
- chr.advance = advance;
+ chr.advance = p_advance;
if (shape.validate() && shape.contours.size() > 0) {
int w = (bounds.r - bounds.l);
int h = (bounds.t - bounds.b);
+ if (w == 0 || h == 0) {
+ chr.texture_idx = -1;
+ chr.uv_rect = Rect2();
+ chr.rect = Rect2();
+ return chr;
+ }
+
int mw = w + p_rect_margin * 4;
int mh = h + p_rect_margin * 4;
@@ -1056,12 +1063,24 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
#endif
#ifdef MODULE_FREETYPE_ENABLED
-_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const {
- int w = bitmap.width;
- int h = bitmap.rows;
+_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const {
+ FontGlyph chr;
+ chr.advance = p_advance * p_data->scale / p_data->oversampling;
+ chr.found = true;
+
+ int w = p_bitmap.width;
+ int h = p_bitmap.rows;
+
+ if (w == 0 || h == 0) {
+ chr.texture_idx = -1;
+ chr.uv_rect = Rect2();
+ chr.rect = Rect2();
+ return chr;
+ }
+
int color_size = 2;
- switch (bitmap.pixel_mode) {
+ switch (p_bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO:
case FT_PIXEL_MODE_GRAY: {
color_size = 2;
@@ -1100,54 +1119,54 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
for (int j = 0; j < w; j++) {
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
- switch (bitmap.pixel_mode) {
+ switch (p_bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
- int byte = i * bitmap.pitch + (j >> 3);
+ int byte = i * p_bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
wr[ofs + 0] = 255; // grayscale as 1
- wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
+ wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
wr[ofs + 0] = 255; // grayscale as 1
- wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
+ wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];
break;
case FT_PIXEL_MODE_BGRA: {
- int ofs_color = i * bitmap.pitch + (j << 2);
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
- wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
- wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
+ int ofs_color = i * p_bitmap.pitch + (j << 2);
+ wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
+ wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];
} break;
case FT_PIXEL_MODE_LCD: {
- int ofs_color = i * bitmap.pitch + (j * 3);
+ int ofs_color = i * p_bitmap.pitch + (j * 3);
if (p_bgra) {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
- wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];
+ wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
wr[ofs + 3] = 255;
} else {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
- wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = 255;
}
} break;
case FT_PIXEL_MODE_LCD_V: {
- int ofs_color = i * bitmap.pitch * 3 + j;
+ int ofs_color = i * p_bitmap.pitch * 3 + j;
if (p_bgra) {
- wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
- wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];
+ wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];
+ wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
wr[ofs + 3] = 255;
} else {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
- wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
- wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];
+ wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];
wr[ofs + 3] = 255;
}
} break;
default:
- ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
+ ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");
break;
}
}
@@ -1156,13 +1175,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
tex.dirty = true;
- FontGlyph chr;
- chr.advance = advance * p_data->scale / p_data->oversampling;
chr.texture_idx = tex_pos.index;
- chr.found = true;
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
- chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
+ chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -1432,8 +1448,25 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
#endif
if (!p_font_data->face_init) {
- // Get style flags and name.
- if (fd->face->family_name != nullptr) {
+ // When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
+ // FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
+ // To avoid that behavior, use the format-specific name directly if available.
+ hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
+ unsigned int num_entries = 0;
+ const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);
+ const hb_language_t english = hb_language_from_string("en", -1);
+ for (unsigned int i = 0; i < num_entries; i++) {
+ if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {
+ continue;
+ }
+ if (!p_font_data->font_name.is_empty() && names[i].language != english) {
+ continue;
+ }
+ unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;
+ p_font_data->font_name.resize(text_size);
+ hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());
+ }
+ if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {
p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
}
if (fd->face->style_name != nullptr) {
@@ -1452,7 +1485,6 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
}
- hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
// Get supported scripts from OpenType font data.
p_font_data->supported_scripts.clear();
unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);
@@ -3603,9 +3635,6 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
const FontGlyph &gl = fd->cache[size]->glyph_map[index];
if (gl.found) {
- if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) {
- return; // Nothing to draw.
- }
ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size());
if (gl.texture_idx != -1) {
@@ -3714,9 +3743,6 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
const FontGlyph &gl = fd->cache[size]->glyph_map[index];
if (gl.found) {
- if (gl.uv_rect.size.x <= 2 || gl.uv_rect.size.y <= 2) {
- return; // Nothing to draw.
- }
ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size());
if (gl.texture_idx != -1) {
@@ -6976,6 +7002,34 @@ String TextServerAdvanced::_string_to_lower(const String &p_string, const String
return String::utf16(lower.ptr(), len);
}
+String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {
+#ifndef ICU_STATIC_DATA
+ if (!icu_data_loaded) {
+ return p_string.capitalize();
+ }
+#endif
+
+ if (p_string.is_empty()) {
+ return p_string;
+ }
+ const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ Vector<char16_t> upper;
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
+ upper.resize(len);
+ err = U_ZERO_ERROR;
+ u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
+
+ // Convert back to UTF-32.
+ return String::utf16(upper.ptr(), len);
+}
+
PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.