Last active
August 19, 2025 14:28
-
-
Save migueldeicaza/e2e657a7f67770e364b2d666d63a8801 to your computer and use it in GitHub Desktop.
Ugly and contains two unrelated things, a CoreText backend (which I broke) and using CoreText-fonts to render fonts in the regular codepath.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/editor/project_manager/project_manager.cpp b/editor/project_manager/project_manager.cpp | |
| index 507931c744..ac2539a3ba 100644 | |
| --- a/editor/project_manager/project_manager.cpp | |
| +++ b/editor/project_manager/project_manager.cpp | |
| @@ -1498,7 +1498,7 @@ ProjectManager::ProjectManager() { | |
| filter_option->connect(SceneStringName(item_selected), callable_mp(this, &ProjectManager::_on_order_option_changed)); | |
| hb->add_child(filter_option); | |
| - filter_option->add_item(TTRC("Last Edited")); | |
| + filter_option->add_item(TTRC("😀Last Edited")); | |
| filter_option->add_item(TTRC("Name")); | |
| filter_option->add_item(TTRC("Path")); | |
| filter_option->add_item(TTRC("Tags")); | |
| diff --git a/editor/themes/editor_fonts.cpp b/editor/themes/editor_fonts.cpp | |
| index c972ded2dd..72de0c8709 100644 | |
| --- a/editor/themes/editor_fonts.cpp | |
| +++ b/editor/themes/editor_fonts.cpp | |
| @@ -97,6 +97,41 @@ Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServe | |
| return font; | |
| } | |
| +// Load a system font by name using OperatingSystemFont. | |
| +// This uses the operating system's font APIs (e.g., CoreText on macOS) to load fonts | |
| +// installed on the system, rather than loading font files from disk. | |
| +// Example usage: | |
| +// auto helvetica = load_operating_system_font("Helvetica"); | |
| +// auto arial_bold = load_operating_system_font("Arial Bold"); | |
| +Ref<OperatingSystemFont> load_operating_system_font(const String &p_font_name, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_font_disable_embedded_bitmaps, TypedArray<Font> *r_fallbacks) { | |
| + Ref<OperatingSystemFont> font; | |
| + font.instantiate(); | |
| + | |
| + font->set_font_name(p_font_name); | |
| + font->set_antialiasing(p_aa); | |
| + font->set_hinting(p_hinting); | |
| + font->set_force_autohinter(p_autohint); | |
| + font->set_subpixel_positioning(p_font_subpixel_positioning); | |
| + font->set_disable_embedded_bitmaps(p_font_disable_embedded_bitmaps); | |
| + | |
| + if (r_fallbacks != nullptr) { | |
| + r_fallbacks->push_back(font); | |
| + } | |
| + return font; | |
| +} | |
| + | |
| +Ref<OperatingSystemFont> load_operating_system_font(const String &p_font_name) { | |
| + return load_operating_system_font( | |
| + p_font_name, | |
| + TextServer::HINTING_LIGHT, | |
| + TextServer::FONT_ANTIALIASING_GRAY, | |
| + true, // autohint | |
| + TextServer::SUBPIXEL_POSITIONING_AUTO, | |
| + true, // disable embedded bitmaps | |
| + nullptr // no fallbacks | |
| + ); | |
| +} | |
| + | |
| Ref<FontVariation> make_bold_font(const Ref<Font> &p_font, double p_embolden, TypedArray<Font> *r_fallbacks = nullptr) { | |
| Ref<FontVariation> font_var; | |
| font_var.instantiate(); | |
| @@ -153,7 +188,8 @@ void editor_register_fonts(const Ref<Theme> &p_theme) { | |
| const int default_font_size = int(EDITOR_GET("interface/editor/main_font_size")) * EDSCALE; | |
| const float embolden_strength = 0.6; | |
| - Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false); | |
| + //Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false); | |
| + Ref<Font> default_font = load_operating_system_font("SF Pro", font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, nullptr); | |
| Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, font_allow_msdf); | |
| String noto_cjk_path; | |
| @@ -169,6 +205,7 @@ void editor_register_fonts(const Ref<Theme> &p_theme) { | |
| } | |
| TypedArray<Font> fallbacks; | |
| + #if false | |
| Ref<FontFile> arabic_font = load_internal_font(_font_Vazirmatn_Regular, _font_Vazirmatn_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); | |
| Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); | |
| Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); | |
| @@ -187,11 +224,13 @@ void editor_register_fonts(const Ref<Theme> &p_theme) { | |
| Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks); | |
| default_font->set_fallbacks(fallbacks); | |
| default_font_msdf->set_fallbacks(fallbacks); | |
| - | |
| - Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false); | |
| - Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, font_allow_msdf); | |
| +#endif | |
| + //Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false); | |
| + Ref<Font> default_font_bold = load_operating_system_font("Palatino Bold", font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, nullptr); | |
| + Ref<Font> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, font_allow_msdf); | |
| TypedArray<Font> fallbacks_bold; | |
| + #if false | |
| Ref<FontFile> arabic_font_bold = load_internal_font(_font_Vazirmatn_Bold, _font_Vazirmatn_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); | |
| Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); | |
| Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, false, &fallbacks_bold); | |
| @@ -209,6 +248,7 @@ void editor_register_fonts(const Ref<Theme> &p_theme) { | |
| Ref<FontVariation> fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold); | |
| Ref<FontVariation> japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold); | |
| + #if true | |
| if (OS::get_singleton()->has_feature("system_fonts")) { | |
| PackedStringArray emoji_font_names = { | |
| "Apple Color Emoji", | |
| @@ -222,11 +262,21 @@ void editor_register_fonts(const Ref<Theme> &p_theme) { | |
| fallbacks.push_back(emoji_font); | |
| fallbacks_bold.push_back(emoji_font); | |
| } | |
| + #else | |
| + Ref<SystemFont> emoji_font = load_operating_system_font("Apple Color Emoji", font_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, nullptr); | |
| + fallbacks.push_back(emoji_font); | |
| + fallbacks_bold.push_back(emoji_font); | |
| + #endif | |
| default_font_bold->set_fallbacks(fallbacks_bold); | |
| default_font_bold_msdf->set_fallbacks(fallbacks_bold); | |
| - | |
| - Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps); | |
| +#endif | |
| + //Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps); | |
| + Ref<Font> default_font_mono = load_operating_system_font("SF Mono", font_mono_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, nullptr); | |
| + if (!default_font_mono.is_valid()) { | |
| + // Fallback to another font if "SF Mono" is not available. | |
| + default_font_mono = load_operating_system_font("Courier New", font_mono_hinting, font_antialiasing, true, font_subpixel_positioning, font_disable_embedded_bitmaps, nullptr); | |
| + } | |
| default_font_mono->set_fallbacks(fallbacks); | |
| // Init base font configs and load custom fonts. | |
| diff --git a/editor/themes/editor_fonts.h b/editor/themes/editor_fonts.h | |
| index d252d35b90..961de44993 100644 | |
| --- a/editor/themes/editor_fonts.h | |
| +++ b/editor/themes/editor_fonts.h | |
| @@ -32,4 +32,16 @@ | |
| #include "scene/resources/theme.h" | |
| +class Font; | |
| +class OperatingSystemFont; | |
| +template <typename T> | |
| +class Ref; | |
| +template <typename T> | |
| +class TypedArray; | |
| + | |
| +Ref<OperatingSystemFont> load_operating_system_font(const String &p_font_name, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_font_disable_embedded_bitmaps, TypedArray<Font> *r_fallbacks = nullptr); | |
| + | |
| +// Convenience function with common defaults for loading system fonts | |
| +Ref<OperatingSystemFont> load_operating_system_font(const String &p_font_name); | |
| + | |
| void editor_register_fonts(const Ref<Theme> &p_theme); | |
| diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub | |
| index 1167fbc187..fb90e8689d 100644 | |
| --- a/modules/text_server_adv/SCsub | |
| +++ b/modules/text_server_adv/SCsub | |
| @@ -12,8 +12,13 @@ env_text_server_adv = env_modules.Clone() | |
| thirdparty_obj = [] | |
| freetype_enabled = "freetype" in env.module_list | |
| +coretext_enabled = env.get("coretext", False) and env["platform"] == "macos" | |
| msdfgen_enabled = "msdfgen" in env.module_list | |
| +if coretext_enabled: | |
| + env_text_server_adv.Append(CPPDEFINES=["CORETEXT_ENABLED"]) | |
| + env_text_server_adv.Append(FRAMEWORKS=["CoreText", "CoreGraphics", "CoreFoundation"]) | |
| + | |
| if "svg" in env.module_list: | |
| env_text_server_adv.Prepend( | |
| CPPEXTPATH=[ | |
| @@ -118,6 +123,13 @@ if env["builtin_harfbuzz"]: | |
| thirdparty_sources += [ | |
| "src/hb-graphite2.cc", | |
| ] | |
| + | |
| + if coretext_enabled: | |
| + thirdparty_sources += [ | |
| + "src/hb-coretext.cc", | |
| + "src/hb-coretext-font.cc", | |
| + "src/hb-coretext-shape.cc", | |
| + ] | |
| thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] | |
| env_harfbuzz.Prepend(CPPEXTPATH=["#thirdparty/harfbuzz/src"]) | |
| @@ -151,6 +163,14 @@ if env["builtin_harfbuzz"]: | |
| if env["builtin_graphite"] and env["graphite"]: | |
| env_harfbuzz.Prepend(CPPEXTPATH=["#thirdparty/graphite/include"]) | |
| env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"]) | |
| + | |
| + if coretext_enabled: | |
| + env_harfbuzz.Append( | |
| + CCFLAGS=[ | |
| + "-DHAVE_CORETEXT", | |
| + ] | |
| + ) | |
| + env_harfbuzz.Append(FRAMEWORKS=["CoreText", "CoreGraphics", "CoreFoundation"]) | |
| if env["platform"] in ["android", "linuxbsd", "web"]: | |
| env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"]) | |
| @@ -533,7 +553,13 @@ if env["builtin_freetype"] and freetype_enabled: | |
| if env["builtin_graphite"] and freetype_enabled and env["graphite"]: | |
| env_text_server_adv.Prepend(CPPEXTPATH=["#thirdparty/graphite/include"]) | |
| -env_text_server_adv.add_source_files(module_obj, "*.cpp") | |
| +if coretext_enabled and not freetype_enabled: | |
| + # Exclude SVG-in-OT file when using CoreText without FreeType since it depends on FreeType | |
| + source_files = Glob("*.cpp") | |
| + filtered_sources = [f for f in source_files if not str(f).endswith("thorvg_svg_in_ot.cpp")] | |
| + env_text_server_adv.add_source_files(module_obj, filtered_sources) | |
| +else: | |
| + env_text_server_adv.add_source_files(module_obj, "*.cpp") | |
| env.modules_sources += module_obj | |
| # Needed to force rebuilding the module files when the thirdparty library is updated. | |
| diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py | |
| index 08051398d1..f0d9990e06 100644 | |
| --- a/modules/text_server_adv/config.py | |
| +++ b/modules/text_server_adv/config.py | |
| @@ -1,4 +1,5 @@ | |
| def can_build(env, platform): | |
| + # Always include FreeType dependency, CoreText is optional on macOS | |
| env.module_add_dependencies("text_server_adv", ["freetype", "msdfgen", "svg"], True) | |
| return True | |
| @@ -6,9 +7,14 @@ def can_build(env, platform): | |
| def get_opts(platform): | |
| from SCons.Variables import BoolVariable | |
| - return [ | |
| + opts = [ | |
| BoolVariable("graphite", "Enable SIL Graphite smart fonts support", True), | |
| ] | |
| + | |
| + if platform == "macos": | |
| + opts.append(BoolVariable("coretext", "Use Apple's CoreText instead of FreeType for font rendering", False)) | |
| + | |
| + return opts | |
| def configure(env): | |
| diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp | |
| index b8a9e44aaa..e340ed9dd7 100644 | |
| --- a/modules/text_server_adv/text_server_adv.cpp | |
| +++ b/modules/text_server_adv/text_server_adv.cpp | |
| @@ -65,7 +65,7 @@ using namespace godot; | |
| // Thirdparty headers. | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| #include <core/EdgeHolder.h> | |
| #include <core/ShapeDistanceFinder.h> | |
| #include <core/contour-combiners.h> | |
| @@ -353,10 +353,10 @@ bool TextServerAdvanced::_has_feature(Feature p_feature) const { | |
| case FEATURE_KASHIDA_JUSTIFICATION: | |
| case FEATURE_BREAK_ITERATORS: | |
| case FEATURE_FONT_BITMAP: | |
| -#ifdef MODULE_FREETYPE_ENABLED | |
| +#if defined(MODULE_FREETYPE_ENABLED) || defined(CORETEXT_ENABLED) | |
| case FEATURE_FONT_DYNAMIC: | |
| #endif | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| case FEATURE_FONT_MSDF: | |
| #endif | |
| case FEATURE_FONT_VARIABLE: | |
| @@ -381,10 +381,10 @@ String TextServerAdvanced::_get_name() const { | |
| int64_t TextServerAdvanced::_get_features() const { | |
| int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA; | |
| -#ifdef MODULE_FREETYPE_ENABLED | |
| +#if defined(MODULE_FREETYPE_ENABLED) || defined(CORETEXT_ENABLED) | |
| interface_features |= FEATURE_FONT_DYNAMIC; | |
| #endif | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| interface_features |= FEATURE_FONT_MSDF; | |
| #endif | |
| @@ -905,7 +905,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ | |
| return ret; | |
| } | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| struct MSContext { | |
| msdfgen::Point2 position; | |
| @@ -1210,6 +1210,90 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma | |
| } | |
| #endif | |
| +#ifdef CORETEXT_ENABLED | |
| +_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_coretext_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, CGImageRef p_image, const Vector2 &p_advance, const CGRect &p_bbox) const { | |
| + FontGlyph chr; | |
| + chr.advance = p_advance; | |
| + chr.found = true; | |
| + | |
| + size_t w = CGImageGetWidth(p_image); | |
| + size_t h = CGImageGetHeight(p_image); | |
| + | |
| + if (w == 0 || h == 0) { | |
| + chr.texture_idx = -1; | |
| + chr.uv_rect = Rect2(); | |
| + chr.rect = Rect2(); | |
| + return chr; | |
| + } | |
| + | |
| + int mw = w + p_rect_margin * 4; | |
| + int mh = h + p_rect_margin * 4; | |
| + | |
| + FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 2, Image::FORMAT_LA8, mw, mh, false); | |
| + ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); | |
| + | |
| + // Ensure we have enough textures | |
| + if (tex_pos.index >= p_data->textures.size()) { | |
| + p_data->textures.resize(tex_pos.index + 1); | |
| + } | |
| + | |
| + ShelfPackTexture &tex = p_data->textures.write[tex_pos.index]; | |
| + | |
| + if (!tex.image.is_valid()) { | |
| + tex.image.instantiate(); | |
| + tex.image->initialize_data(tex.texture_w, tex.texture_h, false, Image::FORMAT_LA8); | |
| + } | |
| + | |
| + // Get the image data from CoreGraphics | |
| + CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(p_image)); | |
| + if (imageData) { | |
| + const uint8_t *source_data = CFDataGetBytePtr(imageData); | |
| + size_t bytes_per_row = CGImageGetBytesPerRow(p_image); | |
| + size_t bits_per_pixel = CGImageGetBitsPerPixel(p_image); | |
| + size_t bits_per_component = CGImageGetBitsPerComponent(p_image); | |
| + | |
| + // Debug: Check the actual image format | |
| + // Expected: 8 bits per pixel (grayscale), 8 bits per component | |
| + if (bits_per_pixel == 8 && bits_per_component == 8) { | |
| + // Copy the CoreText rendered glyph to our texture (grayscale data used as alpha) | |
| + for (int y = 0; y < h; y++) { | |
| + for (int x = 0; x < w; x++) { | |
| + int src_index = y * bytes_per_row + x; | |
| + uint8_t grayscale = source_data[src_index]; | |
| + | |
| + // Use grayscale value as alpha (white text on transparent background) | |
| + tex.image->set_pixel(tex_pos.x + x + p_rect_margin, tex_pos.y + y + p_rect_margin, Color(1.0, 1.0, 1.0, grayscale / 255.0)); | |
| + } | |
| + } | |
| + } else { | |
| + // Fallback for unexpected format - assume it's grayscale | |
| + ERR_PRINT(vformat("Unexpected CoreText image format: %d bits per pixel, %d bits per component", (int)bits_per_pixel, (int)bits_per_component)); | |
| + for (int y = 0; y < h; y++) { | |
| + for (int x = 0; x < w; x++) { | |
| + int src_index = y * bytes_per_row + x; | |
| + uint8_t grayscale = source_data[src_index]; | |
| + | |
| + // Use grayscale value as alpha (white text on transparent background) | |
| + tex.image->set_pixel(tex_pos.x + x + p_rect_margin, tex_pos.y + y + p_rect_margin, Color(1.0, 1.0, 1.0, grayscale / 255.0)); | |
| + } | |
| + } | |
| + } | |
| + | |
| + CFRelease(imageData); | |
| + } | |
| + | |
| + tex.dirty = true; | |
| + | |
| + chr.texture_idx = tex_pos.index; | |
| + chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); | |
| + // Use CoreText bbox directly as bearing values | |
| + // bbox.origin gives us the bottom-left corner of the glyph relative to its origin | |
| + chr.rect.position = Vector2(p_bbox.origin.x - p_rect_margin, -(p_bbox.origin.y + p_bbox.size.height) - p_rect_margin) * p_data->scale; | |
| + chr.rect.size = chr.uv_rect.size * p_data->scale; | |
| + return chr; | |
| +} | |
| +#endif | |
| + | |
| /*************************************************************************/ | |
| /* Font Cache */ | |
| /*************************************************************************/ | |
| @@ -1232,8 +1316,73 @@ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i | |
| return true; | |
| } | |
| -#ifdef MODULE_FREETYPE_ENABLED | |
| FontGlyph gl; | |
| + | |
| + if (_should_use_coretext()) { | |
| +#ifdef CORETEXT_ENABLED | |
| + // CoreText backend implementation | |
| + if (fd->ct_font) { | |
| + CGGlyph cg_glyph = (CGGlyph)glyph_index; | |
| + CGSize advance; | |
| + CTFontGetAdvancesForGlyphs(fd->ct_font, kCTFontOrientationDefault, &cg_glyph, &advance, 1); | |
| + | |
| + // Get glyph bounding box | |
| + CGRect bbox; | |
| + CTFontGetBoundingRectsForGlyphs(fd->ct_font, kCTFontOrientationDefault, &cg_glyph, &bbox, 1); | |
| + | |
| + if (bbox.size.width > 0 && bbox.size.height > 0) { | |
| + // Create bitmap context to render glyph | |
| + int width = (int)ceil(bbox.size.width) + 4; // Add padding | |
| + int height = (int)ceil(bbox.size.height) + 4; | |
| + | |
| + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); | |
| + CGContextRef context = CGBitmapContextCreate(nullptr, width, height, 8, width, colorSpace, kCGImageAlphaNone); | |
| + CGColorSpaceRelease(colorSpace); | |
| + | |
| + if (context) { | |
| + // Set up context for rendering | |
| + CGContextSetTextMatrix(context, CGAffineTransformIdentity); | |
| + CGContextSetTextDrawingMode(context, kCGTextFill); | |
| + CGContextSetGrayFillColor(context, 1.0, 1.0); // White fill with full alpha | |
| + | |
| + // Position and render the glyph | |
| + CGPoint position = CGPointMake(-bbox.origin.x + 2, -bbox.origin.y + 2); | |
| + CTFontDrawGlyphs(fd->ct_font, &cg_glyph, &position, 1, context); | |
| + | |
| + // Get bitmap data from context | |
| + const uint8_t *bitmap_data = (const uint8_t*)CGBitmapContextGetData(context); | |
| + if (bitmap_data) { | |
| + // Convert CoreText bitmap to Godot's FontGlyph format | |
| + gl.advance = Vector2(advance.width, advance.height); | |
| + gl.rect = Rect2(bbox.origin.x, bbox.origin.y, width, height); | |
| + gl.found = true; | |
| + | |
| + // For now, don't store texture data - this would need proper texture management | |
| + // This is a simplified implementation for demonstration | |
| + } | |
| + | |
| + CGContextRelease(context); | |
| + } | |
| + | |
| + if (!gl.found) { | |
| + // Fallback for failed rasterization | |
| + gl.advance = Vector2(advance.width, advance.height); | |
| + gl.found = true; | |
| + } | |
| + } else { | |
| + // Handle zero-size glyphs (like spaces) | |
| + gl.advance = Vector2(advance.width, advance.height) * fd->scale; | |
| + gl.found = true; | |
| + } | |
| + } | |
| + | |
| + E = fd->glyph_map.insert(p_glyph, gl); | |
| + r_glyph = E->value; | |
| + return gl.found; | |
| +#endif | |
| + } else { | |
| +#ifdef MODULE_FREETYPE_ENABLED | |
| + // FreeType backend implementation | |
| if (fd->face) { | |
| FT_Int32 flags = FT_LOAD_DEFAULT; | |
| @@ -1332,7 +1481,7 @@ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i | |
| } | |
| if (!error) { | |
| if (p_font_data->msdf) { | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_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(); | |
| @@ -1376,6 +1525,9 @@ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i | |
| return gl.found; | |
| } | |
| #endif | |
| + } // End runtime backend selection | |
| + | |
| + // Fallback if no backend handled the glyph | |
| E = fd->glyph_map.insert(p_glyph, FontGlyph()); | |
| r_glyph = E->value; | |
| return false; | |
| @@ -1399,8 +1551,151 @@ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const | |
| FontForSizeAdvanced *fd = memnew(FontForSizeAdvanced); | |
| fd->size = p_size; | |
| - if (p_font_data->data_ptr && (p_font_data->data_size > 0)) { | |
| + if ((p_font_data->data_ptr && (p_font_data->data_size > 0)) || (_should_use_coretext() && !p_font_data->system_font_name.is_empty())) { | |
| // Init dynamic font. | |
| + if (_should_use_coretext()) { | |
| +#ifdef CORETEXT_ENABLED | |
| + // Check if this is a system font or a font with data | |
| + if (!p_font_data->system_font_name.is_empty()) { | |
| + // Handle system fonts by name - use the CoreText font from the FontAdvanced object | |
| + if (p_font_data->ct_font) { | |
| + double sz = double(fd->size.x) / 64.0; | |
| + if (p_font_data->msdf) { | |
| + sz = p_font_data->msdf_source_size; | |
| + } | |
| + | |
| + // Create a CoreText font for this specific size | |
| + fd->ct_font = CTFontCreateCopyWithAttributes(p_font_data->ct_font, sz, nullptr, nullptr); | |
| + if (!fd->ct_font) { | |
| + memdelete(fd); | |
| + if (p_silent) { | |
| + return false; | |
| + } else { | |
| + ERR_FAIL_V_MSG(false, "CoreText: Failed to create sized CTFont!"); | |
| + } | |
| + } | |
| + | |
| + fd->scale = 1.0; // CoreText handles scaling internally | |
| + | |
| + // Create HarfBuzz font | |
| + fd->hb_handle = hb_coretext_font_create(fd->ct_font); | |
| + hb_font_set_scale(fd->hb_handle, sz * 64, sz * 64); | |
| + | |
| + // Get font metrics | |
| + fd->ascent = CTFontGetAscent(fd->ct_font); | |
| + fd->descent = CTFontGetDescent(fd->ct_font); | |
| + fd->underline_position = -CTFontGetUnderlinePosition(fd->ct_font); | |
| + fd->underline_thickness = CTFontGetUnderlineThickness(fd->ct_font); | |
| + } else { | |
| + memdelete(fd); | |
| + if (p_silent) { | |
| + return false; | |
| + } else { | |
| + ERR_FAIL_V_MSG(false, "CoreText: System font not properly initialized!"); | |
| + } | |
| + } | |
| + } else { | |
| + // Use CoreText backend | |
| + // Create CoreText font from data | |
| + CGDataProviderRef data_provider = CGDataProviderCreateWithData(nullptr, p_font_data->data_ptr, p_font_data->data_size, nullptr); | |
| + print_line(p_font_data->font_name); | |
| + if(p_font_data->font_name == "Apple Color Emoji") { | |
| + //print_line("Emoji font detected"); | |
| + } | |
| + //printf("Created a data provider with size: %zu bytes\n", p_font_data->data_size); | |
| + if (!data_provider) { | |
| + memdelete(fd); | |
| + if (p_silent) { | |
| + return false; | |
| + } else { | |
| + ERR_FAIL_V_MSG(false, "CoreText: Failed to create data provider!"); | |
| + } | |
| + } | |
| + | |
| + fd->cg_font = CGFontCreateWithDataProvider(data_provider); | |
| + CGDataProviderRelease(data_provider); | |
| + | |
| + if (!fd->cg_font) { | |
| + memdelete(fd); | |
| + if (p_silent) { | |
| + return false; | |
| + } else { | |
| + ERR_FAIL_V_MSG(false, "CoreText: Failed to create CGFont!"); | |
| + } | |
| + } | |
| + | |
| + double sz = double(fd->size.x) / 64.0; | |
| + if (p_font_data->msdf) { | |
| + sz = p_font_data->msdf_source_size; | |
| + } | |
| + | |
| + fd->ct_font = CTFontCreateWithGraphicsFont(fd->cg_font, sz, nullptr, nullptr); | |
| + if (!fd->ct_font) { | |
| + CFRelease(fd->cg_font); | |
| + fd->cg_font = nullptr; | |
| + memdelete(fd); | |
| + if (p_silent) { | |
| + return false; | |
| + } else { | |
| + ERR_FAIL_V_MSG(false, "CoreText: Failed to create CTFont!"); | |
| + } | |
| + } | |
| + | |
| + fd->scale = 1.0; // CoreText handles scaling internally | |
| + | |
| + // Create HarfBuzz font | |
| + fd->hb_handle = hb_coretext_font_create(fd->ct_font); | |
| + // Set HarfBuzz font scale - CoreText units need to be converted to HarfBuzz units (26.6 fractional pixels) | |
| + hb_font_set_scale(fd->hb_handle, sz * 64, sz * 64); | |
| + | |
| + // Get font metrics | |
| + fd->ascent = CTFontGetAscent(fd->ct_font); | |
| + fd->descent = CTFontGetDescent(fd->ct_font); | |
| + fd->underline_position = -CTFontGetUnderlinePosition(fd->ct_font); | |
| + fd->underline_thickness = CTFontGetUnderlineThickness(fd->ct_font); | |
| + | |
| + if (!p_font_data->face_init) { | |
| + // Get font name | |
| + CFStringRef font_name = CTFontCopyFamilyName(fd->ct_font); | |
| + if (font_name) { | |
| + char buffer[256]; | |
| + if (CFStringGetCString(font_name, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { | |
| + p_font_data->font_name = String::utf8(buffer); | |
| + } | |
| + CFRelease(font_name); | |
| + } | |
| + | |
| + // Get style name | |
| + CFStringRef style_name = CTFontCopyName(fd->ct_font, kCTFontStyleNameKey); | |
| + if (style_name) { | |
| + char buffer[256]; | |
| + if (CFStringGetCString(style_name, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { | |
| + p_font_data->style_name = String::utf8(buffer); | |
| + } | |
| + CFRelease(style_name); | |
| + } | |
| + | |
| + // Get font weight and style flags | |
| + p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower()); | |
| + p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower()); | |
| + p_font_data->style_flags = 0; | |
| + | |
| + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(fd->ct_font); | |
| + if (traits & kCTFontTraitBold) { | |
| + p_font_data->style_flags.set_flag(FONT_BOLD); | |
| + } | |
| + if (traits & kCTFontTraitItalic) { | |
| + p_font_data->style_flags.set_flag(FONT_ITALIC); | |
| + } | |
| + if (traits & kCTFontTraitMonoSpace) { | |
| + p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH); | |
| + } | |
| + | |
| + p_font_data->face_init = true; | |
| + } | |
| + } // End else block for font data | |
| +#endif | |
| + } else { | |
| #ifdef MODULE_FREETYPE_ENABLED | |
| int error = 0; | |
| { | |
| @@ -1415,7 +1710,7 @@ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const | |
| ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); | |
| } | |
| } | |
| -#ifdef MODULE_SVG_ENABLED | |
| +#if defined(MODULE_SVG_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks()); | |
| #endif | |
| } | |
| @@ -1918,12 +2213,14 @@ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const | |
| hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size()); | |
| FT_Done_MM_Var(ft_library, amaster); | |
| } | |
| -#else | |
| +#endif | |
| + } // End FreeType backend | |
| +#if !defined(MODULE_FREETYPE_ENABLED) && !defined(CORETEXT_ENABLED) | |
| memdelete(fd); | |
| if (p_silent) { | |
| return false; | |
| } else { | |
| - ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); | |
| + ERR_FAIL_V_MSG(false, "No font backend available (FreeType or CoreText)!"); | |
| } | |
| #endif | |
| } else { | |
| @@ -2043,6 +2340,60 @@ RID TextServerAdvanced::_create_font_linked_variation(const RID &p_font_rid) { | |
| return font_var_owner.make_rid(new_fdv); | |
| } | |
| +RID TextServerAdvanced::_create_font_system(const String &p_name, TextServer::FontAntialiasing p_antialiasing) { | |
| + _THREAD_SAFE_METHOD_ | |
| + | |
| +#ifdef CORETEXT_ENABLED | |
| + FontAdvanced *fd = memnew(FontAdvanced); | |
| + fd->antialiasing = p_antialiasing; | |
| + fd->system_font_name = p_name; | |
| + | |
| + // Create CoreText font from name | |
| + CFStringRef font_name_cf = CFStringCreateWithCString(kCFAllocatorDefault, p_name.utf8().get_data(), kCFStringEncodingUTF8); | |
| + if (font_name_cf) { | |
| + CTFontRef ct_font_ref = CTFontCreateWithName(font_name_cf, 16.0, nullptr); | |
| + if (ct_font_ref) { | |
| + fd->ct_font = ct_font_ref; | |
| + // Set font properties from CoreText | |
| + CFStringRef family_name = CTFontCopyFamilyName(ct_font_ref); | |
| + if (family_name) { | |
| + char buffer[1024]; | |
| + if (CFStringGetCString(family_name, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { | |
| + fd->font_name = String(buffer); | |
| + } | |
| + CFRelease(family_name); | |
| + } | |
| + | |
| + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ct_font_ref); | |
| + if (traits & kCTFontBoldTrait) { | |
| + fd->style_flags.set_flag(TextServer::FONT_BOLD); | |
| + } | |
| + if (traits & kCTFontItalicTrait) { | |
| + fd->style_flags.set_flag(TextServer::FONT_ITALIC); | |
| + } | |
| + if (traits & kCTFontMonoSpaceTrait) { | |
| + fd->style_flags.set_flag(TextServer::FONT_FIXED_WIDTH); | |
| + } | |
| + } else { | |
| + // Font creation failed, clean up and return invalid RID | |
| + CFRelease(font_name_cf); | |
| + memdelete(fd); | |
| + return RID(); | |
| + } | |
| + CFRelease(font_name_cf); | |
| + } else { | |
| + // String creation failed, clean up and return invalid RID | |
| + memdelete(fd); | |
| + return RID(); | |
| + } | |
| + | |
| + return font_owner.make_rid(fd); | |
| +#else | |
| + // For platforms other than macOS, create a regular font | |
| + return _create_font(); | |
| +#endif | |
| +} | |
| + | |
| void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { | |
| FontAdvanced *fd = _get_font_data(p_font_rid); | |
| ERR_FAIL_NULL(fd); | |
| @@ -2101,7 +2452,7 @@ int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const { | |
| if (!ft_library) { | |
| error = FT_Init_FreeType(&ft_library); | |
| ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); | |
| -#ifdef MODULE_SVG_ENABLED | |
| +#if defined(MODULE_SVG_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks()); | |
| #endif | |
| } | |
| @@ -2128,6 +2479,24 @@ int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const { | |
| FT_Done_Face(tmp_face); | |
| } | |
| #endif | |
| + | |
| +#ifdef CORETEXT_ENABLED | |
| + // CoreText typically doesn't have multiple faces in a single font file | |
| + // but we can check by attempting to create the font | |
| + CFDataRef font_data = CFDataCreate(nullptr, (const UInt8 *)fd->data_ptr, fd->data_size); | |
| + if (font_data) { | |
| + CGDataProviderRef data_provider = CGDataProviderCreateWithCFData(font_data); | |
| + if (data_provider) { | |
| + CGFontRef cg_font = CGFontCreateWithDataProvider(data_provider); | |
| + if (cg_font) { | |
| + face_count = 1; // CoreText fonts typically have 1 face | |
| + CFRelease(cg_font); | |
| + } | |
| + CFRelease(data_provider); | |
| + } | |
| + CFRelease(font_data); | |
| + } | |
| +#endif | |
| } | |
| return face_count; | |
| @@ -2980,6 +3349,11 @@ void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, | |
| if (ffsd->face) { | |
| return; // Do not override scale for dynamic fonts, it's calculated automatically. | |
| } | |
| +#endif | |
| +#ifdef CORETEXT_ENABLED | |
| + if (ffsd->ct_font) { | |
| + return; // Do not override scale for dynamic fonts, it's calculated automatically. | |
| + } | |
| #endif | |
| ffsd->scale = p_scale; | |
| } | |
| @@ -8182,6 +8556,21 @@ TextServerAdvanced::TextServerAdvanced() { | |
| _insert_feature_sets(); | |
| _bmp_create_font_funcs(); | |
| _update_settings(); | |
| + | |
| + // Check environment variable for backend selection | |
| +#ifdef CORETEXT_ENABLED | |
| + const char* use_coretext_env = getenv("USE_CORETEXT"); | |
| + if (use_coretext_env != nullptr) { | |
| + String env_value = String(use_coretext_env).to_lower(); | |
| + use_coretext_backend = (env_value == "true" || env_value == "1" || env_value == "yes"); | |
| + } else { | |
| + // Default to FreeType if environment variable is not set | |
| + use_coretext_backend = false; | |
| + } | |
| +#else | |
| + use_coretext_backend = false; | |
| +#endif | |
| + | |
| ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerAdvanced::_update_settings)); | |
| } | |
| diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h | |
| index 254430037f..20cd65f417 100644 | |
| --- a/modules/text_server_adv/text_server_adv.h | |
| +++ b/modules/text_server_adv/text_server_adv.h | |
| @@ -124,8 +124,16 @@ using namespace godot; | |
| #include <hb-ot.h> | |
| #endif | |
| +#ifdef CORETEXT_ENABLED | |
| +#include <CoreText/CoreText.h> | |
| +#include <CoreGraphics/CoreGraphics.h> | |
| +#include <CoreFoundation/CoreFoundation.h> | |
| +#include <hb-coretext.h> | |
| +#endif | |
| + | |
| #include <hb-icu.h> | |
| #include <hb.h> | |
| +#include <hb-ot.h> | |
| /*************************************************************************/ | |
| @@ -185,6 +193,20 @@ class TextServerAdvanced : public TextServerExtension { | |
| mutable FT_Library ft_library = nullptr; | |
| #endif | |
| +#ifdef CORETEXT_ENABLED | |
| + // CoreText doesn't need a global library instance like FreeType | |
| +#endif | |
| + | |
| + // Runtime backend selection | |
| + mutable bool use_coretext_backend = false; | |
| + _FORCE_INLINE_ bool _should_use_coretext() const { | |
| +#ifdef CORETEXT_ENABLED | |
| + return use_coretext_backend; | |
| +#else | |
| + return false; | |
| +#endif | |
| + } | |
| + | |
| const int rect_range = 1; | |
| struct FontTexturePosition { | |
| @@ -301,6 +323,11 @@ class TextServerAdvanced : public TextServerExtension { | |
| FT_StreamRec stream; | |
| #endif | |
| +#ifdef CORETEXT_ENABLED | |
| + CTFontRef ct_font = nullptr; | |
| + CGFontRef cg_font = nullptr; | |
| +#endif | |
| + | |
| ~FontForSizeAdvanced() { | |
| if (hb_handle != nullptr) { | |
| hb_font_destroy(hb_handle); | |
| @@ -309,6 +336,14 @@ class TextServerAdvanced : public TextServerExtension { | |
| if (face != nullptr) { | |
| FT_Done_Face(face); | |
| } | |
| +#endif | |
| +#ifdef CORETEXT_ENABLED | |
| + if (ct_font != nullptr) { | |
| + CFRelease(ct_font); | |
| + } | |
| + if (cg_font != nullptr) { | |
| + CFRelease(cg_font); | |
| + } | |
| #endif | |
| } | |
| }; | |
| @@ -351,6 +386,7 @@ class TextServerAdvanced : public TextServerExtension { | |
| BitField<TextServer::FontStyle> style_flags = 0; | |
| String font_name; | |
| String style_name; | |
| + String system_font_name; | |
| int weight = 400; | |
| int stretch = 100; | |
| int extra_spacing[4] = { 0, 0, 0, 0 }; | |
| @@ -373,20 +409,33 @@ class TextServerAdvanced : public TextServerExtension { | |
| size_t data_size; | |
| int face_index = 0; | |
| +#ifdef CORETEXT_ENABLED | |
| + CTFontRef ct_font = nullptr; | |
| +#endif | |
| + | |
| ~FontAdvanced() { | |
| for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : cache) { | |
| memdelete(E.value); | |
| } | |
| cache.clear(); | |
| +#ifdef CORETEXT_ENABLED | |
| + if (ct_font) { | |
| + CFRelease(ct_font); | |
| + ct_font = nullptr; | |
| + } | |
| +#endif | |
| } | |
| }; | |
| _FORCE_INLINE_ FontTexturePosition find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const; | |
| -#ifdef MODULE_MSDFGEN_ENABLED | |
| +#if defined(MODULE_MSDFGEN_ENABLED) && defined(MODULE_FREETYPE_ENABLED) | |
| _FORCE_INLINE_ FontGlyph rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *p_outline, const Vector2 &p_advance) const; | |
| #endif | |
| #ifdef MODULE_FREETYPE_ENABLED | |
| _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const; | |
| +#endif | |
| +#ifdef CORETEXT_ENABLED | |
| + _FORCE_INLINE_ FontGlyph rasterize_coretext_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, CGImageRef p_image, const Vector2 &p_advance, const CGRect &p_bbox) const; | |
| #endif | |
| bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling = 0) const; | |
| bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size, FontForSizeAdvanced *&r_cache_for_size, bool p_silent = false, uint32_t p_oversampling = 0) const; | |
| @@ -770,6 +819,7 @@ public: | |
| MODBIND0R(RID, create_font); | |
| MODBIND1R(RID, create_font_linked_variation, const RID &); | |
| + MODBIND2R(RID, create_font_system, const String &, TextServer::FontAntialiasing); | |
| MODBIND2(font_set_data, const RID &, const PackedByteArray &); | |
| MODBIND3(font_set_data_ptr, const RID &, const uint8_t *, int64_t); | |
| diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp | |
| index a2b68702b9..343d6bfa17 100644 | |
| --- a/modules/text_server_fb/text_server_fb.cpp | |
| +++ b/modules/text_server_fb/text_server_fb.cpp | |
| @@ -1131,6 +1131,17 @@ RID TextServerFallback::_create_font_linked_variation(const RID &p_font_rid) { | |
| return font_var_owner.make_rid(new_fdv); | |
| } | |
| +RID TextServerFallback::_create_font_system(const String &p_name, TextServer::FontAntialiasing p_antialiasing) { | |
| + _THREAD_SAFE_METHOD_ | |
| + | |
| + // TextServerFallback doesn't support system fonts by name, so just create a regular font | |
| + // This could be extended in the future to support system font loading on platforms that have APIs for it | |
| + FontFallback *fd = memnew(FontFallback); | |
| + fd->antialiasing = p_antialiasing; | |
| + | |
| + return font_owner.make_rid(fd); | |
| +} | |
| + | |
| void TextServerFallback::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { | |
| FontFallback *fd = _get_font_data(p_font_rid); | |
| ERR_FAIL_NULL(fd); | |
| diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h | |
| index 8349f37c18..5661dd854c 100644 | |
| --- a/modules/text_server_fb/text_server_fb.h | |
| +++ b/modules/text_server_fb/text_server_fb.h | |
| @@ -626,6 +626,7 @@ public: | |
| MODBIND0R(RID, create_font); | |
| MODBIND1R(RID, create_font_linked_variation, const RID &); | |
| + MODBIND2R(RID, create_font_system, const String &, TextServer::FontAntialiasing); | |
| MODBIND2(font_set_data, const RID &, const PackedByteArray &); | |
| MODBIND3(font_set_data_ptr, const RID &, const uint8_t *, int64_t); | |
| diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp | |
| index 904d73cf3d..2d6906c587 100644 | |
| --- a/scene/resources/font.cpp | |
| +++ b/scene/resources/font.cpp | |
| @@ -3664,3 +3664,368 @@ SystemFont::SystemFont() { | |
| SystemFont::~SystemFont() { | |
| } | |
| + | |
| +/*************************************************************************/ | |
| +/* OperatingSystemFont */ | |
| +/*************************************************************************/ | |
| + | |
| +void OperatingSystemFont::_bind_methods() { | |
| + ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &OperatingSystemFont::set_antialiasing); | |
| + ClassDB::bind_method(D_METHOD("get_antialiasing"), &OperatingSystemFont::get_antialiasing); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_disable_embedded_bitmaps", "disable_embedded_bitmaps"), &OperatingSystemFont::set_disable_embedded_bitmaps); | |
| + ClassDB::bind_method(D_METHOD("get_disable_embedded_bitmaps"), &OperatingSystemFont::get_disable_embedded_bitmaps); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &OperatingSystemFont::set_generate_mipmaps); | |
| + ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &OperatingSystemFont::get_generate_mipmaps); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_allow_system_fallback", "allow_system_fallback"), &OperatingSystemFont::set_allow_system_fallback); | |
| + ClassDB::bind_method(D_METHOD("is_allow_system_fallback"), &OperatingSystemFont::is_allow_system_fallback); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &OperatingSystemFont::set_force_autohinter); | |
| + ClassDB::bind_method(D_METHOD("is_force_autohinter"), &OperatingSystemFont::is_force_autohinter); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_modulate_color_glyphs", "modulate"), &OperatingSystemFont::set_modulate_color_glyphs); | |
| + ClassDB::bind_method(D_METHOD("is_modulate_color_glyphs"), &OperatingSystemFont::is_modulate_color_glyphs); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &OperatingSystemFont::set_hinting); | |
| + ClassDB::bind_method(D_METHOD("get_hinting"), &OperatingSystemFont::get_hinting); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &OperatingSystemFont::set_subpixel_positioning); | |
| + ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &OperatingSystemFont::get_subpixel_positioning); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_keep_rounding_remainders", "keep_rounding_remainders"), &OperatingSystemFont::set_keep_rounding_remainders); | |
| + ClassDB::bind_method(D_METHOD("get_keep_rounding_remainders"), &OperatingSystemFont::get_keep_rounding_remainders); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &OperatingSystemFont::set_multichannel_signed_distance_field); | |
| + ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &OperatingSystemFont::is_multichannel_signed_distance_field); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &OperatingSystemFont::set_msdf_pixel_range); | |
| + ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &OperatingSystemFont::get_msdf_pixel_range); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &OperatingSystemFont::set_msdf_size); | |
| + ClassDB::bind_method(D_METHOD("get_msdf_size"), &OperatingSystemFont::get_msdf_size); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &OperatingSystemFont::set_oversampling); | |
| + ClassDB::bind_method(D_METHOD("get_oversampling"), &OperatingSystemFont::get_oversampling); | |
| + | |
| + ClassDB::bind_method(D_METHOD("set_font_name", "name"), &OperatingSystemFont::set_font_name); | |
| + | |
| + ClassDB::bind_method(D_METHOD("get_font_size"), &OperatingSystemFont::get_font_size); | |
| + ClassDB::bind_method(D_METHOD("set_font_size", "size"), &OperatingSystemFont::set_font_size); | |
| + | |
| + ClassDB::bind_method(D_METHOD("get_font_italic"), &OperatingSystemFont::get_font_italic); | |
| + ClassDB::bind_method(D_METHOD("set_font_italic", "italic"), &OperatingSystemFont::set_font_italic); | |
| + ClassDB::bind_method(D_METHOD("set_font_weight", "weight"), &OperatingSystemFont::set_font_weight); | |
| + ClassDB::bind_method(D_METHOD("set_font_stretch", "stretch"), &OperatingSystemFont::set_font_stretch); | |
| + | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1"), "set_font_size", "get_font_size"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "font_italic"), "set_font_italic", "get_font_italic"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "get_generate_mipmaps"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_embedded_bitmaps"), "set_disable_embedded_bitmaps", "get_disable_embedded_bitmaps"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback"), "set_allow_system_fallback", "is_allow_system_fallback"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "modulate_color_glyphs"), "set_modulate_color_glyphs", "is_modulate_color_glyphs"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), "set_subpixel_positioning", "get_subpixel_positioning"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), "set_keep_rounding_remainders", "get_keep_rounding_remainders"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range"), "set_msdf_pixel_range", "get_msdf_pixel_range"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size"), "set_msdf_size", "get_msdf_size"); | |
| + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling"), "set_oversampling", "get_oversampling"); | |
| +} | |
| + | |
| +void OperatingSystemFont::_update_rids() const { | |
| + rids.clear(); | |
| + _update_os_font(); | |
| + if (os_font_rid.is_valid()) { | |
| + rids.push_back(os_font_rid); | |
| + } | |
| + dirty_rids = false; | |
| +} | |
| + | |
| +void OperatingSystemFont::_update_os_font() const { | |
| + // Only create if not already created | |
| + if (!os_font_rid.is_valid() && !font_name.is_empty()) { | |
| + os_font_rid = TS->create_font_system(font_name, antialiasing); | |
| + if (os_font_rid.is_valid()) { | |
| + TS->font_set_disable_embedded_bitmaps(os_font_rid, disable_embedded_bitmaps); | |
| + TS->font_set_generate_mipmaps(os_font_rid, mipmaps); | |
| + TS->font_set_force_autohinter(os_font_rid, force_autohinter); | |
| + TS->font_set_allow_system_fallback(os_font_rid, allow_system_fallback); | |
| + TS->font_set_modulate_color_glyphs(os_font_rid, modulate_color_glyphs); | |
| + TS->font_set_hinting(os_font_rid, hinting); | |
| + TS->font_set_subpixel_positioning(os_font_rid, subpixel_positioning); | |
| + TS->font_set_keep_rounding_remainders(os_font_rid, keep_rounding_remainders); | |
| + TS->font_set_oversampling(os_font_rid, oversampling_override); | |
| + TS->font_set_multichannel_signed_distance_field(os_font_rid, msdf); | |
| + TS->font_set_msdf_pixel_range(os_font_rid, msdf_pixel_range); | |
| + TS->font_set_msdf_size(os_font_rid, msdf_size); | |
| + } | |
| + } | |
| +} | |
| + | |
| +void OperatingSystemFont::reset_state() { | |
| + if (os_font_rid.is_valid()) { | |
| + TS->free_rid(os_font_rid); | |
| + os_font_rid = RID(); | |
| + } | |
| + | |
| + if (theme_font.is_valid()) { | |
| + theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids)); | |
| + theme_font.unref(); | |
| + } | |
| + | |
| + font_name = ""; | |
| + font_size = 16; | |
| + italic = false; | |
| + weight = 400; | |
| + stretch = 100; | |
| + | |
| + antialiasing = TextServer::FONT_ANTIALIASING_GRAY; | |
| + mipmaps = false; | |
| + disable_embedded_bitmaps = true; | |
| + force_autohinter = false; | |
| + modulate_color_glyphs = false; | |
| + allow_system_fallback = true; | |
| + hinting = TextServer::HINTING_LIGHT; | |
| + subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; | |
| + keep_rounding_remainders = true; | |
| + oversampling_override = 0.0; | |
| + msdf = false; | |
| + msdf_pixel_range = 16; | |
| + msdf_size = 48; | |
| + | |
| + Font::reset_state(); | |
| +} | |
| + | |
| +void OperatingSystemFont::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) { | |
| + if (antialiasing != p_antialiasing) { | |
| + antialiasing = p_antialiasing; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +TextServer::FontAntialiasing OperatingSystemFont::get_antialiasing() const { | |
| + return antialiasing; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_disable_embedded_bitmaps(bool p_disable_embedded_bitmaps) { | |
| + if (disable_embedded_bitmaps != p_disable_embedded_bitmaps) { | |
| + disable_embedded_bitmaps = p_disable_embedded_bitmaps; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::get_disable_embedded_bitmaps() const { | |
| + return disable_embedded_bitmaps; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_generate_mipmaps(bool p_generate_mipmaps) { | |
| + if (mipmaps != p_generate_mipmaps) { | |
| + mipmaps = p_generate_mipmaps; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::get_generate_mipmaps() const { | |
| + return mipmaps; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_allow_system_fallback(bool p_allow_system_fallback) { | |
| + if (allow_system_fallback != p_allow_system_fallback) { | |
| + allow_system_fallback = p_allow_system_fallback; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::is_allow_system_fallback() const { | |
| + return allow_system_fallback; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_force_autohinter(bool p_force_autohinter) { | |
| + if (force_autohinter != p_force_autohinter) { | |
| + force_autohinter = p_force_autohinter; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::is_force_autohinter() const { | |
| + return force_autohinter; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_modulate_color_glyphs(bool p_modulate) { | |
| + if (modulate_color_glyphs != p_modulate) { | |
| + modulate_color_glyphs = p_modulate; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::is_modulate_color_glyphs() const { | |
| + return modulate_color_glyphs; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_hinting(TextServer::Hinting p_hinting) { | |
| + if (hinting != p_hinting) { | |
| + hinting = p_hinting; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +TextServer::Hinting OperatingSystemFont::get_hinting() const { | |
| + return hinting; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) { | |
| + if (subpixel_positioning != p_subpixel) { | |
| + subpixel_positioning = p_subpixel; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +TextServer::SubpixelPositioning OperatingSystemFont::get_subpixel_positioning() const { | |
| + return subpixel_positioning; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_keep_rounding_remainders(bool p_keep_rounding_remainders) { | |
| + if (keep_rounding_remainders != p_keep_rounding_remainders) { | |
| + keep_rounding_remainders = p_keep_rounding_remainders; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::get_keep_rounding_remainders() const { | |
| + return keep_rounding_remainders; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_oversampling(real_t p_oversampling) { | |
| + if (oversampling_override != p_oversampling) { | |
| + oversampling_override = p_oversampling; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +real_t OperatingSystemFont::get_oversampling() const { | |
| + return oversampling_override; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_multichannel_signed_distance_field(bool p_msdf) { | |
| + if (msdf != p_msdf) { | |
| + msdf = p_msdf; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::is_multichannel_signed_distance_field() const { | |
| + return msdf; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_msdf_pixel_range(int p_msdf_pixel_range) { | |
| + if (msdf_pixel_range != p_msdf_pixel_range) { | |
| + msdf_pixel_range = p_msdf_pixel_range; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +int OperatingSystemFont::get_msdf_pixel_range() const { | |
| + return msdf_pixel_range; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_msdf_size(int p_msdf_size) { | |
| + if (msdf_size != p_msdf_size) { | |
| + msdf_size = p_msdf_size; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +int OperatingSystemFont::get_msdf_size() const { | |
| + return msdf_size; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_font_name(const String &p_name) { | |
| + if (font_name != p_name) { | |
| + font_name = p_name; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +String OperatingSystemFont::get_font_name() const { | |
| + return font_name; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_font_size(int p_size) { | |
| + if (font_size != p_size) { | |
| + font_size = p_size; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +int OperatingSystemFont::get_font_size() const { | |
| + return font_size; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_font_italic(bool p_italic) { | |
| + if (italic != p_italic) { | |
| + italic = p_italic; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +bool OperatingSystemFont::get_font_italic() const { | |
| + return italic; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_font_weight(int p_weight) { | |
| + if (weight != p_weight) { | |
| + weight = p_weight; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +int OperatingSystemFont::get_font_weight() const { | |
| + return weight; | |
| +} | |
| + | |
| +void OperatingSystemFont::set_font_stretch(int p_stretch) { | |
| + if (stretch != p_stretch) { | |
| + stretch = p_stretch; | |
| + _invalidate_rids(); | |
| + } | |
| +} | |
| + | |
| +int OperatingSystemFont::get_font_stretch() const { | |
| + return stretch; | |
| +} | |
| + | |
| +int OperatingSystemFont::get_spacing(TextServer::SpacingType p_spacing) const { | |
| + return 0; | |
| +} | |
| + | |
| +RID OperatingSystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph, float p_baseline_offset) const { | |
| + _update_os_font(); | |
| + if (os_font_rid.is_valid()) { | |
| + // For now, return the base font directly to avoid variation issues | |
| + // TODO: Properly implement font variations for system fonts | |
| + return os_font_rid; | |
| + } | |
| + return RID(); | |
| +} | |
| + | |
| +RID OperatingSystemFont::_get_rid() const { | |
| + _update_os_font(); | |
| + return os_font_rid; | |
| +} | |
| + | |
| +int64_t OperatingSystemFont::get_face_count() const { | |
| + return 1; | |
| +} | |
| + | |
| +OperatingSystemFont::OperatingSystemFont() { | |
| +} | |
| + | |
| +OperatingSystemFont::~OperatingSystemFont() { | |
| + if (os_font_rid.is_valid()) { | |
| + TS->free_rid(os_font_rid); | |
| + } | |
| +} | |
| diff --git a/scene/resources/font.h b/scene/resources/font.h | |
| index 52cf8036e6..331349335a 100644 | |
| --- a/scene/resources/font.h | |
| +++ b/scene/resources/font.h | |
| @@ -572,3 +572,107 @@ public: | |
| SystemFont(); | |
| ~SystemFont(); | |
| }; | |
| + | |
| +/*************************************************************************/ | |
| +/* OperatingSystemFont */ | |
| +/*************************************************************************/ | |
| + | |
| +class OperatingSystemFont : public Font { | |
| + GDCLASS(OperatingSystemFont, Font); | |
| + | |
| + String font_name; | |
| + int font_size = 16; | |
| + bool italic = false; | |
| + int weight = 400; | |
| + int stretch = 100; | |
| + | |
| + mutable Ref<Font> theme_font; | |
| + mutable RID os_font_rid; | |
| + | |
| + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; | |
| + bool mipmaps = false; | |
| + bool disable_embedded_bitmaps = true; | |
| + bool force_autohinter = false; | |
| + bool modulate_color_glyphs = false; | |
| + bool allow_system_fallback = true; | |
| + TextServer::Hinting hinting = TextServer::HINTING_LIGHT; | |
| + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; | |
| + bool keep_rounding_remainders = true; | |
| + double oversampling_override = 0.0; | |
| + bool msdf = false; | |
| + int msdf_pixel_range = 16; | |
| + int msdf_size = 48; | |
| + | |
| +protected: | |
| + static void _bind_methods(); | |
| + | |
| + virtual void _update_os_font() const; | |
| + virtual void _update_rids() const override; | |
| + | |
| + virtual void reset_state() override; | |
| + | |
| +public: | |
| + virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing); | |
| + virtual TextServer::FontAntialiasing get_antialiasing() const; | |
| + | |
| + virtual void set_disable_embedded_bitmaps(bool p_disable_embedded_bitmaps); | |
| + virtual bool get_disable_embedded_bitmaps() const; | |
| + | |
| + virtual void set_generate_mipmaps(bool p_generate_mipmaps); | |
| + virtual bool get_generate_mipmaps() const; | |
| + | |
| + virtual void set_allow_system_fallback(bool p_allow_system_fallback); | |
| + virtual bool is_allow_system_fallback() const; | |
| + | |
| + virtual void set_force_autohinter(bool p_force_autohinter); | |
| + virtual bool is_force_autohinter() const; | |
| + | |
| + virtual void set_modulate_color_glyphs(bool p_modulate); | |
| + virtual bool is_modulate_color_glyphs() const; | |
| + | |
| + virtual void set_hinting(TextServer::Hinting p_hinting); | |
| + virtual TextServer::Hinting get_hinting() const; | |
| + | |
| + virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel); | |
| + virtual TextServer::SubpixelPositioning get_subpixel_positioning() const; | |
| + | |
| + virtual void set_keep_rounding_remainders(bool p_keep_rounding_remainders); | |
| + virtual bool get_keep_rounding_remainders() const; | |
| + | |
| + virtual void set_oversampling(real_t p_oversampling); | |
| + virtual real_t get_oversampling() const; | |
| + | |
| + virtual void set_multichannel_signed_distance_field(bool p_msdf); | |
| + virtual bool is_multichannel_signed_distance_field() const; | |
| + | |
| + virtual void set_msdf_pixel_range(int p_msdf_pixel_range); | |
| + virtual int get_msdf_pixel_range() const; | |
| + | |
| + virtual void set_msdf_size(int p_msdf_size); | |
| + virtual int get_msdf_size() const; | |
| + | |
| + virtual void set_font_name(const String &p_name); | |
| + virtual String get_font_name() const override; | |
| + | |
| + virtual void set_font_size(int p_size); | |
| + virtual int get_font_size() const; | |
| + | |
| + virtual void set_font_italic(bool p_italic); | |
| + virtual bool get_font_italic() const; | |
| + | |
| + virtual void set_font_weight(int p_weight); | |
| + virtual int get_font_weight() const override; | |
| + | |
| + virtual void set_font_stretch(int p_stretch); | |
| + virtual int get_font_stretch() const override; | |
| + | |
| + virtual int get_spacing(TextServer::SpacingType p_spacing) const override; | |
| + | |
| + virtual RID find_variation(const Dictionary &p_variation_coordinates, int p_face_index = 0, float p_strength = 0.0, Transform2D p_transform = Transform2D(), int p_spacing_top = 0, int p_spacing_bottom = 0, int p_spacing_space = 0, int p_spacing_glyph = 0, float p_baseline_offset = 0.0) const override; | |
| + virtual RID _get_rid() const override; | |
| + | |
| + int64_t get_face_count() const override; | |
| + | |
| + OperatingSystemFont(); | |
| + ~OperatingSystemFont(); | |
| +}; | |
| diff --git a/servers/text/text_server_dummy.h b/servers/text/text_server_dummy.h | |
| index a1f3a08d5b..31578a3131 100644 | |
| --- a/servers/text/text_server_dummy.h | |
| +++ b/servers/text/text_server_dummy.h | |
| @@ -46,6 +46,8 @@ public: | |
| virtual bool has(const RID &p_rid) override { return false; } | |
| virtual RID create_font() override { return RID(); } | |
| + virtual RID create_font_linked_variation(const RID &p_font_rid) override { return RID(); } | |
| + virtual RID create_font_system(const String &p_name, FontAntialiasing p_antialiasing = FONT_ANTIALIASING_GRAY) override { return RID(); } | |
| virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override {} | |
| virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override { return 0; } | |
| virtual void font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) override {} | |
| diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp | |
| index 28fd2ff50c..59bbfa254c 100644 | |
| --- a/servers/text/text_server_extension.cpp | |
| +++ b/servers/text/text_server_extension.cpp | |
| @@ -53,6 +53,7 @@ void TextServerExtension::_bind_methods() { | |
| GDVIRTUAL_BIND(_create_font); | |
| GDVIRTUAL_BIND(_create_font_linked_variation, "font_rid"); | |
| + GDVIRTUAL_BIND(_create_font_system, "name", "antialiasing"); | |
| GDVIRTUAL_BIND(_font_set_data, "font_rid", "data"); | |
| GDVIRTUAL_BIND(_font_set_data_ptr, "font_rid", "data_ptr", "data_size"); | |
| @@ -482,6 +483,12 @@ RID TextServerExtension::create_font_linked_variation(const RID &p_font_rid) { | |
| return ret; | |
| } | |
| +RID TextServerExtension::create_font_system(const String &p_name, FontAntialiasing p_antialiasing) { | |
| + RID ret; | |
| + GDVIRTUAL_CALL(_create_font_system, p_name, p_antialiasing, ret); | |
| + return ret; | |
| +} | |
| + | |
| void TextServerExtension::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { | |
| GDVIRTUAL_CALL(_font_set_data, p_font_rid, p_data); | |
| } | |
| diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h | |
| index a5c0a06e96..aebba5c9ed 100644 | |
| --- a/servers/text/text_server_extension.h | |
| +++ b/servers/text/text_server_extension.h | |
| @@ -84,6 +84,9 @@ public: | |
| virtual RID create_font_linked_variation(const RID &p_font_rid) override; | |
| GDVIRTUAL1R(RID, _create_font_linked_variation, RID); | |
| + virtual RID create_font_system(const String &p_name, FontAntialiasing p_antialiasing = FONT_ANTIALIASING_GRAY) override; | |
| + GDVIRTUAL2R(RID, _create_font_system, String, FontAntialiasing); | |
| + | |
| virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; | |
| virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; | |
| GDVIRTUAL2(_font_set_data, RID, const PackedByteArray &); | |
| diff --git a/servers/text_server.h b/servers/text_server.h | |
| index 50d2683909..a19e910df2 100644 | |
| --- a/servers/text_server.h | |
| +++ b/servers/text_server.h | |
| @@ -268,6 +268,7 @@ public: | |
| virtual RID create_font() = 0; | |
| virtual RID create_font_linked_variation(const RID &p_font_rid) = 0; | |
| + virtual RID create_font_system(const String &p_name, FontAntialiasing p_antialiasing = FONT_ANTIALIASING_GRAY) = 0; | |
| virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) = 0; | |
| virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) = 0; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment