From 85df221610e72e4b93f4eaf57a2f470c6da8e54d Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Sun, 28 Jan 2024 12:34:56 +0200 Subject: [PATCH] [TextServer / Font] Add support for customizable baseline offset. --- doc/classes/Font.xml | 1 + doc/classes/FontFile.xml | 15 +++++ doc/classes/FontVariation.xml | 3 + doc/classes/TextServer.xml | 15 +++++ doc/classes/TextServerExtension.xml | 13 ++++ .../4.1-stable_4.2-stable.expected | 2 +- .../4.2-stable.expected | 7 +++ modules/text_server_adv/text_server_adv.cpp | 41 +++++++++++++ modules/text_server_adv/text_server_adv.h | 11 +++- modules/text_server_fb/text_server_fb.cpp | 35 ++++++++++- modules/text_server_fb/text_server_fb.h | 10 +++- scene/resources/font.compat.inc | 7 ++- scene/resources/font.cpp | 59 ++++++++++++++++--- scene/resources/font.h | 20 +++++-- scene/resources/text_paragraph.h | 3 - servers/text/text_server_extension.cpp | 13 ++++ servers/text/text_server_extension.h | 5 ++ servers/text_server.cpp | 3 + servers/text_server.h | 3 + 19 files changed, 242 insertions(+), 24 deletions(-) diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index 63e7d80737b8..f2bbb747b104 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -118,6 +118,7 @@ + Returns [TextServer] RID of the font cache for specific variation. diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 87d647486c46..acc12e04f292 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -131,6 +131,13 @@ Returns embolden strength, if is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness. + + + + + Returns extra baseline offset (as a fraction of font height). + + @@ -445,6 +452,14 @@ Sets embolden strength, if is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness. + + + + + + Sets extra baseline offset (as a fraction of font height). + + diff --git a/doc/classes/FontVariation.xml b/doc/classes/FontVariation.xml index e21881fc3e7a..8a09c49f4862 100644 --- a/doc/classes/FontVariation.xml +++ b/doc/classes/FontVariation.xml @@ -46,6 +46,9 @@ Base font used to create a variation. If not set, default [Theme] font is used. + + Extra baseline offset (as a fraction of font height). + A set of OpenType feature tags. More info: [url=https://docs.microsoft.com/en-us/typography/opentype/spec/featuretags]OpenType feature tags[/url]. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index cf4d92d119dd..244ed08b9e85 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -120,6 +120,13 @@ Returns the font ascent (number of pixels above the baseline). + + + + + Returns extra baseline offset (as a fraction of font height). + + @@ -640,6 +647,14 @@ Sets the font ascent (number of pixels above the baseline). + + + + + + Sets extra baseline offset (as a fraction of font height). + + diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 9555718b262a..5beb5797dbdd 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -105,6 +105,12 @@ + + + + + + @@ -552,6 +558,13 @@ + + + + + + + diff --git a/misc/extension_api_validation/4.1-stable_4.2-stable.expected b/misc/extension_api_validation/4.1-stable_4.2-stable.expected index d51523bd38df..11cf8531c639 100644 --- a/misc/extension_api_validation/4.1-stable_4.2-stable.expected +++ b/misc/extension_api_validation/4.1-stable_4.2-stable.expected @@ -91,7 +91,7 @@ Added optional argument. Compatibility methods registered. GH-80954 -------- -Validate extension JSON: Error: Field 'classes/Font/methods/find_variation/arguments': size changed value in new API, from 4 to 8. +Validate extension JSON: Error: Field 'classes/Font/methods/find_variation/arguments': size changed value in new API, from 4 to 9. Added optional arguments. Compatibility method registered. diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 2c18b4394816..f6e3661c7b7f 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -66,3 +66,10 @@ GH-86158 Validate extension JSON: Error: Field 'classes/GraphEdit/methods/get_connection_line': is_const changed value in new API, from false to true. get_connection_line was made const. + + +GH-87668 +-------- +Validate extension JSON: Error: Field 'classes/Font/methods/find_variation/arguments': size changed value in new API, from 8 to 9. + +Added optional "baseline_offset" argument. Compatibility method registered. diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 19f302423cdf..b4028492c76b 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2409,6 +2409,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); @@ -5750,6 +5781,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; @@ -5964,6 +6000,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. diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 0b5fe47b8ba9..6f53ecfa8f22 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -297,6 +297,7 @@ class TextServerAdvanced : public TextServerExtension { struct FontAdvancedLinkedVariation { RID base_font; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; }; struct FontAdvanced { @@ -324,6 +325,7 @@ class TextServerAdvanced : public TextServerExtension { int weight = 400; int stretch = 100; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; HashMap cache; @@ -574,9 +576,10 @@ class TextServerAdvanced : public TextServerExtension { double embolden = 0.0; Transform2D transform; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; bool operator==(const SystemFontKey &p_b) const { - return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]); + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); } SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerAdvanced *p_fb) { @@ -601,6 +604,7 @@ class TextServerAdvanced : public TextServerExtension { extra_spacing[SPACING_BOTTOM] = p_fb->_font_get_spacing(p_font, SPACING_BOTTOM); extra_spacing[SPACING_SPACE] = p_fb->_font_get_spacing(p_font, SPACING_SPACE); extra_spacing[SPACING_GLYPH] = p_fb->_font_get_spacing(p_font, SPACING_GLYPH); + baseline_offset = p_fb->_font_get_baseline_offset(p_font); } }; @@ -633,7 +637,7 @@ class TextServerAdvanced : public TextServerExtension { hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_BOTTOM], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_SPACE], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_GLYPH], hash); - + hash = hash_murmur3_one_double(p_a.baseline_offset, hash); return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12), hash)); } }; @@ -781,6 +785,9 @@ public: MODBIND3(font_set_spacing, const RID &, SpacingType, int64_t); MODBIND2RC(int64_t, font_get_spacing, const RID &, SpacingType); + MODBIND2(font_set_baseline_offset, const RID &, float); + MODBIND1RC(float, font_get_baseline_offset, const RID &); + MODBIND2(font_set_transform, const RID &, const Transform2D &); MODBIND1RC(Transform2D, font_get_transform, const RID &); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 0b486b7d7bc3..d9689f0441ce 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -1403,6 +1403,37 @@ int64_t TextServerFallback::_font_get_spacing(const RID &p_font_rid, SpacingType } } +void TextServerFallback::_font_set_baseline_offset(const RID &p_font_rid, float p_baseline_offset) { + FontFallbackLinkedVariation *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 { + FontFallback *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 TextServerFallback::_font_get_baseline_offset(const RID &p_font_rid) const { + FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid); + if (fdv) { + return fdv->baseline_offset; + } else { + FontFallback *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 TextServerFallback::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { FontFallback *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -4105,12 +4136,12 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x; gl.x_off = 0; - gl.y_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)); sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP)); sd->descent = MAX(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, 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.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); 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)); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 2bb3724858be..74534174b198 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -248,6 +248,7 @@ class TextServerFallback : public TextServerExtension { struct FontFallbackLinkedVariation { RID base_font; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; }; struct FontFallback { @@ -275,6 +276,7 @@ class TextServerFallback : public TextServerExtension { int weight = 400; int stretch = 100; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; HashMap cache; @@ -490,9 +492,10 @@ class TextServerFallback : public TextServerExtension { double embolden = 0.0; Transform2D transform; int extra_spacing[4] = { 0, 0, 0, 0 }; + float baseline_offset = 0.0; bool operator==(const SystemFontKey &p_b) const { - return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]); + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); } SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerFallback *p_fb) { @@ -517,6 +520,7 @@ class TextServerFallback : public TextServerExtension { extra_spacing[SPACING_BOTTOM] = p_fb->_font_get_spacing(p_font, SPACING_BOTTOM); extra_spacing[SPACING_SPACE] = p_fb->_font_get_spacing(p_font, SPACING_SPACE); extra_spacing[SPACING_GLYPH] = p_fb->_font_get_spacing(p_font, SPACING_GLYPH); + baseline_offset = p_fb->_font_get_baseline_offset(p_font); } }; @@ -549,6 +553,7 @@ class TextServerFallback : public TextServerExtension { hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_BOTTOM], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_SPACE], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_GLYPH], hash); + hash = hash_murmur3_one_double(p_a.baseline_offset, hash); return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12), hash)); } }; @@ -648,6 +653,9 @@ public: MODBIND3(font_set_spacing, const RID &, SpacingType, int64_t); MODBIND2RC(int64_t, font_get_spacing, const RID &, SpacingType); + MODBIND2(font_set_baseline_offset, const RID &, float); + MODBIND1RC(float, font_get_baseline_offset, const RID &); + MODBIND2(font_set_transform, const RID &, const Transform2D &); MODBIND1RC(Transform2D, font_get_transform, const RID &); diff --git a/scene/resources/font.compat.inc b/scene/resources/font.compat.inc index bf504325564d..23fdee229d6c 100644 --- a/scene/resources/font.compat.inc +++ b/scene/resources/font.compat.inc @@ -31,11 +31,16 @@ #ifndef DISABLE_DEPRECATED RID Font::_find_variation_compat_80954(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform) const { - return find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, 0, 0, 0, 0); + return find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, 0, 0, 0, 0, 0.0); +} + +RID Font::_find_variation_compat_87668(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const { + return find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph, 0.0); } void Font::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform"), &Font::_find_variation_compat_80954, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D())); + ClassDB::bind_compatibility_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform", "spacing_top", "spacing_bottom", "spacing_space", "spacing_glyph"), &Font::_find_variation_compat_87668, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()), DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0)); } #endif diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 60c38160207b..d0ad664c8891 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -51,7 +51,7 @@ void Font::_bind_methods() { ClassDB::bind_method(D_METHOD("get_fallbacks"), &Font::get_fallbacks); // Output. - ClassDB::bind_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform", "spacing_top", "spacing_bottom", "spacing_space", "spacing_glyph"), &Font::find_variation, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()), DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform", "spacing_top", "spacing_bottom", "spacing_space", "spacing_glyph", "baseline_offset"), &Font::find_variation, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()), DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids); // Font metrics. @@ -928,6 +928,9 @@ void FontFile::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extra_spacing", "cache_index", "spacing", "value"), &FontFile::set_extra_spacing); ClassDB::bind_method(D_METHOD("get_extra_spacing", "cache_index", "spacing"), &FontFile::get_extra_spacing); + ClassDB::bind_method(D_METHOD("set_extra_baseline_offset", "cache_index", "baseline_offset"), &FontFile::set_extra_baseline_offset); + ClassDB::bind_method(D_METHOD("get_extra_baseline_offset", "cache_index"), &FontFile::get_extra_baseline_offset); + ClassDB::bind_method(D_METHOD("set_face_index", "cache_index", "face_index"), &FontFile::set_face_index); ClassDB::bind_method(D_METHOD("get_face_index", "cache_index"), &FontFile::get_face_index); @@ -1151,6 +1154,9 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) { } else if (tokens.size() == 3 && tokens[2] == "spacing_glyph") { set_extra_spacing(cache_index, TextServer::SPACING_GLYPH, p_value); return true; + } else if (tokens.size() == 3 && tokens[2] == "baseline_offset") { + set_extra_baseline_offset(cache_index, p_value); + return true; } if (tokens.size() >= 5) { Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int()); @@ -1242,6 +1248,9 @@ bool FontFile::_get(const StringName &p_name, Variant &r_ret) const { } else if (tokens.size() == 3 && tokens[2] == "spacing_glyph") { r_ret = get_extra_spacing(cache_index, TextServer::SPACING_GLYPH); return true; + } else if (tokens.size() == 3 && tokens[2] == "baseline_offset") { + r_ret = get_extra_baseline_offset(cache_index); + return true; } if (tokens.size() >= 5) { Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int()); @@ -1317,6 +1326,7 @@ void FontFile::_get_property_list(List *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_bottom", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_glyph", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + "baseline_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); for (int j = 0; j < sizes.size(); j++) { Vector2i sz = sizes[j]; @@ -2240,7 +2250,7 @@ real_t FontFile::get_oversampling() const { return oversampling; } -RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const { +RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph, float p_baseline_offset) const { // Find existing variation cache. const Dictionary &supported_coords = get_supported_variation_list(); int make_linked_from = -1; @@ -2256,6 +2266,7 @@ RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_fa match_linked = match_linked && (TS->font_get_spacing(cache[i], TextServer::SPACING_BOTTOM) == p_spacing_bottom); match_linked = match_linked && (TS->font_get_spacing(cache[i], TextServer::SPACING_SPACE) == p_spacing_space); match_linked = match_linked && (TS->font_get_spacing(cache[i], TextServer::SPACING_GLYPH) == p_spacing_glyph); + match_linked = match_linked && (TS->font_get_baseline_offset(cache[i]) == p_baseline_offset); for (const Variant *V = supported_coords.next(nullptr); V && match; V = supported_coords.next(V)) { const Vector3 &def = supported_coords[*V]; @@ -2299,6 +2310,7 @@ RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_fa TS->font_set_spacing(cache[idx], TextServer::SPACING_BOTTOM, p_spacing_bottom); TS->font_set_spacing(cache[idx], TextServer::SPACING_SPACE, p_spacing_space); TS->font_set_spacing(cache[idx], TextServer::SPACING_GLYPH, p_spacing_glyph); + TS->font_set_baseline_offset(cache[idx], p_baseline_offset); } else { _ensure_rid(idx); TS->font_set_variation_coordinates(cache[idx], p_variation_coordinates); @@ -2309,6 +2321,7 @@ RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_fa TS->font_set_spacing(cache[idx], TextServer::SPACING_BOTTOM, p_spacing_bottom); TS->font_set_spacing(cache[idx], TextServer::SPACING_SPACE, p_spacing_space); TS->font_set_spacing(cache[idx], TextServer::SPACING_GLYPH, p_spacing_glyph); + TS->font_set_baseline_offset(cache[idx], p_baseline_offset); } return cache[idx]; } @@ -2403,6 +2416,18 @@ int64_t FontFile::get_extra_spacing(int p_cache_index, TextServer::SpacingType p return TS->font_get_spacing(cache[p_cache_index], p_spacing); } +float FontFile::get_extra_baseline_offset(int p_cache_index) const { + ERR_FAIL_COND_V(p_cache_index < 0, 0); + _ensure_rid(p_cache_index); + return TS->font_get_baseline_offset(cache[p_cache_index]); +} + +void FontFile::set_extra_baseline_offset(int p_cache_index, float p_baseline_offset) { + ERR_FAIL_COND(p_cache_index < 0); + _ensure_rid(p_cache_index); + TS->font_set_baseline_offset(cache[p_cache_index], p_baseline_offset); +} + void FontFile::set_face_index(int p_cache_index, int64_t p_index) { ERR_FAIL_COND(p_cache_index < 0); ERR_FAIL_COND(p_index < 0); @@ -2731,6 +2756,9 @@ void FontVariation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &FontVariation::set_spacing); + ClassDB::bind_method(D_METHOD("set_baseline_offset", "baseline_offset"), &FontVariation::set_baseline_offset); + ClassDB::bind_method(D_METHOD("get_baseline_offset"), &FontVariation::get_baseline_offset); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_base_font", "get_base_font"); ADD_GROUP("Variation", "variation_"); @@ -2747,6 +2775,9 @@ void FontVariation::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_space", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_SPACE); ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP); ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM); + + ADD_GROUP("Baseline", "baseline_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "baseline_offset", PROPERTY_HINT_RANGE, "-2,2,0.005"), "set_baseline_offset", "get_baseline_offset"); } void FontVariation::_update_rids() const { @@ -2786,6 +2817,7 @@ void FontVariation::reset_state() { for (int i = 0; i < TextServer::SPACING_MAX; i++) { extra_spacing[i] = 0; } + baseline_offset = 0.0; Font::reset_state(); } @@ -2925,10 +2957,21 @@ int FontVariation::get_spacing(TextServer::SpacingType p_spacing) const { return extra_spacing[p_spacing]; } -RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const { +void FontVariation::set_baseline_offset(float p_baseline_offset) { + if (baseline_offset != p_baseline_offset) { + baseline_offset = p_baseline_offset; + _invalidate_rids(); + } +} + +float FontVariation::get_baseline_offset() const { + return baseline_offset; +} + +RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph, float p_baseline_offset) const { Ref f = _get_base_font_or_default(); if (f.is_valid()) { - return f->find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph); + return f->find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph, p_baseline_offset); } return RID(); } @@ -2936,7 +2979,7 @@ RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int RID FontVariation::_get_rid() const { Ref f = _get_base_font_or_default(); if (f.is_valid()) { - return f->find_variation(variation.opentype, variation.face_index, variation.embolden, variation.transform, extra_spacing[TextServer::SPACING_TOP], extra_spacing[TextServer::SPACING_BOTTOM], extra_spacing[TextServer::SPACING_SPACE], extra_spacing[TextServer::SPACING_GLYPH]); + return f->find_variation(variation.opentype, variation.face_index, variation.embolden, variation.transform, extra_spacing[TextServer::SPACING_TOP], extra_spacing[TextServer::SPACING_BOTTOM], extra_spacing[TextServer::SPACING_SPACE], extra_spacing[TextServer::SPACING_GLYPH], baseline_offset); } return RID(); } @@ -3396,7 +3439,7 @@ int SystemFont::get_spacing(TextServer::SpacingType p_spacing) const { } } -RID SystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const { +RID SystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph, float p_baseline_offset) const { Ref f = _get_base_font_or_default(); if (f.is_valid()) { Dictionary var = p_variation_coordinates; @@ -3412,9 +3455,9 @@ RID SystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_ if (!face_indeces.is_empty()) { int face_index = CLAMP(p_face_index, 0, face_indeces.size() - 1); - return f->find_variation(var, face_indeces[face_index], p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph); + return f->find_variation(var, face_indeces[face_index], p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph, p_baseline_offset); } else { - return f->find_variation(var, 0, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph); + return f->find_variation(var, 0, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph, p_baseline_offset); } } return RID(); diff --git a/scene/resources/font.h b/scene/resources/font.h index 77bff8e8b0f0..1cce46a3e35b 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -105,6 +105,7 @@ protected: #ifndef DISABLE_DEPRECATED RID _find_variation_compat_80954(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D()) const; + RID _find_variation_compat_87668(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0) const; static void _bind_compatibility_methods(); #endif @@ -118,8 +119,8 @@ public: virtual TypedArray get_fallbacks() const; // Output. - virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0) const { return RID(); }; - virtual RID _get_rid() const { return RID(); }; + virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0, float p_baseline_offset = 0.0) const { return RID(); } + virtual RID _get_rid() const { return RID(); } virtual TypedArray get_rids() const; // Font metrics. @@ -136,7 +137,7 @@ public: virtual int get_font_weight() const; virtual int get_font_stretch() const; - virtual int get_spacing(TextServer::SpacingType p_spacing) const { return 0; }; + virtual int get_spacing(TextServer::SpacingType p_spacing) const { return 0; } virtual Dictionary get_opentype_features() const; // Drawing string. @@ -277,7 +278,7 @@ public: virtual real_t get_oversampling() const; // Cache. - virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0) const override; + virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0, float p_baseline_offset = 0.0) const override; virtual RID _get_rid() const override; virtual int get_cache_count() const; @@ -300,6 +301,9 @@ public: virtual void set_extra_spacing(int p_cache_index, TextServer::SpacingType p_spacing, int64_t p_value); virtual int64_t get_extra_spacing(int p_cache_index, TextServer::SpacingType p_spacing) const; + virtual float get_extra_baseline_offset(int p_cache_index) const; + virtual void set_extra_baseline_offset(int p_cache_index, float p_baseline_offset); + virtual void set_face_index(int p_cache_index, int64_t p_index); virtual int64_t get_face_index(int p_cache_index) const; @@ -400,6 +404,7 @@ class FontVariation : public Font { Variation variation; Dictionary opentype_features; int extra_spacing[TextServer::SPACING_MAX]; + float baseline_offset = 0.0; protected: static void _bind_methods(); @@ -431,8 +436,11 @@ public: virtual void set_spacing(TextServer::SpacingType p_spacing, int p_value); virtual int get_spacing(TextServer::SpacingType p_spacing) const override; + virtual float get_baseline_offset() const; + virtual void set_baseline_offset(float p_baseline_offset); + // Output. - virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0) const override; + virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0, float p_baseline_offset = 0.0) const override; virtual RID _get_rid() const override; FontVariation(); @@ -525,7 +533,7 @@ public: virtual int get_spacing(TextServer::SpacingType p_spacing) const override; - virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0) const override; + virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0, float p_baseline_offset = 0.0) const override; virtual RID _get_rid() const override; int64_t get_face_count() const override; diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 28c69967ac2b..7512955fb3b7 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -138,9 +138,6 @@ public: float get_line_underline_position(int p_line) const; float get_line_underline_thickness(int p_line) const; - int get_spacing_top() const; - int get_spacing_bottom() const; - Size2 get_dropcap_size() const; int get_dropcap_lines() const; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index ec622cdb1c71..d5080e586d18 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -116,6 +116,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_spacing, "font_rid", "spacing", "value"); GDVIRTUAL_BIND(_font_get_spacing, "font_rid", "spacing"); + GDVIRTUAL_BIND(_font_set_baseline_offset, "font_rid", "baseline_offset"); + GDVIRTUAL_BIND(_font_get_baseline_offset, "font_rid"); + GDVIRTUAL_BIND(_font_set_transform, "font_rid", "transform"); GDVIRTUAL_BIND(_font_get_transform, "font_rid"); @@ -635,6 +638,16 @@ int64_t TextServerExtension::font_get_spacing(const RID &p_font_rid, SpacingType return ret; } +void TextServerExtension::font_set_baseline_offset(const RID &p_font_rid, float p_baseline_offset) { + GDVIRTUAL_CALL(_font_set_baseline_offset, p_font_rid, p_baseline_offset); +} + +float TextServerExtension::font_get_baseline_offset(const RID &p_font_rid) const { + float ret = 0.0; + GDVIRTUAL_CALL(_font_get_baseline_offset, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { GDVIRTUAL_CALL(_font_set_transform, p_font_rid, p_transform); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index d0d7ee31adae..4f9ea55d33db 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -173,6 +173,11 @@ public: GDVIRTUAL3(_font_set_spacing, const RID &, SpacingType, int64_t); GDVIRTUAL2RC(int64_t, _font_get_spacing, const RID &, SpacingType); + virtual void font_set_baseline_offset(const RID &p_font_rid, float p_baseline_offset) override; + virtual float font_get_baseline_offset(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_baseline_offset, const RID &, float); + GDVIRTUAL1RC(float, _font_get_baseline_offset, const RID &); + virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; virtual Transform2D font_get_transform(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_transform, RID, Transform2D); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index e05d55787a63..cd06027f9f6a 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -270,6 +270,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_spacing", "font_rid", "spacing", "value"), &TextServer::font_set_spacing); ClassDB::bind_method(D_METHOD("font_get_spacing", "font_rid", "spacing"), &TextServer::font_get_spacing); + ClassDB::bind_method(D_METHOD("font_set_baseline_offset", "font_rid", "baseline_offset"), &TextServer::font_set_baseline_offset); + ClassDB::bind_method(D_METHOD("font_get_baseline_offset", "font_rid"), &TextServer::font_get_baseline_offset); + ClassDB::bind_method(D_METHOD("font_set_transform", "font_rid", "transform"), &TextServer::font_set_transform); ClassDB::bind_method(D_METHOD("font_get_transform", "font_rid"), &TextServer::font_get_transform); diff --git a/servers/text_server.h b/servers/text_server.h index 70d2129b51ae..e48b1bf890ca 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -308,6 +308,9 @@ public: virtual void font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) = 0; virtual int64_t font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const = 0; + virtual void font_set_baseline_offset(const RID &p_font_rid, float p_baseline_offset) = 0; + virtual float font_get_baseline_offset(const RID &p_font_rid) const = 0; + virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) = 0; virtual Transform2D font_get_transform(const RID &p_font_rid) const = 0;