summaryrefslogtreecommitdiff
path: root/modules/text_server_fb
diff options
context:
space:
mode:
Diffstat (limited to 'modules/text_server_fb')
-rw-r--r--modules/text_server_fb/register_types.cpp4
-rw-r--r--modules/text_server_fb/register_types.h4
-rw-r--r--modules/text_server_fb/text_server_fb.cpp207
-rw-r--r--modules/text_server_fb/text_server_fb.h12
4 files changed, 179 insertions, 48 deletions
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
index 0b59040ce8..a545f84939 100644
--- a/modules/text_server_fb/register_types.cpp
+++ b/modules/text_server_fb/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h
index c854db92e5..8652a8e9db 100644
--- a/modules/text_server_fb/register_types.h
+++ b/modules/text_server_fb/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 97a53143cf..ffbd2da22d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
+#include "core/string/ucaps.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
@@ -399,7 +400,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
FontGlyph chr;
chr.found = true;
- chr.advance = advance.round();
+ chr.advance = advance;
if (shape.validate() && shape.contours.size() > 0) {
int w = (bounds.r - bounds.l);
@@ -552,12 +553,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
}
FontGlyph chr;
- chr.advance = (advance * p_data->scale / p_data->oversampling).round();
+ 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, h);
- chr.rect.position = (Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling).round();
+ chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -729,7 +730,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
}
FT_Select_Size(fd->face, best_match);
} else {
- FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling);
+ FT_Set_Pixel_Sizes(fd->face, 0, Math::round(fd->size.x * fd->oversampling));
+ fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem;
}
fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
@@ -1824,7 +1826,7 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -1846,9 +1848,9 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -1864,7 +1866,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
if (!_ensure_glyph(fd, size, p_index)) {
- return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw.
+ return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
}
const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
@@ -1886,9 +1888,9 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
- Point2i cpos = p_pos;
+ Point2 cpos = p_pos.floor();
cpos += gl.rect.position;
- Size2i csize = gl.rect.size;
+ Size2 csize = gl.rect.size;
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
}
}
@@ -1994,6 +1996,24 @@ Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font_
return out;
}
+void TextServerFallback::font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, 16);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->feature_overrides = p_overrides;
+}
+
+Dictionary TextServerFallback::font_get_opentype_feature_overrides(RID p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+
+ MutexLock lock(fd->mutex);
+ return fd->feature_overrides;
+}
+
Dictionary TextServerFallback::font_supported_feature_list(RID p_font_rid) const {
return Dictionary();
}
@@ -2109,6 +2129,10 @@ TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped
return TextServer::DIRECTION_LTR;
}
+TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(RID p_shaped) const {
+ return TextServer::DIRECTION_LTR;
+}
+
void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
@@ -2260,7 +2284,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
ShapedTextData::Span span;
- span.start = sd->text.length();
+ span.start = sd->start + sd->text.length();
span.end = span.start + p_length;
span.embedded_key = p_key;
@@ -2441,7 +2465,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->uthk = sd->uthk;
if (p_length > 0) {
- new_sd->text = sd->text.substr(p_start, p_length);
+ new_sd->text = sd->text.substr(p_start - sd->start, p_length);
int sd_size = sd->glyphs.size();
const Glyph *sd_glyphs = sd->glyphs.ptr();
@@ -2612,17 +2636,38 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
+ float justification_width;
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ if (sd->overrun_trim_data.trim_pos >= 0) {
+ end_pos = sd->overrun_trim_data.trim_pos;
+ justification_width = sd->width_trimmed;
+ } else {
+ return sd->width;
+ }
+ } else {
+ justification_width = sd->width;
+ }
+
if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == 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)) {
- sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
+ 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)) {
- sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
+ 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)) {
+ 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)) {
+ end_pos -= sd->glyphs[end_pos].count;
+ }
}
int space_count = 0;
@@ -2636,20 +2681,28 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- float delta_width_per_space = (p_width - sd->width) / space_count;
+ float delta_width_per_space = (p_width - justification_width) / space_count;
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) {
float old_adv = gl.advance;
gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
- sd->width += (gl.advance - old_adv);
+ justification_width += (gl.advance - old_adv);
}
}
}
}
- return sd->width;
+ if (Math::floor(p_width) < Math::floor(justification_width)) {
+ sd->fit_width_minimum_reached = true;
+ }
+
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) != JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ sd->width = justification_width;
+ }
+
+ return justification_width;
}
float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
@@ -2664,6 +2717,12 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat3
const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped);
}
+ for (int i = 0; i < p_tab_stops.size(); i++) {
+ if (p_tab_stops[i] <= 0) {
+ return 0.f;
+ }
+ }
+
int tab_index = 0;
float off = 0.f;
@@ -2723,7 +2782,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
for (int i = 0; i < sd_size; i++) {
if (sd_glyphs[i].count > 0) {
- char32_t c = sd->text[sd_glyphs[i].start];
+ char32_t c = sd->text[sd_glyphs[i].start - sd->start];
if (c_punct_size == 0) {
if (is_punct(c)) {
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
@@ -2744,6 +2803,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
}
if (is_linebreak(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
}
if (c == 0x0009 || c == 0x000b) {
@@ -2802,17 +2862,50 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
return;
}
+ Vector<ShapedTextData::Span> &spans = sd->spans;
+ if (sd->parent != RID()) {
+ ShapedTextData *parent_sd = shaped_owner.get_or_null(sd->parent);
+ ERR_FAIL_COND(!parent_sd->valid);
+ spans = parent_sd->spans;
+ }
+
+ if (spans.size() == 0) {
+ return;
+ }
+
int sd_size = sd->glyphs.size();
- RID last_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;
- int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.', 0);
- Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, dot_gl_idx);
- int32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ', 0);
- Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx);
+
+ // 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, '.')) {
+ const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
+ for (const RID &font : fonts) {
+ if (font_has_char(font, '.')) {
+ dot_gl_font_rid = font;
+ break;
+ }
+ }
+ }
+ RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
+ if (!font_has_char(whitespace_gl_font_rid, '.')) {
+ const Vector<RID> &fonts = spans[spans.size() - 1].fonts;
+ for (const RID &font : fonts) {
+ if (font_has_char(font, ' ')) {
+ whitespace_gl_font_rid = font;
+ break;
+ }
+ }
+ }
+
+ int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10;
+ 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, ' ') : -10;
+ 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) {
- ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, TextServer::SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);
+ if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing(whitespace_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
@@ -2866,23 +2959,25 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
- gl.font_rid = last_gl_font_rid;
+ gl.font_rid = whitespace_gl_font_rid;
gl.font_size = last_gl_font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- Glyph gl;
- gl.count = 1;
- gl.repeat = 3;
- gl.advance = dot_adv.x;
- gl.index = dot_gl_idx;
- gl.font_rid = last_gl_font_rid;
- gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;
+ if (dot_gl_idx != 0) {
+ Glyph gl;
+ gl.count = 1;
+ gl.repeat = 3;
+ gl.advance = dot_adv.x;
+ gl.index = dot_gl_idx;
+ gl.font_rid = dot_gl_font_rid;
+ gl.font_size = last_gl_font_size;
+ gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;
- sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
+ }
}
sd->text_trimmed = true;
@@ -2980,7 +3075,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
gl.end = j + 1;
gl.count = 1;
gl.font_size = span.font_size;
- gl.index = (int32_t)sd->text[j]; // Use codepoint.
+ gl.index = (int32_t)sd->text[j - sd->start]; // Use codepoint.
if (gl.index == 0x0009 || gl.index == 0x000b) {
gl.index = 0x0020;
}
@@ -2996,22 +3091,22 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
if (gl.font_rid.is_valid()) {
- if (sd->text[j] != 0 && !is_linebreak(sd->text[j])) {
+ if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;
+ gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x);
gl.x_off = 0;
gl.y_off = 0;
sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size));
sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size));
} else {
- gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y;
+ gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y);
gl.x_off = -Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5);
gl.y_off = font_get_ascent(gl.font_rid, gl.font_size);
sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
}
}
- if (font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE) && is_whitespace(sd->text[j])) {
+ if (font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE) && is_whitespace(sd->text[j - sd->start])) {
gl.advance += font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_SPACE);
} else {
gl.advance += font_get_spacing(gl.font_rid, gl.font_size, TextServer::SPACING_GLYPH);
@@ -3262,6 +3357,34 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons
return sd->uthk;
}
+String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const {
+ String upper = p_string;
+
+ for (int i = 0; i < upper.size(); i++) {
+ const char32_t s = upper[i];
+ const char32_t t = _find_upper(s);
+ if (s != t) { // avoid copy on write
+ upper[i] = t;
+ }
+ }
+
+ return upper;
+}
+
+String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const {
+ String lower = p_string;
+
+ for (int i = 0; i < lower.size(); i++) {
+ const char32_t s = lower[i];
+ const char32_t t = _find_lower(s);
+ if (s != t) { // avoid copy on write
+ lower[i] = t;
+ }
+ }
+
+ return lower;
+}
+
TextServerFallback::TextServerFallback() {
_insert_feature_sets();
};
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index f2b33c2afb..b356b90d2c 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -150,6 +150,7 @@ class TextServerFallback : public TextServer {
bool face_init = false;
Dictionary supported_varaitions;
+ Dictionary feature_overrides;
// Language/script support override.
Map<String, bool> language_support_overrides;
@@ -357,6 +358,9 @@ public:
virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
+ virtual void font_set_opentype_feature_overrides(RID p_font_rid, const Dictionary &p_overrides) override;
+ virtual Dictionary font_get_opentype_feature_overrides(RID p_font_rid) const override;
+
virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
@@ -371,6 +375,7 @@ public:
virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
virtual Direction shaped_text_get_direction(RID p_shaped) const override;
+ virtual Direction shaped_text_get_inferred_direction(RID p_shaped) const override;
virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
@@ -425,6 +430,9 @@ public:
virtual float shaped_text_get_underline_position(RID p_shaped) const override;
virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
+ virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
+ virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+
TextServerFallback();
~TextServerFallback();
};