Merge pull request #88091 from bruvzg/extra_fallback

[TextServer] Add extra fallback step, to lookup for individual characters.
This commit is contained in:
Rémi Verschelde 2024-02-15 17:35:40 +01:00
commit 4bb3af67e0
No known key found for this signature in database
GPG key ID: C3336907360768E1
2 changed files with 70 additions and 28 deletions

View file

@ -5819,7 +5819,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;
@ -5849,29 +5849,71 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
}
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);
@ -6046,7 +6088,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;
}
@ -6076,7 +6118,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));
@ -6200,21 +6242,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;
@ -6227,9 +6269,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)) {
@ -6239,9 +6281,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];
@ -6289,7 +6331,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());
}
}
}

View file

@ -649,7 +649,7 @@ class TextServerAdvanced : public TextServerExtension {
int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const;
void _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 _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);
Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size);
_FORCE_INLINE_ RID _find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text);