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.cpp636
1 files changed, 400 insertions, 236 deletions
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 16046ef053..ea88278a17 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -44,7 +44,7 @@ using namespace godot;
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
-#else
+#elif defined(GODOT_MODULE)
// Headers for building as built-in module.
#include "core/config/project_settings.h"
@@ -338,6 +338,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {
/*************************************************************************/
bool TextServerAdvanced::icu_data_loaded = false;
+PackedByteArray TextServerAdvanced::icu_data;
bool TextServerAdvanced::_has_feature(Feature p_feature) const {
switch (p_feature) {
@@ -369,7 +370,7 @@ bool TextServerAdvanced::_has_feature(Feature p_feature) const {
String TextServerAdvanced::_get_name() const {
#ifdef GDEXTENSION
return "ICU / HarfBuzz / Graphite (GDExtension)";
-#else
+#elif defined(GODOT_MODULE)
return "ICU / HarfBuzz / Graphite (Built-in)";
#endif
}
@@ -438,7 +439,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) {
return false;
}
uint64_t len = f->get_length();
- PackedByteArray icu_data = f->get_buffer(len);
+ icu_data = f->get_buffer(len);
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -476,10 +477,10 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
return false;
}
- PackedByteArray icu_data;
- icu_data.resize(U_ICUDATA_SIZE);
- memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
- f->store_buffer(icu_data);
+ PackedByteArray icu_data_static;
+ icu_data_static.resize(U_ICUDATA_SIZE);
+ memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
+ f->store_buffer(icu_data_static);
return true;
#else
@@ -806,7 +807,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ShelfPackTexture *ct = p_data->textures.ptrw();
for (int32_t i = 0; i < p_data->textures.size(); i++) {
- if (p_image_format != ct[i].format) {
+ if (ct[i].image.is_null()) {
+ continue;
+ }
+ if (p_image_format != ct[i].image->get_format()) {
continue;
}
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
@@ -837,12 +841,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
}
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
- tex.format = p_image_format;
- tex.imgdata.resize(texsize * texsize * p_color_size);
+ tex.image = Image::create_empty(texsize, texsize, false, p_image_format);
{
// Zero texture.
- uint8_t *w = tex.imgdata.ptrw();
- ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
+ uint8_t *w = tex.image->ptrw();
+ ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->data_size(), ret);
// Initialize the texture to all-white pixels to prevent artifacts when the
// font is displayed at a non-default scale with filtering enabled.
if (p_color_size == 2) {
@@ -1019,12 +1022,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
{
- uint8_t *wr = tex.imgdata.ptrw();
+ uint8_t *wr = tex.image->ptrw();
for (int i = 0; i < h; i++) {
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) * 4;
- ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
+ ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
@@ -1085,12 +1088,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
{
- uint8_t *wr = tex.imgdata.ptrw();
+ uint8_t *wr = tex.image->ptrw();
for (int i = 0; i < h; i++) {
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.imgdata.size(), FontGlyph());
+ ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
@@ -1112,14 +1115,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
case FT_PIXEL_MODE_LCD: {
int ofs_color = i * bitmap.pitch + (j * 3);
if (p_bgra) {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
wr[ofs + 3] = 255;
} else {
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = 255;
}
} break;
@@ -2408,6 +2411,37 @@ int64_t TextServerAdvanced::_font_get_spacing(const RID &p_font_rid, SpacingType
}
}
+void TextServerAdvanced::_font_set_baseline_offset(const RID &p_font_rid, float p_baseline_offset) {
+ FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
+ if (fdv) {
+ if (fdv->baseline_offset != p_baseline_offset) {
+ fdv->baseline_offset = p_baseline_offset;
+ }
+ } else {
+ FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_NULL(fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->baseline_offset != p_baseline_offset) {
+ _font_clear_cache(fd);
+ fd->baseline_offset = p_baseline_offset;
+ }
+ }
+}
+
+float TextServerAdvanced::_font_get_baseline_offset(const RID &p_font_rid) const {
+ FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
+ if (fdv) {
+ return fdv->baseline_offset;
+ } else {
+ FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_NULL_V(fd, 0.0);
+
+ MutexLock lock(fd->mutex);
+ return fd->baseline_offset;
+ }
+}
+
void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL(fd);
@@ -2719,16 +2753,15 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve
ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
- tex.imgdata = p_image->get_data();
+ tex.image = p_image;
tex.texture_w = p_image->get_width();
tex.texture_h = p_image->get_height();
- tex.format = p_image->get_format();
- Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
- if (fd->mipmaps) {
+ Ref<Image> img = p_image;
+ if (fd->mipmaps && !img->has_mipmaps()) {
+ img = p_image->duplicate();
img->generate_mipmaps();
}
-
tex.texture = ImageTexture::create_from_image(img);
tex.dirty = false;
}
@@ -2743,7 +2776,7 @@ Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
- return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ return tex.image;
}
void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
@@ -3112,8 +3145,9 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
- if (fd->mipmaps) {
+ Ref<Image> img = tex.image;
+ if (fd->mipmaps && !img->has_mipmaps()) {
+ img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
@@ -3158,8 +3192,9 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
- if (fd->mipmaps) {
+ Ref<Image> img = tex.image;
+ if (fd->mipmaps && !img->has_mipmaps()) {
+ img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
@@ -3242,7 +3277,7 @@ TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_fon
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>());
TypedArray<Vector2i> ret;
- for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
+ for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {
ret.push_back(E.key);
}
return ret;
@@ -3503,6 +3538,9 @@ void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2
}
void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
+ if (p_index == 0) {
+ return; // Non visual character, skip.
+ }
FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL(fd);
@@ -3540,20 +3578,24 @@ 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) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
+ if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
- if (fd->mipmaps) {
+ Ref<Image> img = tex.image;
+ if (fd->mipmaps && !img->has_mipmaps()) {
+ img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
@@ -3607,6 +3649,9 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
}
void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
+ if (p_index == 0) {
+ return; // Non visual character, skip.
+ }
FontAdvanced *fd = _get_font_data(p_font_rid);
ERR_FAIL_NULL(fd);
@@ -3644,20 +3689,24 @@ 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) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
+ if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
- if (fd->mipmaps) {
+ Ref<Image> img = tex.image;
+ if (fd->mipmaps && !img->has_mipmaps()) {
+ img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
@@ -4047,6 +4096,20 @@ String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shap
return sd->custom_punct;
}
+void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL(sd);
+ sd->el_char = p_char;
+}
+
+int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL_V(sd, 0);
+ return sd->el_char;
+}
+
void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL(sd);
@@ -4311,6 +4374,8 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V
sd->width += gl.advance * gl.repeat;
}
}
+ sd->sort_valid = false;
+ sd->glyphs_logical.clear();
_realign(sd);
}
return true;
@@ -4523,6 +4588,12 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
// Copy glyphs.
Glyph gl = sd_glyphs[j];
+ if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
+ uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);
+ float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];
+ gl.index = index;
+ gl.advance = w;
+ }
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
@@ -4643,22 +4714,22 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {
// Trim spaces.
- while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
sd->glyphs.write[start_pos].advance = 0;
start_pos += sd->glyphs[start_pos].count;
}
- while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
sd->glyphs.write[end_pos].advance = 0;
end_pos -= sd->glyphs[end_pos].count;
}
} else {
// Skip breaks, but do not reset size.
- while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
start_pos += sd->glyphs[start_pos].count;
}
- while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
end_pos -= sd->glyphs[end_pos].count;
}
}
@@ -4674,7 +4745,7 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
elongation_count++;
}
}
- if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
+ if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
space_count++;
}
}
@@ -4707,7 +4778,7 @@ double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
- if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
+ if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
double old_adv = gl.advance;
double new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
@@ -4797,6 +4868,166 @@ double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const Pac
return 0.0;
}
+RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {
+ RID f;
+ // Try system fallback.
+ String font_name = _font_get_name(p_fdef);
+ BitField<FontStyle> font_style = _font_get_style(p_fdef);
+ int font_weight = _font_get_weight(p_fdef);
+ int font_stretch = _font_get_stretch(p_fdef);
+ Dictionary dvar = _font_get_variation_coordinates(p_fdef);
+ static int64_t wgth_tag = _name_to_tag("weight");
+ static int64_t wdth_tag = _name_to_tag("width");
+ static int64_t ital_tag = _name_to_tag("italic");
+ if (dvar.has(wgth_tag)) {
+ font_weight = dvar[wgth_tag].operator int();
+ }
+ if (dvar.has(wdth_tag)) {
+ font_stretch = dvar[wdth_tag].operator int();
+ }
+ if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {
+ font_style.set_flag(TextServer::FONT_ITALIC);
+ }
+
+ String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+ PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, p_text, locale, p_script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC);
+#ifdef GDEXTENSION
+ for (int fb = 0; fb < fallback_font_name.size(); fb++) {
+ const String &E = fallback_font_name[fb];
+#elif defined(GODOT_MODULE)
+ for (const String &E : fallback_font_name) {
+#endif
+ SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);
+ if (system_fonts.has(key)) {
+ const SystemFontCache &sysf_cache = system_fonts[key];
+ int best_score = 0;
+ int best_match = -1;
+ for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {
+ const SystemFontCacheRec &F = sysf_cache.var[face_idx];
+ if (unlikely(!_font_has_char(F.rid, p_text[0]))) {
+ continue;
+ }
+ BitField<FontStyle> style = _font_get_style(F.rid);
+ int weight = _font_get_weight(F.rid);
+ int stretch = _font_get_stretch(F.rid);
+ int score = (20 - Math::abs(weight - font_weight) / 50);
+ score += (20 - Math::abs(stretch - font_stretch) / 10);
+ if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
+ score += 30;
+ }
+ if (score >= best_score) {
+ best_score = score;
+ best_match = face_idx;
+ }
+ if (best_score == 70) {
+ break;
+ }
+ }
+ if (best_match != -1) {
+ f = sysf_cache.var[best_match].rid;
+ }
+ }
+ if (!f.is_valid()) {
+ if (system_fonts.has(key)) {
+ const SystemFontCache &sysf_cache = system_fonts[key];
+ if (sysf_cache.max_var == sysf_cache.var.size()) {
+ // All subfonts already tested, skip.
+ continue;
+ }
+ }
+
+ if (!system_font_data.has(E)) {
+ system_font_data[E] = FileAccess::get_file_as_bytes(E);
+ }
+
+ const PackedByteArray &font_data = system_font_data[E];
+
+ SystemFontCacheRec sysf;
+ sysf.rid = _create_font();
+ _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());
+
+ Dictionary var = dvar;
+ // Select matching style from collection.
+ int best_score = 0;
+ int best_match = -1;
+ for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {
+ _font_set_face_index(sysf.rid, face_idx);
+ if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {
+ continue;
+ }
+ BitField<FontStyle> style = _font_get_style(sysf.rid);
+ int weight = _font_get_weight(sysf.rid);
+ int stretch = _font_get_stretch(sysf.rid);
+ int score = (20 - Math::abs(weight - font_weight) / 50);
+ score += (20 - Math::abs(stretch - font_stretch) / 10);
+ if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
+ score += 30;
+ }
+ if (score >= best_score) {
+ best_score = score;
+ best_match = face_idx;
+ }
+ if (best_score == 70) {
+ break;
+ }
+ }
+ if (best_match == -1) {
+ _free_rid(sysf.rid);
+ continue;
+ } else {
+ _font_set_face_index(sysf.rid, best_match);
+ }
+ sysf.index = best_match;
+
+ // If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
+ if (best_score != 70) {
+ Dictionary ftr = _font_supported_variation_list(sysf.rid);
+ if (ftr.has(wdth_tag)) {
+ var[wdth_tag] = font_stretch;
+ _font_set_stretch(sysf.rid, font_stretch);
+ }
+ if (ftr.has(wgth_tag)) {
+ var[wgth_tag] = font_weight;
+ _font_set_weight(sysf.rid, font_weight);
+ }
+ if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {
+ var[ital_tag] = 1;
+ _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);
+ }
+ }
+
+ _font_set_antialiasing(sysf.rid, key.antialiasing);
+ _font_set_generate_mipmaps(sysf.rid, key.mipmaps);
+ _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf);
+ _font_set_msdf_pixel_range(sysf.rid, key.msdf_range);
+ _font_set_msdf_size(sysf.rid, key.msdf_source_size);
+ _font_set_fixed_size(sysf.rid, key.fixed_size);
+ _font_set_force_autohinter(sysf.rid, key.force_autohinter);
+ _font_set_hinting(sysf.rid, key.hinting);
+ _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);
+ _font_set_variation_coordinates(sysf.rid, var);
+ _font_set_oversampling(sysf.rid, key.oversampling);
+ _font_set_embolden(sysf.rid, key.embolden);
+ _font_set_transform(sysf.rid, key.transform);
+ _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);
+ _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);
+ _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);
+ _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);
+
+ if (system_fonts.has(key)) {
+ system_fonts[key].var.push_back(sysf);
+ } else {
+ SystemFontCache &sysf_cache = system_fonts[key];
+ sysf_cache.max_var = _font_get_face_count(sysf.rid);
+ sysf_cache.var.push_back(sysf);
+ }
+ f = sysf.rid;
+ }
+ break;
+ }
+ return f;
+}
+
void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid.");
@@ -4839,20 +5070,52 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
int sd_size = sd->glyphs.size();
int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;
+ bool found_el_char = false;
// Find usable fonts, if fonts from the last glyph do not have required chars.
RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
- if (!_font_has_char(dot_gl_font_rid, '.')) {
+ if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {
const Array &fonts = spans[spans.size() - 1].fonts;
for (int i = 0; i < fonts.size(); i++) {
- if (_font_has_char(fonts[i], '.')) {
+ if (_font_has_char(fonts[i], sd->el_char)) {
dot_gl_font_rid = fonts[i];
+ found_el_char = true;
break;
}
}
+ if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
+ const char32_t u32str[] = { sd->el_char, 0 };
+ RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, u32str);
+ if (rid.is_valid()) {
+ dot_gl_font_rid = rid;
+ found_el_char = true;
+ }
+ }
+ } else {
+ found_el_char = true;
+ }
+ if (!found_el_char) {
+ bool found_dot_char = false;
+ dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
+ if (!_font_has_char(dot_gl_font_rid, '.')) {
+ const Array &fonts = spans[spans.size() - 1].fonts;
+ for (int i = 0; i < fonts.size(); i++) {
+ if (_font_has_char(fonts[i], '.')) {
+ dot_gl_font_rid = fonts[i];
+ found_dot_char = true;
+ break;
+ }
+ }
+ if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
+ RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, ".");
+ if (rid.is_valid()) {
+ dot_gl_font_rid = rid;
+ }
+ }
+ }
}
RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
- if (!_font_has_char(whitespace_gl_font_rid, '.')) {
+ if (!_font_has_char(whitespace_gl_font_rid, ' ')) {
const Array &fonts = spans[spans.size() - 1].fonts;
for (int i = 0; i < fonts.size(); i++) {
if (_font_has_char(fonts[i], ' ')) {
@@ -4862,14 +5125,14 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
}
}
- int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10;
+ int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1;
Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2();
- int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10;
+ int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1;
Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();
int ellipsis_width = 0;
if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {
- ellipsis_width = 3 * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = (found_el_char ? 1 : 3) * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
@@ -4948,7 +5211,7 @@ void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
if (dot_gl_idx != 0) {
Glyph gl;
gl.count = 1;
- gl.repeat = 3;
+ gl.repeat = (found_el_char ? 1 : 3);
gl.advance = dot_adv.x;
gl.index = dot_gl_idx;
gl.font_rid = dot_gl_font_rid;
@@ -5163,6 +5426,9 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
if (c == 0x0009 || c == 0x000b) {
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;
}
+ if (c == 0x00ad) {
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SOFT_HYPHEN;
+ }
if (is_whitespace(c)) {
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;
}
@@ -5184,7 +5450,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
if (sd->breaks.has(sd_glyphs[i].end)) {
if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;
- } else if (is_whitespace(c)) {
+ } else if (is_whitespace(c) || c == 0x00ad) {
sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
int count = sd_glyphs[i].count;
@@ -5403,7 +5669,7 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap
sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;
}
if (sd->jstops.has(sd_glyphs[i].start)) {
- if (c == 0xfffc) {
+ if (c == 0xfffc || c == 0x00ad) {
continue;
}
if (sd->jstops[sd_glyphs[i].start]) {
@@ -5529,6 +5795,11 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char
gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));
}
gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.y_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ } else {
+ gl.x_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ }
if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
gl.flags |= GRAPHEME_IS_VALID;
@@ -5557,7 +5828,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source
}
}
-void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end) {
+void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end, RID p_prev_font) {
RID f;
int fs = p_sd->spans[p_span].font_size;
@@ -5577,193 +5848,81 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
break;
}
}
- String text = p_sd->text.substr(p_start, next - p_start);
-
- String font_name = _font_get_name(fdef);
- BitField<FontStyle> font_style = _font_get_style(fdef);
- int font_weight = _font_get_weight(fdef);
- int font_stretch = _font_get_stretch(fdef);
- Dictionary dvar = _font_get_variation_coordinates(fdef);
- static int64_t wgth_tag = _name_to_tag("weight");
- static int64_t wdth_tag = _name_to_tag("width");
- static int64_t ital_tag = _name_to_tag("italic");
- if (dvar.has(wgth_tag)) {
- font_weight = dvar[wgth_tag].operator int();
- }
- if (dvar.has(wdth_tag)) {
- font_stretch = dvar[wdth_tag].operator int();
- }
- if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {
- font_style.set_flag(TextServer::FONT_ITALIC);
- }
-
char scr_buffer[5] = { 0, 0, 0, 0, 0 };
hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer);
String script_code = String(scr_buffer);
- String locale = (p_sd->spans[p_span].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_sd->spans[p_span].language;
-
- PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC);
-#ifdef GDEXTENSION
- for (int fb = 0; fb < fallback_font_name.size(); fb++) {
- const String &E = fallback_font_name[fb];
-#else
- for (const String &E : fallback_font_name) {
-#endif
- SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this);
- if (system_fonts.has(key)) {
- const SystemFontCache &sysf_cache = system_fonts[key];
- int best_score = 0;
- int best_match = -1;
- for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {
- const SystemFontCacheRec &F = sysf_cache.var[face_idx];
- if (unlikely(!_font_has_char(F.rid, text[0]))) {
- continue;
- }
- BitField<FontStyle> style = _font_get_style(F.rid);
- int weight = _font_get_weight(F.rid);
- int stretch = _font_get_stretch(F.rid);
- int score = (20 - Math::abs(weight - font_weight) / 50);
- score += (20 - Math::abs(stretch - font_stretch) / 10);
- if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
- score += 30;
- }
- if (score >= best_score) {
- best_score = score;
- best_match = face_idx;
- }
- if (best_score == 70) {
- break;
- }
- }
- if (best_match != -1) {
- f = sysf_cache.var[best_match].rid;
- }
- }
- if (!f.is_valid()) {
- if (system_fonts.has(key)) {
- const SystemFontCache &sysf_cache = system_fonts[key];
- if (sysf_cache.max_var == sysf_cache.var.size()) {
- // All subfonts already tested, skip.
- continue;
- }
- }
-
- if (!system_font_data.has(E)) {
- system_font_data[E] = FileAccess::get_file_as_bytes(E);
- }
-
- const PackedByteArray &font_data = system_font_data[E];
-
- SystemFontCacheRec sysf;
- sysf.rid = _create_font();
- _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());
- Dictionary var = dvar;
- // Select matching style from collection.
- int best_score = 0;
- int best_match = -1;
- for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {
- _font_set_face_index(sysf.rid, face_idx);
- if (unlikely(!_font_has_char(sysf.rid, text[0]))) {
- continue;
- }
- BitField<FontStyle> style = _font_get_style(sysf.rid);
- int weight = _font_get_weight(sysf.rid);
- int stretch = _font_get_stretch(sysf.rid);
- int score = (20 - Math::abs(weight - font_weight) / 50);
- score += (20 - Math::abs(stretch - font_stretch) / 10);
- if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
- score += 30;
- }
- if (score >= best_score) {
- best_score = score;
- best_match = face_idx;
- }
- if (best_score == 70) {
- break;
- }
- }
- if (best_match == -1) {
- _free_rid(sysf.rid);
- continue;
- } else {
- _font_set_face_index(sysf.rid, best_match);
- }
- sysf.index = best_match;
-
- // If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
- if (best_score != 70) {
- Dictionary ftr = _font_supported_variation_list(sysf.rid);
- if (ftr.has(wdth_tag)) {
- var[wdth_tag] = font_stretch;
- _font_set_stretch(sysf.rid, font_stretch);
- }
- if (ftr.has(wgth_tag)) {
- var[wgth_tag] = font_weight;
- _font_set_weight(sysf.rid, font_weight);
- }
- if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {
- var[ital_tag] = 1;
- _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);
- }
- }
-
- _font_set_antialiasing(sysf.rid, key.antialiasing);
- _font_set_generate_mipmaps(sysf.rid, key.mipmaps);
- _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf);
- _font_set_msdf_pixel_range(sysf.rid, key.msdf_range);
- _font_set_msdf_size(sysf.rid, key.msdf_source_size);
- _font_set_fixed_size(sysf.rid, key.fixed_size);
- _font_set_force_autohinter(sysf.rid, key.force_autohinter);
- _font_set_hinting(sysf.rid, key.hinting);
- _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);
- _font_set_variation_coordinates(sysf.rid, var);
- _font_set_oversampling(sysf.rid, key.oversampling);
- _font_set_embolden(sysf.rid, key.embolden);
- _font_set_transform(sysf.rid, key.transform);
- _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);
- _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);
- _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);
- _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);
-
- if (system_fonts.has(key)) {
- system_fonts[key].var.push_back(sysf);
- } else {
- SystemFontCache &sysf_cache = system_fonts[key];
- sysf_cache.max_var = _font_get_face_count(sysf.rid);
- sysf_cache.var.push_back(sysf);
- }
- f = sysf.rid;
- }
- break;
- }
+ String text = p_sd->text.substr(p_start, next - p_start);
+ f = _find_sys_font_for_text(fdef, script_code, p_sd->spans[p_span].language, text);
}
}
if (!f.is_valid()) {
- // No valid font, use fallback hex code boxes.
- for (int i = p_start; i < p_end; i++) {
+ // Shaping failed, try looking up raw characters or use fallback hex code boxes.
+ int fb_from = (p_direction != HB_DIRECTION_RTL) ? p_start : p_end - 1;
+ int fb_to = (p_direction != HB_DIRECTION_RTL) ? p_end : p_start - 1;
+ int fb_delta = (p_direction != HB_DIRECTION_RTL) ? +1 : -1;
+
+ for (int i = fb_from; i != fb_to; i += fb_delta) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
Glyph gl;
gl.start = i + p_sd->start;
gl.end = i + 1 + p_sd->start;
gl.count = 1;
- gl.index = p_sd->text[i];
gl.font_size = fs;
- gl.font_rid = RID();
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
}
- if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = get_hex_code_box_size(fs, gl.index).x;
- p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
- } else {
- gl.advance = get_hex_code_box_size(fs, gl.index).y;
- gl.y_off = get_hex_code_box_size(fs, gl.index).y;
- gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);
- p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
- p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
+
+ bool found = false;
+ for (int j = 0; j <= p_fonts.size(); j++) {
+ RID f_rid;
+ if (j == p_fonts.size()) {
+ f_rid = p_prev_font;
+ } else {
+ f_rid = p_fonts[j];
+ }
+ if (f_rid.is_valid() && _font_has_char(f_rid, p_sd->text[i])) {
+ gl.font_rid = f_rid;
+ gl.index = _font_get_glyph_index(gl.font_rid, fs, p_sd->text[i], 0);
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).x;
+ gl.x_off = 0;
+ gl.y_off = _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));
+ p_sd->descent = MAX(p_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));
+ } else {
+ gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).y;
+ gl.x_off = -Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5) + _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ }
+ double scale = _font_get_scale(gl.font_rid, fs);
+ bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
+ if (!subpos) {
+ gl.advance = Math::round(gl.advance);
+ gl.x_off = Math::round(gl.x_off);
+ }
+ found = true;
+ break;
+ }
}
+ if (!found) {
+ gl.font_rid = RID();
+ gl.index = p_sd->text[i];
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.advance = get_hex_code_box_size(fs, gl.index).x;
+ p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
+ } else {
+ gl.advance = get_hex_code_box_size(fs, gl.index).y;
+ gl.y_off = get_hex_code_box_size(fs, gl.index).y;
+ gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
+ }
+ }
+
p_sd->width += gl.advance;
p_sd->glyphs.push_back(gl);
@@ -5897,6 +6056,11 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));
}
gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));
+ if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
+ gl.y_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ } else {
+ gl.x_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));
+ }
}
if (!last_run || i < glyph_count - 1) {
// Do not add extra spacing to the last glyph of the string.
@@ -5933,7 +6097,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
for (unsigned int i = 0; i < glyph_count; i++) {
if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
if (failed_subrun_start != p_end + 1) {
- _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end);
+ _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());
failed_subrun_start = p_end + 1;
failed_subrun_end = p_start;
}
@@ -5963,7 +6127,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
}
memfree(w);
if (failed_subrun_start != p_end + 1) {
- _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end);
+ _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());
}
p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));
p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));
@@ -6087,21 +6251,21 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
for (int i = 0; i < bidi_run_count; i++) {
int32_t _bidi_run_start = 0;
int32_t _bidi_run_length = end - start;
- bool is_rtl = false;
+ bool is_ltr = false;
hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;
if (bidi_iter) {
- is_rtl = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
+ is_ltr = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
}
switch (sd->orientation) {
case ORIENTATION_HORIZONTAL: {
- if (is_rtl) {
+ if (is_ltr) {
bidi_run_direction = HB_DIRECTION_LTR;
} else {
bidi_run_direction = HB_DIRECTION_RTL;
}
} break;
case ORIENTATION_VERTICAL: {
- if (is_rtl) {
+ if (is_ltr) {
bidi_run_direction = HB_DIRECTION_TTB;
} else {
bidi_run_direction = HB_DIRECTION_BTT;
@@ -6114,9 +6278,9 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
// Shape runs.
- int scr_from = (is_rtl) ? 0 : sd->script_iter->script_ranges.size() - 1;
- int scr_to = (is_rtl) ? sd->script_iter->script_ranges.size() : -1;
- int scr_delta = (is_rtl) ? +1 : -1;
+ int scr_from = (is_ltr) ? 0 : sd->script_iter->script_ranges.size() - 1;
+ int scr_to = (is_ltr) ? sd->script_iter->script_ranges.size() : -1;
+ int scr_delta = (is_ltr) ? +1 : -1;
for (int j = scr_from; j != scr_to; j += scr_delta) {
if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {
@@ -6126,9 +6290,9 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);
String script_code = String(scr_buffer);
- int spn_from = (is_rtl) ? 0 : sd->spans.size() - 1;
- int spn_to = (is_rtl) ? sd->spans.size() : -1;
- int spn_delta = (is_rtl) ? +1 : -1;
+ int spn_from = (is_ltr) ? 0 : sd->spans.size() - 1;
+ int spn_to = (is_ltr) ? sd->spans.size() : -1;
+ int spn_delta = (is_ltr) ? +1 : -1;
for (int k = spn_from; k != spn_to; k += spn_delta) {
const ShapedTextDataAdvanced::Span &span = sd->spans[k];
@@ -6176,7 +6340,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
}
fonts.append_array(fonts_scr_only);
fonts.append_array(fonts_no_match);
- _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0, 0, 0);
+ _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0, 0, 0, RID());
}
}
}
@@ -6690,7 +6854,7 @@ String TextServerAdvanced::_strip_diacritics(const String &p_string) const {
if (u_getCombiningClass(normalized_string[i]) == 0) {
#ifdef GDEXTENSION
result = result + String::chr(normalized_string[i]);
-#else
+#elif defined(GODOT_MODULE)
result = result + normalized_string[i];
#endif
}