summaryrefslogtreecommitdiff
path: root/modules/text_server_adv
diff options
context:
space:
mode:
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r--modules/text_server_adv/SCsub13
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp585
-rw-r--r--modules/text_server_adv/bitmap_font_adv.h123
-rw-r--r--modules/text_server_adv/config.py10
-rw-r--r--modules/text_server_adv/doc_classes/TextServerAdvanced.xml10
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp1030
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h195
-rw-r--r--modules/text_server_adv/font_adv.h115
-rw-r--r--modules/text_server_adv/register_types.cpp7
-rw-r--r--modules/text_server_adv/script_iterator.cpp20
-rw-r--r--modules/text_server_adv/script_iterator.h2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp3739
-rw-r--r--modules/text_server_adv/text_server_adv.h378
13 files changed, 3222 insertions, 3005 deletions
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index d06c5c2f14..7cd4db6f67 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -15,7 +15,7 @@ def make_icu_data(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
- g.write("/* License & terms of use: http://www.unicode.org/copyright.html */\n")
+ g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
g.write("#ifndef _ICU_DATA_H\n")
g.write("#define _ICU_DATA_H\n")
g.write('#include "unicode/utypes.h"\n')
@@ -38,7 +38,8 @@ def make_icu_data(target, source, env):
# Thirdparty source files
thirdparty_obj = []
-freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"])
+freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"], True)
+msdngen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True)
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
@@ -63,6 +64,7 @@ if env["builtin_harfbuzz"]:
#'src/hb-gobject-structs.cc',
"src/hb-icu.cc",
"src/hb-map.cc",
+ "src/hb-ms-feature-ranges.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
"src/hb-ot-cff2-table.cc",
@@ -509,6 +511,13 @@ env_text_server_adv.Append(
]
)
+if msdngen_enabled:
+ env_text_server_adv.Append(
+ CPPPATH=[
+ "#thirdparty/msdfgen",
+ ]
+ )
+
if freetype_enabled:
env_text_server_adv.Append(
CPPPATH=[
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
deleted file mode 100644
index df7b42eac6..0000000000
--- a/modules/text_server_adv/bitmap_font_adv.cpp
+++ /dev/null
@@ -1,585 +0,0 @@
-/*************************************************************************/
-/* bitmap_font_adv.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "bitmap_font_adv.h"
-
-/*************************************************************************/
-/* hb_bmp_font_t HarfBuzz Bitmap font interface */
-/*************************************************************************/
-
-struct hb_bmp_font_t {
- BitmapFontDataAdvanced *face = nullptr;
- float font_size = 0.0;
- bool unref = false; /* Whether to destroy bm_face when done. */
-};
-
-static hb_bmp_font_t *_hb_bmp_font_create(BitmapFontDataAdvanced *p_face, float p_font_size, bool p_unref) {
- hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(calloc(1, sizeof(hb_bmp_font_t)));
-
- if (!bm_font) {
- return nullptr;
- }
-
- bm_font->face = p_face;
- bm_font->font_size = p_font_size;
- bm_font->unref = p_unref;
-
- return bm_font;
-}
-
-static void _hb_bmp_font_destroy(void *data) {
- hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(data);
- free(bm_font);
-}
-
-static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return false;
- }
-
- if (!bm_font->face->has_char(unicode)) {
- if (bm_font->face->has_char(0xF000u + unicode)) {
- *glyph = 0xF000u + unicode;
- return true;
- } else {
- return false;
- }
- }
-
- *glyph = unicode;
- return true;
-}
-
-static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return 0;
- }
-
- if (!bm_font->face->has_char(glyph)) {
- return 0;
- }
-
- return bm_font->face->get_advance(glyph, bm_font->font_size).x * 64;
-}
-
-static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return 0;
- }
-
- if (!bm_font->face->has_char(glyph)) {
- return 0;
- }
-
- return -bm_font->face->get_advance(glyph, bm_font->font_size).y * 64;
-}
-
-static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *font, void *font_data, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return 0;
- }
-
- if (!bm_font->face->has_char(left_glyph)) {
- return 0;
- }
-
- if (!bm_font->face->has_char(right_glyph)) {
- return 0;
- }
-
- return bm_font->face->get_kerning(left_glyph, right_glyph, bm_font->font_size).x * 64;
-}
-
-static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return false;
- }
-
- if (!bm_font->face->has_char(glyph)) {
- return false;
- }
-
- *x = bm_font->face->get_advance(glyph, bm_font->font_size).x * 32;
- *y = bm_font->face->get_ascent(bm_font->font_size) * 64;
-
- return true;
-}
-
-static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return false;
- }
-
- if (!bm_font->face->has_char(glyph)) {
- return false;
- }
-
- extents->x_bearing = 0;
- extents->y_bearing = 0;
- extents->width = bm_font->face->get_size(glyph, bm_font->font_size).x * 64;
- extents->height = bm_font->face->get_size(glyph, bm_font->font_size).y * 64;
-
- return true;
-}
-
-static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_font_extents_t *metrics, void *user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(font_data);
-
- if (!bm_font->face) {
- return false;
- }
-
- metrics->ascender = bm_font->face->get_ascent(bm_font->font_size);
- metrics->descender = bm_font->face->get_descent(bm_font->font_size);
- metrics->line_gap = 0;
-
- return true;
-}
-
-static hb_font_funcs_t *funcs = nullptr;
-void hb_bmp_create_font_funcs() {
- funcs = hb_font_funcs_create();
-
- hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
- //hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr);
- hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr);
- //hb_font_funcs_set_variation_glyph_func (funcs, hb_bmp_get_variation_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr);
- //hb_font_funcs_set_glyph_h_origin_func(funcs, hb_bmp_get_glyph_h_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_bmp_get_glyph_v_kerning, nullptr, nullptr);
- hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr);
- //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_bmp_get_glyph_contour_point, nullptr, nullptr);
- //hb_font_funcs_set_glyph_name_func (funcs, hb_bmp_get_glyph_name, nullptr, nullptr);
- //hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr);
-
- hb_font_funcs_make_immutable(funcs);
-}
-
-void hb_bmp_free_font_funcs() {
- if (funcs != nullptr) {
- hb_font_funcs_destroy(funcs);
- funcs = nullptr;
- }
-}
-
-static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) {
- hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
-}
-
-hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) {
- hb_font_t *font;
- hb_face_t *face = hb_face_create(nullptr, 0);
-
- font = hb_font_create(face);
- hb_face_destroy(face);
- _hb_bmp_font_set_funcs(font, p_face, p_size, false);
- return font;
-}
-
-/*************************************************************************/
-/* BitmapFontDataAdvanced */
-/*************************************************************************/
-
-Error BitmapFontDataAdvanced::load_from_file(const String &p_filename, int p_base_size) {
- _THREAD_SAFE_METHOD_
- //fnt format used by angelcode bmfont
- //http://www.angelcode.com/products/bmfont/
-
- FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_FILE_NOT_FOUND, "Can't open font: " + p_filename + ".");
-
- while (true) {
- String line = f->get_line();
-
- int delimiter = line.find(" ");
- String type = line.substr(0, delimiter);
- int pos = delimiter + 1;
- Map<String, String> keys;
-
- while (pos < line.size() && line[pos] == ' ') {
- pos++;
- }
-
- while (pos < line.size()) {
- int eq = line.find("=", pos);
- if (eq == -1) {
- break;
- }
- String key = line.substr(pos, eq - pos);
- int end = -1;
- String value;
- if (line[eq + 1] == '"') {
- end = line.find("\"", eq + 2);
- if (end == -1) {
- break;
- }
- value = line.substr(eq + 2, end - 1 - eq - 1);
- pos = end + 1;
- } else {
- end = line.find(" ", eq + 1);
- if (end == -1) {
- end = line.size();
- }
- value = line.substr(eq + 1, end - eq);
- pos = end;
- }
-
- while (pos < line.size() && line[pos] == ' ') {
- pos++;
- }
-
- keys[key] = value;
- }
-
- if (type == "info") {
- if (keys.has("size")) {
- base_size = keys["size"].to_int();
- }
- } else if (type == "common") {
- if (keys.has("lineHeight")) {
- height = keys["lineHeight"].to_int();
- }
- if (keys.has("base")) {
- ascent = keys["base"].to_int();
- }
- } else if (type == "page") {
- if (keys.has("file")) {
- String base_dir = p_filename.get_base_dir();
- String file = base_dir.plus_file(keys["file"]);
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Texture2D> tex = ResourceLoader::load(file);
- if (tex.is_null()) {
- ERR_PRINT("Can't load font texture!");
- } else {
- ERR_FAIL_COND_V_MSG(tex.is_null(), ERR_FILE_CANT_READ, "It's not a reference to a valid Texture object.");
- textures.push_back(tex);
- }
- }
- }
- } else if (type == "char") {
- Character c;
- char32_t idx = 0;
- if (keys.has("id")) {
- idx = keys["id"].to_int();
- }
- if (keys.has("x")) {
- c.rect.position.x = keys["x"].to_int();
- }
- if (keys.has("y")) {
- c.rect.position.y = keys["y"].to_int();
- }
- if (keys.has("width")) {
- c.rect.size.width = keys["width"].to_int();
- }
- if (keys.has("height")) {
- c.rect.size.height = keys["height"].to_int();
- }
- if (keys.has("xoffset")) {
- c.align.x = keys["xoffset"].to_int();
- }
- if (keys.has("yoffset")) {
- c.align.y = keys["yoffset"].to_int();
- }
- if (keys.has("page")) {
- c.texture_idx = keys["page"].to_int();
- }
- if (keys.has("xadvance")) {
- c.advance.x = keys["xadvance"].to_int();
- }
- if (keys.has("yadvance")) {
- c.advance.x = keys["yadvance"].to_int();
- }
- if (c.advance.x < 0) {
- c.advance.x = c.rect.size.width + 1;
- }
- if (c.advance.y < 0) {
- c.advance.y = c.rect.size.height + 1;
- }
- char_map[idx] = c;
- } else if (type == "kerning") {
- KerningPairKey kpk;
- float k = 0.0;
- if (keys.has("first")) {
- kpk.A = keys["first"].to_int();
- }
- if (keys.has("second")) {
- kpk.B = keys["second"].to_int();
- }
- if (keys.has("amount")) {
- k = keys["amount"].to_int();
- }
- kerning_map[kpk] = k;
- }
-
- if (f->eof_reached()) {
- break;
- }
- }
- if (base_size == 0) {
- base_size = height;
- }
-
- if (hb_handle) {
- hb_font_destroy(hb_handle);
- }
- hb_handle = hb_bmp_font_create(this, base_size, nullptr);
- valid = true;
-
- memdelete(f);
- return OK;
-}
-
-Error BitmapFontDataAdvanced::bitmap_new(float p_height, float p_ascent, int p_base_size) {
- height = p_height;
- ascent = p_ascent;
-
- base_size = p_base_size;
- if (base_size == 0) {
- base_size = height;
- }
-
- char_map.clear();
- textures.clear();
- kerning_map.clear();
- if (hb_handle) {
- hb_font_destroy(hb_handle);
- }
- hb_handle = hb_bmp_font_create(this, base_size, nullptr);
- valid = true;
-
- return OK;
-}
-
-void BitmapFontDataAdvanced::bitmap_add_texture(const Ref<Texture> &p_texture) {
- ERR_FAIL_COND(!valid);
- ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object.");
-
- textures.push_back(p_texture);
-}
-
-void BitmapFontDataAdvanced::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
- ERR_FAIL_COND(!valid);
-
- Character chr;
- chr.rect = p_rect;
- chr.texture_idx = p_texture_idx;
- if (p_advance < 0) {
- chr.advance.x = chr.rect.size.x;
- } else {
- chr.advance.x = p_advance;
- }
- chr.align = p_align;
- char_map[p_char] = chr;
-}
-
-void BitmapFontDataAdvanced::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) {
- ERR_FAIL_COND(!valid);
-
- KerningPairKey kpk;
- kpk.A = p_A;
- kpk.B = p_B;
-
- if (p_kerning == 0 && kerning_map.has(kpk)) {
- kerning_map.erase(kpk);
- } else {
- kerning_map[kpk] = p_kerning;
- }
-}
-
-float BitmapFontDataAdvanced::get_height(int p_size) const {
- ERR_FAIL_COND_V(!valid, 0.f);
- return height * (float(p_size) / float(base_size));
-}
-
-float BitmapFontDataAdvanced::get_ascent(int p_size) const {
- ERR_FAIL_COND_V(!valid, 0.f);
- return ascent * (float(p_size) / float(base_size));
-}
-
-float BitmapFontDataAdvanced::get_descent(int p_size) const {
- ERR_FAIL_COND_V(!valid, 0.f);
- return (height - ascent) * (float(p_size) / float(base_size));
-}
-
-float BitmapFontDataAdvanced::get_underline_position(int p_size) const {
- ERR_FAIL_COND_V(!valid, 0.f);
- return 2 * (float(p_size) / float(base_size));
-}
-
-float BitmapFontDataAdvanced::get_underline_thickness(int p_size) const {
- ERR_FAIL_COND_V(!valid, 0.f);
- return 1 * (float(p_size) / float(base_size));
-}
-
-void BitmapFontDataAdvanced::set_distance_field_hint(bool p_distance_field) {
- distance_field_hint = p_distance_field;
-}
-
-bool BitmapFontDataAdvanced::get_distance_field_hint() const {
- return distance_field_hint;
-}
-
-float BitmapFontDataAdvanced::get_base_size() const {
- return base_size;
-}
-
-hb_font_t *BitmapFontDataAdvanced::get_hb_handle(int p_size) {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, nullptr);
- return hb_handle;
-}
-
-bool BitmapFontDataAdvanced::has_char(char32_t p_char) const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, false);
- return char_map.has(p_char);
-}
-
-String BitmapFontDataAdvanced::get_supported_chars() const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, String());
- String chars;
- const uint32_t *k = nullptr;
- while ((k = char_map.next(k))) {
- chars += char32_t(*k);
- }
- return chars;
-}
-
-Vector2 BitmapFontDataAdvanced::get_advance(uint32_t p_char, int p_size) const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, Vector2());
- const Character *c = char_map.getptr(p_char);
- ERR_FAIL_COND_V(c == nullptr, Vector2());
-
- return c->advance * (float(p_size) / float(base_size));
-}
-
-Vector2 BitmapFontDataAdvanced::get_align(uint32_t p_char, int p_size) const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, Vector2());
- const Character *c = char_map.getptr(p_char);
- ERR_FAIL_COND_V(c == nullptr, Vector2());
-
- return c->align * (float(p_size) / float(base_size));
-}
-
-Vector2 BitmapFontDataAdvanced::get_size(uint32_t p_char, int p_size) const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, Vector2());
- const Character *c = char_map.getptr(p_char);
- ERR_FAIL_COND_V(c == nullptr, Vector2());
-
- return c->rect.size * (float(p_size) / float(base_size));
-}
-
-float BitmapFontDataAdvanced::get_font_scale(int p_size) const {
- return float(p_size) / float(base_size);
-}
-
-Vector2 BitmapFontDataAdvanced::get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!valid, Vector2());
- KerningPairKey kpk;
- kpk.A = p_char;
- kpk.B = p_next;
-
- const Map<KerningPairKey, int>::Element *E = kerning_map.find(kpk);
- if (E) {
- return Vector2(-E->get() * (float(p_size) / float(base_size)), 0.f);
- } else {
- return Vector2();
- }
-}
-
-Vector2 BitmapFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- if (p_index == 0) {
- return Vector2();
- }
- ERR_FAIL_COND_V(!valid, Vector2());
- const Character *c = char_map.getptr(p_index);
-
- ERR_FAIL_COND_V(c == nullptr, Vector2());
- ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
- if (c->texture_idx != -1) {
- Point2i cpos = p_pos;
- cpos += (c->align + Vector2(0, -ascent)) * (float(p_size) / float(base_size));
- Size2i csize = c->rect.size * (float(p_size) / float(base_size));
- if (RenderingServer::get_singleton() != nullptr) {
- //if (distance_field_hint) { // Not implemented.
- // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, true);
- //}
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
- //if (distance_field_hint) {
- // RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, false);
- //}
- }
- }
-
- return c->advance * (float(p_size) / float(base_size));
-}
-
-Vector2 BitmapFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- if (p_index == 0) {
- return Vector2();
- }
- ERR_FAIL_COND_V(!valid, Vector2());
- const Character *c = char_map.getptr(p_index);
-
- ERR_FAIL_COND_V(c == nullptr, Vector2());
- ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
-
- // Not supported, return advance for compatibility.
-
- return c->advance * (float(p_size) / float(base_size));
-}
-
-BitmapFontDataAdvanced::~BitmapFontDataAdvanced() {
- if (hb_handle) {
- hb_font_destroy(hb_handle);
- }
-}
diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h
deleted file mode 100644
index 7b620021e1..0000000000
--- a/modules/text_server_adv/bitmap_font_adv.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*************************************************************************/
-/* bitmap_font_adv.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef BITMAP_FONT_ADV_H
-#define BITMAP_FONT_ADV_H
-
-#include "font_adv.h"
-
-void hb_bmp_create_font_funcs();
-void hb_bmp_free_font_funcs();
-
-struct BitmapFontDataAdvanced : public FontDataAdvanced {
- _THREAD_SAFE_CLASS_
-
-private:
- Vector<Ref<Texture2D>> textures;
-
- struct Character {
- int texture_idx = 0;
- Rect2 rect;
- Vector2 align;
- Vector2 advance = Vector2(-1, -1);
- };
-
- struct KerningPairKey {
- union {
- struct {
- uint32_t A, B;
- };
-
- uint64_t pair = 0;
- };
-
- _FORCE_INLINE_ bool operator<(const KerningPairKey &p_r) const { return pair < p_r.pair; }
- };
-
- HashMap<uint32_t, Character> char_map;
- Map<KerningPairKey, int> kerning_map;
- hb_font_t *hb_handle = nullptr;
-
- float height = 0.f;
- float ascent = 0.f;
- int base_size = 0;
- bool distance_field_hint = false;
-
-public:
- virtual void clear_cache() override{};
-
- virtual Error load_from_file(const String &p_filename, int p_base_size) override;
- virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) override;
-
- virtual void bitmap_add_texture(const Ref<Texture> &p_texture) override;
- virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
- virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) override;
-
- virtual float get_height(int p_size) const override;
- virtual float get_ascent(int p_size) const override;
- virtual float get_descent(int p_size) const override;
-
- virtual float get_underline_position(int p_size) const override;
- virtual float get_underline_thickness(int p_size) const override;
-
- virtual void set_antialiased(bool p_antialiased) override{};
- virtual bool get_antialiased() const override { return false; };
-
- virtual void set_hinting(TextServer::Hinting p_hinting) override{};
- virtual TextServer::Hinting get_hinting() const override { return TextServer::HINTING_NONE; };
-
- virtual void set_distance_field_hint(bool p_distance_field) override;
- virtual bool get_distance_field_hint() const override;
-
- virtual void set_force_autohinter(bool p_enabeld) override{};
- virtual bool get_force_autohinter() const override { return false; };
-
- virtual bool has_outline() const override { return false; };
- virtual float get_base_size() const override;
- virtual float get_font_scale(int p_size) const override;
-
- virtual hb_font_t *get_hb_handle(int p_size) override;
-
- virtual bool has_char(char32_t p_char) const override;
- virtual String get_supported_chars() const override;
-
- virtual Vector2 get_advance(uint32_t p_char, int p_size) const override;
- Vector2 get_align(uint32_t p_char, int p_size) const;
- Vector2 get_size(uint32_t p_char, int p_size) const;
- virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const override;
- virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const override { return (uint32_t)p_char; };
-
- virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
- virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
-
- virtual ~BitmapFontDataAdvanced();
-};
-
-#endif // BITMAP_FONT_ADV_H
diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py
index d22f9454ed..8c8df9b05e 100644
--- a/modules/text_server_adv/config.py
+++ b/modules/text_server_adv/config.py
@@ -4,3 +4,13 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "TextServerAdvanced",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
new file mode 100644
index 0000000000..eff4aa5fae
--- /dev/null
+++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerAdvanced" inherits="TextServer" version="4.0">
+ <brief_description>
+ Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features.
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
deleted file mode 100644
index 62eedebb59..0000000000
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ /dev/null
@@ -1,1030 +0,0 @@
-/*************************************************************************/
-/* dynamic_font_adv.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "dynamic_font_adv.h"
-
-#ifdef MODULE_FREETYPE_ENABLED
-
-#include FT_STROKER_H
-#include FT_ADVANCES_H
-#include FT_MULTIPLE_MASTERS_H
-
-DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
- ERR_FAIL_COND_V(!valid, nullptr);
- ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr);
- ERR_FAIL_COND_V(p_outline_size < 0 || p_outline_size > UINT16_MAX, nullptr);
-
- CacheID id;
- id.size = p_size;
- id.outline_size = p_outline_size;
-
- DataAtSize *fds = nullptr;
- Map<CacheID, DataAtSize *>::Element *E = nullptr;
- if (p_outline_size != 0) {
- E = size_cache_outline.find(id);
- } else {
- E = size_cache.find(id);
- }
-
- if (E != nullptr) {
- fds = E->get();
- } else {
- if (font_mem == nullptr && font_path != String()) {
- if (!font_mem_cache.is_empty()) {
- font_mem = font_mem_cache.ptr();
- font_mem_size = font_mem_cache.size();
- } else {
- FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
- if (!f) {
- ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
- }
-
- uint64_t len = f->get_length();
- font_mem_cache.resize(len);
- f->get_buffer(font_mem_cache.ptrw(), len);
- font_mem = font_mem_cache.ptr();
- font_mem_size = len;
- f->close();
- }
- }
-
- int error = 0;
- fds = memnew(DataAtSize);
- if (font_mem) {
- memset(&fds->stream, 0, sizeof(FT_StreamRec));
- fds->stream.base = (unsigned char *)font_mem;
- fds->stream.size = font_mem_size;
- fds->stream.pos = 0;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.memory_base = (unsigned char *)font_mem;
- fargs.memory_size = font_mem_size;
- fargs.flags = FT_OPEN_MEMORY;
- fargs.stream = &fds->stream;
- error = FT_Open_Face(library, &fargs, 0, &fds->face);
-
- } else {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "DynamicFont uninitialized.");
- }
-
- if (error == FT_Err_Unknown_File_Format) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Unknown font format.");
- } else if (error) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Error loading font.");
- }
-
- oversampling = TS->font_get_oversampling();
-
- if (FT_HAS_COLOR(fds->face) && fds->face->num_fixed_sizes > 0) {
- int best_match = 0;
- int diff = ABS(p_size - ((int64_t)fds->face->available_sizes[0].width));
- fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[0].width;
- for (int i = 1; i < fds->face->num_fixed_sizes; i++) {
- int ndiff = ABS(p_size - ((int64_t)fds->face->available_sizes[i].width));
- if (ndiff < diff) {
- best_match = i;
- diff = ndiff;
- fds->scale_color_font = float(p_size * oversampling) / fds->face->available_sizes[i].width;
- }
- }
- FT_Select_Size(fds->face, best_match);
- } else {
- FT_Set_Pixel_Sizes(fds->face, 0, p_size * oversampling);
- }
-
- fds->size = p_size;
- fds->ascent = (fds->face->size->metrics.ascender / 64.0) / oversampling * fds->scale_color_font;
- fds->descent = (-fds->face->size->metrics.descender / 64.0) / oversampling * fds->scale_color_font;
- fds->underline_position = (-FT_MulFix(fds->face->underline_position, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
- fds->underline_thickness = (FT_MulFix(fds->face->underline_thickness, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
-
- //Load os2 TTF table
- fds->os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fds->face, FT_SFNT_OS2);
-
- fds->hb_handle = hb_ft_font_create(fds->face, nullptr);
- if (fds->hb_handle == nullptr) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
- }
-
- if (p_outline_size != 0) {
- size_cache_outline[id] = fds;
- } else {
- size_cache[id] = fds;
- }
-
- // Write variations.
- if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
- FT_MM_Var *amaster;
-
- FT_Get_MM_Var(fds->face, &amaster);
-
- Vector<hb_variation_t> hb_vars;
- Vector<FT_Fixed> coords;
- coords.resize(amaster->num_axis);
-
- FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
-
- for (FT_UInt i = 0; i < amaster->num_axis; i++) {
- hb_variation_t var;
-
- // Reset to default.
- var.tag = amaster->axis[i].tag;
- var.value = (double)amaster->axis[i].def / 65536.f;
- coords.write[i] = amaster->axis[i].def;
-
- if (variations.has(var.tag)) {
- var.value = variations[var.tag];
- coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
- }
-
- hb_vars.push_back(var);
- }
-
- FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
- hb_font_set_variations(fds->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
-
- FT_Done_MM_Var(library, amaster);
- }
- }
- return fds;
-}
-
-Dictionary DynamicFontDataAdvanced::get_variation_list() const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- if (fds == nullptr) {
- return Dictionary();
- }
-
- Dictionary ret;
- // Read variations.
- if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
- FT_MM_Var *amaster;
-
- FT_Get_MM_Var(fds->face, &amaster);
-
- for (FT_UInt i = 0; i < amaster->num_axis; i++) {
- ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
- }
-
- FT_Done_MM_Var(library, amaster);
- }
- return ret;
-}
-
-void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
- _THREAD_SAFE_METHOD_
- int32_t tag = TS->name_to_tag(p_name);
- if (!variations.has(tag) || (variations[tag] != p_value)) {
- variations[tag] = p_value;
- clear_cache();
- }
-}
-
-double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
- _THREAD_SAFE_METHOD_
- int32_t tag = TS->name_to_tag(p_name);
- if (!variations.has(tag)) {
- return 0.f;
- }
- return variations[tag];
-}
-
-Dictionary DynamicFontDataAdvanced::get_feature_list() const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- if (fds == nullptr) {
- return Dictionary();
- }
-
- Dictionary out;
- // Read feature flags.
- unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
- if (count != 0) {
- hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
- hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags);
- for (unsigned int i = 0; i < count; i++) {
- out[feature_tags[i]] = 1;
- }
- memfree(feature_tags);
- }
- count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
- if (count != 0) {
- hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
- hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags);
- for (unsigned int i = 0; i < count; i++) {
- out[feature_tags[i]] = 1;
- }
- memfree(feature_tags);
- }
-
- return out;
-}
-
-DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
- TexturePosition ret;
- ret.index = -1;
-
- int mw = p_width;
- int mh = p_height;
-
- for (int i = 0; i < p_data->textures.size(); i++) {
- const CharTexture &ct = p_data->textures[i];
-
- if (RenderingServer::get_singleton() != nullptr) {
- if (ct.texture->get_format() != p_image_format) {
- continue;
- }
- }
-
- if (mw > ct.texture_size || mh > ct.texture_size) { //too big for this texture
- continue;
- }
-
- ret.y = 0x7FFFFFFF;
- ret.x = 0;
-
- for (int j = 0; j < ct.texture_size - mw; j++) {
- int max_y = 0;
-
- for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
- if (y > max_y) {
- max_y = y;
- }
- }
-
- if (max_y < ret.y) {
- ret.y = max_y;
- ret.x = j;
- }
- }
-
- if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size) {
- continue; //fail, could not fit it here
- }
-
- ret.index = i;
- break;
- }
-
- if (ret.index == -1) {
- //could not find texture to fit, create one
- ret.x = 0;
- ret.y = 0;
-
- int texsize = MAX(p_data->size * oversampling * 8, 256);
- if (mw > texsize) {
- texsize = mw; //special case, adapt to it?
- }
- if (mh > texsize) {
- texsize = mh; //special case, adapt to it?
- }
-
- texsize = next_power_of_2(texsize);
-
- texsize = MIN(texsize, 4096);
-
- CharTexture tex;
- tex.texture_size = texsize;
- tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha
-
- {
- //zero texture
- uint8_t *w = tex.imgdata.ptrw();
- ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.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) {
- for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8
- w[i + 0] = 255;
- w[i + 1] = 0;
- }
- } else if (p_color_size == 4) {
- for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8
- w[i + 0] = 255;
- w[i + 1] = 255;
- w[i + 2] = 255;
- w[i + 3] = 0;
- }
- } else {
- ERR_FAIL_V(ret);
- }
- }
- tex.offsets.resize(texsize);
- for (int i = 0; i < texsize; i++) { //zero offsets
- tex.offsets.write[i] = 0;
- }
-
- p_data->textures.push_back(tex);
- ret.index = p_data->textures.size() - 1;
- }
-
- return ret;
-}
-
-DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::Character::not_found() {
- Character ch;
- return ch;
-}
-
-DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::bitmap_to_character(DynamicFontDataAdvanced::DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) {
- int w = bitmap.width;
- int h = bitmap.rows;
-
- int mw = w + rect_margin * 2;
- int mh = h + rect_margin * 2;
-
- ERR_FAIL_COND_V(mw > 4096, Character::not_found());
- ERR_FAIL_COND_V(mh > 4096, Character::not_found());
-
- int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
- Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
-
- TexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh);
- ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found());
-
- //fit character in char texture
-
- CharTexture &tex = p_data->textures.write[tex_pos.index];
-
- {
- uint8_t *wr = tex.imgdata.ptrw();
-
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size;
- ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found());
- switch (bitmap.pixel_mode) {
- case FT_PIXEL_MODE_MONO: {
- int byte = i * bitmap.pitch + (j >> 3);
- int bit = 1 << (7 - (j % 8));
- wr[ofs + 0] = 255; //grayscale as 1
- wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
- } break;
- case FT_PIXEL_MODE_GRAY:
- wr[ofs + 0] = 255; //grayscale as 1
- wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
- break;
- case FT_PIXEL_MODE_BGRA: {
- int ofs_color = i * bitmap.pitch + (j << 2);
- wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
- wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
- wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
- wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
- } break;
- // TODO: FT_PIXEL_MODE_LCD
- default:
- ERR_FAIL_V_MSG(Character::not_found(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
- break;
- }
- }
- }
- }
-
- //blit to image and texture
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
-
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img); //update
- }
- }
- }
-
- // update height array
- for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets.write[k] = tex_pos.y + mh;
- }
-
- Character chr;
- chr.align = (Vector2(xofs, -yofs) * p_data->scale_color_font / oversampling).round();
- chr.advance = (advance * p_data->scale_color_font / oversampling).round();
- chr.texture_idx = tex_pos.index;
- chr.found = true;
-
- chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h);
- chr.rect = chr.rect_uv;
- chr.rect.position /= oversampling;
- chr.rect.size *= (p_data->scale_color_font / oversampling);
- return chr;
-}
-
-void DynamicFontDataAdvanced::update_glyph(int p_size, uint32_t p_index) {
- DataAtSize *fds = get_data_for_size(p_size, false);
- ERR_FAIL_COND(fds == nullptr);
-
- if (fds->glyph_map.has(p_index)) {
- return;
- }
-
- Character character = Character::not_found();
- FT_GlyphSlot slot = fds->face->glyph;
-
- if (p_index == 0) {
- fds->glyph_map[p_index] = character;
- return;
- }
-
- int ft_hinting;
- switch (hinting) {
- case TextServer::HINTING_NONE:
- ft_hinting = FT_LOAD_NO_HINTING;
- break;
- case TextServer::HINTING_LIGHT:
- ft_hinting = FT_LOAD_TARGET_LIGHT;
- break;
- default:
- ft_hinting = FT_LOAD_TARGET_NORMAL;
- break;
- }
-
- FT_Fixed v, h;
- FT_Get_Advance(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting, &h);
- FT_Get_Advance(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting | FT_LOAD_VERTICAL_LAYOUT, &v);
-
- int error = FT_Load_Glyph(fds->face, p_index, FT_HAS_COLOR(fds->face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting);
- if (error) {
- fds->glyph_map[p_index] = character;
- return;
- }
-
- error = FT_Render_Glyph(fds->face->glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
- if (!error) {
- character = bitmap_to_character(fds, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
- }
-
- fds->glyph_map[p_index] = character;
-}
-
-void DynamicFontDataAdvanced::update_glyph_outline(int p_size, int p_outline_size, uint32_t p_index) {
- DataAtSize *fds = get_data_for_size(p_size, p_outline_size);
- ERR_FAIL_COND(fds == nullptr);
-
- if (fds->glyph_map.has(p_index)) {
- return;
- }
-
- Character character = Character::not_found();
- if (p_index == 0) {
- fds->glyph_map[p_index] = character;
- return;
- }
-
- int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- if (error) {
- fds->glyph_map[p_index] = character;
- return;
- }
-
- FT_Stroker stroker;
- if (FT_Stroker_New(library, &stroker) != 0) {
- fds->glyph_map[p_index] = character;
- return;
- }
-
- FT_Stroker_Set(stroker, (int)(p_outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
- FT_Glyph glyph;
- FT_BitmapGlyph glyph_bitmap;
-
- if (FT_Get_Glyph(fds->face->glyph, &glyph) != 0) {
- goto cleanup_stroker;
- }
- if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
- goto cleanup_glyph;
- }
- if (FT_Glyph_To_Bitmap(&glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
- goto cleanup_glyph;
- }
-
- glyph_bitmap = (FT_BitmapGlyph)glyph;
- character = bitmap_to_character(fds, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
-
-cleanup_glyph:
- FT_Done_Glyph(glyph);
-cleanup_stroker:
- FT_Stroker_Done(stroker);
-
- fds->glyph_map[p_index] = character;
-}
-
-void DynamicFontDataAdvanced::clear_cache() {
- _THREAD_SAFE_METHOD_
- for (Map<CacheID, DataAtSize *>::Element *E = size_cache.front(); E; E = E->next()) {
- memdelete(E->get());
- }
- size_cache.clear();
- for (Map<CacheID, DataAtSize *>::Element *E = size_cache_outline.front(); E; E = E->next()) {
- memdelete(E->get());
- }
- size_cache_outline.clear();
-}
-
-Error DynamicFontDataAdvanced::load_from_file(const String &p_filename, int p_base_size) {
- _THREAD_SAFE_METHOD_
- if (library == nullptr) {
- int error = FT_Init_FreeType(&library);
- ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
- }
- clear_cache();
-
- font_path = p_filename;
- base_size = p_base_size;
-
- valid = true;
- DataAtSize *fds = get_data_for_size(base_size); // load base size.
- if (fds == nullptr) {
- valid = false;
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
-
- return OK;
-}
-
-Error DynamicFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
- _THREAD_SAFE_METHOD_
- if (library == nullptr) {
- int error = FT_Init_FreeType(&library);
- ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
- }
- clear_cache();
-
- font_mem = p_data;
- font_mem_size = p_size;
- base_size = p_base_size;
-
- valid = true;
- DataAtSize *fds = get_data_for_size(base_size); // load base size.
- if (fds == nullptr) {
- valid = false;
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
-
- return OK;
-}
-
-float DynamicFontDataAdvanced::get_height(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 0.f);
- return fds->ascent + fds->descent;
-}
-
-float DynamicFontDataAdvanced::get_ascent(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 0.f);
- return fds->ascent;
-}
-
-float DynamicFontDataAdvanced::get_descent(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 0.f);
- return fds->descent;
-}
-
-float DynamicFontDataAdvanced::get_underline_position(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 0.f);
- return fds->underline_position;
-}
-
-float DynamicFontDataAdvanced::get_underline_thickness(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 0.f);
- return fds->underline_thickness;
-}
-
-bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- ERR_FAIL_COND_V(fds == nullptr, false);
-
- unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
- if (count != 0) {
- hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
- hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags);
- for (unsigned int i = 0; i < count; i++) {
- if (p_script == script_tags[i]) {
- memfree(script_tags);
- return true;
- }
- }
- memfree(script_tags);
- }
- count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
- if (count != 0) {
- hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
- hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags);
- for (unsigned int i = 0; i < count; i++) {
- if (p_script == script_tags[i]) {
- memfree(script_tags);
- return true;
- }
- }
- memfree(script_tags);
- }
-
- if (!fds->os2) {
- return false;
- }
-
- switch (p_script) {
- case HB_SCRIPT_COMMON:
- return (fds->os2->ulUnicodeRange1 & 1L << 4) || (fds->os2->ulUnicodeRange1 & 1L << 5) || (fds->os2->ulUnicodeRange1 & 1L << 6) || (fds->os2->ulUnicodeRange1 & 1L << 31) || (fds->os2->ulUnicodeRange2 & 1L << 0) || (fds->os2->ulUnicodeRange2 & 1L << 1) || (fds->os2->ulUnicodeRange2 & 1L << 2) || (fds->os2->ulUnicodeRange2 & 1L << 3) || (fds->os2->ulUnicodeRange2 & 1L << 4) || (fds->os2->ulUnicodeRange2 & 1L << 5) || (fds->os2->ulUnicodeRange2 & 1L << 6) || (fds->os2->ulUnicodeRange2 & 1L << 7) || (fds->os2->ulUnicodeRange2 & 1L << 8) || (fds->os2->ulUnicodeRange2 & 1L << 9) || (fds->os2->ulUnicodeRange2 & 1L << 10) || (fds->os2->ulUnicodeRange2 & 1L << 11) || (fds->os2->ulUnicodeRange2 & 1L << 12) || (fds->os2->ulUnicodeRange2 & 1L << 13) || (fds->os2->ulUnicodeRange2 & 1L << 14) || (fds->os2->ulUnicodeRange2 & 1L << 15) || (fds->os2->ulUnicodeRange2 & 1L << 30) || (fds->os2->ulUnicodeRange3 & 1L << 0) || (fds->os2->ulUnicodeRange3 & 1L << 1) || (fds->os2->ulUnicodeRange3 & 1L << 2) || (fds->os2->ulUnicodeRange3 & 1L << 4) || (fds->os2->ulUnicodeRange3 & 1L << 5) || (fds->os2->ulUnicodeRange3 & 1L << 18) || (fds->os2->ulUnicodeRange3 & 1L << 24) || (fds->os2->ulUnicodeRange3 & 1L << 25) || (fds->os2->ulUnicodeRange3 & 1L << 26) || (fds->os2->ulUnicodeRange3 & 1L << 27) || (fds->os2->ulUnicodeRange3 & 1L << 28) || (fds->os2->ulUnicodeRange4 & 1L << 3) || (fds->os2->ulUnicodeRange4 & 1L << 6) || (fds->os2->ulUnicodeRange4 & 1L << 15) || (fds->os2->ulUnicodeRange4 & 1L << 23) || (fds->os2->ulUnicodeRange4 & 1L << 24) || (fds->os2->ulUnicodeRange4 & 1L << 26);
- case HB_SCRIPT_LATIN:
- return (fds->os2->ulUnicodeRange1 & 1L << 0) || (fds->os2->ulUnicodeRange1 & 1L << 1) || (fds->os2->ulUnicodeRange1 & 1L << 2) || (fds->os2->ulUnicodeRange1 & 1L << 3) || (fds->os2->ulUnicodeRange1 & 1L << 29);
- case HB_SCRIPT_GREEK:
- return (fds->os2->ulUnicodeRange1 & 1L << 7) || (fds->os2->ulUnicodeRange1 & 1L << 30);
- case HB_SCRIPT_COPTIC:
- return (fds->os2->ulUnicodeRange1 & 1L << 8);
- case HB_SCRIPT_CYRILLIC:
- return (fds->os2->ulUnicodeRange1 & 1L << 9);
- case HB_SCRIPT_ARMENIAN:
- return (fds->os2->ulUnicodeRange1 & 1L << 10);
- case HB_SCRIPT_HEBREW:
- return (fds->os2->ulUnicodeRange1 & 1L << 11);
- case HB_SCRIPT_VAI:
- return (fds->os2->ulUnicodeRange1 & 1L << 12);
- case HB_SCRIPT_ARABIC:
- return (fds->os2->ulUnicodeRange1 & 1L << 13) || (fds->os2->ulUnicodeRange2 & 1L << 31) || (fds->os2->ulUnicodeRange3 & 1L << 3);
- case HB_SCRIPT_NKO:
- return (fds->os2->ulUnicodeRange1 & 1L << 14);
- case HB_SCRIPT_DEVANAGARI:
- return (fds->os2->ulUnicodeRange1 & 1L << 15);
- case HB_SCRIPT_BENGALI:
- return (fds->os2->ulUnicodeRange1 & 1L << 16);
- case HB_SCRIPT_GURMUKHI:
- return (fds->os2->ulUnicodeRange1 & 1L << 17);
- case HB_SCRIPT_GUJARATI:
- return (fds->os2->ulUnicodeRange1 & 1L << 18);
- case HB_SCRIPT_ORIYA:
- return (fds->os2->ulUnicodeRange1 & 1L << 19);
- case HB_SCRIPT_TAMIL:
- return (fds->os2->ulUnicodeRange1 & 1L << 20);
- case HB_SCRIPT_TELUGU:
- return (fds->os2->ulUnicodeRange1 & 1L << 21);
- case HB_SCRIPT_KANNADA:
- return (fds->os2->ulUnicodeRange1 & 1L << 22);
- case HB_SCRIPT_MALAYALAM:
- return (fds->os2->ulUnicodeRange1 & 1L << 23);
- case HB_SCRIPT_THAI:
- return (fds->os2->ulUnicodeRange1 & 1L << 24);
- case HB_SCRIPT_LAO:
- return (fds->os2->ulUnicodeRange1 & 1L << 25);
- case HB_SCRIPT_GEORGIAN:
- return (fds->os2->ulUnicodeRange1 & 1L << 26);
- case HB_SCRIPT_BALINESE:
- return (fds->os2->ulUnicodeRange1 & 1L << 27);
- case HB_SCRIPT_HANGUL:
- return (fds->os2->ulUnicodeRange1 & 1L << 28) || (fds->os2->ulUnicodeRange2 & 1L << 20) || (fds->os2->ulUnicodeRange2 & 1L << 24);
- case HB_SCRIPT_HAN:
- return (fds->os2->ulUnicodeRange2 & 1L << 21) || (fds->os2->ulUnicodeRange2 & 1L << 22) || (fds->os2->ulUnicodeRange2 & 1L << 23) || (fds->os2->ulUnicodeRange2 & 1L << 26) || (fds->os2->ulUnicodeRange2 & 1L << 27) || (fds->os2->ulUnicodeRange2 & 1L << 29);
- case HB_SCRIPT_HIRAGANA:
- return (fds->os2->ulUnicodeRange2 & 1L << 17);
- case HB_SCRIPT_KATAKANA:
- return (fds->os2->ulUnicodeRange2 & 1L << 18);
- case HB_SCRIPT_BOPOMOFO:
- return (fds->os2->ulUnicodeRange2 & 1L << 19);
- case HB_SCRIPT_TIBETAN:
- return (fds->os2->ulUnicodeRange3 & 1L << 6);
- case HB_SCRIPT_SYRIAC:
- return (fds->os2->ulUnicodeRange3 & 1L << 7);
- case HB_SCRIPT_THAANA:
- return (fds->os2->ulUnicodeRange3 & 1L << 8);
- case HB_SCRIPT_SINHALA:
- return (fds->os2->ulUnicodeRange3 & 1L << 9);
- case HB_SCRIPT_MYANMAR:
- return (fds->os2->ulUnicodeRange3 & 1L << 10);
- case HB_SCRIPT_ETHIOPIC:
- return (fds->os2->ulUnicodeRange3 & 1L << 11);
- case HB_SCRIPT_CHEROKEE:
- return (fds->os2->ulUnicodeRange3 & 1L << 12);
- case HB_SCRIPT_CANADIAN_SYLLABICS:
- return (fds->os2->ulUnicodeRange3 & 1L << 13);
- case HB_SCRIPT_OGHAM:
- return (fds->os2->ulUnicodeRange3 & 1L << 14);
- case HB_SCRIPT_RUNIC:
- return (fds->os2->ulUnicodeRange3 & 1L << 15);
- case HB_SCRIPT_KHMER:
- return (fds->os2->ulUnicodeRange3 & 1L << 16);
- case HB_SCRIPT_MONGOLIAN:
- return (fds->os2->ulUnicodeRange3 & 1L << 17);
- case HB_SCRIPT_YI:
- return (fds->os2->ulUnicodeRange3 & 1L << 19);
- case HB_SCRIPT_HANUNOO:
- case HB_SCRIPT_TAGBANWA:
- case HB_SCRIPT_BUHID:
- case HB_SCRIPT_TAGALOG:
- return (fds->os2->ulUnicodeRange3 & 1L << 20);
- case HB_SCRIPT_OLD_ITALIC:
- return (fds->os2->ulUnicodeRange3 & 1L << 21);
- case HB_SCRIPT_GOTHIC:
- return (fds->os2->ulUnicodeRange3 & 1L << 22);
- case HB_SCRIPT_DESERET:
- return (fds->os2->ulUnicodeRange3 & 1L << 23);
- case HB_SCRIPT_LIMBU:
- return (fds->os2->ulUnicodeRange3 & 1L << 29);
- case HB_SCRIPT_TAI_LE:
- return (fds->os2->ulUnicodeRange3 & 1L << 30);
- case HB_SCRIPT_NEW_TAI_LUE:
- return (fds->os2->ulUnicodeRange3 & 1L << 31);
- case HB_SCRIPT_BUGINESE:
- return (fds->os2->ulUnicodeRange4 & 1L << 0);
- case HB_SCRIPT_GLAGOLITIC:
- return (fds->os2->ulUnicodeRange4 & 1L << 1);
- case HB_SCRIPT_TIFINAGH:
- return (fds->os2->ulUnicodeRange4 & 1L << 2);
- case HB_SCRIPT_SYLOTI_NAGRI:
- return (fds->os2->ulUnicodeRange4 & 1L << 4);
- case HB_SCRIPT_LINEAR_B:
- return (fds->os2->ulUnicodeRange4 & 1L << 5);
- case HB_SCRIPT_UGARITIC:
- return (fds->os2->ulUnicodeRange4 & 1L << 7);
- case HB_SCRIPT_OLD_PERSIAN:
- return (fds->os2->ulUnicodeRange4 & 1L << 8);
- case HB_SCRIPT_SHAVIAN:
- return (fds->os2->ulUnicodeRange4 & 1L << 9);
- case HB_SCRIPT_OSMANYA:
- return (fds->os2->ulUnicodeRange4 & 1L << 10);
- case HB_SCRIPT_CYPRIOT:
- return (fds->os2->ulUnicodeRange4 & 1L << 11);
- case HB_SCRIPT_KHAROSHTHI:
- return (fds->os2->ulUnicodeRange4 & 1L << 12);
- case HB_SCRIPT_TAI_VIET:
- return (fds->os2->ulUnicodeRange4 & 1L << 13);
- case HB_SCRIPT_CUNEIFORM:
- return (fds->os2->ulUnicodeRange4 & 1L << 14);
- case HB_SCRIPT_SUNDANESE:
- return (fds->os2->ulUnicodeRange4 & 1L << 16);
- case HB_SCRIPT_LEPCHA:
- return (fds->os2->ulUnicodeRange4 & 1L << 17);
- case HB_SCRIPT_OL_CHIKI:
- return (fds->os2->ulUnicodeRange4 & 1L << 18);
- case HB_SCRIPT_SAURASHTRA:
- return (fds->os2->ulUnicodeRange4 & 1L << 19);
- case HB_SCRIPT_KAYAH_LI:
- return (fds->os2->ulUnicodeRange4 & 1L << 20);
- case HB_SCRIPT_REJANG:
- return (fds->os2->ulUnicodeRange4 & 1L << 21);
- case HB_SCRIPT_CHAM:
- return (fds->os2->ulUnicodeRange4 & 1L << 22);
- case HB_SCRIPT_ANATOLIAN_HIEROGLYPHS:
- return (fds->os2->ulUnicodeRange4 & 1L << 25);
- default:
- return false;
- };
-}
-
-void DynamicFontDataAdvanced::set_antialiased(bool p_antialiased) {
- if (antialiased != p_antialiased) {
- clear_cache();
- antialiased = p_antialiased;
- }
-}
-
-bool DynamicFontDataAdvanced::get_antialiased() const {
- return antialiased;
-}
-
-void DynamicFontDataAdvanced::set_force_autohinter(bool p_enabled) {
- if (force_autohinter != p_enabled) {
- clear_cache();
- force_autohinter = p_enabled;
- }
-}
-
-bool DynamicFontDataAdvanced::get_force_autohinter() const {
- return force_autohinter;
-}
-
-void DynamicFontDataAdvanced::set_hinting(TextServer::Hinting p_hinting) {
- if (hinting != p_hinting) {
- clear_cache();
- hinting = p_hinting;
- }
-}
-
-TextServer::Hinting DynamicFontDataAdvanced::get_hinting() const {
- return hinting;
-}
-
-bool DynamicFontDataAdvanced::has_outline() const {
- return true;
-}
-
-float DynamicFontDataAdvanced::get_base_size() const {
- return base_size;
-}
-
-String DynamicFontDataAdvanced::get_supported_chars() const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- ERR_FAIL_COND_V(fds == nullptr, String());
-
- String chars;
-
- FT_UInt gindex;
- FT_ULong charcode = FT_Get_First_Char(fds->face, &gindex);
- while (gindex != 0) {
- if (charcode != 0) {
- chars += char32_t(charcode);
- }
- charcode = FT_Get_Next_Char(fds->face, charcode, &gindex);
- }
-
- return chars;
-}
-
-float DynamicFontDataAdvanced::get_font_scale(int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, 1.0f);
-
- return fds->scale_color_font / oversampling;
-}
-
-bool DynamicFontDataAdvanced::has_char(char32_t p_char) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- ERR_FAIL_COND_V(fds == nullptr, false);
-
- const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(base_size, FT_Get_Char_Index(fds->face, p_char));
- Character ch = fds->glyph_map[FT_Get_Char_Index(fds->face, p_char)];
-
- return (ch.found);
-}
-
-hb_font_t *DynamicFontDataAdvanced::get_hb_handle(int p_size) {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, nullptr);
-
- return fds->hb_handle;
-}
-
-uint32_t DynamicFontDataAdvanced::get_glyph_index(char32_t p_char, char32_t p_variation_selector) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
- ERR_FAIL_COND_V(fds == nullptr, 0);
-
- if (p_variation_selector == 0x0000) {
- return FT_Get_Char_Index(fds->face, p_char);
- } else {
- return FT_Face_GetCharVariantIndex(fds->face, p_char, p_variation_selector);
- }
-}
-
-Vector2 DynamicFontDataAdvanced::get_advance(uint32_t p_index, int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, Vector2());
-
- const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(p_size, p_index);
- Character ch = fds->glyph_map[p_index];
-
- return ch.advance;
-}
-
-Vector2 DynamicFontDataAdvanced::get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, Vector2());
-
- FT_Vector delta;
- FT_Get_Kerning(fds->face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
- return Vector2(delta.x, delta.y);
-}
-
-Vector2 DynamicFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, Vector2());
-
- const_cast<DynamicFontDataAdvanced *>(this)->update_glyph(p_size, p_index);
- Character ch = fds->glyph_map[p_index];
-
- Vector2 advance;
- if (ch.found) {
- ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
-
- if (ch.texture_idx != -1) {
- Point2i cpos = p_pos;
- cpos += ch.align;
- Color modulate = p_color;
- if (FT_HAS_COLOR(fds->face)) {
- modulate.r = modulate.g = modulate.b = 1.0;
- }
- if (RenderingServer::get_singleton() != nullptr) {
- RID texture = fds->textures[ch.texture_idx].texture->get_rid();
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
- }
- }
-
- advance = ch.advance;
- }
-
- return advance;
-}
-
-Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size, p_outline_size);
- ERR_FAIL_COND_V(fds == nullptr, Vector2());
-
- const_cast<DynamicFontDataAdvanced *>(this)->update_glyph_outline(p_size, p_outline_size, p_index);
- Character ch = fds->glyph_map[p_index];
-
- Vector2 advance;
- if (ch.found) {
- ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2());
-
- if (ch.texture_idx != -1) {
- Point2i cpos = p_pos;
- cpos += ch.align;
- Color modulate = p_color;
- if (FT_HAS_COLOR(fds->face)) {
- modulate.r = modulate.g = modulate.b = 1.0;
- }
- if (RenderingServer::get_singleton() != nullptr) {
- RID texture = fds->textures[ch.texture_idx].texture->get_rid();
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, ch.rect.size), texture, ch.rect_uv, modulate, false, false);
- }
- }
-
- advance = ch.advance;
- }
-
- return advance;
-}
-
-bool DynamicFontDataAdvanced::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
- _THREAD_SAFE_METHOD_
- DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
- ERR_FAIL_COND_V(fds == nullptr, false);
-
- int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- ERR_FAIL_COND_V(error, false);
-
- r_points.clear();
- r_contours.clear();
-
- float h = fds->ascent;
- float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font;
- for (short i = 0; i < fds->face->glyph->outline.n_points; i++) {
- r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i])));
- }
- for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) {
- r_contours.push_back(fds->face->glyph->outline.contours[i]);
- }
- r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
- return true;
-}
-
-DynamicFontDataAdvanced::~DynamicFontDataAdvanced() {
- clear_cache();
- if (library != nullptr) {
- FT_Done_FreeType(library);
- }
-}
-
-#endif // MODULE_FREETYPE_ENABLED
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
deleted file mode 100644
index b3f97bb029..0000000000
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*************************************************************************/
-/* dynamic_font_adv.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef DYNAMIC_FONT_ADV_H
-#define DYNAMIC_FONT_ADV_H
-
-#include "font_adv.h"
-
-#include "modules/modules_enabled.gen.h"
-#ifdef MODULE_FREETYPE_ENABLED
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_TRUETYPE_TABLES_H
-
-#include <hb-ft.h>
-#include <hb-ot.h>
-
-struct DynamicFontDataAdvanced : public FontDataAdvanced {
- _THREAD_SAFE_CLASS_
-
-private:
- struct CharTexture {
- Vector<uint8_t> imgdata;
- int texture_size = 0;
- Vector<int> offsets;
- Ref<ImageTexture> texture;
- };
-
- struct Character {
- bool found = false;
- int texture_idx = 0;
- Rect2 rect;
- Rect2 rect_uv;
- Vector2 align;
- Vector2 advance = Vector2(-1, -1);
-
- static Character not_found();
- };
-
- struct TexturePosition {
- int index = 0;
- int x = 0;
- int y = 0;
- };
-
- struct CacheID {
- union {
- struct {
- uint32_t size : 16;
- uint32_t outline_size : 16;
- };
- uint32_t key = 0;
- };
- bool operator<(CacheID right) const {
- return key < right.key;
- }
- };
-
- struct DataAtSize {
- FT_Face face = nullptr;
- TT_OS2 *os2 = nullptr;
- FT_StreamRec stream;
-
- int size = 0;
- float scale_color_font = 1.f;
- float ascent = 0.0;
- float descent = 0.0;
- float underline_position = 0.0;
- float underline_thickness = 0.0;
-
- Vector<CharTexture> textures;
- HashMap<uint32_t, Character> glyph_map;
-
- hb_font_t *hb_handle = nullptr;
- ~DataAtSize() {
- if (hb_handle != nullptr) {
- hb_font_destroy(hb_handle);
- }
- if (face != nullptr) {
- FT_Done_Face(face);
- }
- }
- };
-
- FT_Library library = nullptr;
-
- // Source data.
- const uint8_t *font_mem = nullptr;
- int font_mem_size = 0;
- String font_path;
- Vector<uint8_t> font_mem_cache;
-
- Map<int32_t, double> variations;
-
- float rect_margin = 1.f;
- int base_size = 16;
- float oversampling = 1.f;
- bool antialiased = true;
- bool force_autohinter = false;
- TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
-
- Map<CacheID, DataAtSize *> size_cache;
- Map<CacheID, DataAtSize *> size_cache_outline;
-
- DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
-
- TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
- Character bitmap_to_character(DataAtSize *p_data, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance);
- _FORCE_INLINE_ void update_glyph(int p_size, uint32_t p_index);
- _FORCE_INLINE_ void update_glyph_outline(int p_size, int p_outline_size, uint32_t p_index);
-
-public:
- virtual void clear_cache() override;
-
- virtual Error load_from_file(const String &p_filename, int p_base_size) override;
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
-
- virtual float get_height(int p_size) const override;
- virtual float get_ascent(int p_size) const override;
- virtual float get_descent(int p_size) const override;
-
- virtual Dictionary get_feature_list() const override;
- virtual Dictionary get_variation_list() const override;
-
- virtual void set_variation(const String &p_name, double p_value) override;
- virtual double get_variation(const String &p_name) const override;
-
- virtual float get_underline_position(int p_size) const override;
- virtual float get_underline_thickness(int p_size) const override;
-
- virtual void set_antialiased(bool p_antialiased) override;
- virtual bool get_antialiased() const override;
-
- virtual void set_hinting(TextServer::Hinting p_hinting) override;
- virtual TextServer::Hinting get_hinting() const override;
-
- virtual void set_force_autohinter(bool p_enabled) override;
- virtual bool get_force_autohinter() const override;
-
- virtual void set_distance_field_hint(bool p_distance_field) override{};
- virtual bool get_distance_field_hint() const override { return false; };
-
- virtual bool has_outline() const override;
- virtual float get_base_size() const override;
-
- virtual bool is_script_supported(uint32_t p_script) const override;
-
- virtual bool has_char(char32_t p_char) const override;
- virtual String get_supported_chars() const override;
- virtual float get_font_scale(int p_size) const override;
-
- virtual hb_font_t *get_hb_handle(int p_size) override;
- virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const override;
- virtual Vector2 get_advance(uint32_t p_index, int p_size) const override;
- virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const override;
-
- virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
- virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
-
- virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
-
- virtual ~DynamicFontDataAdvanced() override;
-};
-
-#endif // MODULE_FREETYPE_ENABLED
-
-#endif // DYNAMIC_FONT_ADV_H
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
deleted file mode 100644
index 4fadefc569..0000000000
--- a/modules/text_server_adv/font_adv.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*************************************************************************/
-/* font_adv.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef FONT_ADV_H
-#define FONT_ADV_H
-
-#include "servers/text_server.h"
-
-#include <hb.h>
-
-struct FontDataAdvanced {
- Map<String, bool> lang_support_overrides;
- Map<String, bool> script_support_overrides;
- bool valid = false;
- int spacing_space = 0;
- int spacing_glyph = 0;
-
- virtual void clear_cache() = 0;
-
- virtual Error load_from_file(const String &p_filename, int p_base_size) { return ERR_CANT_CREATE; };
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) { return ERR_CANT_CREATE; };
- virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) { return ERR_CANT_CREATE; };
-
- virtual void bitmap_add_texture(const Ref<Texture> &p_texture) { ERR_FAIL_MSG("Not supported."); };
- virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { ERR_FAIL_MSG("Not supported."); };
- virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { ERR_FAIL_MSG("Not supported."); };
-
- virtual float get_height(int p_size) const = 0;
- virtual float get_ascent(int p_size) const = 0;
- virtual float get_descent(int p_size) const = 0;
-
- virtual Dictionary get_feature_list() const { return Dictionary(); };
- virtual Dictionary get_variation_list() const { return Dictionary(); };
-
- virtual void set_variation(const String &p_name, double p_value){};
- virtual double get_variation(const String &p_name) const { return 0; };
-
- virtual float get_underline_position(int p_size) const = 0;
- virtual float get_underline_thickness(int p_size) const = 0;
-
- virtual int get_spacing_space() const { return spacing_space; };
- virtual void set_spacing_space(int p_value) {
- spacing_space = p_value;
- clear_cache();
- };
-
- virtual int get_spacing_glyph() const { return spacing_glyph; };
- virtual void set_spacing_glyph(int p_value) {
- spacing_glyph = p_value;
- clear_cache();
- };
-
- virtual void set_antialiased(bool p_antialiased) = 0;
- virtual bool get_antialiased() const = 0;
-
- virtual void set_hinting(TextServer::Hinting p_hinting) = 0;
- virtual TextServer::Hinting get_hinting() const = 0;
-
- virtual void set_distance_field_hint(bool p_distance_field) = 0;
- virtual bool get_distance_field_hint() const = 0;
-
- virtual void set_force_autohinter(bool p_enabeld) = 0;
- virtual bool get_force_autohinter() const = 0;
-
- virtual bool has_outline() const = 0;
- virtual float get_base_size() const = 0;
-
- virtual bool is_lang_supported(const String &p_lang) const { return true; };
- virtual bool is_script_supported(uint32_t p_script) const { return true; };
-
- virtual bool has_char(char32_t p_char) const = 0;
- virtual String get_supported_chars() const = 0;
- virtual float get_font_scale(int p_size) const { return 1.0f; };
-
- virtual hb_font_t *get_hb_handle(int p_size) = 0;
- virtual uint32_t get_glyph_index(char32_t p_char, char32_t p_variation_selector) const = 0;
- virtual Vector2 get_advance(uint32_t p_char, int p_size) const = 0;
- virtual Vector2 get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const = 0;
-
- virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
- virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
-
- virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; };
-
- virtual ~FontDataAdvanced(){};
-};
-
-#endif // FONT_ADV_H
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index abefa83b9b..b711d1561f 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -33,7 +33,12 @@
#include "text_server_adv.h"
void preregister_text_server_adv_types() {
- TextServerAdvanced::register_server();
+ GDREGISTER_CLASS(TextServerAdvanced);
+ if (TextServerManager::get_singleton()) {
+ Ref<TextServerAdvanced> ts;
+ ts.instantiate();
+ TextServerManager::get_singleton()->add_interface(ts);
+ }
}
void register_text_server_adv_types() {
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index f9bbd25a5f..d1e849def8 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -30,6 +30,8 @@
#include "script_iterator.h"
+// This implementation is derived from ICU: icu4c/source/extra/scrptrun/scrptrun.cpp
+
bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) {
return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two;
}
@@ -48,7 +50,8 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
p_start = 0;
}
- ParenStackEntry paren_stack[128];
+ int paren_size = PAREN_STACK_DEPTH;
+ ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry));
int script_start;
int script_end = p_start;
@@ -64,13 +67,22 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
UChar32 ch = str[script_end];
UScriptCode sc = uscript_getScript(ch, &err);
if (U_FAILURE(err)) {
+ memfree(paren_stack);
ERR_FAIL_MSG(u_errorName(err));
}
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) {
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) {
- paren_stack[++paren_sp].pair_index = ch;
+ // If it's an open character, push it onto the stack.
+ paren_sp++;
+ if (unlikely(paren_sp >= paren_size)) {
+ // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text.
+ paren_size += PAREN_STACK_DEPTH;
+ paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry));
+ }
+ paren_stack[paren_sp].pair_index = ch;
paren_stack[paren_sp].script_code = script_code;
} else if (paren_sp >= 0) {
+ // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be poped.
UChar32 paired_ch = u_getBidiPairedBracket(ch);
while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) {
paren_sp -= 1;
@@ -87,11 +99,13 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
if (same_script(script_code, sc)) {
if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
script_code = sc;
+ // Now that we have a final script code, fix any open characters we pushed before we knew the script code.
while (start_sp < paren_sp) {
paren_stack[++start_sp].script_code = script_code;
}
}
if ((u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) && paren_sp >= 0) {
+ // If this character is a close paired character pop the matching open character from the stack.
paren_sp -= 1;
if (start_sp >= 0) {
start_sp -= 1;
@@ -109,4 +123,6 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
script_ranges.push_back(rng);
} while (script_end < p_length);
+
+ memfree(paren_stack);
}
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
index 896a0e5c15..5efd40f7c4 100644
--- a/modules/text_server_adv/script_iterator.h
+++ b/modules/text_server_adv/script_iterator.h
@@ -43,6 +43,8 @@
#include <hb.h>
class ScriptIterator {
+ static const int PAREN_STACK_DEPTH = 128;
+
public:
struct ScriptRange {
int start = 0;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 66816f32d1..f5d159040f 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -29,15 +29,199 @@
/*************************************************************************/
#include "text_server_adv.h"
-#include "bitmap_font_adv.h"
-#include "dynamic_font_adv.h"
+#include "core/error/error_macros.h"
+#include "core/string/print_string.h"
#include "core/string/translation.h"
#ifdef ICU_STATIC_DATA
#include "thirdparty/icu4c/icudata.gen.h"
#endif
+#ifdef MODULE_MSDFGEN_ENABLED
+#include "core/ShapeDistanceFinder.h"
+#include "core/contour-combiners.h"
+#include "core/edge-selectors.h"
+#include "msdfgen.h"
+#endif
+
+/*************************************************************************/
+/* hb_bmp_font_t HarfBuzz Bitmap font interface */
+/*************************************************************************/
+
+hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;
+
+TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ hb_bmp_font_t *bm_font = memnew(hb_bmp_font_t);
+
+ if (!bm_font) {
+ return nullptr;
+ }
+
+ bm_font->face = p_face;
+ bm_font->unref = p_unref;
+
+ return bm_font;
+}
+
+void TextServerAdvanced::_hb_bmp_font_destroy(void *p_data) {
+ hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(p_data);
+ memdelete(bm_font);
+}
+
+hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->glyph_map.has(p_unicode)) {
+ if (bm_font->face->glyph_map.has(0xF000u + p_unicode)) {
+ *r_glyph = 0xF000u + p_unicode;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ *r_glyph = p_unicode;
+ return true;
+}
+
+hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->glyph_map.has(p_glyph)) {
+ return 0;
+ }
+
+ return bm_font->face->glyph_map[p_glyph].advance.x * 64;
+}
+
+hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->glyph_map.has(p_glyph)) {
+ return 0;
+ }
+
+ return -bm_font->face->glyph_map[p_glyph].advance.y * 64;
+}
+
+hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return 0;
+ }
+
+ if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {
+ return 0;
+ }
+
+ return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;
+}
+
+hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->glyph_map.has(p_glyph)) {
+ return false;
+ }
+
+ *r_x = bm_font->face->glyph_map[p_glyph].advance.x * 32;
+ *r_y = -bm_font->face->ascent * 64;
+
+ return true;
+}
+
+hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ if (!bm_font->face->glyph_map.has(p_glyph)) {
+ return false;
+ }
+
+ r_extents->x_bearing = 0;
+ r_extents->y_bearing = 0;
+ r_extents->width = bm_font->face->glyph_map[p_glyph].rect.size.x * 64;
+ r_extents->height = bm_font->face->glyph_map[p_glyph].rect.size.y * 64;
+
+ return true;
+}
+
+hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
+ const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+
+ if (!bm_font->face) {
+ return false;
+ }
+
+ r_metrics->ascender = bm_font->face->ascent;
+ r_metrics->descender = bm_font->face->descent;
+ r_metrics->line_gap = 0;
+
+ return true;
+}
+
+void TextServerAdvanced::hb_bmp_create_font_funcs() {
+ if (funcs == nullptr) {
+ funcs = hb_font_funcs_create();
+
+ hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr);
+
+ hb_font_funcs_make_immutable(funcs);
+ }
+}
+
+void TextServerAdvanced::hb_bmp_free_font_funcs() {
+ if (funcs != nullptr) {
+ hb_font_funcs_destroy(funcs);
+ funcs = nullptr;
+ }
+}
+
+void TextServerAdvanced::_hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_unref), _hb_bmp_font_destroy);
+}
+
+hb_font_t *TextServerAdvanced::hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
+ hb_font_t *font;
+ hb_face_t *face = hb_face_create(nullptr, 0);
+
+ font = hb_font_create(face);
+ hb_face_destroy(face);
+ _hb_bmp_font_set_funcs(font, p_face, false);
+ return font;
+}
+
+/*************************************************************************/
+/* Character properties. */
+/*************************************************************************/
+
_FORCE_INLINE_ bool is_ain(char32_t p_chr) {
return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;
}
@@ -138,7 +322,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
-bool TextServerAdvanced::has_feature(Feature p_feature) {
+bool TextServerAdvanced::has_feature(Feature p_feature) const {
return (interface_features & p_feature) == p_feature;
}
@@ -146,14 +330,18 @@ String TextServerAdvanced::get_name() const {
return interface_name;
}
+uint32_t TextServerAdvanced::get_features() const {
+ return interface_features;
+}
+
void TextServerAdvanced::free(RID p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
- FontDataAdvanced *fd = font_owner.getornull(p_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_rid);
font_owner.free(p_rid);
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_rid);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);
shaped_owner.free(p_rid);
memdelete(sd);
}
@@ -210,9 +398,23 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
return true;
}
-#ifdef TOOLS_ENABLED
+String TextServerAdvanced::get_support_data_filename() const {
+#ifdef ICU_STATIC_DATA
+ return _MKSTR(ICU_DATA_NAME);
+#else
+ return String();
+#endif
+}
+
+String TextServerAdvanced::get_support_data_info() const {
+#ifdef ICU_STATIC_DATA
+ return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(").");
+#else
+ return String();
+#endif
+}
-bool TextServerAdvanced::save_support_data(const String &p_filename) {
+bool TextServerAdvanced::save_support_data(const String &p_filename) const {
_THREAD_SAFE_METHOD_
#ifdef ICU_STATIC_DATA
@@ -231,9 +433,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) {
#endif
}
-#endif
-
-bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
+bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const {
String l = p_locale.get_slicec('_', 0);
if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
return true;
@@ -242,276 +442,270 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
}
}
-struct FeatureInfo {
- int32_t tag;
- String name;
-};
+static Map<StringName, int32_t> feature_sets;
-static FeatureInfo feature_set[] = {
+static void _insert_feature_sets() {
// Registered OpenType feature tags.
- { HB_TAG('a', 'a', 'l', 't'), "access_all_alternates" },
- { HB_TAG('a', 'b', 'v', 'f'), "above_base_forms" },
- { HB_TAG('a', 'b', 'v', 'm'), "above_base_mark_positioning" },
- { HB_TAG('a', 'b', 'v', 's'), "above_base_substitutions" },
- { HB_TAG('a', 'f', 'r', 'c'), "alternative_fractions" },
- { HB_TAG('a', 'k', 'h', 'n'), "akhands" },
- { HB_TAG('b', 'l', 'w', 'f'), "below_base_forms" },
- { HB_TAG('b', 'l', 'w', 'm'), "below_base_mark_positioning" },
- { HB_TAG('b', 'l', 'w', 's'), "below_base_substitutions" },
- { HB_TAG('c', 'a', 'l', 't'), "contextual_alternates" },
- { HB_TAG('c', 'a', 's', 'e'), "case_sensitive_forms" },
- { HB_TAG('c', 'c', 'm', 'p'), "glyph_composition" },
- { HB_TAG('c', 'f', 'a', 'r'), "conjunct_form_after_ro" },
- { HB_TAG('c', 'j', 'c', 't'), "conjunct_forms" },
- { HB_TAG('c', 'l', 'i', 'g'), "contextual_ligatures" },
- { HB_TAG('c', 'p', 'c', 't'), "centered_cjk_punctuation" },
- { HB_TAG('c', 'p', 's', 'p'), "capital_spacing" },
- { HB_TAG('c', 's', 'w', 'h'), "contextual_swash" },
- { HB_TAG('c', 'u', 'r', 's'), "cursive_positioning" },
- { HB_TAG('c', 'v', '0', '1'), "character_variant_01" },
- { HB_TAG('c', 'v', '0', '2'), "character_variant_02" },
- { HB_TAG('c', 'v', '0', '3'), "character_variant_03" },
- { HB_TAG('c', 'v', '0', '4'), "character_variant_04" },
- { HB_TAG('c', 'v', '0', '5'), "character_variant_05" },
- { HB_TAG('c', 'v', '0', '6'), "character_variant_06" },
- { HB_TAG('c', 'v', '0', '7'), "character_variant_07" },
- { HB_TAG('c', 'v', '0', '8'), "character_variant_08" },
- { HB_TAG('c', 'v', '0', '9'), "character_variant_09" },
- { HB_TAG('c', 'v', '1', '0'), "character_variant_10" },
- { HB_TAG('c', 'v', '1', '1'), "character_variant_11" },
- { HB_TAG('c', 'v', '1', '2'), "character_variant_12" },
- { HB_TAG('c', 'v', '1', '3'), "character_variant_13" },
- { HB_TAG('c', 'v', '1', '4'), "character_variant_14" },
- { HB_TAG('c', 'v', '1', '5'), "character_variant_15" },
- { HB_TAG('c', 'v', '1', '6'), "character_variant_16" },
- { HB_TAG('c', 'v', '1', '7'), "character_variant_17" },
- { HB_TAG('c', 'v', '1', '8'), "character_variant_18" },
- { HB_TAG('c', 'v', '1', '9'), "character_variant_19" },
- { HB_TAG('c', 'v', '2', '0'), "character_variant_20" },
- { HB_TAG('c', 'v', '2', '1'), "character_variant_21" },
- { HB_TAG('c', 'v', '2', '2'), "character_variant_22" },
- { HB_TAG('c', 'v', '2', '3'), "character_variant_23" },
- { HB_TAG('c', 'v', '2', '4'), "character_variant_24" },
- { HB_TAG('c', 'v', '2', '5'), "character_variant_25" },
- { HB_TAG('c', 'v', '2', '6'), "character_variant_26" },
- { HB_TAG('c', 'v', '2', '7'), "character_variant_27" },
- { HB_TAG('c', 'v', '2', '8'), "character_variant_28" },
- { HB_TAG('c', 'v', '2', '9'), "character_variant_29" },
- { HB_TAG('c', 'v', '3', '0'), "character_variant_30" },
- { HB_TAG('c', 'v', '3', '1'), "character_variant_31" },
- { HB_TAG('c', 'v', '3', '2'), "character_variant_32" },
- { HB_TAG('c', 'v', '3', '3'), "character_variant_33" },
- { HB_TAG('c', 'v', '3', '4'), "character_variant_34" },
- { HB_TAG('c', 'v', '3', '5'), "character_variant_35" },
- { HB_TAG('c', 'v', '3', '6'), "character_variant_36" },
- { HB_TAG('c', 'v', '3', '7'), "character_variant_37" },
- { HB_TAG('c', 'v', '3', '8'), "character_variant_38" },
- { HB_TAG('c', 'v', '3', '9'), "character_variant_39" },
- { HB_TAG('c', 'v', '4', '0'), "character_variant_40" },
- { HB_TAG('c', 'v', '4', '1'), "character_variant_41" },
- { HB_TAG('c', 'v', '4', '2'), "character_variant_42" },
- { HB_TAG('c', 'v', '4', '3'), "character_variant_43" },
- { HB_TAG('c', 'v', '4', '4'), "character_variant_44" },
- { HB_TAG('c', 'v', '4', '5'), "character_variant_45" },
- { HB_TAG('c', 'v', '4', '6'), "character_variant_46" },
- { HB_TAG('c', 'v', '4', '7'), "character_variant_47" },
- { HB_TAG('c', 'v', '4', '8'), "character_variant_48" },
- { HB_TAG('c', 'v', '4', '9'), "character_variant_49" },
- { HB_TAG('c', 'v', '5', '0'), "character_variant_50" },
- { HB_TAG('c', 'v', '5', '1'), "character_variant_51" },
- { HB_TAG('c', 'v', '5', '2'), "character_variant_52" },
- { HB_TAG('c', 'v', '5', '3'), "character_variant_53" },
- { HB_TAG('c', 'v', '5', '4'), "character_variant_54" },
- { HB_TAG('c', 'v', '5', '5'), "character_variant_55" },
- { HB_TAG('c', 'v', '5', '6'), "character_variant_56" },
- { HB_TAG('c', 'v', '5', '7'), "character_variant_57" },
- { HB_TAG('c', 'v', '5', '8'), "character_variant_58" },
- { HB_TAG('c', 'v', '5', '9'), "character_variant_59" },
- { HB_TAG('c', 'v', '6', '0'), "character_variant_60" },
- { HB_TAG('c', 'v', '6', '1'), "character_variant_61" },
- { HB_TAG('c', 'v', '6', '2'), "character_variant_62" },
- { HB_TAG('c', 'v', '6', '3'), "character_variant_63" },
- { HB_TAG('c', 'v', '6', '4'), "character_variant_64" },
- { HB_TAG('c', 'v', '6', '5'), "character_variant_65" },
- { HB_TAG('c', 'v', '6', '6'), "character_variant_66" },
- { HB_TAG('c', 'v', '6', '7'), "character_variant_67" },
- { HB_TAG('c', 'v', '6', '8'), "character_variant_68" },
- { HB_TAG('c', 'v', '6', '9'), "character_variant_69" },
- { HB_TAG('c', 'v', '7', '0'), "character_variant_70" },
- { HB_TAG('c', 'v', '7', '1'), "character_variant_71" },
- { HB_TAG('c', 'v', '7', '2'), "character_variant_72" },
- { HB_TAG('c', 'v', '7', '3'), "character_variant_73" },
- { HB_TAG('c', 'v', '7', '4'), "character_variant_74" },
- { HB_TAG('c', 'v', '7', '5'), "character_variant_75" },
- { HB_TAG('c', 'v', '7', '6'), "character_variant_76" },
- { HB_TAG('c', 'v', '7', '7'), "character_variant_77" },
- { HB_TAG('c', 'v', '7', '8'), "character_variant_78" },
- { HB_TAG('c', 'v', '7', '9'), "character_variant_79" },
- { HB_TAG('c', 'v', '8', '0'), "character_variant_80" },
- { HB_TAG('c', 'v', '8', '1'), "character_variant_81" },
- { HB_TAG('c', 'v', '8', '2'), "character_variant_82" },
- { HB_TAG('c', 'v', '8', '3'), "character_variant_83" },
- { HB_TAG('c', 'v', '8', '4'), "character_variant_84" },
- { HB_TAG('c', 'v', '8', '5'), "character_variant_85" },
- { HB_TAG('c', 'v', '8', '6'), "character_variant_86" },
- { HB_TAG('c', 'v', '8', '7'), "character_variant_87" },
- { HB_TAG('c', 'v', '8', '8'), "character_variant_88" },
- { HB_TAG('c', 'v', '8', '9'), "character_variant_89" },
- { HB_TAG('c', 'v', '9', '0'), "character_variant_90" },
- { HB_TAG('c', 'v', '9', '1'), "character_variant_91" },
- { HB_TAG('c', 'v', '9', '2'), "character_variant_92" },
- { HB_TAG('c', 'v', '9', '3'), "character_variant_93" },
- { HB_TAG('c', 'v', '9', '4'), "character_variant_94" },
- { HB_TAG('c', 'v', '9', '5'), "character_variant_95" },
- { HB_TAG('c', 'v', '9', '6'), "character_variant_96" },
- { HB_TAG('c', 'v', '9', '7'), "character_variant_97" },
- { HB_TAG('c', 'v', '9', '8'), "character_variant_98" },
- { HB_TAG('c', 'v', '9', '9'), "character_variant_99" },
- { HB_TAG('c', '2', 'p', 'c'), "petite_capitals_from_capitals" },
- { HB_TAG('c', '2', 's', 'c'), "small_capitals_from_capitals" },
- { HB_TAG('d', 'i', 's', 't'), "distances" },
- { HB_TAG('d', 'l', 'i', 'g'), "discretionary_ligatures" },
- { HB_TAG('d', 'n', 'o', 'm'), "denominators" },
- { HB_TAG('d', 't', 'l', 's'), "dotless_forms" },
- { HB_TAG('e', 'x', 'p', 't'), "expert_forms" },
- { HB_TAG('f', 'a', 'l', 't'), "final_glyph_on_line_alternates" },
- { HB_TAG('f', 'i', 'n', '2'), "terminal_forms_2" },
- { HB_TAG('f', 'i', 'n', '3'), "terminal_forms_3" },
- { HB_TAG('f', 'i', 'n', 'a'), "terminal_forms" },
- { HB_TAG('f', 'l', 'a', 'c'), "flattened_accent_forms" },
- { HB_TAG('f', 'r', 'a', 'c'), "fractions" },
- { HB_TAG('f', 'w', 'i', 'd'), "full_widths" },
- { HB_TAG('h', 'a', 'l', 'f'), "half_forms" },
- { HB_TAG('h', 'a', 'l', 'n'), "halant_forms" },
- { HB_TAG('h', 'a', 'l', 't'), "alternate_half_widths" },
- { HB_TAG('h', 'i', 's', 't'), "historical_forms" },
- { HB_TAG('h', 'k', 'n', 'a'), "horizontal_kana_alternates" },
- { HB_TAG('h', 'l', 'i', 'g'), "historical_ligatures" },
- { HB_TAG('h', 'n', 'g', 'l'), "hangul" },
- { HB_TAG('h', 'o', 'j', 'o'), "hojo_kanji_forms" },
- { HB_TAG('h', 'w', 'i', 'd'), "half_widths" },
- { HB_TAG('i', 'n', 'i', 't'), "initial_forms" },
- { HB_TAG('i', 's', 'o', 'l'), "isolated_forms" },
- { HB_TAG('i', 't', 'a', 'l'), "italics" },
- { HB_TAG('j', 'a', 'l', 't'), "justification_alternates" },
- { HB_TAG('j', 'p', '7', '8'), "jis78_forms" },
- { HB_TAG('j', 'p', '8', '3'), "jis83_forms" },
- { HB_TAG('j', 'p', '9', '0'), "jis90_forms" },
- { HB_TAG('j', 'p', '0', '4'), "jis2004_forms" },
- { HB_TAG('k', 'e', 'r', 'n'), "kerning" },
- { HB_TAG('l', 'f', 'b', 'd'), "left_bounds" },
- { HB_TAG('l', 'i', 'g', 'a'), "standard_ligatures" },
- { HB_TAG('l', 'j', 'm', 'o'), "leading_jamo_forms" },
- { HB_TAG('l', 'n', 'u', 'm'), "lining_figures" },
- { HB_TAG('l', 'o', 'c', 'l'), "localized_forms" },
- { HB_TAG('l', 't', 'r', 'a'), "left_to_right_alternates" },
- { HB_TAG('l', 't', 'r', 'm'), "left_to_right_mirrored_forms" },
- { HB_TAG('m', 'a', 'r', 'k'), "mark_positioning" },
- { HB_TAG('m', 'e', 'd', '2'), "medial_forms_2" },
- { HB_TAG('m', 'e', 'd', 'i'), "medial_forms" },
- { HB_TAG('m', 'g', 'r', 'k'), "mathematical_greek" },
- { HB_TAG('m', 'k', 'm', 'k'), "mark_to_mark_positioning" },
- { HB_TAG('m', 's', 'e', 't'), "mark_positioning_via_substitution" },
- { HB_TAG('n', 'a', 'l', 't'), "alternate_annotation_forms" },
- { HB_TAG('n', 'l', 'c', 'k'), "nlc_kanji_forms" },
- { HB_TAG('n', 'u', 'k', 't'), "nukta_forms" },
- { HB_TAG('n', 'u', 'm', 'r'), "numerators" },
- { HB_TAG('o', 'n', 'u', 'm'), "oldstyle_figures" },
- { HB_TAG('o', 'p', 'b', 'd'), "optical_bounds" },
- { HB_TAG('o', 'r', 'd', 'n'), "ordinals" },
- { HB_TAG('o', 'r', 'n', 'm'), "ornaments" },
- { HB_TAG('p', 'a', 'l', 't'), "proportional_alternate_widths" },
- { HB_TAG('p', 'c', 'a', 'p'), "petite_capitals" },
- { HB_TAG('p', 'k', 'n', 'a'), "proportional_kana" },
- { HB_TAG('p', 'n', 'u', 'm'), "proportional_figures" },
- { HB_TAG('p', 'r', 'e', 'f'), "pre_base_forms" },
- { HB_TAG('p', 'r', 'e', 's'), "pre_base_substitutions" },
- { HB_TAG('p', 's', 't', 'f'), "post_base_forms" },
- { HB_TAG('p', 's', 't', 's'), "post_base_substitutions" },
- { HB_TAG('p', 'w', 'i', 'd'), "proportional_widths" },
- { HB_TAG('q', 'w', 'i', 'd'), "quarter_widths" },
- { HB_TAG('r', 'a', 'n', 'd'), "randomize" },
- { HB_TAG('r', 'c', 'l', 't'), "required_contextual_alternates" },
- { HB_TAG('r', 'k', 'r', 'f'), "rakar_forms" },
- { HB_TAG('r', 'l', 'i', 'g'), "required_ligatures" },
- { HB_TAG('r', 'p', 'h', 'f'), "reph_forms" },
- { HB_TAG('r', 't', 'b', 'd'), "right_bounds" },
- { HB_TAG('r', 't', 'l', 'a'), "right_to_left_alternates" },
- { HB_TAG('r', 't', 'l', 'm'), "right_to_left_mirrored_forms" },
- { HB_TAG('r', 'u', 'b', 'y'), "ruby_notation_forms" },
- { HB_TAG('r', 'v', 'r', 'n'), "required_variation_alternates" },
- { HB_TAG('s', 'a', 'l', 't'), "stylistic_alternates" },
- { HB_TAG('s', 'i', 'n', 'f'), "scientific_inferiors" },
- { HB_TAG('s', 'i', 'z', 'e'), "optical_size" },
- { HB_TAG('s', 'm', 'c', 'p'), "small_capitals" },
- { HB_TAG('s', 'm', 'p', 'l'), "simplified_forms" },
- { HB_TAG('s', 's', '0', '1'), "stylistic_set_01" },
- { HB_TAG('s', 's', '0', '2'), "stylistic_set_02" },
- { HB_TAG('s', 's', '0', '3'), "stylistic_set_03" },
- { HB_TAG('s', 's', '0', '4'), "stylistic_set_04" },
- { HB_TAG('s', 's', '0', '5'), "stylistic_set_05" },
- { HB_TAG('s', 's', '0', '6'), "stylistic_set_06" },
- { HB_TAG('s', 's', '0', '7'), "stylistic_set_07" },
- { HB_TAG('s', 's', '0', '8'), "stylistic_set_08" },
- { HB_TAG('s', 's', '0', '9'), "stylistic_set_09" },
- { HB_TAG('s', 's', '1', '0'), "stylistic_set_10" },
- { HB_TAG('s', 's', '1', '1'), "stylistic_set_11" },
- { HB_TAG('s', 's', '1', '2'), "stylistic_set_12" },
- { HB_TAG('s', 's', '1', '3'), "stylistic_set_13" },
- { HB_TAG('s', 's', '1', '4'), "stylistic_set_14" },
- { HB_TAG('s', 's', '1', '5'), "stylistic_set_15" },
- { HB_TAG('s', 's', '1', '6'), "stylistic_set_16" },
- { HB_TAG('s', 's', '1', '7'), "stylistic_set_17" },
- { HB_TAG('s', 's', '1', '8'), "stylistic_set_18" },
- { HB_TAG('s', 's', '1', '9'), "stylistic_set_19" },
- { HB_TAG('s', 's', '2', '0'), "stylistic_set_20" },
- { HB_TAG('s', 's', 't', 'y'), "math_script_style_alternates" },
- { HB_TAG('s', 't', 'c', 'h'), "stretching_glyph_decomposition" },
- { HB_TAG('s', 'u', 'b', 's'), "subscript" },
- { HB_TAG('s', 'u', 'p', 's'), "superscript" },
- { HB_TAG('s', 'w', 's', 'h'), "swash" },
- { HB_TAG('t', 'i', 't', 'l'), "titling" },
- { HB_TAG('t', 'j', 'm', 'o'), "trailing_jamo_forms" },
- { HB_TAG('t', 'n', 'a', 'm'), "traditional_name_forms" },
- { HB_TAG('t', 'n', 'u', 'm'), "tabular_figures" },
- { HB_TAG('t', 'r', 'a', 'd'), "traditional_forms" },
- { HB_TAG('t', 'w', 'i', 'd'), "third_widths" },
- { HB_TAG('u', 'n', 'i', 'c'), "unicase" },
- { HB_TAG('v', 'a', 'l', 't'), "alternate_vertical_metrics" },
- { HB_TAG('v', 'a', 't', 'u'), "vattu_variants" },
- { HB_TAG('v', 'e', 'r', 't'), "vertical_writing" },
- { HB_TAG('v', 'h', 'a', 'l'), "alternate_vertical_half_metrics" },
- { HB_TAG('v', 'j', 'm', 'o'), "vowel_jamo_forms" },
- { HB_TAG('v', 'k', 'n', 'a'), "vertical_kana_alternates" },
- { HB_TAG('v', 'k', 'r', 'n'), "vertical_kerning" },
- { HB_TAG('v', 'p', 'a', 'l'), "proportional_alternate_vertical_metrics" },
- { HB_TAG('v', 'r', 't', '2'), "vertical_alternates_and_rotation" },
- { HB_TAG('v', 'r', 't', 'r'), "vertical_alternates_for_rotation" },
- { HB_TAG('z', 'e', 'r', 'o'), "slashed_zero" },
- // Registered OpenType variation tags.
- { HB_TAG('i', 't', 'a', 'l'), "italic" },
- { HB_TAG('o', 'p', 's', 'z'), "optical_size" },
- { HB_TAG('s', 'l', 'n', 't'), "slant" },
- { HB_TAG('w', 'd', 't', 'h'), "width" },
- { HB_TAG('w', 'g', 'h', 't'), "weight" },
- { 0, String() },
-};
-
-int32_t TextServerAdvanced::name_to_tag(const String &p_name) {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].name == p_name) {
- return feature_set[i].tag;
- }
+ feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't'));
+ feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f'));
+ feature_sets.insert("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'));
+ feature_sets.insert("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'));
+ feature_sets.insert("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'));
+ feature_sets.insert("akhands", HB_TAG('a', 'k', 'h', 'n'));
+ feature_sets.insert("below_base_forms", HB_TAG('b', 'l', 'w', 'f'));
+ feature_sets.insert("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'));
+ feature_sets.insert("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'));
+ feature_sets.insert("contextual_alternates", HB_TAG('c', 'a', 'l', 't'));
+ feature_sets.insert("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'));
+ feature_sets.insert("glyph_composition", HB_TAG('c', 'c', 'm', 'p'));
+ feature_sets.insert("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'));
+ feature_sets.insert("conjunct_forms", HB_TAG('c', 'j', 'c', 't'));
+ feature_sets.insert("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'));
+ feature_sets.insert("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'));
+ feature_sets.insert("capital_spacing", HB_TAG('c', 'p', 's', 'p'));
+ feature_sets.insert("contextual_swash", HB_TAG('c', 's', 'w', 'h'));
+ feature_sets.insert("cursive_positioning", HB_TAG('c', 'u', 'r', 's'));
+ feature_sets.insert("character_variant_01", HB_TAG('c', 'v', '0', '1'));
+ feature_sets.insert("character_variant_02", HB_TAG('c', 'v', '0', '2'));
+ feature_sets.insert("character_variant_03", HB_TAG('c', 'v', '0', '3'));
+ feature_sets.insert("character_variant_04", HB_TAG('c', 'v', '0', '4'));
+ feature_sets.insert("character_variant_05", HB_TAG('c', 'v', '0', '5'));
+ feature_sets.insert("character_variant_06", HB_TAG('c', 'v', '0', '6'));
+ feature_sets.insert("character_variant_07", HB_TAG('c', 'v', '0', '7'));
+ feature_sets.insert("character_variant_08", HB_TAG('c', 'v', '0', '8'));
+ feature_sets.insert("character_variant_09", HB_TAG('c', 'v', '0', '9'));
+ feature_sets.insert("character_variant_10", HB_TAG('c', 'v', '1', '0'));
+ feature_sets.insert("character_variant_11", HB_TAG('c', 'v', '1', '1'));
+ feature_sets.insert("character_variant_12", HB_TAG('c', 'v', '1', '2'));
+ feature_sets.insert("character_variant_13", HB_TAG('c', 'v', '1', '3'));
+ feature_sets.insert("character_variant_14", HB_TAG('c', 'v', '1', '4'));
+ feature_sets.insert("character_variant_15", HB_TAG('c', 'v', '1', '5'));
+ feature_sets.insert("character_variant_16", HB_TAG('c', 'v', '1', '6'));
+ feature_sets.insert("character_variant_17", HB_TAG('c', 'v', '1', '7'));
+ feature_sets.insert("character_variant_18", HB_TAG('c', 'v', '1', '8'));
+ feature_sets.insert("character_variant_19", HB_TAG('c', 'v', '1', '9'));
+ feature_sets.insert("character_variant_20", HB_TAG('c', 'v', '2', '0'));
+ feature_sets.insert("character_variant_21", HB_TAG('c', 'v', '2', '1'));
+ feature_sets.insert("character_variant_22", HB_TAG('c', 'v', '2', '2'));
+ feature_sets.insert("character_variant_23", HB_TAG('c', 'v', '2', '3'));
+ feature_sets.insert("character_variant_24", HB_TAG('c', 'v', '2', '4'));
+ feature_sets.insert("character_variant_25", HB_TAG('c', 'v', '2', '5'));
+ feature_sets.insert("character_variant_26", HB_TAG('c', 'v', '2', '6'));
+ feature_sets.insert("character_variant_27", HB_TAG('c', 'v', '2', '7'));
+ feature_sets.insert("character_variant_28", HB_TAG('c', 'v', '2', '8'));
+ feature_sets.insert("character_variant_29", HB_TAG('c', 'v', '2', '9'));
+ feature_sets.insert("character_variant_30", HB_TAG('c', 'v', '3', '0'));
+ feature_sets.insert("character_variant_31", HB_TAG('c', 'v', '3', '1'));
+ feature_sets.insert("character_variant_32", HB_TAG('c', 'v', '3', '2'));
+ feature_sets.insert("character_variant_33", HB_TAG('c', 'v', '3', '3'));
+ feature_sets.insert("character_variant_34", HB_TAG('c', 'v', '3', '4'));
+ feature_sets.insert("character_variant_35", HB_TAG('c', 'v', '3', '5'));
+ feature_sets.insert("character_variant_36", HB_TAG('c', 'v', '3', '6'));
+ feature_sets.insert("character_variant_37", HB_TAG('c', 'v', '3', '7'));
+ feature_sets.insert("character_variant_38", HB_TAG('c', 'v', '3', '8'));
+ feature_sets.insert("character_variant_39", HB_TAG('c', 'v', '3', '9'));
+ feature_sets.insert("character_variant_40", HB_TAG('c', 'v', '4', '0'));
+ feature_sets.insert("character_variant_41", HB_TAG('c', 'v', '4', '1'));
+ feature_sets.insert("character_variant_42", HB_TAG('c', 'v', '4', '2'));
+ feature_sets.insert("character_variant_43", HB_TAG('c', 'v', '4', '3'));
+ feature_sets.insert("character_variant_44", HB_TAG('c', 'v', '4', '4'));
+ feature_sets.insert("character_variant_45", HB_TAG('c', 'v', '4', '5'));
+ feature_sets.insert("character_variant_46", HB_TAG('c', 'v', '4', '6'));
+ feature_sets.insert("character_variant_47", HB_TAG('c', 'v', '4', '7'));
+ feature_sets.insert("character_variant_48", HB_TAG('c', 'v', '4', '8'));
+ feature_sets.insert("character_variant_49", HB_TAG('c', 'v', '4', '9'));
+ feature_sets.insert("character_variant_50", HB_TAG('c', 'v', '5', '0'));
+ feature_sets.insert("character_variant_51", HB_TAG('c', 'v', '5', '1'));
+ feature_sets.insert("character_variant_52", HB_TAG('c', 'v', '5', '2'));
+ feature_sets.insert("character_variant_53", HB_TAG('c', 'v', '5', '3'));
+ feature_sets.insert("character_variant_54", HB_TAG('c', 'v', '5', '4'));
+ feature_sets.insert("character_variant_55", HB_TAG('c', 'v', '5', '5'));
+ feature_sets.insert("character_variant_56", HB_TAG('c', 'v', '5', '6'));
+ feature_sets.insert("character_variant_57", HB_TAG('c', 'v', '5', '7'));
+ feature_sets.insert("character_variant_58", HB_TAG('c', 'v', '5', '8'));
+ feature_sets.insert("character_variant_59", HB_TAG('c', 'v', '5', '9'));
+ feature_sets.insert("character_variant_60", HB_TAG('c', 'v', '6', '0'));
+ feature_sets.insert("character_variant_61", HB_TAG('c', 'v', '6', '1'));
+ feature_sets.insert("character_variant_62", HB_TAG('c', 'v', '6', '2'));
+ feature_sets.insert("character_variant_63", HB_TAG('c', 'v', '6', '3'));
+ feature_sets.insert("character_variant_64", HB_TAG('c', 'v', '6', '4'));
+ feature_sets.insert("character_variant_65", HB_TAG('c', 'v', '6', '5'));
+ feature_sets.insert("character_variant_66", HB_TAG('c', 'v', '6', '6'));
+ feature_sets.insert("character_variant_67", HB_TAG('c', 'v', '6', '7'));
+ feature_sets.insert("character_variant_68", HB_TAG('c', 'v', '6', '8'));
+ feature_sets.insert("character_variant_69", HB_TAG('c', 'v', '6', '9'));
+ feature_sets.insert("character_variant_70", HB_TAG('c', 'v', '7', '0'));
+ feature_sets.insert("character_variant_71", HB_TAG('c', 'v', '7', '1'));
+ feature_sets.insert("character_variant_72", HB_TAG('c', 'v', '7', '2'));
+ feature_sets.insert("character_variant_73", HB_TAG('c', 'v', '7', '3'));
+ feature_sets.insert("character_variant_74", HB_TAG('c', 'v', '7', '4'));
+ feature_sets.insert("character_variant_75", HB_TAG('c', 'v', '7', '5'));
+ feature_sets.insert("character_variant_76", HB_TAG('c', 'v', '7', '6'));
+ feature_sets.insert("character_variant_77", HB_TAG('c', 'v', '7', '7'));
+ feature_sets.insert("character_variant_78", HB_TAG('c', 'v', '7', '8'));
+ feature_sets.insert("character_variant_79", HB_TAG('c', 'v', '7', '9'));
+ feature_sets.insert("character_variant_80", HB_TAG('c', 'v', '8', '0'));
+ feature_sets.insert("character_variant_81", HB_TAG('c', 'v', '8', '1'));
+ feature_sets.insert("character_variant_82", HB_TAG('c', 'v', '8', '2'));
+ feature_sets.insert("character_variant_83", HB_TAG('c', 'v', '8', '3'));
+ feature_sets.insert("character_variant_84", HB_TAG('c', 'v', '8', '4'));
+ feature_sets.insert("character_variant_85", HB_TAG('c', 'v', '8', '5'));
+ feature_sets.insert("character_variant_86", HB_TAG('c', 'v', '8', '6'));
+ feature_sets.insert("character_variant_87", HB_TAG('c', 'v', '8', '7'));
+ feature_sets.insert("character_variant_88", HB_TAG('c', 'v', '8', '8'));
+ feature_sets.insert("character_variant_89", HB_TAG('c', 'v', '8', '9'));
+ feature_sets.insert("character_variant_90", HB_TAG('c', 'v', '9', '0'));
+ feature_sets.insert("character_variant_91", HB_TAG('c', 'v', '9', '1'));
+ feature_sets.insert("character_variant_92", HB_TAG('c', 'v', '9', '2'));
+ feature_sets.insert("character_variant_93", HB_TAG('c', 'v', '9', '3'));
+ feature_sets.insert("character_variant_94", HB_TAG('c', 'v', '9', '4'));
+ feature_sets.insert("character_variant_95", HB_TAG('c', 'v', '9', '5'));
+ feature_sets.insert("character_variant_96", HB_TAG('c', 'v', '9', '6'));
+ feature_sets.insert("character_variant_97", HB_TAG('c', 'v', '9', '7'));
+ feature_sets.insert("character_variant_98", HB_TAG('c', 'v', '9', '8'));
+ feature_sets.insert("character_variant_99", HB_TAG('c', 'v', '9', '9'));
+ feature_sets.insert("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'));
+ feature_sets.insert("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'));
+ feature_sets.insert("distances", HB_TAG('d', 'i', 's', 't'));
+ feature_sets.insert("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'));
+ feature_sets.insert("denominators", HB_TAG('d', 'n', 'o', 'm'));
+ feature_sets.insert("dotless_forms", HB_TAG('d', 't', 'l', 's'));
+ feature_sets.insert("expert_forms", HB_TAG('e', 'x', 'p', 't'));
+ feature_sets.insert("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'));
+ feature_sets.insert("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'));
+ feature_sets.insert("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'));
+ feature_sets.insert("terminal_forms", HB_TAG('f', 'i', 'n', 'a'));
+ feature_sets.insert("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'));
+ feature_sets.insert("fractions", HB_TAG('f', 'r', 'a', 'c'));
+ feature_sets.insert("full_widths", HB_TAG('f', 'w', 'i', 'd'));
+ feature_sets.insert("half_forms", HB_TAG('h', 'a', 'l', 'f'));
+ feature_sets.insert("halant_forms", HB_TAG('h', 'a', 'l', 'n'));
+ feature_sets.insert("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'));
+ feature_sets.insert("historical_forms", HB_TAG('h', 'i', 's', 't'));
+ feature_sets.insert("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'));
+ feature_sets.insert("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'));
+ feature_sets.insert("hangul", HB_TAG('h', 'n', 'g', 'l'));
+ feature_sets.insert("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'));
+ feature_sets.insert("half_widths", HB_TAG('h', 'w', 'i', 'd'));
+ feature_sets.insert("initial_forms", HB_TAG('i', 'n', 'i', 't'));
+ feature_sets.insert("isolated_forms", HB_TAG('i', 's', 'o', 'l'));
+ feature_sets.insert("italics", HB_TAG('i', 't', 'a', 'l'));
+ feature_sets.insert("justification_alternates", HB_TAG('j', 'a', 'l', 't'));
+ feature_sets.insert("jis78_forms", HB_TAG('j', 'p', '7', '8'));
+ feature_sets.insert("jis83_forms", HB_TAG('j', 'p', '8', '3'));
+ feature_sets.insert("jis90_forms", HB_TAG('j', 'p', '9', '0'));
+ feature_sets.insert("jis2004_forms", HB_TAG('j', 'p', '0', '4'));
+ feature_sets.insert("kerning", HB_TAG('k', 'e', 'r', 'n'));
+ feature_sets.insert("left_bounds", HB_TAG('l', 'f', 'b', 'd'));
+ feature_sets.insert("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'));
+ feature_sets.insert("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'));
+ feature_sets.insert("lining_figures", HB_TAG('l', 'n', 'u', 'm'));
+ feature_sets.insert("localized_forms", HB_TAG('l', 'o', 'c', 'l'));
+ feature_sets.insert("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'));
+ feature_sets.insert("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'));
+ feature_sets.insert("mark_positioning", HB_TAG('m', 'a', 'r', 'k'));
+ feature_sets.insert("medial_forms_2", HB_TAG('m', 'e', 'd', '2'));
+ feature_sets.insert("medial_forms", HB_TAG('m', 'e', 'd', 'i'));
+ feature_sets.insert("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'));
+ feature_sets.insert("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'));
+ feature_sets.insert("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'));
+ feature_sets.insert("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'));
+ feature_sets.insert("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'));
+ feature_sets.insert("nukta_forms", HB_TAG('n', 'u', 'k', 't'));
+ feature_sets.insert("numerators", HB_TAG('n', 'u', 'm', 'r'));
+ feature_sets.insert("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'));
+ feature_sets.insert("optical_bounds", HB_TAG('o', 'p', 'b', 'd'));
+ feature_sets.insert("ordinals", HB_TAG('o', 'r', 'd', 'n'));
+ feature_sets.insert("ornaments", HB_TAG('o', 'r', 'n', 'm'));
+ feature_sets.insert("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'));
+ feature_sets.insert("petite_capitals", HB_TAG('p', 'c', 'a', 'p'));
+ feature_sets.insert("proportional_kana", HB_TAG('p', 'k', 'n', 'a'));
+ feature_sets.insert("proportional_figures", HB_TAG('p', 'n', 'u', 'm'));
+ feature_sets.insert("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'));
+ feature_sets.insert("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'));
+ feature_sets.insert("post_base_forms", HB_TAG('p', 's', 't', 'f'));
+ feature_sets.insert("post_base_substitutions", HB_TAG('p', 's', 't', 's'));
+ feature_sets.insert("proportional_widths", HB_TAG('p', 'w', 'i', 'd'));
+ feature_sets.insert("quarter_widths", HB_TAG('q', 'w', 'i', 'd'));
+ feature_sets.insert("randomize", HB_TAG('r', 'a', 'n', 'd'));
+ feature_sets.insert("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'));
+ feature_sets.insert("rakar_forms", HB_TAG('r', 'k', 'r', 'f'));
+ feature_sets.insert("required_ligatures", HB_TAG('r', 'l', 'i', 'g'));
+ feature_sets.insert("reph_forms", HB_TAG('r', 'p', 'h', 'f'));
+ feature_sets.insert("right_bounds", HB_TAG('r', 't', 'b', 'd'));
+ feature_sets.insert("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'));
+ feature_sets.insert("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'));
+ feature_sets.insert("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'));
+ feature_sets.insert("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'));
+ feature_sets.insert("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'));
+ feature_sets.insert("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'));
+ feature_sets.insert("optical_size", HB_TAG('s', 'i', 'z', 'e'));
+ feature_sets.insert("small_capitals", HB_TAG('s', 'm', 'c', 'p'));
+ feature_sets.insert("simplified_forms", HB_TAG('s', 'm', 'p', 'l'));
+ feature_sets.insert("stylistic_set_01", HB_TAG('s', 's', '0', '1'));
+ feature_sets.insert("stylistic_set_02", HB_TAG('s', 's', '0', '2'));
+ feature_sets.insert("stylistic_set_03", HB_TAG('s', 's', '0', '3'));
+ feature_sets.insert("stylistic_set_04", HB_TAG('s', 's', '0', '4'));
+ feature_sets.insert("stylistic_set_05", HB_TAG('s', 's', '0', '5'));
+ feature_sets.insert("stylistic_set_06", HB_TAG('s', 's', '0', '6'));
+ feature_sets.insert("stylistic_set_07", HB_TAG('s', 's', '0', '7'));
+ feature_sets.insert("stylistic_set_08", HB_TAG('s', 's', '0', '8'));
+ feature_sets.insert("stylistic_set_09", HB_TAG('s', 's', '0', '9'));
+ feature_sets.insert("stylistic_set_10", HB_TAG('s', 's', '1', '0'));
+ feature_sets.insert("stylistic_set_11", HB_TAG('s', 's', '1', '1'));
+ feature_sets.insert("stylistic_set_12", HB_TAG('s', 's', '1', '2'));
+ feature_sets.insert("stylistic_set_13", HB_TAG('s', 's', '1', '3'));
+ feature_sets.insert("stylistic_set_14", HB_TAG('s', 's', '1', '4'));
+ feature_sets.insert("stylistic_set_15", HB_TAG('s', 's', '1', '5'));
+ feature_sets.insert("stylistic_set_16", HB_TAG('s', 's', '1', '6'));
+ feature_sets.insert("stylistic_set_17", HB_TAG('s', 's', '1', '7'));
+ feature_sets.insert("stylistic_set_18", HB_TAG('s', 's', '1', '8'));
+ feature_sets.insert("stylistic_set_19", HB_TAG('s', 's', '1', '9'));
+ feature_sets.insert("stylistic_set_20", HB_TAG('s', 's', '2', '0'));
+ feature_sets.insert("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'));
+ feature_sets.insert("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'));
+ feature_sets.insert("subscript", HB_TAG('s', 'u', 'b', 's'));
+ feature_sets.insert("superscript", HB_TAG('s', 'u', 'p', 's'));
+ feature_sets.insert("swash", HB_TAG('s', 'w', 's', 'h'));
+ feature_sets.insert("titling", HB_TAG('t', 'i', 't', 'l'));
+ feature_sets.insert("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'));
+ feature_sets.insert("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'));
+ feature_sets.insert("tabular_figures", HB_TAG('t', 'n', 'u', 'm'));
+ feature_sets.insert("traditional_forms", HB_TAG('t', 'r', 'a', 'd'));
+ feature_sets.insert("third_widths", HB_TAG('t', 'w', 'i', 'd'));
+ feature_sets.insert("unicase", HB_TAG('u', 'n', 'i', 'c'));
+ feature_sets.insert("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'));
+ feature_sets.insert("vattu_variants", HB_TAG('v', 'a', 't', 'u'));
+ feature_sets.insert("vertical_writing", HB_TAG('v', 'e', 'r', 't'));
+ feature_sets.insert("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'));
+ feature_sets.insert("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'));
+ feature_sets.insert("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'));
+ feature_sets.insert("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'));
+ feature_sets.insert("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'));
+ feature_sets.insert("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'));
+ feature_sets.insert("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'));
+ feature_sets.insert("slashed_zero", HB_TAG('z', 'e', 'r', 'o'));
+ // Registered OpenType variation tag.
+ feature_sets.insert("italic", HB_TAG('i', 't', 'a', 'l'));
+ feature_sets.insert("optical_size", HB_TAG('o', 'p', 's', 'z'));
+ feature_sets.insert("slant", HB_TAG('s', 'l', 'n', 't'));
+ feature_sets.insert("width", HB_TAG('w', 'd', 't', 'h'));
+ feature_sets.insert("weight", HB_TAG('w', 'g', 'h', 't'));
+}
+
+int32_t TextServerAdvanced::name_to_tag(const String &p_name) const {
+ if (feature_sets.has(p_name)) {
+ return feature_sets[p_name];
}
// No readable name, use tag string.
return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
}
-String TextServerAdvanced::tag_to_name(int32_t p_tag) {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].tag == p_tag) {
- return feature_set[i].name;
+String TextServerAdvanced::tag_to_name(int32_t p_tag) const {
+ for (const KeyValue<StringName, int32_t> &E : feature_sets) {
+ if (E.value == p_tag) {
+ return E.key;
}
}
@@ -523,426 +717,2095 @@ String TextServerAdvanced::tag_to_name(int32_t p_tag) {
}
/*************************************************************************/
-/* Font interface */
+/* Font Glyph Rendering */
/*************************************************************************/
-RID TextServerAdvanced::create_font_system(const String &p_name, int p_base_size) {
- ERR_FAIL_V_MSG(RID(), "System fonts are not supported by this text server.");
+_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const {
+ FontTexturePosition ret;
+ ret.index = -1;
+
+ int mw = p_width;
+ int mh = p_height;
+
+ for (int i = 0; i < p_data->textures.size(); i++) {
+ const FontTexture &ct = p_data->textures[i];
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (ct.texture->get_format() != p_image_format) {
+ continue;
+ }
+ }
+
+ if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
+ continue;
+ }
+
+ ret.y = 0x7FFFFFFF;
+ ret.x = 0;
+
+ for (int j = 0; j < ct.texture_w - mw; j++) {
+ int max_y = 0;
+
+ for (int k = j; k < j + mw; k++) {
+ int y = ct.offsets[k];
+ if (y > max_y) {
+ max_y = y;
+ }
+ }
+
+ if (max_y < ret.y) {
+ ret.y = max_y;
+ ret.x = j;
+ }
+ }
+
+ if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_h) {
+ continue; // Fail, could not fit it here.
+ }
+
+ ret.index = i;
+ break;
+ }
+
+ if (ret.index == -1) {
+ // Could not find texture to fit, create one.
+ ret.x = 0;
+ ret.y = 0;
+
+ int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
+ if (mw > texsize) {
+ texsize = mw; // Special case, adapt to it?
+ }
+ if (mh > texsize) {
+ texsize = mh; // Special case, adapt to it?
+ }
+
+ texsize = next_power_of_2(texsize);
+
+ texsize = MIN(texsize, 4096);
+
+ FontTexture tex;
+ tex.texture_w = texsize;
+ tex.texture_h = texsize;
+ tex.format = p_image_format;
+ tex.imgdata.resize(texsize * texsize * p_color_size);
+
+ {
+ // Zero texture.
+ uint8_t *w = tex.imgdata.ptrw();
+ ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.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) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.
+ w[i + 0] = 255;
+ w[i + 1] = 0;
+ }
+ } else if (p_color_size == 4) {
+ for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.
+ w[i + 0] = 255;
+ w[i + 1] = 255;
+ w[i + 2] = 255;
+ w[i + 3] = 0;
+ }
+ } else {
+ ERR_FAIL_V(ret);
+ }
+ }
+ tex.offsets.resize(texsize);
+ for (int i = 0; i < texsize; i++) { // Zero offsets.
+ tex.offsets.write[i] = 0;
+ }
+
+ p_data->textures.push_back(tex);
+ ret.index = p_data->textures.size() - 1;
+ }
+
+ return ret;
}
-RID TextServerAdvanced::create_font_resource(const String &p_filename, int p_base_size) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = nullptr;
- if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
- fd = memnew(BitmapFontDataAdvanced);
+#ifdef MODULE_MSDFGEN_ENABLED
+
+struct MSContext {
+ msdfgen::Point2 position;
+ msdfgen::Shape *shape;
+ msdfgen::Contour *contour;
+};
+
+class DistancePixelConversion {
+ double invRange;
+
+public:
+ _FORCE_INLINE_ explicit DistancePixelConversion(double range) :
+ invRange(1 / range) {}
+ _FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {
+ pixels[0] = float(invRange * distance.r + .5);
+ pixels[1] = float(invRange * distance.g + .5);
+ pixels[2] = float(invRange * distance.b + .5);
+ pixels[3] = float(invRange * distance.a + .5);
+ }
+};
+
+struct MSDFThreadData {
+ msdfgen::Bitmap<float, 4> *output;
+ msdfgen::Shape *shape;
+ msdfgen::Projection *projection;
+ DistancePixelConversion *distancePixelConversion;
+};
+
+static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
+ return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);
+}
+
+static int ft_move_to(const FT_Vector *to, void *user) {
+ MSContext *context = reinterpret_cast<MSContext *>(user);
+ if (!(context->contour && context->contour->edges.empty())) {
+ context->contour = &context->shape->addContour();
+ }
+ context->position = ft_point2(*to);
+ return 0;
+}
+
+static int ft_line_to(const FT_Vector *to, void *user) {
+ MSContext *context = reinterpret_cast<MSContext *>(user);
+ msdfgen::Point2 endpoint = ft_point2(*to);
+ if (endpoint != context->position) {
+ context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
+ context->position = endpoint;
+ }
+ return 0;
+}
+
+static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
+ MSContext *context = reinterpret_cast<MSContext *>(user);
+ context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
+ context->position = ft_point2(*to);
+ return 0;
+}
+
+static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
+ MSContext *context = reinterpret_cast<MSContext *>(user);
+ context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
+ context->position = ft_point2(*to);
+ return 0;
+}
+
+void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+ MSDFThreadData *td = (MSDFThreadData *)p_td;
+
+ msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
+ int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+ for (int col = 0; col < td->output->width(); ++col) {
+ int x = (y % 2) ? td->output->width() - col - 1 : col;
+ msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+ msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
+ td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
+ }
+}
+
+_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(FontDataAdvanced *p_font_data, FontDataForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const {
+ msdfgen::Shape shape;
+
+ shape.contours.clear();
+ shape.inverseYAxis = false;
+
+ MSContext context = {};
+ context.shape = &shape;
+ FT_Outline_Funcs ft_functions;
+ ft_functions.move_to = &ft_move_to;
+ ft_functions.line_to = &ft_line_to;
+ ft_functions.conic_to = &ft_conic_to;
+ ft_functions.cubic_to = &ft_cubic_to;
+ ft_functions.shift = 0;
+ ft_functions.delta = 0;
+
+ int error = FT_Outline_Decompose(outline, &ft_functions, &context);
+ ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");
+ if (!shape.contours.empty() && shape.contours.back().edges.empty()) {
+ shape.contours.pop_back();
+ }
+
+ if (FT_Outline_Get_Orientation(outline) == 1) {
+ for (int i = 0; i < (int)shape.contours.size(); ++i) {
+ shape.contours[i].reverse();
+ }
+ }
+
+ shape.inverseYAxis = true;
+ shape.normalize();
+
+ msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);
+
+ FontGlyph chr;
+ chr.found = true;
+ chr.advance = advance.round();
+
+ if (shape.validate() && shape.contours.size() > 0) {
+ int w = (bounds.r - bounds.l);
+ int h = (bounds.t - bounds.b);
+
+ int mw = w + p_rect_margin * 2;
+ int mh = h + p_rect_margin * 2;
+
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
+
+ FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh);
+ ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
+ FontTexture &tex = p_data->textures.write[tex_pos.index];
+
+ edgeColoringSimple(shape, 3.0); // Max. angle.
+ msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
+ //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
+
+ DistancePixelConversion distancePixelConversion(p_pixel_range);
+ msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
+ msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());
+
+ MSDFThreadData td;
+ td.output = &image;
+ td.shape = &shape;
+ td.projection = &projection;
+ td.distancePixelConversion = &distancePixelConversion;
+
+ if (p_font_data->work_pool.get_thread_count() == 0) {
+ p_font_data->work_pool.init();
+ }
+ p_font_data->work_pool.do_work(h, this, &TextServerAdvanced::_generateMTSDF_threaded, &td);
+
+ msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
+
+ {
+ uint8_t *wr = tex.imgdata.ptrw();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4;
+ ERR_FAIL_COND_V(ofs >= tex.imgdata.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));
+ wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));
+ //wr[ofs + 0] = 100;
+ //wr[ofs + 1] = 100;
+ //wr[ofs + 2] = 100;
+ //wr[ofs + 3] = 100;
+ }
+ }
+ }
+
+ // Blit to image and texture.
+ {
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata));
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ }
+ }
+
+ // Update height array.
+ for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
+ tex.offsets.write[k] = tex_pos.y + mh;
+ }
+
+ chr.texture_idx = tex_pos.index;
+
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
+ chr.rect.position = Vector2(bounds.l, -bounds.t);
+ chr.rect.size = chr.uv_rect.size;
+ }
+ return chr;
+}
+#endif
+
#ifdef MODULE_FREETYPE_ENABLED
- } else if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
- fd = memnew(DynamicFontDataAdvanced);
+_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontDataForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const {
+ int w = bitmap.width;
+ int h = bitmap.rows;
+
+ int mw = w + p_rect_margin * 2;
+ int mh = h + p_rect_margin * 2;
+
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
+
+ int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
+ Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
+
+ FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh);
+ ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
+
+ // Fit character in char texture.
+
+ FontTexture &tex = p_data->textures.write[tex_pos.index];
+
+ {
+ uint8_t *wr = tex.imgdata.ptrw();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size;
+ ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO: {
+ int byte = i * bitmap.pitch + (j >> 3);
+ int bit = 1 << (7 - (j % 8));
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
+ } break;
+ case FT_PIXEL_MODE_GRAY:
+ wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
+ //wr[ofs + 1] = 100;
+ break;
+ case FT_PIXEL_MODE_BGRA: {
+ int ofs_color = i * bitmap.pitch + (j << 2);
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
+ } break;
+ default:
+ ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + itos(bitmap.pixel_mode) + ".");
+ break;
+ }
+ }
+ }
+ }
+
+ // Blit to image and texture.
+ {
+ if (RenderingServer::get_singleton() != nullptr) {
+ Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata));
+
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ }
+ }
+
+ // Update height array.
+ for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
+ tex.offsets.write[k] = tex_pos.y + mh;
+ }
+
+ FontGlyph chr;
+ chr.advance = (advance * p_data->scale / p_data->oversampling).round();
+ 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.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
+ return chr;
+}
#endif
- } else {
- return RID();
+
+/*************************************************************************/
+/* Font Cache */
+/*************************************************************************/
+
+_FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const {
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false);
+
+ FontDataForSizeAdvanced *fd = p_font_data->cache[p_size];
+ if (fd->glyph_map.has(p_glyph)) {
+ return fd->glyph_map[p_glyph].found;
}
- Error err = fd->load_from_file(p_filename, p_base_size);
- if (err != OK) {
- memdelete(fd);
- return RID();
+ if (p_glyph == 0) { // Non graphical or invalid glyph, do not render.
+ fd->glyph_map[p_glyph] = FontGlyph();
+ return true;
}
- return font_owner.make_rid(fd);
+#ifdef MODULE_FREETYPE_ENABLED
+ FontGlyph gl;
+ if (fd->face) {
+ FT_Int32 flags = FT_LOAD_DEFAULT;
+
+ bool outline = p_size.y > 0;
+ switch (p_font_data->hinting) {
+ case TextServer::HINTING_NONE:
+ flags |= FT_LOAD_NO_HINTING;
+ break;
+ case TextServer::HINTING_LIGHT:
+ flags |= FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ flags |= FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+ if (p_font_data->force_autohinter) {
+ flags |= FT_LOAD_FORCE_AUTOHINT;
+ }
+ if (outline) {
+ flags |= FT_LOAD_NO_BITMAP;
+ } else if (FT_HAS_COLOR(fd->face)) {
+ flags |= FT_LOAD_COLOR;
+ }
+
+ FT_Fixed v, h;
+ FT_Get_Advance(fd->face, p_glyph, flags, &h);
+ FT_Get_Advance(fd->face, p_glyph, flags | FT_LOAD_VERTICAL_LAYOUT, &v);
+
+ int error = FT_Load_Glyph(fd->face, p_glyph, flags);
+ if (error) {
+ fd->glyph_map[p_glyph] = FontGlyph();
+ return false;
+ }
+
+ if (!outline) {
+ if (!p_font_data->msdf) {
+ error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ }
+ FT_GlyphSlot slot = fd->face->glyph;
+ if (!error) {
+ if (p_font_data->msdf) {
+#ifdef MODULE_MSDFGEN_ENABLED
+ gl = rasterize_msdf(p_font_data, fd, p_font_data->msdf_range, rect_range, &slot->outline, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+#else
+ fd->glyph_map[p_glyph] = FontGlyph();
+ ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
+#endif
+ } else {
+ gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ }
+ }
+ } else {
+ FT_Stroker stroker;
+ if (FT_Stroker_New(library, &stroker) != 0) {
+ fd->glyph_map[p_glyph] = FontGlyph();
+ ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");
+ }
+
+ FT_Stroker_Set(stroker, (int)(fd->size.y * fd->oversampling * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
+ FT_Glyph glyph;
+ FT_BitmapGlyph glyph_bitmap;
+
+ if (FT_Get_Glyph(fd->face->glyph, &glyph) != 0) {
+ goto cleanup_stroker;
+ }
+ if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
+ goto cleanup_glyph;
+ }
+ if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ goto cleanup_glyph;
+ }
+ glyph_bitmap = (FT_BitmapGlyph)glyph;
+ gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+
+ cleanup_glyph:
+ FT_Done_Glyph(glyph);
+ cleanup_stroker:
+ FT_Stroker_Done(stroker);
+ }
+ fd->glyph_map[p_glyph] = gl;
+ return gl.found;
+ }
+#endif
+ fd->glyph_map[p_glyph] = FontGlyph();
+ return false;
}
-RID TextServerAdvanced::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = nullptr;
- if (p_type == "fnt" || p_type == "font") {
- fd = memnew(BitmapFontDataAdvanced);
+_FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced *p_font_data, const Vector2i &p_size) const {
+ if (p_font_data->cache.has(p_size)) {
+ return true;
+ }
+
+ FontDataForSizeAdvanced *fd = memnew(FontDataForSizeAdvanced);
+ fd->size = p_size;
+ if (p_font_data->data_ptr) {
+ // Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
- } else if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
- fd = memnew(DynamicFontDataAdvanced);
+ int error = 0;
+ if (!library) {
+ error = FT_Init_FreeType(&library);
+ ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
+
+ memset(&fd->stream, 0, sizeof(FT_StreamRec));
+ fd->stream.base = (unsigned char *)p_font_data->data_ptr;
+ fd->stream.size = p_font_data->data_size;
+ fd->stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
+ fargs.memory_size = p_font_data->data_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &fd->stream;
+ error = FT_Open_Face(library, &fargs, 0, &fd->face);
+ if (error) {
+ FT_Done_Face(fd->face);
+ fd->face = nullptr;
+ ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
+ }
+
+ if (p_font_data->msdf) {
+ fd->oversampling = 1.0f;
+ fd->size.x = p_font_data->msdf_source_size;
+ } else if (p_font_data->oversampling <= 0.0f) {
+ fd->oversampling = font_get_global_oversampling();
+ } else {
+ fd->oversampling = p_font_data->oversampling;
+ }
+
+ if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
+ int best_match = 0;
+ int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+ for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
+ int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
+ if (ndiff < diff) {
+ best_match = i;
+ diff = ndiff;
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+ }
+ }
+ FT_Select_Size(fd->face, best_match);
+ } else {
+ FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling);
+ }
+
+ fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
+
+ fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
+ fd->descent = (-fd->face->size->metrics.descender / 64.0) / fd->oversampling * fd->scale;
+ fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
+ fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
+
+ if (!p_font_data->face_init) {
+ // Get supported scripts from OpenType font data.
+ p_font_data->supported_scripts.clear();
+ unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
+ if (count != 0) {
+ hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ p_font_data->supported_scripts.insert(script_tags[i]);
+ }
+ memfree(script_tags);
+ }
+ count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
+ if (count != 0) {
+ hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ p_font_data->supported_scripts.insert(script_tags[i]);
+ }
+ memfree(script_tags);
+ }
+
+ // Get supported scripts from OS2 table.
+ TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fd->face, FT_SFNT_OS2);
+ if (os2) {
+ if ((os2->ulUnicodeRange1 & 1L << 4) || (os2->ulUnicodeRange1 & 1L << 5) || (os2->ulUnicodeRange1 & 1L << 6) || (os2->ulUnicodeRange1 & 1L << 31) || (os2->ulUnicodeRange2 & 1L << 0) || (os2->ulUnicodeRange2 & 1L << 1) || (os2->ulUnicodeRange2 & 1L << 2) || (os2->ulUnicodeRange2 & 1L << 3) || (os2->ulUnicodeRange2 & 1L << 4) || (os2->ulUnicodeRange2 & 1L << 5) || (os2->ulUnicodeRange2 & 1L << 6) || (os2->ulUnicodeRange2 & 1L << 7) || (os2->ulUnicodeRange2 & 1L << 8) || (os2->ulUnicodeRange2 & 1L << 9) || (os2->ulUnicodeRange2 & 1L << 10) || (os2->ulUnicodeRange2 & 1L << 11) || (os2->ulUnicodeRange2 & 1L << 12) || (os2->ulUnicodeRange2 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 14) || (os2->ulUnicodeRange2 & 1L << 15) || (os2->ulUnicodeRange2 & 1L << 30) || (os2->ulUnicodeRange3 & 1L << 0) || (os2->ulUnicodeRange3 & 1L << 1) || (os2->ulUnicodeRange3 & 1L << 2) || (os2->ulUnicodeRange3 & 1L << 4) || (os2->ulUnicodeRange3 & 1L << 5) || (os2->ulUnicodeRange3 & 1L << 18) || (os2->ulUnicodeRange3 & 1L << 24) || (os2->ulUnicodeRange3 & 1L << 25) || (os2->ulUnicodeRange3 & 1L << 26) || (os2->ulUnicodeRange3 & 1L << 27) || (os2->ulUnicodeRange3 & 1L << 28) || (os2->ulUnicodeRange4 & 1L << 3) || (os2->ulUnicodeRange4 & 1L << 6) || (os2->ulUnicodeRange4 & 1L << 15) || (os2->ulUnicodeRange4 & 1L << 23) || (os2->ulUnicodeRange4 & 1L << 24) || (os2->ulUnicodeRange4 & 1L << 26)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_COMMON);
+ }
+ if ((os2->ulUnicodeRange1 & 1L << 0) || (os2->ulUnicodeRange1 & 1L << 1) || (os2->ulUnicodeRange1 & 1L << 2) || (os2->ulUnicodeRange1 & 1L << 3) || (os2->ulUnicodeRange1 & 1L << 29)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_LATIN);
+ }
+ if ((os2->ulUnicodeRange1 & 1L << 7) || (os2->ulUnicodeRange1 & 1L << 30)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GREEK);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 8) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_COPTIC);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 9) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CYRILLIC);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 10) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_ARMENIAN);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 11) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_HEBREW);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 12) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_VAI);
+ }
+ if ((os2->ulUnicodeRange1 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 31) || (os2->ulUnicodeRange3 & 1L << 3)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_ARABIC);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 14) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_NKO);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 15) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_DEVANAGARI);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 16) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_BENGALI);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 17) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GURMUKHI);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 18) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GUJARATI);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 19) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_ORIYA);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 20) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TAMIL);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 21) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TELUGU);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 22) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_KANNADA);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 23) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_MALAYALAM);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 24) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_THAI);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 25) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_LAO);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 26) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GEORGIAN);
+ }
+ if (os2->ulUnicodeRange1 & 1L << 27) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_BALINESE);
+ }
+ if ((os2->ulUnicodeRange1 & 1L << 28) || (os2->ulUnicodeRange2 & 1L << 20) || (os2->ulUnicodeRange2 & 1L << 24)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_HANGUL);
+ }
+ if ((os2->ulUnicodeRange2 & 1L << 21) || (os2->ulUnicodeRange2 & 1L << 22) || (os2->ulUnicodeRange2 & 1L << 23) || (os2->ulUnicodeRange2 & 1L << 26) || (os2->ulUnicodeRange2 & 1L << 27) || (os2->ulUnicodeRange2 & 1L << 29)) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_HAN);
+ }
+ if (os2->ulUnicodeRange2 & 1L << 17) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_HIRAGANA);
+ }
+ if (os2->ulUnicodeRange2 & 1L << 18) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_KATAKANA);
+ }
+ if (os2->ulUnicodeRange2 & 1L << 19) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_BOPOMOFO);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 6) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TIBETAN);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 7) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SYRIAC);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 8) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_THAANA);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 9) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SINHALA);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 10) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_MYANMAR);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 11) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_ETHIOPIC);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 12) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CHEROKEE);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 13) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CANADIAN_SYLLABICS);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 14) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_OGHAM);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 15) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_RUNIC);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 16) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_KHMER);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 17) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_MONGOLIAN);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 19) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_YI);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 20) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_HANUNOO);
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TAGBANWA);
+ p_font_data->supported_scripts.insert(HB_SCRIPT_BUHID);
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TAGALOG);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 21) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_ITALIC);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 22) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GOTHIC);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 23) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_DESERET);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 29) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_LIMBU);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 30) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_LE);
+ }
+ if (os2->ulUnicodeRange3 & 1L << 31) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_NEW_TAI_LUE);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 0) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_BUGINESE);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 1) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_GLAGOLITIC);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 2) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TIFINAGH);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 4) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SYLOTI_NAGRI);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 5) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_LINEAR_B);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 7) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_UGARITIC);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 8) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_PERSIAN);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 9) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SHAVIAN);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 10) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_OSMANYA);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 11) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CYPRIOT);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 12) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_KHAROSHTHI);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 13) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_VIET);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 14) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CUNEIFORM);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 16) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SUNDANESE);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 17) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_LEPCHA);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 18) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_OL_CHIKI);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 19) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_SAURASHTRA);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 20) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_KAYAH_LI);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 21) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_REJANG);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 22) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_CHAM);
+ }
+ if (os2->ulUnicodeRange4 & 1L << 25) {
+ p_font_data->supported_scripts.insert(HB_SCRIPT_ANATOLIAN_HIEROGLYPHS);
+ }
+ }
+
+ // Read OpenType feature tags.
+ p_font_data->supported_features.clear();
+ count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
+ if (count != 0) {
+ hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_feature_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ p_font_data->supported_features[feature_tags[i]] = 1;
+ }
+ memfree(feature_tags);
+ }
+ count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
+ if (count != 0) {
+ hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
+ hb_ot_layout_table_get_feature_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags);
+ for (unsigned int i = 0; i < count; i++) {
+ p_font_data->supported_features[feature_tags[i]] = 1;
+ }
+ memfree(feature_tags);
+ }
+
+ // Read OpenType variations.
+ p_font_data->supported_varaitions.clear();
+ if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+ FT_Get_MM_Var(fd->face, &amaster);
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ p_font_data->supported_varaitions[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
+ }
+ FT_Done_MM_Var(library, amaster);
+ }
+ p_font_data->face_init = true;
+ }
+
+ // Write variations.
+ if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fd->face, &amaster);
+
+ Vector<hb_variation_t> hb_vars;
+ Vector<FT_Fixed> coords;
+ coords.resize(amaster->num_axis);
+
+ FT_Get_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ hb_variation_t var;
+
+ // Reset to default.
+ var.tag = amaster->axis[i].tag;
+ var.value = (double)amaster->axis[i].def / 65536.f;
+ coords.write[i] = amaster->axis[i].def;
+
+ if (p_font_data->variation_coordinates.has(var.tag)) {
+ var.value = p_font_data->variation_coordinates[var.tag];
+ coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ if (p_font_data->variation_coordinates.has(tag_to_name(var.tag))) {
+ var.value = p_font_data->variation_coordinates[tag_to_name(var.tag)];
+ coords.write[i] = CLAMP(var.value * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ hb_vars.push_back(var);
+ }
+
+ FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
+ hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
+ FT_Done_MM_Var(library, amaster);
+ }
+#else
+ ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
} else {
- return RID();
+ // Init bitmap font.
+ fd->hb_handle = hb_bmp_font_create(fd, nullptr);
}
+ p_font_data->cache[p_size] = fd;
+ return true;
+}
- Error err = fd->load_from_memory(p_data, p_size, p_base_size);
- if (err != OK) {
- memdelete(fd);
- return RID();
+_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_font_data) {
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : p_font_data->cache) {
+ memdelete(E.value);
}
+ p_font_data->cache.clear();
+ p_font_data->face_init = false;
+ p_font_data->supported_features.clear();
+ p_font_data->supported_varaitions.clear();
+ p_font_data->supported_scripts.clear();
+}
+
+hb_font_t *TextServerAdvanced::_font_get_hb_handle(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, nullptr);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), nullptr);
+
+ return fd->cache[size]->hb_handle;
+}
+
+RID TextServerAdvanced::create_font() {
+ FontDataAdvanced *fd = memnew(FontDataAdvanced);
return font_owner.make_rid(fd);
}
-RID TextServerAdvanced::create_font_bitmap(float p_height, float p_ascent, int p_base_size) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = memnew(BitmapFontDataAdvanced);
- Error err = fd->bitmap_new(p_height, p_ascent, p_base_size);
- if (err != OK) {
- memdelete(fd);
- return RID();
+void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ _font_clear_cache(fd);
+ fd->data = p_data;
+ fd->data_ptr = fd->data.ptr();
+ fd->data_size = fd->data.size();
+}
+
+void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ _font_clear_cache(fd);
+ fd->data.clear();
+ fd->data_ptr = p_data_ptr;
+ fd->data_size = p_data_size;
+}
+
+void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->antialiased != p_antialiased) {
+ _font_clear_cache(fd);
+ fd->antialiased = p_antialiased;
}
+}
- return font_owner.make_rid(fd);
+bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->antialiased;
}
-void TextServerAdvanced::font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->bitmap_add_texture(p_texture);
+
+ MutexLock lock(fd->mutex);
+ if (fd->msdf != p_msdf) {
+ _font_clear_cache(fd);
+ fd->msdf = p_msdf;
+ }
}
-void TextServerAdvanced::font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->msdf;
+}
+
+void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->bitmap_add_char(p_char, p_texture_idx, p_rect, p_align, p_advance);
+
+ MutexLock lock(fd->mutex);
+ if (fd->msdf_range != p_msdf_pixel_range) {
+ _font_clear_cache(fd);
+ fd->msdf_range = p_msdf_pixel_range;
+ }
}
-void TextServerAdvanced::font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->msdf_range;
+}
+
+void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->bitmap_add_kerning_pair(p_A, p_B, p_kerning);
+
+ MutexLock lock(fd->mutex);
+ if (fd->msdf_source_size != p_msdf_size) {
+ _font_clear_cache(fd);
+ fd->msdf_source_size = p_msdf_size;
+ }
}
-float TextServerAdvanced::font_get_height(RID p_font, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->msdf_source_size;
+}
+
+void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->fixed_size != p_fixed_size) {
+ fd->fixed_size = p_fixed_size;
+ }
+}
+
+int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->fixed_size;
+}
+
+void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->force_autohinter != p_force_autohinter) {
+ _font_clear_cache(fd);
+ fd->force_autohinter = p_force_autohinter;
+ }
+}
+
+bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->force_autohinter;
+}
+
+void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->hinting != p_hinting) {
+ _font_clear_cache(fd);
+ fd->hinting = p_hinting;
+ }
+}
+
+TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, HINTING_NONE);
+
+ MutexLock lock(fd->mutex);
+ return fd->hinting;
+}
+
+void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->variation_coordinates != p_variation_coordinates) {
+ _font_clear_cache(fd);
+ fd->variation_coordinates = p_variation_coordinates;
+ }
+}
+
+Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+
+ MutexLock lock(fd->mutex);
+ return fd->variation_coordinates;
+}
+
+void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->oversampling != p_oversampling) {
+ _font_clear_cache(fd);
+ fd->oversampling = p_oversampling;
+ }
+}
+
+float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_height(p_size);
+
+ MutexLock lock(fd->mutex);
+ return fd->oversampling;
}
-float TextServerAdvanced::font_get_ascent(RID p_font, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Array());
+
+ MutexLock lock(fd->mutex);
+ Array ret;
+ for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = fd->cache.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ memdelete(E.value);
+ }
+ fd->cache.clear();
+}
+
+void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->cache.has(p_size)) {
+ memdelete(fd->cache[p_size]);
+ fd->cache.erase(p_size);
+ }
+}
+
+void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->ascent = p_ascent;
+}
+
+float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_ascent(p_size);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+
+ if (fd->msdf) {
+ return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->ascent;
+ }
}
-float TextServerAdvanced::font_get_descent(RID p_font, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->descent = p_descent;
+}
+
+float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0.f);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+
+ if (fd->msdf) {
+ return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->descent;
+ }
+}
+
+void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->underline_position = p_underline_position;
+}
+
+float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_descent(p_size);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+
+ if (fd->msdf) {
+ return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->underline_position;
+ }
}
-float TextServerAdvanced::font_get_underline_position(RID p_font, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->underline_thickness = p_underline_thickness;
+}
+
+float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_underline_position(p_size);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+
+ if (fd->msdf) {
+ return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->underline_thickness;
+ }
}
-float TextServerAdvanced::font_get_underline_thickness(RID p_font, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->scale = p_scale;
+}
+
+float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_underline_thickness(p_size);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
+
+ if (fd->msdf) {
+ return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->scale / fd->cache[size]->oversampling;
+ }
}
-int TextServerAdvanced::font_get_spacing_space(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ switch (p_spacing) {
+ case TextServer::SPACING_GLYPH: {
+ fd->cache[size]->spacing_glyph = p_value;
+ } break;
+ case TextServer::SPACING_SPACE: {
+ fd->cache[size]->spacing_space = p_value;
+ } break;
+ default: {
+ ERR_FAIL_MSG("Invalid spacing type: " + itos(p_spacing));
+ } break;
+ }
+}
+
+int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
- return fd->get_spacing_space();
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
+
+ switch (p_spacing) {
+ case TextServer::SPACING_GLYPH: {
+ if (fd->msdf) {
+ return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->spacing_glyph;
+ }
+ } break;
+ case TextServer::SPACING_SPACE: {
+ if (fd->msdf) {
+ return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return fd->cache[size]->spacing_space;
+ }
+ } break;
+ default: {
+ ERR_FAIL_V_MSG(0, "Invalid spacing type: " + itos(p_spacing));
+ } break;
+ }
+ return 0;
}
-void TextServerAdvanced::font_set_spacing_space(RID p_font, int p_value) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
+
+ return fd->cache[size]->textures.size();
+}
+
+void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_spacing_space(p_value);
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->textures.clear();
}
-int TextServerAdvanced::font_get_spacing_glyph(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, 0);
- return fd->get_spacing_glyph();
+void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size());
+
+ fd->cache[size]->textures.remove(p_texture_index);
}
-void TextServerAdvanced::font_set_spacing_glyph(RID p_font, int p_value) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_spacing_glyph(p_value);
+ ERR_FAIL_COND(p_image.is_null());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ ERR_FAIL_COND(p_texture_index < 0);
+ if (p_texture_index >= fd->cache[size]->textures.size()) {
+ fd->cache[size]->textures.resize(p_texture_index + 1);
+ }
+
+ FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+
+ tex.imgdata = p_image->get_data();
+ tex.texture_w = p_image->get_width();
+ tex.texture_h = p_image->get_height();
+ tex.format = p_image->get_format();
+
+ Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+ tex.texture = Ref<ImageTexture>();
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
}
-void TextServerAdvanced::font_set_antialiased(RID p_font, bool p_antialiased) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Ref<Image>());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
+ ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
+
+ const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ Ref<Image> img = memnew(Image(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata));
+
+ return img;
+}
+
+void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_antialiased(p_antialiased);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ if (p_texture_index >= fd->cache[size]->textures.size()) {
+ fd->cache[size]->textures.resize(p_texture_index + 1);
+ }
+
+ FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ tex.offsets = p_offset;
}
-Dictionary TextServerAdvanced::font_get_feature_list(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Dictionary());
- return fd->get_feature_list();
+PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, PackedInt32Array());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
+ ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
+
+ const FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ return tex.offsets;
}
-bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- return fd->get_antialiased();
+Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Array());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+
+ Array ret;
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ const int32_t *E = nullptr;
+ while ((E = gl.next(E))) {
+ ret.push_back(*E);
+ }
+ return ret;
}
-Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Dictionary());
- return fd->get_variation_list();
+void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ fd->cache[size]->glyph_map.clear();
}
-void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_variation(p_name, p_value);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ fd->cache[size]->glyph_map.erase(p_glyph);
}
-double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, 0);
- return fd->get_variation(p_name);
+Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Vector2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Vector2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ if (fd->msdf) {
+ return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return gl[p_glyph].advance;
+ }
}
-void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_distance_field_hint(p_distance_field);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ gl[p_glyph].advance = p_advance;
+ gl[p_glyph].found = true;
}
-bool TextServerAdvanced::font_get_distance_field_hint(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- return fd->get_distance_field_hint();
+Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Vector2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Vector2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ if (fd->msdf) {
+ return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
+ } else {
+ return gl[p_glyph].rect.position;
+ }
}
-void TextServerAdvanced::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_hinting(p_hinting);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ gl[p_glyph].rect.position = p_offset;
+ gl[p_glyph].found = true;
}
-TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, TextServer::HINTING_NONE);
- return fd->get_hinting();
+Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Vector2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Vector2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ if (fd->msdf) {
+ return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
+ } else {
+ return gl[p_glyph].rect.size;
+ }
}
-void TextServerAdvanced::font_set_force_autohinter(RID p_font, bool p_enabeld) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->set_force_autohinter(p_enabeld);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ gl[p_glyph].rect.size = p_gl_size;
+ gl[p_glyph].found = true;
}
-bool TextServerAdvanced::font_get_force_autohinter(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- return fd->get_force_autohinter();
+Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Rect2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Rect2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ return gl[p_glyph].uv_rect;
}
-bool TextServerAdvanced::font_has_char(RID p_font, char32_t p_char) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ gl[p_glyph].uv_rect = p_uv_rect;
+ gl[p_glyph].found = true;
+}
+
+int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, -1);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1);
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return -1; // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ return gl[p_glyph].texture_idx;
+}
+
+void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+
+ HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+
+ gl[p_glyph].texture_idx = p_texture_idx;
+ gl[p_glyph].found = true;
+}
+
+Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+
+ Vector<Vector3> points;
+ Vector<int32_t> contours;
+ bool orientation;
+#ifdef MODULE_FREETYPE_ENABLED
+ int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, Dictionary());
+
+ points.clear();
+ contours.clear();
+
+ float h = fd->cache[size]->ascent;
+ float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+ if (fd->msdf) {
+ scale = scale * (float)p_size / (float)fd->msdf_source_size;
+ }
+ for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
+ points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
+ }
+ for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
+ contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
+ }
+ orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+#else
+ return Dictionary();
+#endif
+
+ Dictionary out;
+ out["points"] = points;
+ out["contours"] = contours;
+ out["orientation"] = orientation;
+ return out;
+}
+
+Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Array());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+
+ Array ret;
+ for (const Map<Vector2i, Vector2>::Element *E = fd->cache[size]->kerning_map.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->kerning_map.clear();
+}
+
+void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->kerning_map.erase(p_glyph_pair);
+}
+
+void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning;
+}
+
+Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Vector2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
+
+ const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
+
+ if (kern.has(p_glyph_pair)) {
+ if (fd->msdf) {
+ return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return kern[p_glyph_pair];
+ }
+ } else {
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->face) {
+ FT_Vector delta;
+ FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
+ if (fd->msdf) {
+ return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
+ } else {
+ return Vector2(delta.x, delta.y);
+ }
+ }
+#endif
+ }
+ return Vector2();
+}
+
+int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
+
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->face) {
+ if (p_variation_selector) {
+ return FT_Face_GetCharVariantIndex(fd->cache[size]->face, p_char, p_variation_selector);
+ } else {
+ return FT_Get_Char_Index(fd->cache[size]->face, p_char);
+ }
+ } else {
+ return 0;
+ }
+#else
+ return (int32_t)p_char;
+#endif
+}
+
+bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
- return fd->has_char(p_char);
+
+ MutexLock lock(fd->mutex);
+ if (fd->cache.is_empty()) {
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
+ }
+ FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+
+#ifdef MODULE_FREETYPE_ENABLED
+ if (at_size && at_size->face) {
+ return FT_Get_Char_Index(at_size->face, p_char) != 0;
+ }
+#endif
+ return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false;
}
-String TextServerAdvanced::font_get_supported_chars(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
- return fd->get_supported_chars();
+
+ MutexLock lock(fd->mutex);
+ if (fd->cache.is_empty()) {
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
+ }
+ FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+
+ String chars;
+#ifdef MODULE_FREETYPE_ENABLED
+ if (at_size && at_size->face) {
+ FT_UInt gindex;
+ FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
+ while (gindex != 0) {
+ if (charcode != 0) {
+ chars += char32_t(charcode);
+ }
+ charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
+ }
+ return chars;
+ }
+#endif
+ if (at_size) {
+ const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
+ const int32_t *E = nullptr;
+ while ((E = gl.next(E))) {
+ chars += char32_t(*E);
+ }
+ }
+ return chars;
}
-bool TextServerAdvanced::font_has_outline(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- return fd->has_outline();
+void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ for (char32_t i = p_start; i <= p_end; i++) {
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->face) {
+ _ensure_glyph(fd, size, FT_Get_Char_Index(fd->cache[size]->face, i));
+ continue;
+ }
+#endif
+ _ensure_glyph(fd, size, (int32_t)i);
+ }
}
-float TextServerAdvanced::font_get_base_size(RID p_font) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, 0.f);
- return fd->get_base_size();
+void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+ ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ ERR_FAIL_COND(!_ensure_glyph(fd, size, p_index));
}
-bool TextServerAdvanced::font_is_language_supported(RID p_font, const String &p_language) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- if (fd->lang_support_overrides.has(p_language)) {
- return fd->lang_support_overrides[p_language];
- } else {
- Vector<String> tags = p_language.replace("-", "_").split("_");
- if (tags.size() > 0) {
- if (fd->lang_support_overrides.has(tags[0])) {
- return fd->lang_support_overrides[tags[0]];
+void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ 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.
+ }
+
+ const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
+ if (gl.found) {
+ 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 && FT_HAS_COLOR(fd->cache[size]->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+#endif
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
+ if (fd->msdf) {
+ Point2 cpos = p_pos;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ 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;
+ cpos += gl.rect.position;
+ Size2i 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);
+ }
}
}
- return fd->is_lang_supported(p_language);
}
}
-void TextServerAdvanced::font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->lang_support_overrides[p_language] = p_supported;
+
+ MutexLock lock(fd->mutex);
+ 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.
+ }
+
+ const FontGlyph &gl = fd->cache[size]->glyph_map[p_index];
+ if (gl.found) {
+ 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 && FT_HAS_COLOR(fd->cache[size]->face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+#endif
+ if (RenderingServer::get_singleton() != nullptr) {
+ RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
+ if (fd->msdf) {
+ Point2 cpos = p_pos;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ 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;
+ cpos += gl.rect.position;
+ Size2i 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);
+ }
+ }
+ }
+ }
}
-bool TextServerAdvanced::font_get_language_support_override(RID p_font, const String &p_language) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String &p_language) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
- return fd->lang_support_overrides[p_language];
+
+ MutexLock lock(fd->mutex);
+ if (fd->language_support_overrides.has(p_language)) {
+ return fd->language_support_overrides[p_language];
+ } else {
+ return true;
+ }
}
-void TextServerAdvanced::font_remove_language_support_override(RID p_font, const String &p_language) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
- fd->lang_support_overrides.erase(p_language);
+
+ MutexLock lock(fd->mutex);
+ fd->language_support_overrides[p_language] = p_supported;
}
-Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, const String &p_language) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->language_support_overrides[p_language];
+}
+
+void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ fd->language_support_overrides.erase(p_language);
+}
+
+Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font_rid) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
- Vector<String> ret;
- for (Map<String, bool>::Element *E = fd->lang_support_overrides.front(); E; E = E->next()) {
- ret.push_back(E->key());
+
+ MutexLock lock(fd->mutex);
+ Vector<String> out;
+ for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
+ out.push_back(E.key);
}
- return ret;
+ return out;
}
-bool TextServerAdvanced::font_is_script_supported(RID p_font, const String &p_script) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
+bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &p_script) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
if (fd->script_support_overrides.has(p_script)) {
return fd->script_support_overrides[p_script];
} else {
- hb_script_t scr = hb_script_from_string(p_script.ascii().get_data(), -1);
- return fd->is_script_supported(scr);
+ Vector2i size = _get_size(fd, 16);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
+ return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));
}
}
-void TextServerAdvanced::font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
fd->script_support_overrides[p_script] = p_supported;
}
-bool TextServerAdvanced::font_get_script_support_override(RID p_font, const String &p_script) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const String &p_script) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
return fd->script_support_overrides[p_script];
}
-void TextServerAdvanced::font_remove_script_support_override(RID p_font, const String &p_script) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
fd->script_support_overrides.erase(p_script);
}
-Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font) {
- _THREAD_SAFE_METHOD_
- FontDataAdvanced *fd = font_owner.getornull(p_font);
+Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_rid) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
- Vector<String> ret;
- for (Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
- ret.push_back(E->key());
- }
- return ret;
-}
-uint32_t TextServerAdvanced::font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, 0);
- return fd->get_glyph_index(p_char, p_variation_selector);
-}
-
-Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Vector2());
- return fd->get_advance(p_index, p_size);
+ MutexLock lock(fd->mutex);
+ Vector<String> out;
+ for (const Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
+ out.push_back(E->key());
+ }
+ return out;
}
-Vector2 TextServerAdvanced::font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Vector2());
- return fd->get_kerning(p_index_a, p_index_b, p_size);
-}
+Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
-Vector2 TextServerAdvanced::font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Vector2());
- return fd->draw_glyph(p_canvas, p_size, p_pos, p_index, p_color);
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, 16);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+ return fd->supported_features;
}
-Vector2 TextServerAdvanced::font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, Vector2());
- return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
-}
+Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
-bool TextServerAdvanced::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
- _THREAD_SAFE_METHOD_
- const FontDataAdvanced *fd = font_owner.getornull(p_font);
- ERR_FAIL_COND_V(!fd, false);
- return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation);
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, 16);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+ return fd->supported_varaitions;
}
-float TextServerAdvanced::font_get_oversampling() const {
+float TextServerAdvanced::font_get_global_oversampling() const {
return oversampling;
}
-void TextServerAdvanced::font_set_oversampling(float p_oversampling) {
+void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
List<RID> fonts;
font_owner.get_owned_list(&fonts);
+ bool font_cleared = false;
for (const RID &E : fonts) {
- font_owner.getornull(E)->clear_cache();
+ if (!font_is_multichannel_signed_distance_field(E) && font_get_oversampling(E) <= 0) {
+ font_clear_size_cache(E);
+ font_cleared = true;
+ }
}
- List<RID> text_bufs;
- shaped_owner.get_owned_list(&text_bufs);
- for (const RID &E : text_bufs) {
- invalidate(shaped_owner.getornull(E));
+ if (font_cleared) {
+ List<RID> text_bufs;
+ shaped_owner.get_owned_list(&text_bufs);
+ for (const RID &E : text_bufs) {
+ invalidate(shaped_owner.get_or_null(E));
+ }
}
}
}
-Vector<String> TextServerAdvanced::get_system_fonts() const {
- return Vector<String>();
-}
-
/*************************************************************************/
/* Shaped text buffer interface */
/*************************************************************************/
@@ -977,6 +2840,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->sort_valid = false;
p_shaped->line_breaks_valid = false;
p_shaped->justification_ops_valid = false;
+ p_shaped->text_trimmed = false;
p_shaped->ascent = 0.f;
p_shaped->descent = 0.f;
p_shaped->width = 0.f;
@@ -984,6 +2848,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->uthk = 0.f;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
+ p_shaped->overrun_trim_data = TrimData();
p_shaped->utf16 = Char16String();
if (p_shaped->script_iter != nullptr) {
memdelete(p_shaped->script_iter);
@@ -996,11 +2861,11 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
}
void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
- ShapedTextDataAdvanced *parent = shaped_owner.getornull(p_shaped->parent);
+ ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) {
- if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) {
- p_shaped->objects[E->key()] = E->get();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) {
+ if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
+ p_shaped->objects[E.key] = E.value;
}
}
@@ -1027,10 +2892,10 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te
}
void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+ MutexLock lock(sd->mutex);
sd->parent = RID();
sd->start = 0;
sd->end = 0;
@@ -1042,10 +2907,10 @@ void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
}
void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+ MutexLock lock(sd->mutex);
if (sd->direction != p_direction) {
if (sd->parent != RID()) {
full_copy(sd);
@@ -1056,27 +2921,33 @@ void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Dir
}
TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
+
+ MutexLock lock(sd->mutex);
return sd->direction;
}
-void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+
+ MutexLock lock(sd->mutex);
if (sd->parent != RID()) {
full_copy(sd);
}
- sd->bidi_override = p_override;
+ sd->bidi_override.clear();
+ for (int i = 0; i < p_override.size(); i++) {
+ sd->bidi_override.push_back(p_override[i]);
+ }
invalidate(sd);
}
void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+
+ MutexLock lock(sd->mutex);
if (sd->orientation != p_orientation) {
if (sd->parent != RID()) {
full_copy(sd);
@@ -1087,9 +2958,10 @@ void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+
+ MutexLock lock(sd->mutex);
ERR_FAIL_COND(sd->parent != RID());
if (sd->preserve_invalid != p_enabled) {
sd->preserve_invalid = p_enabled;
@@ -1098,16 +2970,18 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e
}
bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
return sd->preserve_invalid;
}
void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
+
+ MutexLock lock(sd->mutex);
if (sd->preserve_control != p_enabled) {
if (sd->parent != RID()) {
full_copy(sd);
@@ -1118,25 +2992,31 @@ void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_e
}
bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
return sd->preserve_control;
}
TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
+
+ MutexLock lock(sd->mutex);
return sd->orientation;
}
bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_size <= 0, false);
+ MutexLock lock(sd->mutex);
+ for (int i = 0; i < p_fonts.size(); i++) {
+ ERR_FAIL_COND_V(!font_owner.get_or_null(p_fonts[i]), false);
+ }
+
if (p_text.is_empty()) {
return true;
}
@@ -1163,7 +3043,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_key == Variant(), false);
ERR_FAIL_COND_V(sd->objects.has(p_key), false);
@@ -1192,9 +3072,10 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
- _THREAD_SAFE_METHOD_
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
sd->objects[p_key].rect.size = p_size;
sd->objects[p_key].inline_align = p_inline_align;
@@ -1211,9 +3092,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
- key = E->key();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
+ key = E.key;
break;
}
}
@@ -1229,22 +3110,20 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
- const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid);
- if (fd != nullptr) {
+ if (gl.font_rid.is_valid()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
- sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
+ sd->ascent = MAX(sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off));
+ sd->descent = MAX(sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off));
} else {
- sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
- sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ 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));
}
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -1257,64 +3136,64 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -1325,9 +3204,10 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
+
+ MutexLock lock(sd->mutex);
if (sd->parent != RID()) {
return shaped_text_substr(sd->parent, p_start, p_length);
}
@@ -1361,9 +3241,6 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
int sd_size = sd->glyphs.size();
const Glyph *sd_glyphs = sd->glyphs.ptr();
- const FontDataAdvanced *fd = nullptr;
- RID prev_rid = RID();
-
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
UErrorCode err = U_ZERO_ERROR;
@@ -1375,7 +3252,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range.");
- //Create temporary line bidi & shape
+ // Create temporary line bidi & shape.
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err);
@@ -1403,11 +3280,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
find_embedded = true;
- key = E->key();
- new_sd->objects[key] = E->get();
+ key = E.key;
+ new_sd->objects[key] = E.value;
break;
}
}
@@ -1421,23 +3298,18 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->width += new_sd->objects[key].rect.size.y;
}
} else {
- if (prev_rid != gl.font_rid) {
- fd = font_owner.getornull(gl.font_rid);
- prev_rid = gl.font_rid;
- }
- if (fd != nullptr) {
+ if (gl.font_rid.is_valid()) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
- new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
+ new_sd->ascent = MAX(new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off));
+ new_sd->descent = MAX(new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off));
} else {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
- new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
}
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -1454,64 +3326,64 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
// Align embedded objects to baseline.
float full_ascent = new_sd->ascent;
float full_descent = new_sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
+ if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -new_sd->ascent;
+ E.value.rect.position.y = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = new_sd->descent;
+ E.value.rect.position.y = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -new_sd->ascent;
+ E.value.rect.position.x = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = new_sd->descent;
+ E.value.rect.position.x = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -1524,16 +3396,18 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
+
+ MutexLock lock(sd->mutex);
return sd->parent;
}
-float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -1541,6 +3415,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped);
}
+ sd->fit_width_minimum_reached = false;
int start_pos = 0;
int end_pos = sd->glyphs.size() - 1;
@@ -1569,14 +3444,26 @@ float TextServerAdvanced::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) {
+ start_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) {
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;
}
@@ -1597,7 +3484,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
- float delta_width_per_kashida = (p_width - sd->width) / elongation_count;
+ float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -1605,41 +3492,58 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
int count = delta_width_per_kashida / gl.advance;
int prev_count = gl.repeat;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.repeat = count;
- } else {
- gl.repeat = count + 1;
+ gl.repeat = MAX(count, 0);
}
- sd->width += (gl.repeat - prev_count) * gl.advance;
+ justification_width += (gl.repeat - prev_count) * gl.advance;
}
}
}
}
-
+ float adv_remain = 0;
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;
+ float new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
} else {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);
}
- sd->width += (gl.advance - old_adv);
+ gl.advance = new_advance;
+ adv_remain += (new_advance - gl.advance);
+ if (adv_remain >= 1.0) {
+ gl.advance++;
+ adv_remain -= 1.0;
+ } else if (adv_remain <= -1.0) {
+ gl.advance = MAX(gl.advance - 1, 0);
+ adv_remain -= 1.0;
+ }
+ justification_width += (gl.advance - old_adv);
}
}
}
}
+ 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 sd->width;
}
-float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -1685,35 +3589,46 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
return 0.f;
}
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line);
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
shaped_text_shape(p_shaped_line);
}
- bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
- bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
- bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ sd->text_trimmed = false;
+ sd->overrun_trim_data.ellipsis_glyph_buf.clear();
+
+ bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
+ bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
+ bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE;
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ sd->overrun_trim_data.trim_pos = -1;
+ sd->overrun_trim_data.ellipsis_pos = -1;
+ return;
+ }
+
+ if (justification_aware && !sd->fit_width_minimum_reached) {
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;
- uint32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, '.');
- Vector2 dot_adv = font_get_glyph_advance(last_gl_font_rid, dot_gl_idx, last_gl_font_size);
- uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ');
- Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size);
+ int32_t dot_gl_idx = font_get_glyph_index(last_gl_font_rid, last_gl_font_size, '.');
+ 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, last_gl_font_size, ' ');
+ Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, last_gl_font_size, whitespace_gl_idx);
- int ellipsis_advance = 0;
+ int ellipsis_width = 0;
if (add_ellipsis) {
- ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing(last_gl_font_rid, last_gl_font_size, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
@@ -1733,12 +3648,12 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
if (!is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
if (sd_glyphs[i].count > 0) {
bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
- if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) {
+ if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
if (cut_per_word && above_min_char_treshold) {
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_valid_cut = i;
@@ -1751,7 +3666,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
if (found) {
trim_pos = last_valid_cut;
- if (above_min_char_treshold && width - ellipsis_advance <= p_width) {
+ if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
ellipsis_pos = trim_pos;
}
break;
@@ -1759,18 +3674,21 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
}
if (is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
}
+ sd->overrun_trim_data.trim_pos = trim_pos;
+ sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
+ if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
+ sd->overrun_trim_data.ellipsis_pos = 0;
+ }
+
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
- int added_glyphs = 0;
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
+ Glyph gl;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
@@ -1778,72 +3696,63 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
gl.font_size = last_gl_font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- for (int d = 0; d < 3; d++) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
- gl.count = 1;
- 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 | (is_rtl ? GRAPHEME_IS_RTL : 0);
-
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
- }
+ 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 | (is_rtl ? GRAPHEME_IS_RTL : 0);
+
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
- // Cut the remaining glyphs off.
- if (!is_rtl) {
- sd->glyphs.resize(trim_pos + added_glyphs);
- } else {
- if (trim_pos - added_glyphs >= 0) {
- sd->glyphs = sd->glyphs.subarray(trim_pos - added_glyphs, sd->glyphs.size() - 1);
- }
- }
-
- // Update to correct width.
- sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0);
+ sd->text_trimmed = true;
+ sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
}
}
+int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.trim_pos;
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_pos;
+}
+
+const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.size();
+}
+
bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
shaped_text_shape(p_shaped);
}
@@ -1866,7 +3775,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
int r_end = sd->spans[i].end;
UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);
if (U_FAILURE(err)) {
- //No data loaded - use fallback.
+ // No data loaded - use fallback.
for (int j = r_start; j < r_end; j++) {
char32_t c = sd->text[j - sd->start];
if (is_whitespace(c)) {
@@ -1923,14 +3832,19 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
if (is_whitespace(c)) {
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = sd_glyphs[i].start;
gl.end = sd_glyphs[i].end;
gl.count = 1;
gl.font_rid = sd_glyphs[i].font_rid;
gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+ if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
+ gl.flags |= GRAPHEME_IS_RTL;
+ sd->glyphs.insert(i, gl); // Insert before.
+ } else {
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
+ }
// Update write pointer and size.
sd_size = sd->glyphs.size();
@@ -2027,9 +3941,10 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
}
bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
shaped_text_shape(p_shaped);
}
@@ -2050,7 +3965,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
UErrorCode err = U_ZERO_ERROR;
UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);
if (U_FAILURE(err)) {
- // No data - use fallback
+ // No data - use fallback.
int limit = 0;
for (int i = 0; i < sd->text.length(); i++) {
if (is_whitespace(data[i])) {
@@ -2098,7 +4013,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION;
} else {
if (sd->glyphs[i].font_rid != RID()) {
- TextServer::Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
+ Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
@@ -2116,14 +4031,19 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
}
}
} else if (!is_whitespace(c)) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
gl.count = 1;
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
+ if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
+ gl.flags |= GRAPHEME_IS_RTL;
+ sd->glyphs.insert(i, gl); // Insert before.
+ } else {
+ sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
+ }
i += sd->glyphs[i].count;
continue;
}
@@ -2136,9 +4056,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
return sd->justification_ops_valid;
}
-TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font);
- hb_font_t *hb_font = fd->get_hb_handle(p_font_size);
+Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
+ hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
+ ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
hb_buffer_clear_contents(p_sd->hb_buffer);
hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
@@ -2153,7 +4073,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
// Process glyphs.
- TextServer::Glyph gl;
+ Glyph gl;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -2163,16 +4083,17 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
gl.font_size = p_font_size;
if (glyph_count > 0) {
+ float scale = font_get_scale(p_font, p_font_size);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale));
} else {
- gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / scale));
}
gl.count = 1;
gl.index = glyph_info[0].codepoint;
- gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)));
- gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / scale));
+ gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / scale));
if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
gl.flags |= GRAPHEME_IS_VALID;
@@ -2182,17 +4103,12 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
}
void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index) {
- FontDataAdvanced *fd = nullptr;
- if (p_fb_index < p_fonts.size()) {
- fd = font_owner.getornull(p_fonts[p_fb_index]);
- }
-
int fs = p_sd->spans[p_span].font_size;
- if (fd == nullptr) {
- // Add fallback glyphs
+ if (p_fb_index >= p_fonts.size()) {
+ // Add fallback glyphs.
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = i;
gl.end = i + 1;
gl.count = 1;
@@ -2204,8 +4120,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = get_hex_code_box_size(fs, gl.index).x;
- p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
- p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
+ 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;
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
@@ -2219,7 +4134,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
return;
}
- hb_font_t *hb_font = fd->get_hb_handle(fs);
+ RID f = p_fonts[p_fb_index];
+ hb_font_t *hb_font = _font_get_hb_handle(f, fs);
ERR_FAIL_COND(hb_font == nullptr);
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -2258,7 +4174,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
// Process glyphs.
if (glyph_count > 0) {
- TextServer::Glyph *w = (TextServer::Glyph *)memalloc(glyph_count * sizeof(TextServer::Glyph));
+ Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));
int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
uint32_t last_cluster_id = UINT32_MAX;
@@ -2275,7 +4191,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
}
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
- w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
}
if (last_cluster_valid) {
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
@@ -2287,8 +4203,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
last_cluster_id = glyph_info[i].cluster;
- TextServer::Glyph &gl = w[i];
- gl = TextServer::Glyph();
+ Glyph &gl = w[i];
+ gl = Glyph();
gl.start = glyph_info[i].cluster;
gl.end = end;
@@ -2297,26 +4213,31 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.font_rid = p_fonts[p_fb_index];
gl.font_size = fs;
+ if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) {
+ gl.flags |= GRAPHEME_IS_CONNECTED;
+ }
+
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
+ float scale = font_get_scale(f, fs);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs)));
+ gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
} else {
- gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs)));
+ gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / scale));
}
- gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
- gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
+ gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale));
+ gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale));
}
- if (fd->get_spacing_space() && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
- gl.advance += fd->get_spacing_space();
+ if (font_get_spacing(f, fs, SPACING_SPACE) && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
+ gl.advance += font_get_spacing(f, fs, SPACING_SPACE);
} else {
- gl.advance += fd->get_spacing_glyph();
+ gl.advance += font_get_spacing(f, fs, SPACING_GLYPH);
}
if (p_sd->preserve_control) {
- last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || is_whitespace(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster]));
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster])));
} else {
- last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || !u_isgraph(p_sd->text[glyph_info[i].cluster]));
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster])));
}
}
if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {
@@ -2326,13 +4247,13 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
w[last_cluster_index].count = glyph_count - last_cluster_index;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
- w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
}
if (last_cluster_valid) {
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
}
- //Fallback.
+ // Fallback.
int failed_subrun_start = p_end + 1;
int failed_subrun_end = p_start;
@@ -2348,8 +4269,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
} else {
- p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
- p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5));
}
p_sd->width += w[i + j].advance;
p_sd->glyphs.push_back(w[i + j]);
@@ -2368,18 +4289,18 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
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_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs));
- p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs));
- p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs));
- p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs));
+ p_sd->ascent = MAX(p_sd->ascent, font_get_ascent(f, fs));
+ p_sd->descent = MAX(p_sd->descent, font_get_descent(f, fs));
+ p_sd->upos = MAX(p_sd->upos, font_get_underline_position(f, fs));
+ p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(f, fs));
}
}
bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+ MutexLock lock(sd->mutex);
if (sd->valid) {
return true;
}
@@ -2540,63 +4461,63 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
sd->ascent = full_ascent;
@@ -2606,62 +4527,79 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
+
+ MutexLock lock(sd->mutex);
return sd->valid;
}
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
- return sd->glyphs;
+ return sd->glyphs.ptr();
}
-Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector2i());
- return Vector2(sd->start, sd->end);
+int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0);
+
+ MutexLock lock(sd->mutex);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->glyphs.size();
}
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
- _THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
if (!sd->sort_valid) {
sd->glyphs_logical = sd->glyphs;
- sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>();
+ sd->glyphs_logical.sort_custom<GlyphCompare>();
sd->sort_valid = true;
}
- return sd->glyphs_logical;
+ return sd->glyphs_logical.ptr();
+}
+
+Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector2i());
+
+ MutexLock lock(sd->mutex);
+ return Vector2(sd->start, sd->end);
}
Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
Array ret;
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
- for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- ret.push_back(E->key());
+
+ MutexLock lock(sd->mutex);
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ ret.push_back(E.key);
}
return ret;
}
Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Rect2());
+
+ MutexLock lock(sd->mutex);
ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
@@ -2670,23 +4608,25 @@ Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_ke
}
Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(sd->width, sd->ascent + sd->descent);
+ return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent);
} else {
- return Size2(sd->ascent + sd->descent, sd->width);
+ return Size2(sd->ascent + sd->descent, (sd->text_trimmed ? sd->width_trimmed : sd->width));
}
}
float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -2694,9 +4634,10 @@ float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
}
float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -2704,19 +4645,21 @@ float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
}
float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
- return sd->width;
+ return (sd->text_trimmed ? sd->width_trimmed : sd->width);
}
float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -2725,9 +4668,10 @@ float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const
}
float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
- _THREAD_SAFE_METHOD_
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
+
+ MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
@@ -2736,31 +4680,76 @@ float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) cons
}
struct num_system_data {
- String lang;
+ Set<String> lang;
String digits;
String percent_sign;
String exp;
};
static num_system_data num_systems[]{
- { "ar,ar_AR,ar_BH,ar_DJ,ar_EG,ar_ER,ar_IL,ar_IQ,ar_JO,ar_KM,ar_KW,ar_LB,ar_MR,ar_OM,ar_PS,ar_QA,ar_SA,ar_SD,ar_SO,ar_SS,ar_SY,ar_TD,ar_YE", U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" },
- { "fa,ks,pa_Arab,ps,ug,ur_IN,ur,uz_Arab", U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" },
- { "as,bn,mni", U"০১২৩৪৫৬৭৮৯.", U"%", U"e" },
- { "mr,ne", U"०१२३४५६७८९.", U"%", U"e" },
- { "dz", U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" },
- { "sat", U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" },
- { "my", U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" },
- { String(), String(), String(), String() },
+ { Set<String>(), U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" },
+ { Set<String>(), U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" },
+ { Set<String>(), U"০১২৩৪৫৬৭৮৯.", U"%", U"e" },
+ { Set<String>(), U"०१२३४५६७८९.", U"%", U"e" },
+ { Set<String>(), U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" },
+ { Set<String>(), U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" },
+ { Set<String>(), U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" },
+ { Set<String>(), String(), String(), String() },
};
+static void _insert_num_systems_lang() {
+ num_systems[0].lang.insert(StringName("ar"));
+ num_systems[0].lang.insert(StringName("ar_AR"));
+ num_systems[0].lang.insert(StringName("ar_BH"));
+ num_systems[0].lang.insert(StringName("ar_DJ"));
+ num_systems[0].lang.insert(StringName("ar_EG"));
+ num_systems[0].lang.insert(StringName("ar_ER"));
+ num_systems[0].lang.insert(StringName("ar_IL"));
+ num_systems[0].lang.insert(StringName("ar_IQ"));
+ num_systems[0].lang.insert(StringName("ar_JO"));
+ num_systems[0].lang.insert(StringName("ar_KM"));
+ num_systems[0].lang.insert(StringName("ar_KW"));
+ num_systems[0].lang.insert(StringName("ar_LB"));
+ num_systems[0].lang.insert(StringName("ar_MR"));
+ num_systems[0].lang.insert(StringName("ar_OM"));
+ num_systems[0].lang.insert(StringName("ar_PS"));
+ num_systems[0].lang.insert(StringName("ar_QA"));
+ num_systems[0].lang.insert(StringName("ar_SA"));
+ num_systems[0].lang.insert(StringName("ar_SD"));
+ num_systems[0].lang.insert(StringName("ar_SO"));
+ num_systems[0].lang.insert(StringName("ar_SS"));
+ num_systems[0].lang.insert(StringName("ar_SY"));
+ num_systems[0].lang.insert(StringName("ar_TD"));
+ num_systems[0].lang.insert(StringName("ar_YE"));
+
+ num_systems[1].lang.insert(StringName("fa"));
+ num_systems[1].lang.insert(StringName("ks"));
+ num_systems[1].lang.insert(StringName("pa_Arab"));
+ num_systems[1].lang.insert(StringName("ug"));
+ num_systems[1].lang.insert(StringName("ur_IN"));
+ num_systems[1].lang.insert(StringName("ur"));
+ num_systems[1].lang.insert(StringName("uz_Arab"));
+
+ num_systems[2].lang.insert(StringName("as"));
+ num_systems[2].lang.insert(StringName("bn"));
+ num_systems[2].lang.insert(StringName("mni"));
+
+ num_systems[3].lang.insert(StringName("mr"));
+ num_systems[3].lang.insert(StringName("ne"));
+
+ num_systems[4].lang.insert(StringName("dz"));
+
+ num_systems[5].lang.insert(StringName("sat"));
+
+ num_systems[6].lang.insert(StringName("my"));
+}
+
String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const {
- _THREAD_SAFE_METHOD_
- String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+ const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang != String(); i++) {
- Vector<String> langs = num_systems[i].lang.split(",");
- if (langs.has(lang)) {
+ for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
}
@@ -2781,13 +4770,11 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p
}
String TextServerAdvanced::parse_number(const String &p_string, const String &p_language) const {
- _THREAD_SAFE_METHOD_
- String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+ const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang != String(); i++) {
- Vector<String> langs = num_systems[i].lang.split(",");
- if (langs.has(lang)) {
+ for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
}
@@ -2811,12 +4798,10 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
}
String TextServerAdvanced::percent_sign(const String &p_language) const {
- _THREAD_SAFE_METHOD_
- String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+ const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
- for (int i = 0; num_systems[i].lang != String(); i++) {
- Vector<String> langs = num_systems[i].lang.split(",");
- if (langs.has(lang)) {
+ for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ if (num_systems[i].lang.has(lang)) {
if (num_systems[i].percent_sign == String()) {
return "%";
}
@@ -2826,21 +4811,17 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
-TextServer *TextServerAdvanced::create_func(Error &r_error, void *p_user_data) {
- r_error = OK;
- return memnew(TextServerAdvanced());
-}
-
-void TextServerAdvanced::register_server() {
- TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
-}
-
TextServerAdvanced::TextServerAdvanced() {
+ _insert_num_systems_lang();
+ _insert_feature_sets();
hb_bmp_create_font_funcs();
}
TextServerAdvanced::~TextServerAdvanced() {
hb_bmp_free_font_funcs();
+ if (library != nullptr) {
+ FT_Done_FreeType(library);
+ }
u_cleanup();
#ifndef ICU_STATIC_DATA
if (icu_data != nullptr) {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index c54686c114..1feeada76d 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -39,6 +39,7 @@
#include "servers/text_server.h"
#include "core/templates/rid_owner.h"
+#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
#include "script_iterator.h"
@@ -53,11 +54,24 @@
#include <unicode/ustring.h>
#include <unicode/utypes.h>
+#include "modules/modules_enabled.gen.h"
+
+#ifdef MODULE_FREETYPE_ENABLED
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_STROKER_H
+#include FT_ADVANCES_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_BBOX_H
+
+#include <hb-ft.h>
+#include <hb-ot.h>
+#endif
+
#include <hb-icu.h>
#include <hb.h>
-#include "font_adv.h"
-
class TextServerAdvanced : public TextServer {
GDCLASS(TextServerAdvanced, TextServer);
_THREAD_SAFE_CLASS_
@@ -65,8 +79,149 @@ class TextServerAdvanced : public TextServer {
static String interface_name;
static uint32_t interface_features;
+ // ICU support data.
+
uint8_t *icu_data = nullptr;
+ // Font cache data.
+
+#ifdef MODULE_FREETYPE_ENABLED
+ mutable FT_Library library = nullptr;
+#endif
+
+ const int rect_range = 2;
+
+ struct FontTexture {
+ Image::Format format;
+ PackedByteArray imgdata;
+ int texture_w = 0;
+ int texture_h = 0;
+ PackedInt32Array offsets;
+ Ref<ImageTexture> texture;
+ };
+
+ struct FontTexturePosition {
+ int index = 0;
+ int x = 0;
+ int y = 0;
+ };
+
+ struct FontGlyph {
+ bool found = false;
+ int texture_idx = -1;
+ Rect2 rect;
+ Rect2 uv_rect;
+ Vector2 advance;
+ };
+
+ struct FontDataForSizeAdvanced {
+ float ascent = 0.f;
+ float descent = 0.f;
+ float underline_position = 0.f;
+ float underline_thickness = 0.f;
+ float scale = 1.f;
+ float oversampling = 1.f;
+
+ int spacing_glyph = 0;
+ int spacing_space = 0;
+
+ Vector2i size;
+
+ Vector<FontTexture> textures;
+ HashMap<int32_t, FontGlyph> glyph_map;
+ Map<Vector2i, Vector2> kerning_map;
+
+ hb_font_t *hb_handle = nullptr;
+
+#ifdef MODULE_FREETYPE_ENABLED
+ FT_Face face = nullptr;
+ FT_StreamRec stream;
+#endif
+
+ ~FontDataForSizeAdvanced() {
+ if (hb_handle != nullptr) {
+ hb_font_destroy(hb_handle);
+ }
+#ifdef MODULE_FREETYPE_ENABLED
+ if (face != nullptr) {
+ FT_Done_Face(face);
+ }
+#endif
+ }
+ };
+
+ struct FontDataAdvanced {
+ Mutex mutex;
+
+ bool antialiased = true;
+ bool msdf = false;
+ int msdf_range = 14;
+ int msdf_source_size = 48;
+ int fixed_size = 0;
+ bool force_autohinter = false;
+ TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
+ Dictionary variation_coordinates;
+ float oversampling = 0.f;
+
+ Map<Vector2i, FontDataForSizeAdvanced *> cache;
+
+ bool face_init = false;
+ Set<uint32_t> supported_scripts;
+ Dictionary supported_features;
+ Dictionary supported_varaitions;
+
+ // Language/script support override.
+ Map<String, bool> language_support_overrides;
+ Map<String, bool> script_support_overrides;
+
+ PackedByteArray data;
+ const uint8_t *data_ptr;
+ size_t data_size;
+ mutable ThreadWorkPool work_pool;
+
+ ~FontDataAdvanced() {
+ work_pool.finish();
+ for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = cache.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ cache.clear();
+ }
+ };
+
+ _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontDataForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) const;
+#ifdef MODULE_MSDFGEN_ENABLED
+ _FORCE_INLINE_ FontGlyph rasterize_msdf(FontDataAdvanced *p_font_data, FontDataForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const;
+#endif
+#ifdef MODULE_FREETYPE_ENABLED
+ _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontDataForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const;
+#endif
+ _FORCE_INLINE_ bool _ensure_glyph(FontDataAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
+ _FORCE_INLINE_ bool _ensure_cache_for_size(FontDataAdvanced *p_font_data, const Vector2i &p_size) const;
+ _FORCE_INLINE_ void _font_clear_cache(FontDataAdvanced *p_font_data);
+ void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+
+ _FORCE_INLINE_ Vector2i _get_size(const FontDataAdvanced *p_font_data, int p_size) const {
+ if (p_font_data->msdf) {
+ return Vector2i(p_font_data->msdf_source_size, 0);
+ } else if (p_font_data->fixed_size > 0) {
+ return Vector2i(p_font_data->fixed_size, 0);
+ } else {
+ return Vector2i(p_size, 0);
+ }
+ }
+
+ _FORCE_INLINE_ Vector2i _get_size_outline(const FontDataAdvanced *p_font_data, const Vector2i &p_size) const {
+ if (p_font_data->msdf) {
+ return Vector2i(p_font_data->msdf_source_size, 0);
+ } else if (p_font_data->fixed_size > 0) {
+ return Vector2i(p_font_data->fixed_size, MIN(p_size.y, 1));
+ } else {
+ return p_size;
+ }
+ }
+
+ // Shaped text cache data.
+
struct ShapedTextDataAdvanced : public ShapedTextData {
/* Intermediate data */
Char16String utf16;
@@ -88,6 +243,8 @@ class TextServerAdvanced : public TextServer {
}
};
+ // Common data.
+
float oversampling = 1.f;
mutable RID_PtrOwner<FontDataAdvanced> font_owner;
mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
@@ -95,7 +252,30 @@ class TextServerAdvanced : public TextServer {
int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index);
- TextServer::Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
+ Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
+
+ // HarfBuzz bitmap font interface.
+
+ static hb_font_funcs_t *funcs;
+
+ struct hb_bmp_font_t {
+ TextServerAdvanced::FontDataForSizeAdvanced *face = nullptr;
+ bool unref = false; /* Whether to destroy bm_face when done. */
+ };
+
+ static hb_bmp_font_t *_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static void _hb_bmp_font_destroy(void *p_data);
+ static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data);
+ static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
+ static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data);
+ static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data);
+ static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data);
+ static void hb_bmp_create_font_funcs();
+ static void hb_bmp_free_font_funcs();
+ static void _hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static hb_font_t *hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
protected:
static void _bind_methods(){};
@@ -104,96 +284,146 @@ protected:
void invalidate(ShapedTextDataAdvanced *p_shaped);
public:
- virtual bool has_feature(Feature p_feature) override;
+ virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
+ virtual uint32_t get_features() const override;
virtual void free(RID p_rid) override;
virtual bool has(RID p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
-#ifdef TOOLS_ENABLED
- virtual String get_support_data_filename() override { return _MKSTR(ICU_DATA_NAME); };
- virtual String get_support_data_info() override { return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); };
- virtual bool save_support_data(const String &p_filename) override;
-#endif
+ virtual String get_support_data_filename() const override;
+ virtual String get_support_data_info() const override;
+ virtual bool save_support_data(const String &p_filename) const override;
- virtual bool is_locale_right_to_left(const String &p_locale) override;
+ virtual bool is_locale_right_to_left(const String &p_locale) const override;
- virtual int32_t name_to_tag(const String &p_name) override;
- virtual String tag_to_name(int32_t p_tag) override;
+ virtual int32_t name_to_tag(const String &p_name) const override;
+ virtual String tag_to_name(int32_t p_tag) const override;
/* Font interface */
- virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
- virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
- virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
- virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) override;
+ virtual RID create_font() override;
+
+ virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
+ virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
+
+ virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
+ virtual bool font_is_antialiased(RID p_font_rid) const override;
+
+ virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
+ virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
+
+ virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
+ virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
+
+ virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
+ virtual int font_get_msdf_size(RID p_font_rid) const override;
- virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) override;
- virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
- virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) override;
+ virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
+ virtual int font_get_fixed_size(RID p_font_rid) const override;
- virtual float font_get_height(RID p_font, int p_size) const override;
- virtual float font_get_ascent(RID p_font, int p_size) const override;
- virtual float font_get_descent(RID p_font, int p_size) const override;
+ virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
+ virtual bool font_is_force_autohinter(RID p_font_rid) const override;
- virtual float font_get_underline_position(RID p_font, int p_size) const override;
- virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+ virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override;
+ virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override;
- virtual int font_get_spacing_space(RID p_font) const override;
- virtual void font_set_spacing_space(RID p_font, int p_value) override;
+ virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
+ virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
- virtual int font_get_spacing_glyph(RID p_font) const override;
- virtual void font_set_spacing_glyph(RID p_font, int p_value) override;
+ virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+ virtual float font_get_oversampling(RID p_font_rid) const override;
- virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
- virtual bool font_get_antialiased(RID p_font) const override;
+ virtual Array font_get_size_cache_list(RID p_font_rid) const override;
+ virtual void font_clear_size_cache(RID p_font_rid) override;
+ virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
- virtual Dictionary font_get_feature_list(RID p_font) const override;
- virtual Dictionary font_get_variation_list(RID p_font) const override;
+ hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const;
- virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
- virtual double font_get_variation(RID p_font, const String &p_name) const override;
+ virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+ virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
- virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
- virtual Hinting font_get_hinting(RID p_font) const override;
+ virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+ virtual float font_get_descent(RID p_font_rid, int p_size) const override;
- virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) override;
- virtual bool font_get_distance_field_hint(RID p_font) const override;
+ virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+ virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
- virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) override;
- virtual bool font_get_force_autohinter(RID p_font) const override;
+ virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+ virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
- virtual bool font_has_char(RID p_font, char32_t p_char) const override;
- virtual String font_get_supported_chars(RID p_font) const override;
+ virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+ virtual float font_get_scale(RID p_font_rid, int p_size) const override;
- virtual bool font_has_outline(RID p_font) const override;
- virtual float font_get_base_size(RID p_font) const override;
+ virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
+ virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
- virtual bool font_is_language_supported(RID p_font, const String &p_language) const override;
- virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) override;
- virtual bool font_get_language_support_override(RID p_font, const String &p_language) override;
- virtual void font_remove_language_support_override(RID p_font, const String &p_language) override;
- Vector<String> font_get_language_support_overrides(RID p_font) override;
+ virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
- virtual bool font_is_script_supported(RID p_font, const String &p_script) const override;
- virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) override;
- virtual bool font_get_script_support_override(RID p_font, const String &p_script) override;
- virtual void font_remove_script_support_override(RID p_font, const String &p_script) override;
- Vector<String> font_get_script_support_overrides(RID p_font) override;
+ virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
+ virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
- virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const override;
- virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const override;
- virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const override;
+ virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
+ virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
- virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
+ virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
+ virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
- virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+ virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
+ virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
- virtual float font_get_oversampling() const override;
- virtual void font_set_oversampling(float p_oversampling) override;
+ virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+ virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
- virtual Vector<String> get_system_fonts() const override;
+ virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+ virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
+
+ virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+ virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
+
+ virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+ virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
+
+ virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
+
+ virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
+ virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
+ virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
+
+ virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
+ virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
+
+ virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
+
+ virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
+ virtual String font_get_supported_chars(RID p_font_rid) const override;
+
+ virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
+ virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
+
+ virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+
+ virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
+ virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
+ virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
+ virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
+ virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
+
+ virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
+ virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
+ virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
+ 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 Dictionary font_supported_feature_list(RID p_font_rid) const override;
+ virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
+
+ virtual float font_get_global_oversampling() const override;
+ virtual void font_set_global_oversampling(float p_oversampling) override;
/* Shaped text buffer interface */
@@ -204,7 +434,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 void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
@@ -222,23 +452,28 @@ public:
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
- virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) override;
+ virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
virtual bool shaped_text_shape(RID p_shaped) override;
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+ virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-
virtual Array shaped_text_get_objects(RID p_shaped) const override;
virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
@@ -253,9 +488,6 @@ public:
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
- static TextServer *create_func(Error &r_error, void *p_user_data);
- static void register_server();
-
TextServerAdvanced();
~TextServerAdvanced();
};