diff options
51 files changed, 2752 insertions, 146 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 1fe34cb4fd..9503bd2575 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -236,8 +236,12 @@ Vector<String> OS::get_system_fonts() const { return ::OS::get_singleton()->get_system_fonts(); } -String OS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { - return ::OS::get_singleton()->get_system_font_path(p_font_name, p_bold, p_italic); +String OS::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { + return ::OS::get_singleton()->get_system_font_path(p_font_name, p_weight, p_stretch, p_italic); +} + +Vector<String> OS::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { + return ::OS::get_singleton()->get_system_font_path_for_text(p_font_name, p_text, p_locale, p_script, p_weight, p_stretch, p_italic); } String OS::get_executable_path() const { @@ -532,7 +536,8 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_processor_name"), &OS::get_processor_name); ClassDB::bind_method(D_METHOD("get_system_fonts"), &OS::get_system_fonts); - ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "bold", "italic"), &OS::get_system_font_path, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); ClassDB::bind_method(D_METHOD("read_string_from_stdin", "block"), &OS::read_string_from_stdin, DEFVAL(true)); ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false)); diff --git a/core/core_bind.h b/core/core_bind.h index 748ecb4929..c863a8094c 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -170,7 +170,8 @@ public: void crash(const String &p_message); Vector<String> get_system_fonts() const; - String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const; + String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const; + Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const; String get_executable_path() const; String read_string_from_stdin(bool p_block = true); int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false); diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index cb25564342..0ceb300f97 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -690,7 +690,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) { _store_buffer(buff); } -Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) { +Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) { Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error); if (f.is_null()) { if (r_error) { // if error requested, do not throw error @@ -706,7 +706,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { Error err; - Vector<uint8_t> array = get_file_as_array(p_path, &err); + Vector<uint8_t> array = get_file_as_bytes(p_path, &err); if (r_error) { *r_error = err; } @@ -810,6 +810,9 @@ void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0)); ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string); + ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush); ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path); ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute); diff --git a/core/io/file_access.h b/core/io/file_access.h index 8ca44306a0..54a0235333 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -192,9 +192,12 @@ public: static String get_sha256(const String &p_file); static String get_multiple_md5(const Vector<String> &p_file); - static Vector<uint8_t> get_file_as_array(const String &p_path, Error *r_error = nullptr); + static Vector<uint8_t> get_file_as_bytes(const String &p_path, Error *r_error = nullptr); static String get_file_as_string(const String &p_path, Error *r_error = nullptr); + static PackedByteArray _get_file_as_bytes(const String &p_path) { return get_file_as_bytes(p_path); } + static String _get_file_as_string(const String &p_path) { return get_file_as_string(p_path); }; + template <class T> static void make_default(AccessType p_access) { create_func[p_access] = _create_builtin<T>; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 0118b4c6af..0556f45b0c 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -120,7 +120,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr pf.ofs = ofs; pf.size = f->get_length(); - Vector<uint8_t> data = FileAccess::get_file_as_array(p_src); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_src); { unsigned char hash[16]; CryptoCore::md5(data.ptr(), data.size(), hash); diff --git a/core/os/os.h b/core/os/os.h index af7b40f3ec..72a91f318a 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -150,7 +150,8 @@ public: virtual int get_low_processor_usage_mode_sleep_usec() const; virtual Vector<String> get_system_fonts() const { return Vector<String>(); }; - virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const { return String(); }; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return String(); }; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return Vector<String>(); }; virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0; diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index e52f897164..be0c8fd6ca 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -153,6 +153,20 @@ Returns the last error that happened when trying to perform operations. Compare with the [code]ERR_FILE_*[/code] constants from [enum Error]. </description> </method> + <method name="get_file_as_bytes" qualifiers="static"> + <return type="PackedByteArray" /> + <param index="0" name="path" type="String" /> + <description> + Returns the whole [param path] file contents as a [PackedByteArray] without any decoding. + </description> + </method> + <method name="get_file_as_string" qualifiers="static"> + <return type="String" /> + <param index="0" name="path" type="String" /> + <description> + Returns the whole [param path] file contents as a [String]. Text is interpreted as being UTF-8 encoded. + </description> + </method> <method name="get_float" qualifiers="const"> <return type="float" /> <description> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index 6a42b62bcf..761e75339a 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -161,6 +161,12 @@ Returns font family name. </description> </method> + <method name="get_font_stretch" qualifiers="const"> + <return type="int" /> + <description> + Returns font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code]. + </description> + </method> <method name="get_font_style" qualifiers="const"> <return type="int" enum="TextServer.FontStyle" /> <description> @@ -173,6 +179,12 @@ Returns font style name. </description> </method> + <method name="get_font_weight" qualifiers="const"> + <return type="int" /> + <description> + Returns weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. + </description> + </method> <method name="get_height" qualifiers="const"> <return type="float" /> <param index="0" name="font_size" type="int" default="16" /> diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 271f6a13e0..1019c271dc 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -542,6 +542,9 @@ </method> </methods> <members> + <member name="allow_system_fallback" type="bool" setter="set_allow_system_fallback" getter="is_allow_system_fallback" default="true"> + If set to [code]true[/code], system fonts can be automatically used as fallbacks. + </member> <member name="antialiasing" type="int" setter="set_antialiasing" getter="get_antialiasing" enum="TextServer.FontAntialiasing" default="1"> Font anti-aliasing mode. </member> @@ -557,9 +560,15 @@ <member name="font_name" type="String" setter="set_font_name" getter="get_font_name" default=""""> Font family name. </member> + <member name="font_stretch" type="int" setter="set_font_stretch" getter="get_font_stretch" default="100"> + Font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code]. + </member> <member name="font_style" type="int" setter="set_font_style" getter="get_font_style" enum="TextServer.FontStyle" default="0"> Font style flags, see [enum TextServer.FontStyle]. </member> + <member name="font_weight" type="int" setter="set_font_weight" getter="get_font_weight" default="400"> + Weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. + </member> <member name="force_autohinter" type="bool" setter="set_force_autohinter" getter="is_force_autohinter" default="false"> If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only. </member> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 610f77e3d8..0efc6ab399 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -394,18 +394,38 @@ <method name="get_system_font_path" qualifiers="const"> <return type="String" /> <param index="0" name="font_name" type="String" /> - <param index="1" name="bold" type="bool" default="false" /> - <param index="2" name="italic" type="bool" default="false" /> + <param index="1" name="weight" type="int" default="400" /> + <param index="2" name="stretch" type="int" default="100" /> + <param index="3" name="italic" type="bool" default="false" /> <description> - Returns path to the system font file with [param font_name] and style. Return empty string if no matching fonts found. - [b]Note:[/b] This method is implemented on iOS, Linux, macOS and Windows. + Returns path to the system font file with [param font_name] and style. Returns empty string if no matching fonts found. + The following aliases can be used to request default fonts: "sans-serif", "serif", "monospace", "cursive", and "fantasy". + [b]Note:[/b] Returned font might have different style if the requested style is not available. + [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + </description> + </method> + <method name="get_system_font_path_for_text" qualifiers="const"> + <return type="PackedStringArray" /> + <param index="0" name="font_name" type="String" /> + <param index="1" name="text" type="String" /> + <param index="2" name="locale" type="String" default="""" /> + <param index="3" name="script" type="String" default="""" /> + <param index="4" name="weight" type="int" default="400" /> + <param index="5" name="stretch" type="int" default="100" /> + <param index="6" name="italic" type="bool" default="false" /> + <description> + Returns an array of the system substitute font file paths, which are similar to the font with [param font_name] and style for the specified text, locale and script. Returns empty array if no matching fonts found. + The following aliases can be used to request default fonts: "sans-serif", "serif", "monospace", "cursive", and "fantasy". + [b]Note:[/b] Depending on OS, it's not guaranteed that any of the returned fonts is suitable for rendering specified text. Fonts should be loaded and checked in the order they are returned, and the first suitable one used. + [b]Note:[/b] Returned fonts might have different style if the requested style is not available or belong to a different font family. + [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> <method name="get_system_fonts" qualifiers="const"> <return type="PackedStringArray" /> <description> Returns list of font family names available. - [b]Note:[/b] This method is implemented on iOS, Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. </description> </method> <method name="get_thread_caller_id" qualifiers="const"> diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml index b47d6ded7d..20bfd0d8ae 100644 --- a/doc/classes/SystemFont.xml +++ b/doc/classes/SystemFont.xml @@ -7,23 +7,32 @@ <description> [SystemFont] loads a font from a system font with the first matching name from [member font_names]. It will attempt to match font style, but it's not guaranteed. - The returned font might be part of a font collection or be a variable font with OpenType "weight" and/or "italic" features set. + The returned font might be part of a font collection or be a variable font with OpenType "weight", "width" and/or "italic" features set. You can create [FontVariation] of the system font for fine control over its features. </description> <tutorials> </tutorials> <members> + <member name="allow_system_fallback" type="bool" setter="set_allow_system_fallback" getter="is_allow_system_fallback" default="true"> + If set to [code]true[/code], system fonts can be automatically used as fallbacks. + </member> <member name="antialiasing" type="int" setter="set_antialiasing" getter="get_antialiasing" enum="TextServer.FontAntialiasing" default="1"> Font anti-aliasing mode. </member> <member name="fallbacks" type="Font[]" setter="set_fallbacks" getter="get_fallbacks" default="[]"> Array of fallback [Font]s. </member> + <member name="font_italic" type="bool" setter="set_font_italic" getter="get_font_italic" default="false"> + If set to [code]true[/code], italic or oblique font is preferred. + </member> <member name="font_names" type="PackedStringArray" setter="set_font_names" getter="get_font_names" default="PackedStringArray()"> Array of font family names to search, first matching font found is used. </member> - <member name="font_style" type="int" setter="set_font_style" getter="get_font_style" enum="TextServer.FontStyle" default="0"> - Font style flags, see [enum TextServer.FontStyle]. + <member name="font_stretch" type="int" setter="set_font_stretch" getter="get_font_stretch" default="100"> + Preferred font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code]. + </member> + <member name="font_weight" type="int" setter="set_font_weight" getter="get_font_weight" default="400"> + Preferred weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. </member> <member name="force_autohinter" type="bool" setter="set_force_autohinter" getter="is_force_autohinter" default="false"> If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index f4d92ab9b6..b3e55b5cd0 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -362,6 +362,13 @@ Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size. </description> </method> + <method name="font_get_stretch" qualifiers="const"> + <return type="int" /> + <param index="0" name="font_rid" type="RID" /> + <description> + Returns font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code]. + </description> + </method> <method name="font_get_style" qualifiers="const"> <return type="int" enum="TextServer.FontStyle" /> <param index="0" name="font_rid" type="RID" /> @@ -446,6 +453,13 @@ Returns variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info. </description> </method> + <method name="font_get_weight" qualifiers="const"> + <return type="int" /> + <param index="0" name="font_rid" type="RID" /> + <description> + Returns weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. + </description> + </method> <method name="font_has_char" qualifiers="const"> <return type="bool" /> <param index="0" name="font_rid" type="RID" /> @@ -454,6 +468,13 @@ Returns [code]true[/code] if a Unicode [param char] is available in the font. </description> </method> + <method name="font_is_allow_system_fallback" qualifiers="const"> + <return type="bool" /> + <param index="0" name="font_rid" type="RID" /> + <description> + Returns [code]true[/code] if system fonts can be automatically used as fallbacks. + </description> + </method> <method name="font_is_force_autohinter" qualifiers="const"> <return type="bool" /> <param index="0" name="font_rid" type="RID" /> @@ -556,6 +577,14 @@ Renders the range of characters to the font cache texture. </description> </method> + <method name="font_set_allow_system_fallback"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="allow_system_fallback" type="bool" /> + <description> + If set to [code]true[/code], system fonts can be automatically used as fallbacks. + </description> + </method> <method name="font_set_antialiasing"> <return type="void" /> <param index="0" name="font_rid" type="RID" /> @@ -783,12 +812,22 @@ Adds override for [method font_is_script_supported]. </description> </method> + <method name="font_set_stretch"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="weight" type="int" /> + <description> + Sets font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code]. + [b]Note:[/b] This value is used for font matching only and will not affect font rendering. Use [method font_set_face_index], [method font_set_variation_coordinates], or [method font_set_transform] instead. + </description> + </method> <method name="font_set_style"> <return type="void" /> <param index="0" name="font_rid" type="RID" /> <param index="1" name="style" type="int" enum="TextServer.FontStyle" /> <description> Sets the font style flags, see [enum FontStyle]. + [b]Note:[/b] This value is used for font matching only and will not affect font rendering. Use [method font_set_face_index], [method font_set_variation_coordinates], [method font_set_embolden], or [method font_set_transform] instead. </description> </method> <method name="font_set_style_name"> @@ -862,6 +901,15 @@ Sets variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info. </description> </method> + <method name="font_set_weight"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="weight" type="int" /> + <description> + Sets weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. + [b]Note:[/b] This value is used for font matching only and will not affect font rendering. Use [method font_set_face_index], [method font_set_variation_coordinates], or [method font_set_embolden] instead. + </description> + </method> <method name="font_supported_feature_list" qualifiers="const"> <return type="Dictionary" /> <param index="0" name="font_rid" type="RID" /> diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 37d2698dd4..4c9817fcd4 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -9,6 +9,11 @@ <tutorials> </tutorials> <methods> + <method name="_cleanup" qualifiers="virtual"> + <return type="void" /> + <description> + </description> + </method> <method name="_create_font" qualifiers="virtual"> <return type="RID" /> <description> @@ -306,6 +311,12 @@ <description> </description> </method> + <method name="_font_get_stretch" qualifiers="virtual const"> + <return type="int" /> + <param index="0" name="font_rid" type="RID" /> + <description> + </description> + </method> <method name="_font_get_style" qualifiers="virtual const"> <return type="int" enum="TextServer.FontStyle" /> <param index="0" name="font_rid" type="RID" /> @@ -379,6 +390,12 @@ <description> </description> </method> + <method name="_font_get_weight" qualifiers="virtual const"> + <return type="int" /> + <param index="0" name="font_rid" type="RID" /> + <description> + </description> + </method> <method name="_font_has_char" qualifiers="virtual const"> <return type="bool" /> <param index="0" name="font_rid" type="RID" /> @@ -386,6 +403,12 @@ <description> </description> </method> + <method name="_font_is_allow_system_fallback" qualifiers="virtual const"> + <return type="bool" /> + <param index="0" name="font_rid" type="RID" /> + <description> + </description> + </method> <method name="_font_is_force_autohinter" qualifiers="virtual const"> <return type="bool" /> <param index="0" name="font_rid" type="RID" /> @@ -474,6 +497,13 @@ <description> </description> </method> + <method name="_font_set_allow_system_fallback" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="allow_system_fallback" type="bool" /> + <description> + </description> + </method> <method name="_font_set_antialiasing" qualifiers="virtual"> <return type="void" /> <param index="0" name="font_rid" type="RID" /> @@ -680,6 +710,13 @@ <description> </description> </method> + <method name="_font_set_stretch" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="stretch" type="int" /> + <description> + </description> + </method> <method name="_font_set_style" qualifiers="virtual"> <return type="void" /> <param index="0" name="font_rid" type="RID" /> @@ -749,6 +786,13 @@ <description> </description> </method> + <method name="_font_set_weight" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="font_rid" type="RID" /> + <param index="1" name="weight" type="int" /> + <description> + </description> + </method> <method name="_font_supported_feature_list" qualifiers="virtual const"> <return type="Dictionary" /> <param index="0" name="font_rid" type="RID" /> diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index e7d4636ad9..cf413133aa 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -41,7 +41,7 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin Ref<FontFile> font; font.instantiate(); - Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_path); font->set_data(data); font->set_multichannel_signed_distance_field(p_msdf); diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 7c5c7da2ef..4273a31d62 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -1034,7 +1034,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & return err; } // Now actual remapped file: - sarr = FileAccess::get_file_as_array(export_path); + sarr = FileAccess::get_file_as_bytes(export_path); err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1053,7 +1053,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & if (importer_type == "keep") { //just keep file as-is - Vector<uint8_t> array = FileAccess::get_file_as_array(path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(path); err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { @@ -1086,14 +1086,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String remap = F; if (remap == "path") { String remapped_path = config->get_value("remap", remap); - Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path); err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); } else if (remap.begins_with("path.")) { String feature = remap.get_slice(".", 1); if (remap_features.has(feature)) { String remapped_path = config->get_value("remap", remap); - Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path); err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); } } @@ -1104,7 +1104,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } //also save the .import file - Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import"); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(path + ".import"); err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { @@ -1164,7 +1164,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & path_remaps.push_back(export_path); } - Vector<uint8_t> array = FileAccess::get_file_as_array(export_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(export_path); err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1244,14 +1244,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String icon = GLOBAL_GET("application/config/icon"); String splash = GLOBAL_GET("application/boot_splash/image"); if (!icon.is_empty() && FileAccess::exists(icon)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(icon); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(icon); err = p_func(p_udata, icon, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; } } if (!splash.is_empty() && FileAccess::exists(splash) && icon != splash) { - Vector<uint8_t> array = FileAccess::get_file_as_array(splash); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(splash); err = p_func(p_udata, splash, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1259,7 +1259,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String resource_cache_file = ResourceUID::get_cache_file(); if (FileAccess::exists(resource_cache_file)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(resource_cache_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(resource_cache_file); err = p_func(p_udata, resource_cache_file, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1268,7 +1268,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String extension_list_config_file = NativeExtension::get_extension_list_config_file(); if (FileAccess::exists(extension_list_config_file)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(extension_list_config_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(extension_list_config_file); err = p_func(p_udata, extension_list_config_file, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1282,7 +1282,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & // Try using user provided data file. String ts_data = "res://" + TS->get_support_data_filename(); if (FileAccess::exists(ts_data)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(ts_data); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1291,7 +1291,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & // Use default text server data. String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data"); TS->save_support_data(icu_data_file); - Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(icu_data_file); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); DirAccess::remove_file_or_error(icu_data_file); if (err != OK) { @@ -1304,7 +1304,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String config_file = "project.binary"; String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); - Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); return p_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key); diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 0aa77f6ea0..75d0abbb0c 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -469,6 +469,8 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); } else if (p_edited_property == "msdf_size") { font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + } else if (p_edited_property == "allow_system_fallback") { + font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback")); } else if (p_edited_property == "force_autohinter") { font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); } else if (p_edited_property == "hinting") { @@ -936,6 +938,7 @@ void DynamicFontImportSettings::_re_import() { main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field"); main_settings["msdf_pixel_range"] = import_settings_data->get("msdf_pixel_range"); main_settings["msdf_size"] = import_settings_data->get("msdf_size"); + main_settings["allow_system_fallback"] = import_settings_data->get("allow_system_fallback"); main_settings["force_autohinter"] = import_settings_data->get("force_autohinter"); main_settings["hinting"] = import_settings_data->get("hinting"); main_settings["subpixel_positioning"] = import_settings_data->get("subpixel_positioning"); @@ -1036,7 +1039,7 @@ void DynamicFontImportSettings::_process_locales() { void DynamicFontImportSettings::open_settings(const String &p_path) { // Load base font data. - Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> font_data = FileAccess::get_file_as_bytes(p_path); // Load project locale list. locale_tree->clear(); @@ -1202,6 +1205,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback")); font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); font_preview->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); @@ -1232,6 +1236,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), 1)); diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp index 4fb1b726bd..357faf0022 100644 --- a/editor/import/resource_importer_bmfont.cpp +++ b/editor/import/resource_importer_bmfont.cpp @@ -76,6 +76,7 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & Error err = font->load_bitmap_font(p_source_file); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load font to file \"" + p_source_file + "\"."); + font->set_allow_system_fallback(false); font->set_fallbacks(fallbacks); int flg = 0; diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index 44440a92bd..2f1445af48 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -114,6 +114,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), 1)); @@ -150,13 +151,14 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str Dictionary ot_ov = p_options["opentype_features"]; bool autohinter = p_options["force_autohinter"]; + bool allow_system_fallback = p_options["allow_system_fallback"]; int hinting = p_options["hinting"]; int subpixel_positioning = p_options["subpixel_positioning"]; real_t oversampling = p_options["oversampling"]; Array fallbacks = p_options["fallbacks"]; // Load base font data. - Vector<uint8_t> data = FileAccess::get_file_as_array(p_source_file); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_source_file); // Create font. Ref<FontFile> font; @@ -170,6 +172,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str font->set_opentype_feature_overrides(ot_ov); font->set_fixed_size(0); font->set_force_autohinter(autohinter); + font->set_allow_system_fallback(allow_system_fallback); font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning); font->set_hinting((TextServer::Hinting)hinting); font->set_oversampling(oversampling); diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index eb4916663e..9c3304d946 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -121,6 +121,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin font->set_fixed_size(chr_height); font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED); font->set_force_autohinter(false); + font->set_allow_system_fallback(false); font->set_hinting(TextServer::HINTING_NONE); font->set_oversampling(1.0f); font->set_fallbacks(fallbacks); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index a9ce6e9f88..9566c1b23c 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -2448,7 +2448,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Vector<Vector<uint8_t>> mesh_lightmap_caches; { - src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err); + src_lightmap_cache = FileAccess::get_file_as_bytes(p_source_file + ".unwrap_cache", &err); if (err != OK) { src_lightmap_cache.clear(); } diff --git a/main/main.cpp b/main/main.cpp index 2d0843a331..c9a745cf56 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -533,6 +533,10 @@ Error Main::test_setup() { void Main::test_cleanup() { ERR_FAIL_COND(!_start_success); + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + TextServerManager::get_singleton()->get_interface(i)->cleanup(); + } + EngineDebugger::deinitialize(); ResourceLoader::remove_custom_loaders(); @@ -3300,6 +3304,10 @@ void Main::cleanup(bool p_force) { ERR_FAIL_COND(!_start_success); } + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + TextServerManager::get_singleton()->get_interface(i)->cleanup(); + } + if (movie_writer) { movie_writer->end(); } diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 735e35ac1e..a3685daf0e 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -796,7 +796,7 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. - buffer_data = FileAccess::get_file_as_array(uri); + buffer_data = FileAccess::get_file_as_bytes(uri); ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); } @@ -3139,7 +3139,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat // Fallback to loading as byte array. // This enables us to support the spec's requirement that we honor mimetype // regardless of file URI. - data = FileAccess::get_file_as_array(uri); + data = FileAccess::get_file_as_bytes(uri); if (data.size() == 0) { WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s. Skipping it.", i, mimetype, uri)); state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index cf2d8c9986..27fab88956 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -34,6 +34,7 @@ // Headers for building as GDExtension plug-in. #include <godot_cpp/classes/file_access.hpp> +#include <godot_cpp/classes/os.hpp> #include <godot_cpp/classes/project_settings.hpp> #include <godot_cpp/classes/rendering_server.hpp> #include <godot_cpp/classes/translation_server.hpp> @@ -1437,11 +1438,13 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f if (fd->face->style_name != nullptr) { p_font_data->style_name = String::utf8((const char *)fd->face->style_name); } + 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; - if (fd->face->style_flags & FT_STYLE_FLAG_BOLD) { + if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) { p_font_data->style_flags.set_flag(FONT_BOLD); } - if (fd->face->style_flags & FT_STYLE_FLAG_ITALIC) { + if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) { p_font_data->style_flags.set_flag(FONT_ITALIC); } if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { @@ -1967,6 +1970,46 @@ String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const { return fd->style_name; } +void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weight) { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->weight = CLAMP(p_weight, 100, 999); +} + +int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 400); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 400); + return fd->weight; +} + +void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->stretch = CLAMP(p_stretch, 50, 200); +} + +int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 100); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 100); + return fd->stretch; +} + void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2103,6 +2146,25 @@ int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const { return fd->fixed_size; } +void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->allow_system_fallback != p_allow_system_fallback) { + _font_clear_cache(fd); + fd->allow_system_fallback = p_allow_system_fallback; + } +} + +bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const { + FontAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, false); + + MutexLock lock(fd->mutex); + return fd->allow_system_fallback; +} + void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -4632,12 +4694,11 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { sd->breaks[pos] = true; } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) { sd->breaks[pos] = false; - - int pos_p = pos - 1 - sd->start; - char32_t c = sd->text[pos_p]; - if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) { - sd->break_inserts++; - } + } + int pos_p = pos - 1 - sd->start; + char32_t c = sd->text[pos_p]; + if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) { + sd->break_inserts++; } } } @@ -5066,10 +5127,177 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source } } -void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index) { +void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end) { + RID f; int fs = p_sd->spans[p_span].font_size; - if (p_fb_index >= p_fonts.size()) { - // Add fallback glyphs. + + if (p_fb_index >= 0 && p_fb_index < p_fonts.size()) { + // Try font from list. + f = p_fonts[p_fb_index]; + } else if (OS::get_singleton()->has_feature("system_fonts") && p_fonts.size() > 0 && ((p_fb_index == p_fonts.size()) || (p_fb_index > p_fonts.size() && p_start != p_prev_start))) { + // Try system fallback. + RID fdef = p_fonts[0]; + if (_font_is_allow_system_fallback(fdef)) { + String text = p_sd->text.substr(p_start, 1); + String font_name = _font_get_name(fdef); + BitField<FontStyle> font_style = _font_get_style(fdef); + int font_weight = _font_get_weight(fdef); + int font_stretch = _font_get_stretch(fdef); + Dictionary dvar = _font_get_variation_coordinates(fdef); + static int64_t wgth_tag = _name_to_tag("weight"); + static int64_t wdth_tag = _name_to_tag("width"); + static int64_t ital_tag = _name_to_tag("italic"); + if (dvar.has(wgth_tag)) { + font_weight = dvar[wgth_tag].operator int(); + } + if (dvar.has(wdth_tag)) { + font_stretch = dvar[wdth_tag].operator int(); + } + if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { + font_style.set_flag(TextServer::FONT_ITALIC); + } + + char scr_buffer[5] = { 0, 0, 0, 0, 0 }; + hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer); + String script_code = String(scr_buffer); + String locale = (p_sd->spans[p_span].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_sd->spans[p_span].language; + + PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); +#ifdef GDEXTENSION + for (int fb = 0; fb < fallback_font_name.size(); fb++) { + const String &E = fallback_font_name[fb]; +#else + for (const String &E : fallback_font_name) { +#endif + SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this); + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { + const SystemFontCacheRec &F = sysf_cache.var[face_idx]; + if (unlikely(!_font_has_char(F.rid, text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(F.rid); + int weight = _font_get_weight(F.rid); + int stretch = _font_get_stretch(F.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match != -1) { + f = sysf_cache.var[best_match].rid; + } + } + if (!f.is_valid()) { + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + if (sysf_cache.max_var == sysf_cache.var.size()) { + // All subfonts already tested, skip. + continue; + } + } + + if (!system_font_data.has(E)) { + system_font_data[E] = FileAccess::get_file_as_bytes(E); + } + + const PackedByteArray &font_data = system_font_data[E]; + + SystemFontCacheRec sysf; + sysf.rid = _create_font(); + _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); + + Dictionary var = dvar; + // Select matching style from collection. + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { + _font_set_face_index(sysf.rid, face_idx); + if (unlikely(!_font_has_char(sysf.rid, text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(sysf.rid); + int weight = _font_get_weight(sysf.rid); + int stretch = _font_get_stretch(sysf.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match == -1) { + _free_rid(sysf.rid); + continue; + } else { + _font_set_face_index(sysf.rid, best_match); + } + sysf.index = best_match; + + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 70) { + Dictionary ftr = _font_supported_variation_list(sysf.rid); + if (ftr.has(wdth_tag)) { + var[wdth_tag] = font_stretch; + _font_set_stretch(sysf.rid, font_stretch); + } + if (ftr.has(wgth_tag)) { + var[wgth_tag] = font_weight; + _font_set_weight(sysf.rid, font_weight); + } + if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { + var[ital_tag] = 1; + _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); + } + } + + _font_set_antialiasing(sysf.rid, key.antialiasing); + _font_set_generate_mipmaps(sysf.rid, key.mipmaps); + _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); + _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); + _font_set_msdf_size(sysf.rid, key.msdf_source_size); + _font_set_fixed_size(sysf.rid, key.fixed_size); + _font_set_force_autohinter(sysf.rid, key.force_autohinter); + _font_set_hinting(sysf.rid, key.hinting); + _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); + _font_set_variation_coordinates(sysf.rid, var); + _font_set_oversampling(sysf.rid, key.oversampling); + _font_set_embolden(sysf.rid, key.embolden); + _font_set_transform(sysf.rid, key.transform); + + if (system_fonts.has(key)) { + system_fonts[key].var.push_back(sysf); + } else { + SystemFontCache &sysf_cache = system_fonts[key]; + sysf_cache.max_var = _font_get_face_count(sysf.rid); + sysf_cache.var.push_back(sysf); + } + f = sysf.rid; + } + break; + } + } + } + + if (!f.is_valid()) { + // No valid font, use fallback hex code boxes. for (int i = p_start; i < p_end; i++) { if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) { Glyph gl; @@ -5100,7 +5328,6 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star return; } - RID f = p_fonts[p_fb_index]; FontAdvanced *fd = font_owner.get_or_null(f); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -5195,7 +5422,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star gl.end = end; gl.count = 0; - gl.font_rid = p_fonts[p_fb_index]; + gl.font_rid = f; gl.font_size = fs; if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) { @@ -5262,7 +5489,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star for (unsigned int i = 0; i < glyph_count; i++) { if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { if (failed_subrun_start != p_end + 1) { - _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); + _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end); failed_subrun_start = p_end + 1; failed_subrun_end = p_start; } @@ -5292,7 +5519,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star } memfree(w); if (failed_subrun_start != p_end + 1) { - _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); + _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end); } p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs)); p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs)); @@ -5464,7 +5691,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { } fonts.append_array(fonts_scr_only); fonts.append_array(fonts_no_match); - _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0); + _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0, 0, 0); } } } @@ -5961,7 +6188,11 @@ String TextServerAdvanced::_strip_diacritics(const String &p_string) const { String result; for (int i = 0; i < normalized_string.length(); i++) { if (u_getCombiningClass(normalized_string[i]) == 0) { +#ifdef GDEXTENSION + result = result + String::chr(normalized_string[i]); +#else result = result + normalized_string[i]; +#endif } } return result; @@ -6243,6 +6474,17 @@ TextServerAdvanced::TextServerAdvanced() { _bmp_create_font_funcs(); } +void TextServerAdvanced::_cleanup() { + for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) { + const Vector<SystemFontCacheRec> &sysf_cache = E.value.var; + for (const SystemFontCacheRec &F : sysf_cache) { + _free_rid(F.rid); + } + } + system_fonts.clear(); + system_font_data.clear(); +} + TextServerAdvanced::~TextServerAdvanced() { _bmp_free_font_funcs(); #ifdef MODULE_FREETYPE_ENABLED diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 10fe3c2316..5e6d2cc2c0 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -300,6 +300,7 @@ class TextServerAdvanced : public TextServerExtension { int msdf_range = 14; int msdf_source_size = 48; int fixed_size = 0; + bool allow_system_fallback = true; bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; @@ -311,6 +312,8 @@ class TextServerAdvanced : public TextServerExtension { BitField<TextServer::FontStyle> style_flags = 0; String font_name; String style_name; + int weight = 400; + int stretch = 100; HashMap<Vector2i, FontForSizeAdvanced *, VariantHasher, VariantComparator> cache; @@ -372,6 +375,57 @@ class TextServerAdvanced : public TextServerExtension { _FORCE_INLINE_ double _get_extra_advance(RID p_font_rid, int p_font_size) const; _FORCE_INLINE_ Variant::Type _get_tag_type(int64_t p_tag) const; _FORCE_INLINE_ bool _get_tag_hidden(int64_t p_tag) const; + _FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const { + String sty_name = p_sty_name.replace(" ", "").replace("-", ""); + if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) { + return 100; + } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) { + return 200; + } else if (sty_name.find("light") >= 0) { + return 300; + } else if (sty_name.find("semilight") >= 0) { + return 350; + } else if (sty_name.find("regular") >= 0) { + return 400; + } else if (sty_name.find("medium") >= 0) { + return 500; + } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) { + return 600; + } else if (sty_name.find("bold") >= 0) { + return 700; + } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) { + return 800; + } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) { + return 900; + } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) { + return 950; + } + return 400; + } + _FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const { + String sty_name = p_sty_name.replace(" ", "").replace("-", ""); + if (sty_name.find("ultracondensed") >= 0) { + return 50; + } else if (sty_name.find("extracondensed") >= 0) { + return 63; + } else if (sty_name.find("condensed") >= 0) { + return 75; + } else if (sty_name.find("semicondensed") >= 0) { + return 87; + } else if (sty_name.find("semiexpanded") >= 0) { + return 113; + } else if (sty_name.find("expanded") >= 0) { + return 125; + } else if (sty_name.find("extraexpanded") >= 0) { + return 150; + } else if (sty_name.find("ultraexpanded") >= 0) { + return 200; + } + return 100; + } + _FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const { + return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0); + } // Shaped text cache data. struct TrimData { @@ -474,12 +528,87 @@ class TextServerAdvanced : public TextServerExtension { mutable RID_PtrOwner<FontAdvanced> font_owner; mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner; + struct SystemFontKey { + String font_name; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; + bool italic = false; + bool mipmaps = false; + bool msdf = false; + bool force_autohinter = false; + int weight = 400; + int stretch = 100; + int msdf_range = 14; + int msdf_source_size = 48; + int fixed_size = 0; + TextServer::Hinting hinting = TextServer::HINTING_LIGHT; + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + Dictionary variation_coordinates; + double oversampling = 0.0; + double embolden = 0.0; + Transform2D transform; + + bool operator==(const SystemFontKey &p_b) const { + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform); + } + + SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerAdvanced *p_fb) { + font_name = p_font_name; + italic = p_italic; + weight = p_weight; + stretch = p_stretch; + antialiasing = p_fb->_font_get_antialiasing(p_font); + mipmaps = p_fb->_font_get_generate_mipmaps(p_font); + msdf = p_fb->_font_is_multichannel_signed_distance_field(p_font); + msdf_range = p_fb->_font_get_msdf_pixel_range(p_font); + msdf_source_size = p_fb->_font_get_msdf_size(p_font); + fixed_size = p_fb->_font_get_fixed_size(p_font); + force_autohinter = p_fb->_font_is_force_autohinter(p_font); + hinting = p_fb->_font_get_hinting(p_font); + subpixel_positioning = p_fb->_font_get_subpixel_positioning(p_font); + variation_coordinates = p_fb->_font_get_variation_coordinates(p_font); + oversampling = p_fb->_font_get_oversampling(p_font); + embolden = p_fb->_font_get_embolden(p_font); + transform = p_fb->_font_get_transform(p_font); + } + }; + + struct SystemFontCacheRec { + RID rid; + int index = 0; + }; + + struct SystemFontCache { + Vector<SystemFontCacheRec> var; + int max_var = 0; + }; + + struct SystemFontKeyHasher { + _FORCE_INLINE_ static uint32_t hash(const SystemFontKey &p_a) { + uint32_t hash = p_a.font_name.hash(); + hash = hash_murmur3_one_32(p_a.variation_coordinates.hash(), hash); + hash = hash_murmur3_one_32(p_a.weight, hash); + hash = hash_murmur3_one_32(p_a.stretch, hash); + hash = hash_murmur3_one_32(p_a.msdf_range, hash); + hash = hash_murmur3_one_32(p_a.msdf_source_size, hash); + hash = hash_murmur3_one_32(p_a.fixed_size, hash); + hash = hash_murmur3_one_double(p_a.oversampling, hash); + hash = hash_murmur3_one_double(p_a.embolden, hash); + hash = hash_murmur3_one_real(p_a.transform[0].x, hash); + hash = hash_murmur3_one_real(p_a.transform[0].y, hash); + hash = hash_murmur3_one_real(p_a.transform[1].x, hash); + hash = hash_murmur3_one_real(p_a.transform[1].y, hash); + return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12), hash)); + } + }; + mutable HashMap<SystemFontKey, SystemFontCache, SystemFontKeyHasher> system_fonts; + mutable HashMap<String, PackedByteArray> system_font_data; + void _realign(ShapedTextDataAdvanced *p_sd) const; int64_t _convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const; int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const; int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const; bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const; - void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index); + void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end); Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size); _FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs); @@ -568,6 +697,12 @@ public: MODBIND2(font_set_style_name, const RID &, const String &); MODBIND1RC(String, font_get_style_name, const RID &); + MODBIND2(font_set_weight, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_weight, const RID &); + + MODBIND2(font_set_stretch, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_stretch, const RID &); + MODBIND2(font_set_name, const RID &, const String &); MODBIND1RC(String, font_get_name, const RID &); @@ -589,6 +724,9 @@ public: MODBIND2(font_set_fixed_size, const RID &, int64_t); MODBIND1RC(int64_t, font_get_fixed_size, const RID &); + MODBIND2(font_set_allow_system_fallback, const RID &, bool); + MODBIND1RC(bool, font_is_allow_system_fallback, const RID &); + MODBIND2(font_set_force_autohinter, const RID &, bool); MODBIND1RC(bool, font_is_force_autohinter, const RID &); @@ -787,6 +925,8 @@ public: MODBIND2RC(String, string_to_upper, const String &, const String &); MODBIND2RC(String, string_to_lower, const String &, const String &); + MODBIND0(cleanup); + TextServerAdvanced(); ~TextServerAdvanced(); }; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index aaef9c9a3d..9133c277bb 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -34,6 +34,7 @@ // Headers for building as GDExtension plug-in. #include <godot_cpp/classes/file_access.hpp> +#include <godot_cpp/classes/os.hpp> #include <godot_cpp/classes/project_settings.hpp> #include <godot_cpp/classes/rendering_server.hpp> #include <godot_cpp/classes/translation_server.hpp> @@ -49,6 +50,7 @@ using namespace godot; #include "core/config/project_settings.h" #include "core/error/error_macros.h" #include "core/string/print_string.h" +#include "core/string/translation.h" #include "core/string/ucaps.h" #include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. @@ -852,11 +854,13 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f if (fd->face->style_name != nullptr) { p_font_data->style_name = String::utf8((const char *)fd->face->style_name); } + 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; - if (fd->face->style_flags & FT_STYLE_FLAG_BOLD) { + if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) { p_font_data->style_flags.set_flag(FONT_BOLD); } - if (fd->face->style_flags & FT_STYLE_FLAG_ITALIC) { + if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) { p_font_data->style_flags.set_flag(FONT_ITALIC); } if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { @@ -1061,6 +1065,46 @@ String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const { return fd->style_name; } +void TextServerFallback::_font_set_weight(const RID &p_font_rid, int64_t p_weight) { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->weight = CLAMP(p_weight, 100, 999); +} + +int64_t TextServerFallback::_font_get_weight(const RID &p_font_rid) const { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 400); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 400); + return fd->weight; +} + +void TextServerFallback::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->stretch = CLAMP(p_stretch, 50, 200); +} + +int64_t TextServerFallback::_font_get_stretch(const RID &p_font_rid) const { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 100); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 100); + return fd->stretch; +} + void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_name) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1197,6 +1241,25 @@ int64_t TextServerFallback::_font_get_fixed_size(const RID &p_font_rid) const { return fd->fixed_size; } +void TextServerFallback::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->allow_system_fallback != p_allow_system_fallback) { + _font_clear_cache(fd); + fd->allow_system_fallback = p_allow_system_fallback; + } +} + +bool TextServerFallback::_font_is_allow_system_fallback(const RID &p_font_rid) const { + FontFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, false); + + MutexLock lock(fd->mutex); + return fd->allow_system_fallback; +} + void TextServerFallback::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3603,6 +3666,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { sd->glyphs.push_back(gl); } else { // Text span. + RID prev_font; for (int j = span.start; j < span.end; j++) { Glyph gl; gl.start = j; @@ -3623,6 +3687,170 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) { break; } } + if (!gl.font_rid.is_valid() && prev_font.is_valid()) { + if (_font_has_char(prev_font, gl.index)) { + gl.font_rid = prev_font; + } + } + if (!gl.font_rid.is_valid() && OS::get_singleton()->has_feature("system_fonts") && span.fonts.size() > 0) { + // Try system fallback. + RID fdef = span.fonts[0]; + if (_font_is_allow_system_fallback(fdef)) { + String text = sd->text.substr(j, 1); + String font_name = _font_get_name(fdef); + BitField<FontStyle> font_style = _font_get_style(fdef); + int font_weight = _font_get_weight(fdef); + int font_stretch = _font_get_stretch(fdef); + Dictionary dvar = _font_get_variation_coordinates(fdef); + static int64_t wgth_tag = _name_to_tag("weight"); + static int64_t wdth_tag = _name_to_tag("width"); + static int64_t ital_tag = _name_to_tag("italic"); + if (dvar.has(wgth_tag)) { + font_weight = dvar[wgth_tag].operator int(); + } + if (dvar.has(wdth_tag)) { + font_stretch = dvar[wdth_tag].operator int(); + } + if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) { + font_style.set_flag(TextServer::FONT_ITALIC); + } + + String locale = (span.language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : span.language; + + PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, String(), font_weight, font_stretch, font_style & TextServer::FONT_ITALIC); +#ifdef GDEXTENSION + for (int fb = 0; fb < fallback_font_name.size(); fb++) { + const String &E = fallback_font_name[fb]; +#else + for (const String &E : fallback_font_name) { +#endif + SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this); + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) { + const SystemFontCacheRec &F = sysf_cache.var[face_idx]; + if (unlikely(!_font_has_char(F.rid, text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(F.rid); + int weight = _font_get_weight(F.rid); + int stretch = _font_get_stretch(F.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match != -1) { + gl.font_rid = sysf_cache.var[best_match].rid; + } + } + if (!gl.font_rid.is_valid()) { + if (system_fonts.has(key)) { + const SystemFontCache &sysf_cache = system_fonts[key]; + if (sysf_cache.max_var == sysf_cache.var.size()) { + // All subfonts already tested, skip. + continue; + } + } + + if (!system_font_data.has(E)) { + system_font_data[E] = FileAccess::get_file_as_bytes(E); + } + + const PackedByteArray &font_data = system_font_data[E]; + + SystemFontCacheRec sysf; + sysf.rid = _create_font(); + _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size()); + + Dictionary var = dvar; + // Select matching style from collection. + int best_score = 0; + int best_match = -1; + for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) { + _font_set_face_index(sysf.rid, face_idx); + if (unlikely(!_font_has_char(sysf.rid, text[0]))) { + continue; + } + BitField<FontStyle> style = _font_get_style(sysf.rid); + int weight = _font_get_weight(sysf.rid); + int stretch = _font_get_stretch(sysf.rid); + int score = (20 - Math::abs(weight - font_weight) / 50); + score += (20 - Math::abs(stretch - font_stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) { + score += 30; + } + if (score >= best_score) { + best_score = score; + best_match = face_idx; + } + if (best_score == 70) { + break; + } + } + if (best_match == -1) { + _free_rid(sysf.rid); + continue; + } else { + _font_set_face_index(sysf.rid, best_match); + } + sysf.index = best_match; + + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 70) { + Dictionary ftr = _font_supported_variation_list(sysf.rid); + if (ftr.has(wdth_tag)) { + var[wdth_tag] = font_stretch; + _font_set_stretch(sysf.rid, font_stretch); + } + if (ftr.has(wgth_tag)) { + var[wgth_tag] = font_weight; + _font_set_weight(sysf.rid, font_weight); + } + if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) { + var[ital_tag] = 1; + _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC); + } + } + + _font_set_antialiasing(sysf.rid, key.antialiasing); + _font_set_generate_mipmaps(sysf.rid, key.mipmaps); + _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf); + _font_set_msdf_pixel_range(sysf.rid, key.msdf_range); + _font_set_msdf_size(sysf.rid, key.msdf_source_size); + _font_set_fixed_size(sysf.rid, key.fixed_size); + _font_set_force_autohinter(sysf.rid, key.force_autohinter); + _font_set_hinting(sysf.rid, key.hinting); + _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning); + _font_set_variation_coordinates(sysf.rid, var); + _font_set_oversampling(sysf.rid, key.oversampling); + _font_set_embolden(sysf.rid, key.embolden); + _font_set_transform(sysf.rid, key.transform); + + if (system_fonts.has(key)) { + system_fonts[key].var.push_back(sysf); + } else { + SystemFontCache &sysf_cache = system_fonts[key]; + sysf_cache.max_var = _font_get_face_count(sysf.rid); + sysf_cache.var.push_back(sysf); + } + gl.font_rid = sysf.rid; + } + break; + } + } + } + prev_font = gl.font_rid; double scale = _font_get_scale(gl.font_rid, gl.font_size); if (gl.font_rid.is_valid()) { @@ -3893,6 +4121,17 @@ TextServerFallback::TextServerFallback() { _insert_feature_sets(); }; +void TextServerFallback::_cleanup() { + for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) { + const Vector<SystemFontCacheRec> &sysf_cache = E.value.var; + for (const SystemFontCacheRec &F : sysf_cache) { + _free_rid(F.rid); + } + } + system_fonts.clear(); + system_font_data.clear(); +} + TextServerFallback::~TextServerFallback() { #ifdef MODULE_FREETYPE_ENABLED if (ft_library != nullptr) { diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 7e0bc99618..f8a05f9433 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -256,6 +256,7 @@ class TextServerFallback : public TextServerExtension { int msdf_source_size = 48; int fixed_size = 0; bool force_autohinter = false; + bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; Dictionary variation_coordinates; @@ -266,6 +267,8 @@ class TextServerFallback : public TextServerExtension { BitField<TextServer::FontStyle> style_flags = 0; String font_name; String style_name; + int weight = 400; + int stretch = 100; HashMap<Vector2i, FontForSizeFallback *, VariantHasher, VariantComparator> cache; @@ -322,6 +325,58 @@ class TextServerFallback : public TextServerExtension { } } + _FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const { + String sty_name = p_sty_name.replace(" ", "").replace("-", ""); + if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) { + return 100; + } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) { + return 200; + } else if (sty_name.find("light") >= 0) { + return 300; + } else if (sty_name.find("semilight") >= 0) { + return 350; + } else if (sty_name.find("regular") >= 0) { + return 400; + } else if (sty_name.find("medium") >= 0) { + return 500; + } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) { + return 600; + } else if (sty_name.find("bold") >= 0) { + return 700; + } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) { + return 800; + } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) { + return 900; + } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) { + return 950; + } + return 400; + } + _FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const { + String sty_name = p_sty_name.replace(" ", "").replace("-", ""); + if (sty_name.find("ultracondensed") >= 0) { + return 50; + } else if (sty_name.find("extracondensed") >= 0) { + return 63; + } else if (sty_name.find("condensed") >= 0) { + return 75; + } else if (sty_name.find("semicondensed") >= 0) { + return 87; + } else if (sty_name.find("semiexpanded") >= 0) { + return 113; + } else if (sty_name.find("expanded") >= 0) { + return 125; + } else if (sty_name.find("extraexpanded") >= 0) { + return 150; + } else if (sty_name.find("ultraexpanded") >= 0) { + return 200; + } + return 100; + } + _FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const { + return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0); + } + // Shaped text cache data. struct TrimData { int trim_pos = -1; @@ -398,6 +453,81 @@ class TextServerFallback : public TextServerExtension { mutable RID_PtrOwner<FontFallback> font_owner; mutable RID_PtrOwner<ShapedTextDataFallback> shaped_owner; + struct SystemFontKey { + String font_name; + TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; + bool italic = false; + bool mipmaps = false; + bool msdf = false; + bool force_autohinter = false; + int weight = 400; + int stretch = 100; + int msdf_range = 14; + int msdf_source_size = 48; + int fixed_size = 0; + TextServer::Hinting hinting = TextServer::HINTING_LIGHT; + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + Dictionary variation_coordinates; + double oversampling = 0.0; + double embolden = 0.0; + Transform2D transform; + + bool operator==(const SystemFontKey &p_b) const { + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform); + } + + SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerFallback *p_fb) { + font_name = p_font_name; + italic = p_italic; + weight = p_weight; + stretch = p_stretch; + antialiasing = p_fb->_font_get_antialiasing(p_font); + mipmaps = p_fb->_font_get_generate_mipmaps(p_font); + msdf = p_fb->_font_is_multichannel_signed_distance_field(p_font); + msdf_range = p_fb->_font_get_msdf_pixel_range(p_font); + msdf_source_size = p_fb->_font_get_msdf_size(p_font); + fixed_size = p_fb->_font_get_fixed_size(p_font); + force_autohinter = p_fb->_font_is_force_autohinter(p_font); + hinting = p_fb->_font_get_hinting(p_font); + subpixel_positioning = p_fb->_font_get_subpixel_positioning(p_font); + variation_coordinates = p_fb->_font_get_variation_coordinates(p_font); + oversampling = p_fb->_font_get_oversampling(p_font); + embolden = p_fb->_font_get_embolden(p_font); + transform = p_fb->_font_get_transform(p_font); + } + }; + + struct SystemFontCacheRec { + RID rid; + int index = 0; + }; + + struct SystemFontCache { + Vector<SystemFontCacheRec> var; + int max_var = 0; + }; + + struct SystemFontKeyHasher { + _FORCE_INLINE_ static uint32_t hash(const SystemFontKey &p_a) { + uint32_t hash = p_a.font_name.hash(); + hash = hash_murmur3_one_32(p_a.variation_coordinates.hash(), hash); + hash = hash_murmur3_one_32(p_a.weight, hash); + hash = hash_murmur3_one_32(p_a.stretch, hash); + hash = hash_murmur3_one_32(p_a.msdf_range, hash); + hash = hash_murmur3_one_32(p_a.msdf_source_size, hash); + hash = hash_murmur3_one_32(p_a.fixed_size, hash); + hash = hash_murmur3_one_double(p_a.oversampling, hash); + hash = hash_murmur3_one_double(p_a.embolden, hash); + hash = hash_murmur3_one_real(p_a.transform[0].x, hash); + hash = hash_murmur3_one_real(p_a.transform[0].y, hash); + hash = hash_murmur3_one_real(p_a.transform[1].x, hash); + hash = hash_murmur3_one_real(p_a.transform[1].y, hash); + return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12), hash)); + } + }; + mutable HashMap<SystemFontKey, SystemFontCache, SystemFontKeyHasher> system_fonts; + mutable HashMap<String, PackedByteArray> system_font_data; + void _realign(ShapedTextDataFallback *p_sd) const; protected: @@ -442,6 +572,12 @@ public: MODBIND2(font_set_style_name, const RID &, const String &); MODBIND1RC(String, font_get_style_name, const RID &); + MODBIND2(font_set_weight, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_weight, const RID &); + + MODBIND2(font_set_stretch, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_stretch, const RID &); + MODBIND2(font_set_name, const RID &, const String &); MODBIND1RC(String, font_get_name, const RID &); @@ -463,6 +599,9 @@ public: MODBIND2(font_set_fixed_size, const RID &, int64_t); MODBIND1RC(int64_t, font_get_fixed_size, const RID &); + MODBIND2(font_set_allow_system_fallback, const RID &, bool); + MODBIND1RC(bool, font_is_allow_system_fallback, const RID &); + MODBIND2(font_set_force_autohinter, const RID &, bool); MODBIND1RC(bool, font_is_force_autohinter, const RID &); @@ -651,6 +790,8 @@ public: MODBIND2RC(String, string_to_upper, const String &, const String &); MODBIND2RC(String, string_to_lower, const String &, const String &); + MODBIND0(cleanup); + TextServerFallback(); ~TextServerFallback(); }; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 737e25b270..795a542ed5 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -703,7 +703,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj exported = true; String abi = abis[abi_index].abi; String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file()); - Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(p_so.path); Error store_err = store_in_apk(ed, dst_path, array); ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'."); } @@ -748,7 +748,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared String abi = abis[abi_index].abi; String filename = p_so.path.get_file(); String dst_path = base.path_join(type).path_join(abi).path_join(filename); - Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_so.path); print_verbose("Copying .so file from " + p_so.path + " to " + dst_path); Error err = store_file_at_path(dst_path, data); ERR_FAIL_COND_V_MSG(err, err, "Failed to copy .so file from " + p_so.path + " to " + dst_path); diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt index c9282dd247..1a3576a6a9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt @@ -90,6 +90,11 @@ internal enum class StorageScope { return APP } + var rootDir: String? = System.getenv("ANDROID_ROOT") + if (rootDir != null && canonicalPathFile.startsWith(rootDir)) { + return APP + } + if (sharedDir != null && canonicalPathFile.startsWith(sharedDir)) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { // Before R, apps had access to shared storage so long as they have the right diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 4f81e4bccd..317a63f21f 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -337,6 +337,229 @@ String OS_Android::get_data_path() const { return get_user_data_dir(); } +void OS_Android::_load_system_font_config() { + font_aliases.clear(); + fonts.clear(); + font_names.clear(); + + Ref<XMLParser> parser; + parser.instantiate(); + + Error err = parser->open(String(getenv("ANDROID_ROOT")).path_join("/etc/fonts.xml")); + if (err == OK) { + bool in_font_node = false; + String fb, fn; + FontInfo fi; + + while (parser->read() == OK) { + if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { + in_font_node = false; + if (parser->get_node_name() == "familyset") { + int ver = parser->has_attribute("version") ? parser->get_attribute_value("version").to_int() : 0; + if (ver < 21) { + ERR_PRINT(vformat("Unsupported font config version %s", ver)); + break; + } + } else if (parser->get_node_name() == "alias") { + String name = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String(); + String to = parser->has_attribute("to") ? parser->get_attribute_value("to").strip_edges() : String(); + if (!name.is_empty() && !to.is_empty()) { + font_aliases[name] = to; + } + } else if (parser->get_node_name() == "family") { + fn = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String(); + String lang_code = parser->has_attribute("lang") ? parser->get_attribute_value("lang").strip_edges() : String(); + Vector<String> lang_codes = lang_code.split(","); + for (int i = 0; i < lang_codes.size(); i++) { + Vector<String> lang_code_elements = lang_codes[i].split("-"); + if (lang_code_elements.size() >= 1 && lang_code_elements[0] != "und") { + // Add missing script codes. + if (lang_code_elements[0] == "ko") { + fi.script.insert("Hani"); + fi.script.insert("Hang"); + } + if (lang_code_elements[0] == "ja") { + fi.script.insert("Hani"); + fi.script.insert("Kana"); + fi.script.insert("Hira"); + } + if (!lang_code_elements[0].is_empty()) { + fi.lang.insert(lang_code_elements[0]); + } + } + if (lang_code_elements.size() >= 2) { + // Add common codes for variants and remove variants not supported by HarfBuzz/ICU. + if (lang_code_elements[1] == "Aran") { + fi.script.insert("Arab"); + } + if (lang_code_elements[1] == "Cyrs") { + fi.script.insert("Cyrl"); + } + if (lang_code_elements[1] == "Hanb") { + fi.script.insert("Hani"); + fi.script.insert("Bopo"); + } + if (lang_code_elements[1] == "Hans" || lang_code_elements[1] == "Hant") { + fi.script.insert("Hani"); + } + if (lang_code_elements[1] == "Syrj" || lang_code_elements[1] == "Syre" || lang_code_elements[1] == "Syrn") { + fi.script.insert("Syrc"); + } + if (!lang_code_elements[1].is_empty() && lang_code_elements[1] != "Zsym" && lang_code_elements[1] != "Zsye" && lang_code_elements[1] != "Zmth") { + fi.script.insert(lang_code_elements[1]); + } + } + } + } else if (parser->get_node_name() == "font") { + in_font_node = true; + fb = parser->has_attribute("fallbackFor") ? parser->get_attribute_value("fallbackFor").strip_edges() : String(); + fi.weight = parser->has_attribute("weight") ? parser->get_attribute_value("weight").to_int() : 400; + fi.italic = parser->has_attribute("style") && parser->get_attribute_value("style").strip_edges() == "italic"; + } + } + if (parser->get_node_type() == XMLParser::NODE_TEXT) { + if (in_font_node) { + fi.filename = parser->get_node_data().strip_edges(); + fi.font_name = fn; + if (!fb.is_empty() && fn.is_empty()) { + fi.font_name = fb; + fi.priority = 2; + } + if (fi.font_name.is_empty()) { + fi.font_name = "sans-serif"; + fi.priority = 5; + } + if (fi.font_name.ends_with("-condensed")) { + fi.stretch = 75; + fi.font_name = fi.font_name.trim_suffix("-condensed"); + } + fonts.push_back(fi); + font_names.insert(fi.font_name); + } + } + if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { + in_font_node = false; + if (parser->get_node_name() == "font") { + fb = String(); + fi.font_name = String(); + fi.priority = 0; + fi.weight = 400; + fi.stretch = 100; + fi.italic = false; + } else if (parser->get_node_name() == "family") { + fi = FontInfo(); + fn = String(); + } + } + } + parser->close(); + } else { + ERR_PRINT("Unable to load font config"); + } + + font_config_loaded = true; +} + +Vector<String> OS_Android::get_system_fonts() const { + if (!font_config_loaded) { + const_cast<OS_Android *>(this)->_load_system_font_config(); + } + Vector<String> ret; + for (const String &E : font_names) { + ret.push_back(E); + } + return ret; +} + +Vector<String> OS_Android::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { + if (!font_config_loaded) { + const_cast<OS_Android *>(this)->_load_system_font_config(); + } + String font_name = p_font_name.to_lower(); + if (font_aliases.has(font_name)) { + font_name = font_aliases[font_name]; + } + String root = String(getenv("ANDROID_ROOT")).path_join("fonts"); + String lang_prefix = p_locale.split("_")[0]; + Vector<String> ret; + int best_score = 0; + for (const List<FontInfo>::Element *E = fonts.front(); E; E = E->next()) { + int score = 0; + if (!E->get().script.is_empty() && !p_script.is_empty() && !E->get().script.has(p_script)) { + continue; + } + float sim = E->get().font_name.similarity(font_name); + if (sim > 0.0) { + score += (60 * sim + 5 - E->get().priority); + } + if (E->get().lang.has(p_locale)) { + score += 120; + } else if (E->get().lang.has(lang_prefix)) { + score += 115; + } + if (E->get().script.has(p_script)) { + score += 240; + } + score += (20 - Math::abs(E->get().weight - p_weight) / 50); + score += (20 - Math::abs(E->get().stretch - p_stretch) / 10); + if (E->get().italic == p_italic) { + score += 30; + } + if (score > best_score) { + best_score = score; + if (ret.find(root.path_join(E->get().filename)) < 0) { + ret.insert(0, root.path_join(E->get().filename)); + } + } else if (score == best_score || E->get().script.is_empty()) { + if (ret.find(root.path_join(E->get().filename)) < 0) { + ret.push_back(root.path_join(E->get().filename)); + } + } + if (score >= 490) { + break; // Perfect match. + } + } + + return ret; +} + +String OS_Android::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { + if (!font_config_loaded) { + const_cast<OS_Android *>(this)->_load_system_font_config(); + } + String font_name = p_font_name.to_lower(); + if (font_aliases.has(font_name)) { + font_name = font_aliases[font_name]; + } + String root = String(getenv("ANDROID_ROOT")).path_join("fonts"); + + int best_score = 0; + const List<FontInfo>::Element *best_match = nullptr; + + for (const List<FontInfo>::Element *E = fonts.front(); E; E = E->next()) { + int score = 0; + if (E->get().font_name == font_name) { + score += (65 - E->get().priority); + } + score += (20 - Math::abs(E->get().weight - p_weight) / 50); + score += (20 - Math::abs(E->get().stretch - p_stretch) / 10); + if (E->get().italic == p_italic) { + score += 30; + } + if (score >= 60 && score > best_score) { + best_score = score; + best_match = E; + } + if (score >= 140) { + break; // Perfect match. + } + } + if (best_match) { + return root.path_join(best_match->get().filename); + } + return String(); +} + String OS_Android::get_executable_path() const { // Since unix process creation is restricted on Android, we bypass // OS_Unix::get_executable_path() so we can return ANDROID_EXEC_PATH. @@ -449,6 +672,9 @@ String OS_Android::get_config_path() const { } bool OS_Android::_check_internal_feature_support(const String &p_feature) { + if (p_feature == "system_fonts") { + return true; + } if (p_feature == "mobile") { return true; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index d6546a3507..9034615fc4 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -62,9 +62,26 @@ private: MainLoop *main_loop = nullptr; + struct FontInfo { + String font_name; + HashSet<String> lang; + HashSet<String> script; + int weight = 400; + int stretch = 100; + bool italic = false; + int priority = 0; + String filename; + }; + + HashMap<String, String> font_aliases; + List<FontInfo> fonts; + HashSet<String> font_names; + bool font_config_loaded = false; + GodotJavaWrapper *godot_java = nullptr; GodotIOJavaWrapper *godot_io_java = nullptr; + void _load_system_font_config(); String get_system_property(const char *key) const; public: @@ -114,6 +131,10 @@ public: ANativeWindow *get_native_window() const; virtual Error shell_open(String p_uri) override; + + virtual Vector<String> get_system_fonts() const override; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; virtual String get_executable_path() const override; virtual String get_user_data_dir() const override; virtual String get_data_path() const override; diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h index 3560de7486..186efd14a8 100644 --- a/platform/ios/os_ios.h +++ b/platform/ios/os_ios.h @@ -73,6 +73,10 @@ private: bool is_focused = false; + CGFloat _weight_to_ct(int p_weight) const; + CGFloat _stretch_to_ct(int p_stretch) const; + String _get_default_fontname(const String &p_font_name) const; + void deinitialize_modules(); public: @@ -90,7 +94,8 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; virtual Vector<String> get_system_fonts() const override; - virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual Error close_dynamic_library(void *p_library_handle) override; diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index 9a8cfc2593..9617627b6f 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -334,9 +334,7 @@ Vector<String> OS_IOS::get_system_fonts() const { return ret; } -String OS_IOS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { - String ret; - +String OS_IOS::_get_default_fontname(const String &p_font_name) const { String font_name = p_font_name; if (font_name.to_lower() == "sans-serif") { font_name = "Helvetica"; @@ -349,21 +347,153 @@ String OS_IOS::get_system_font_path(const String &p_font_name, bool p_bold, bool } else if (font_name.to_lower() == "cursive") { font_name = "Apple Chancery"; }; + return font_name; +} + +CGFloat OS_IOS::_weight_to_ct(int p_weight) const { + if (p_weight < 150) { + return -0.80; + } else if (p_weight < 250) { + return -0.60; + } else if (p_weight < 350) { + return -0.40; + } else if (p_weight < 450) { + return 0.0; + } else if (p_weight < 550) { + return 0.23; + } else if (p_weight < 650) { + return 0.30; + } else if (p_weight < 750) { + return 0.40; + } else if (p_weight < 850) { + return 0.56; + } else if (p_weight < 925) { + return 0.62; + } else { + return 1.00; + } +} + +CGFloat OS_IOS::_stretch_to_ct(int p_stretch) const { + if (p_stretch < 56) { + return -0.5; + } else if (p_stretch < 69) { + return -0.37; + } else if (p_stretch < 81) { + return -0.25; + } else if (p_stretch < 93) { + return -0.13; + } else if (p_stretch < 106) { + return 0.0; + } else if (p_stretch < 137) { + return 0.13; + } else if (p_stretch < 144) { + return 0.25; + } else if (p_stretch < 162) { + return 0.37; + } else { + return 0.5; + } +} + +Vector<String> OS_IOS::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { + Vector<String> ret; + String font_name = _get_default_fontname(p_font_name); + + CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); + CTFontSymbolicTraits traits = 0; + if (p_weight >= 700) { + traits |= kCTFontBoldTrait; + } + if (p_italic) { + traits |= kCTFontItalicTrait; + } + if (p_stretch < 100) { + traits |= kCTFontCondensedTrait; + } else if (p_stretch > 100) { + traits |= kCTFontExpandedTrait; + } + + CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); + CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + + CGFloat weight = _weight_to_ct(p_weight); + CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight); + CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight); + + CGFloat stretch = _stretch_to_ct(p_stretch); + CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch); + CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch); + + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); + CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); + + CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes); + if (font) { + CTFontRef family = CTFontCreateWithFontDescriptor(font, 0, nullptr); + CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, p_text.utf8().get_data(), kCFStringEncodingUTF8); + CFRange range = CFRangeMake(0, CFStringGetLength(string)); + CTFontRef fallback_family = CTFontCreateForString(family, string, range); + if (fallback_family) { + CTFontDescriptorRef fallback_font = CTFontCopyFontDescriptor(fallback_family); + if (fallback_font) { + CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fallback_font, kCTFontURLAttribute); + if (url) { + NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]]; + ret.push_back(String::utf8([font_path UTF8String])); + CFRelease(url); + } + CFRelease(fallback_font); + } + CFRelease(fallback_family); + } + CFRelease(string); + CFRelease(font); + } + + CFRelease(attributes); + CFRelease(traits_dict); + CFRelease(sym_traits); + CFRelease(font_stretch); + CFRelease(font_weight); + CFRelease(name); + + return ret; +} + +String OS_IOS::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { + String ret; + String font_name = _get_default_fontname(p_font_name); CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); CTFontSymbolicTraits traits = 0; - if (p_bold) { + if (p_weight >= 700) { traits |= kCTFontBoldTrait; } if (p_italic) { traits |= kCTFontItalicTrait; } + if (p_stretch < 100) { + traits |= kCTFontCondensedTrait; + } else if (p_stretch > 100) { + traits |= kCTFontExpandedTrait; + } CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + CGFloat weight = _weight_to_ct(p_weight); + CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight); + CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight); + + CGFloat stretch = _stretch_to_ct(p_stretch); + CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch); + CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch); + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); @@ -382,6 +512,8 @@ String OS_IOS::get_system_font_path(const String &p_font_name, bool p_bold, bool CFRelease(attributes); CFRelease(traits_dict); CFRelease(sym_traits); + CFRelease(font_stretch); + CFRelease(font_weight); CFRelease(name); return ret; diff --git a/platform/linuxbsd/fontconfig-so_wrap.c b/platform/linuxbsd/fontconfig-so_wrap.c index 1a915faf98..a428cf1fb4 100644 --- a/platform/linuxbsd/fontconfig-so_wrap.c +++ b/platform/linuxbsd/fontconfig-so_wrap.c @@ -1,7 +1,7 @@ // This file is generated. Do not edit! // see https://github.com/hpvb/dynload-wrapper for details -// generated by ./generate-wrapper.py 0.3 on 2022-07-29 05:40:07 -// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSet +// generated by ./generate-wrapper.py 0.3 on 2022-11-22 10:28:00 +// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSetFirst --omit-prefix FcCharSetNext // #include <stdint.h> @@ -18,6 +18,8 @@ #define FcDirCacheValid FcDirCacheValid_dylibloader_orig_fontconfig #define FcDirCacheClean FcDirCacheClean_dylibloader_orig_fontconfig #define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_orig_fontconfig +#define FcDirCacheCreateUUID FcDirCacheCreateUUID_dylibloader_orig_fontconfig +#define FcDirCacheDeleteUUID FcDirCacheDeleteUUID_dylibloader_orig_fontconfig #define FcConfigHome FcConfigHome_dylibloader_orig_fontconfig #define FcConfigEnableHome FcConfigEnableHome_dylibloader_orig_fontconfig #define FcConfigFilename FcConfigFilename_dylibloader_orig_fontconfig @@ -44,6 +46,26 @@ #define FcConfigSubstitute FcConfigSubstitute_dylibloader_orig_fontconfig #define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_orig_fontconfig #define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterInit FcConfigFileInfoIterInit_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterNext FcConfigFileInfoIterNext_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterGet FcConfigFileInfoIterGet_dylibloader_orig_fontconfig +#define FcCharSetCreate FcCharSetCreate_dylibloader_orig_fontconfig +#define FcCharSetNew FcCharSetNew_dylibloader_orig_fontconfig +#define FcCharSetDestroy FcCharSetDestroy_dylibloader_orig_fontconfig +#define FcCharSetAddChar FcCharSetAddChar_dylibloader_orig_fontconfig +#define FcCharSetDelChar FcCharSetDelChar_dylibloader_orig_fontconfig +#define FcCharSetCopy FcCharSetCopy_dylibloader_orig_fontconfig +#define FcCharSetEqual FcCharSetEqual_dylibloader_orig_fontconfig +#define FcCharSetIntersect FcCharSetIntersect_dylibloader_orig_fontconfig +#define FcCharSetUnion FcCharSetUnion_dylibloader_orig_fontconfig +#define FcCharSetSubtract FcCharSetSubtract_dylibloader_orig_fontconfig +#define FcCharSetMerge FcCharSetMerge_dylibloader_orig_fontconfig +#define FcCharSetHasChar FcCharSetHasChar_dylibloader_orig_fontconfig +#define FcCharSetCount FcCharSetCount_dylibloader_orig_fontconfig +#define FcCharSetIntersectCount FcCharSetIntersectCount_dylibloader_orig_fontconfig +#define FcCharSetSubtractCount FcCharSetSubtractCount_dylibloader_orig_fontconfig +#define FcCharSetIsSubset FcCharSetIsSubset_dylibloader_orig_fontconfig +#define FcCharSetCoverage FcCharSetCoverage_dylibloader_orig_fontconfig #define FcValuePrint FcValuePrint_dylibloader_orig_fontconfig #define FcPatternPrint FcPatternPrint_dylibloader_orig_fontconfig #define FcFontSetPrint FcFontSetPrint_dylibloader_orig_fontconfig @@ -59,6 +81,7 @@ #define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_orig_fontconfig #define FcDirCacheUnload FcDirCacheUnload_dylibloader_orig_fontconfig #define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_orig_fontconfig +#define FcFreeTypeQueryAll FcFreeTypeQueryAll_dylibloader_orig_fontconfig #define FcFontSetCreate FcFontSetCreate_dylibloader_orig_fontconfig #define FcFontSetDestroy FcFontSetDestroy_dylibloader_orig_fontconfig #define FcFontSetAdd FcFontSetAdd_dylibloader_orig_fontconfig @@ -129,6 +152,7 @@ #define FcValueEqual FcValueEqual_dylibloader_orig_fontconfig #define FcValueSave FcValueSave_dylibloader_orig_fontconfig #define FcPatternDestroy FcPatternDestroy_dylibloader_orig_fontconfig +#define FcPatternObjectCount FcPatternObjectCount_dylibloader_orig_fontconfig #define FcPatternEqual FcPatternEqual_dylibloader_orig_fontconfig #define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_orig_fontconfig #define FcPatternHash FcPatternHash_dylibloader_orig_fontconfig @@ -162,8 +186,18 @@ #define FcRangeDestroy FcRangeDestroy_dylibloader_orig_fontconfig #define FcRangeCopy FcRangeCopy_dylibloader_orig_fontconfig #define FcRangeGetDouble FcRangeGetDouble_dylibloader_orig_fontconfig +#define FcPatternIterStart FcPatternIterStart_dylibloader_orig_fontconfig +#define FcPatternIterNext FcPatternIterNext_dylibloader_orig_fontconfig +#define FcPatternIterEqual FcPatternIterEqual_dylibloader_orig_fontconfig +#define FcPatternFindIter FcPatternFindIter_dylibloader_orig_fontconfig +#define FcPatternIterIsValid FcPatternIterIsValid_dylibloader_orig_fontconfig +#define FcPatternIterGetObject FcPatternIterGetObject_dylibloader_orig_fontconfig +#define FcPatternIterValueCount FcPatternIterValueCount_dylibloader_orig_fontconfig +#define FcPatternIterGetValue FcPatternIterGetValue_dylibloader_orig_fontconfig #define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_orig_fontconfig +#define FcWeightFromOpenTypeDouble FcWeightFromOpenTypeDouble_dylibloader_orig_fontconfig #define FcWeightToOpenType FcWeightToOpenType_dylibloader_orig_fontconfig +#define FcWeightToOpenTypeDouble FcWeightToOpenTypeDouble_dylibloader_orig_fontconfig #define FcStrCopy FcStrCopy_dylibloader_orig_fontconfig #define FcStrCopyFilename FcStrCopyFilename_dylibloader_orig_fontconfig #define FcStrPlus FcStrPlus_dylibloader_orig_fontconfig @@ -207,6 +241,8 @@ #undef FcDirCacheValid #undef FcDirCacheClean #undef FcCacheCreateTagFile +#undef FcDirCacheCreateUUID +#undef FcDirCacheDeleteUUID #undef FcConfigHome #undef FcConfigEnableHome #undef FcConfigFilename @@ -233,6 +269,26 @@ #undef FcConfigSubstitute #undef FcConfigGetSysRoot #undef FcConfigSetSysRoot +#undef FcConfigFileInfoIterInit +#undef FcConfigFileInfoIterNext +#undef FcConfigFileInfoIterGet +#undef FcCharSetCreate +#undef FcCharSetNew +#undef FcCharSetDestroy +#undef FcCharSetAddChar +#undef FcCharSetDelChar +#undef FcCharSetCopy +#undef FcCharSetEqual +#undef FcCharSetIntersect +#undef FcCharSetUnion +#undef FcCharSetSubtract +#undef FcCharSetMerge +#undef FcCharSetHasChar +#undef FcCharSetCount +#undef FcCharSetIntersectCount +#undef FcCharSetSubtractCount +#undef FcCharSetIsSubset +#undef FcCharSetCoverage #undef FcValuePrint #undef FcPatternPrint #undef FcFontSetPrint @@ -248,6 +304,7 @@ #undef FcDirCacheLoadFile #undef FcDirCacheUnload #undef FcFreeTypeQuery +#undef FcFreeTypeQueryAll #undef FcFontSetCreate #undef FcFontSetDestroy #undef FcFontSetAdd @@ -318,6 +375,7 @@ #undef FcValueEqual #undef FcValueSave #undef FcPatternDestroy +#undef FcPatternObjectCount #undef FcPatternEqual #undef FcPatternEqualSubset #undef FcPatternHash @@ -351,8 +409,18 @@ #undef FcRangeDestroy #undef FcRangeCopy #undef FcRangeGetDouble +#undef FcPatternIterStart +#undef FcPatternIterNext +#undef FcPatternIterEqual +#undef FcPatternFindIter +#undef FcPatternIterIsValid +#undef FcPatternIterGetObject +#undef FcPatternIterValueCount +#undef FcPatternIterGetValue #undef FcWeightFromOpenType +#undef FcWeightFromOpenTypeDouble #undef FcWeightToOpenType +#undef FcWeightToOpenTypeDouble #undef FcStrCopy #undef FcStrCopyFilename #undef FcStrPlus @@ -397,6 +465,8 @@ FcBool (*FcDirCacheUnlink_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConf FcBool (*FcDirCacheValid_dylibloader_wrapper_fontconfig)(const FcChar8*); FcBool (*FcDirCacheClean_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool); void (*FcCacheCreateTagFile_dylibloader_wrapper_fontconfig)(const FcConfig*); +FcBool (*FcDirCacheCreateUUID_dylibloader_wrapper_fontconfig)( FcChar8*, FcBool, FcConfig*); +FcBool (*FcDirCacheDeleteUUID_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); FcChar8* (*FcConfigHome_dylibloader_wrapper_fontconfig)( void); FcBool (*FcConfigEnableHome_dylibloader_wrapper_fontconfig)( FcBool); FcChar8* (*FcConfigFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); @@ -423,6 +493,26 @@ FcBool (*FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig)( FcConfig*, F FcBool (*FcConfigSubstitute_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcMatchKind); const FcChar8* (*FcConfigGetSysRoot_dylibloader_wrapper_fontconfig)(const FcConfig*); void (*FcConfigSetSysRoot_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +void (*FcConfigFileInfoIterInit_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*); +FcBool (*FcConfigFileInfoIterNext_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*); +FcBool (*FcConfigFileInfoIterGet_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*, FcChar8**, FcChar8**, FcBool*); +FcCharSet* (*FcCharSetCreate_dylibloader_wrapper_fontconfig)( void); +FcCharSet* (*FcCharSetNew_dylibloader_wrapper_fontconfig)( void); +void (*FcCharSetDestroy_dylibloader_wrapper_fontconfig)( FcCharSet*); +FcBool (*FcCharSetAddChar_dylibloader_wrapper_fontconfig)( FcCharSet*, FcChar32); +FcBool (*FcCharSetDelChar_dylibloader_wrapper_fontconfig)( FcCharSet*, FcChar32); +FcCharSet* (*FcCharSetCopy_dylibloader_wrapper_fontconfig)( FcCharSet*); +FcBool (*FcCharSetEqual_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcCharSet* (*FcCharSetIntersect_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcCharSet* (*FcCharSetUnion_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcCharSet* (*FcCharSetSubtract_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcBool (*FcCharSetMerge_dylibloader_wrapper_fontconfig)( FcCharSet*,const FcCharSet*, FcBool*); +FcBool (*FcCharSetHasChar_dylibloader_wrapper_fontconfig)(const FcCharSet*, FcChar32); +FcChar32 (*FcCharSetCount_dylibloader_wrapper_fontconfig)(const FcCharSet*); +FcChar32 (*FcCharSetIntersectCount_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcChar32 (*FcCharSetSubtractCount_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcBool (*FcCharSetIsSubset_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +FcChar32 (*FcCharSetCoverage_dylibloader_wrapper_fontconfig)(const FcCharSet*, FcChar32, FcChar32*); void (*FcValuePrint_dylibloader_wrapper_fontconfig)(const FcValue); void (*FcPatternPrint_dylibloader_wrapper_fontconfig)(const FcPattern*); void (*FcFontSetPrint_dylibloader_wrapper_fontconfig)(const FcFontSet*); @@ -437,7 +527,8 @@ FcCache* (*FcDirCacheRescan_dylibloader_wrapper_fontconfig)(const FcChar8*, FcCo FcCache* (*FcDirCacheRead_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool, FcConfig*); FcCache* (*FcDirCacheLoadFile_dylibloader_wrapper_fontconfig)(const FcChar8*,struct stat*); void (*FcDirCacheUnload_dylibloader_wrapper_fontconfig)( FcCache*); -FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, int, FcBlanks*, int*); +FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, unsigned int, FcBlanks*, int*); +unsigned int (*FcFreeTypeQueryAll_dylibloader_wrapper_fontconfig)(const FcChar8*, unsigned int, FcBlanks*, int*, FcFontSet*); FcFontSet* (*FcFontSetCreate_dylibloader_wrapper_fontconfig)( void); void (*FcFontSetDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); FcBool (*FcFontSetAdd_dylibloader_wrapper_fontconfig)( FcFontSet*, FcPattern*); @@ -508,6 +599,7 @@ void (*FcValueDestroy_dylibloader_wrapper_fontconfig)( FcValue); FcBool (*FcValueEqual_dylibloader_wrapper_fontconfig)( FcValue, FcValue); FcValue (*FcValueSave_dylibloader_wrapper_fontconfig)( FcValue); void (*FcPatternDestroy_dylibloader_wrapper_fontconfig)( FcPattern*); +int (*FcPatternObjectCount_dylibloader_wrapper_fontconfig)(const FcPattern*); FcBool (*FcPatternEqual_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*); FcBool (*FcPatternEqualSubset_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*,const FcObjectSet*); FcChar32 (*FcPatternHash_dylibloader_wrapper_fontconfig)(const FcPattern*); @@ -541,8 +633,18 @@ FcRange* (*FcRangeCreateInteger_dylibloader_wrapper_fontconfig)( FcChar32, FcCha void (*FcRangeDestroy_dylibloader_wrapper_fontconfig)( FcRange*); FcRange* (*FcRangeCopy_dylibloader_wrapper_fontconfig)(const FcRange*); FcBool (*FcRangeGetDouble_dylibloader_wrapper_fontconfig)(const FcRange*, double*, double*); +void (*FcPatternIterStart_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +FcBool (*FcPatternIterNext_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +FcBool (*FcPatternIterEqual_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*,const FcPattern*, FcPatternIter*); +FcBool (*FcPatternFindIter_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*,const char*); +FcBool (*FcPatternIterIsValid_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +const char* (*FcPatternIterGetObject_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +int (*FcPatternIterValueCount_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +FcResult (*FcPatternIterGetValue_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*, int, FcValue*, FcValueBinding*); int (*FcWeightFromOpenType_dylibloader_wrapper_fontconfig)( int); +double (*FcWeightFromOpenTypeDouble_dylibloader_wrapper_fontconfig)( double); int (*FcWeightToOpenType_dylibloader_wrapper_fontconfig)( int); +double (*FcWeightToOpenTypeDouble_dylibloader_wrapper_fontconfig)( double); FcChar8* (*FcStrCopy_dylibloader_wrapper_fontconfig)(const FcChar8*); FcChar8* (*FcStrCopyFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); FcChar8* (*FcStrPlus_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); @@ -687,6 +789,22 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcDirCacheCreateUUID + *(void **) (&FcDirCacheCreateUUID_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheCreateUUID"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheDeleteUUID + *(void **) (&FcDirCacheDeleteUUID_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheDeleteUUID"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcConfigHome *(void **) (&FcConfigHome_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigHome"); if (verbose) { @@ -895,6 +1013,166 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcConfigFileInfoIterInit + *(void **) (&FcConfigFileInfoIterInit_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigFileInfoIterInit"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigFileInfoIterNext + *(void **) (&FcConfigFileInfoIterNext_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigFileInfoIterNext"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigFileInfoIterGet + *(void **) (&FcConfigFileInfoIterGet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigFileInfoIterGet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetCreate + *(void **) (&FcCharSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetNew + *(void **) (&FcCharSetNew_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetNew"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetDestroy + *(void **) (&FcCharSetDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetAddChar + *(void **) (&FcCharSetAddChar_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetAddChar"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetDelChar + *(void **) (&FcCharSetDelChar_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetDelChar"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetCopy + *(void **) (&FcCharSetCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetCopy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetEqual + *(void **) (&FcCharSetEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetIntersect + *(void **) (&FcCharSetIntersect_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetIntersect"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetUnion + *(void **) (&FcCharSetUnion_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetUnion"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetSubtract + *(void **) (&FcCharSetSubtract_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetSubtract"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetMerge + *(void **) (&FcCharSetMerge_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetMerge"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetHasChar + *(void **) (&FcCharSetHasChar_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetHasChar"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetCount + *(void **) (&FcCharSetCount_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetCount"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetIntersectCount + *(void **) (&FcCharSetIntersectCount_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetIntersectCount"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetSubtractCount + *(void **) (&FcCharSetSubtractCount_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetSubtractCount"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetIsSubset + *(void **) (&FcCharSetIsSubset_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetIsSubset"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCharSetCoverage + *(void **) (&FcCharSetCoverage_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCharSetCoverage"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcValuePrint *(void **) (&FcValuePrint_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcValuePrint"); if (verbose) { @@ -1015,6 +1293,14 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcFreeTypeQueryAll + *(void **) (&FcFreeTypeQueryAll_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFreeTypeQueryAll"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcFontSetCreate *(void **) (&FcFontSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetCreate"); if (verbose) { @@ -1575,6 +1861,14 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcPatternObjectCount + *(void **) (&FcPatternObjectCount_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternObjectCount"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcPatternEqual *(void **) (&FcPatternEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternEqual"); if (verbose) { @@ -1839,6 +2133,70 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcPatternIterStart + *(void **) (&FcPatternIterStart_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterStart"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterNext + *(void **) (&FcPatternIterNext_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterNext"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterEqual + *(void **) (&FcPatternIterEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternFindIter + *(void **) (&FcPatternFindIter_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternFindIter"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterIsValid + *(void **) (&FcPatternIterIsValid_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterIsValid"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterGetObject + *(void **) (&FcPatternIterGetObject_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterGetObject"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterValueCount + *(void **) (&FcPatternIterValueCount_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterValueCount"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternIterGetValue + *(void **) (&FcPatternIterGetValue_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternIterGetValue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcWeightFromOpenType *(void **) (&FcWeightFromOpenType_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightFromOpenType"); if (verbose) { @@ -1847,6 +2205,14 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcWeightFromOpenTypeDouble + *(void **) (&FcWeightFromOpenTypeDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightFromOpenTypeDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcWeightToOpenType *(void **) (&FcWeightToOpenType_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightToOpenType"); if (verbose) { @@ -1855,6 +2221,14 @@ int initialize_fontconfig(int verbose) { fprintf(stderr, "%s\n", error); } } +// FcWeightToOpenTypeDouble + *(void **) (&FcWeightToOpenTypeDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightToOpenTypeDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } // FcStrCopy *(void **) (&FcStrCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrCopy"); if (verbose) { diff --git a/platform/linuxbsd/fontconfig-so_wrap.h b/platform/linuxbsd/fontconfig-so_wrap.h index f0794cce8b..0c8259deb7 100644 --- a/platform/linuxbsd/fontconfig-so_wrap.h +++ b/platform/linuxbsd/fontconfig-so_wrap.h @@ -2,8 +2,8 @@ #define DYLIBLOAD_WRAPPER_FONTCONFIG // This file is generated. Do not edit! // see https://github.com/hpvb/dynload-wrapper for details -// generated by ./generate-wrapper.py 0.3 on 2022-07-29 05:40:07 -// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSet +// generated by ./generate-wrapper.py 0.3 on 2022-11-22 10:28:00 +// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSetFirst --omit-prefix FcCharSetNext // #include <stdint.h> @@ -20,6 +20,8 @@ #define FcDirCacheValid FcDirCacheValid_dylibloader_orig_fontconfig #define FcDirCacheClean FcDirCacheClean_dylibloader_orig_fontconfig #define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_orig_fontconfig +#define FcDirCacheCreateUUID FcDirCacheCreateUUID_dylibloader_orig_fontconfig +#define FcDirCacheDeleteUUID FcDirCacheDeleteUUID_dylibloader_orig_fontconfig #define FcConfigHome FcConfigHome_dylibloader_orig_fontconfig #define FcConfigEnableHome FcConfigEnableHome_dylibloader_orig_fontconfig #define FcConfigFilename FcConfigFilename_dylibloader_orig_fontconfig @@ -46,6 +48,26 @@ #define FcConfigSubstitute FcConfigSubstitute_dylibloader_orig_fontconfig #define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_orig_fontconfig #define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterInit FcConfigFileInfoIterInit_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterNext FcConfigFileInfoIterNext_dylibloader_orig_fontconfig +#define FcConfigFileInfoIterGet FcConfigFileInfoIterGet_dylibloader_orig_fontconfig +#define FcCharSetCreate FcCharSetCreate_dylibloader_orig_fontconfig +#define FcCharSetNew FcCharSetNew_dylibloader_orig_fontconfig +#define FcCharSetDestroy FcCharSetDestroy_dylibloader_orig_fontconfig +#define FcCharSetAddChar FcCharSetAddChar_dylibloader_orig_fontconfig +#define FcCharSetDelChar FcCharSetDelChar_dylibloader_orig_fontconfig +#define FcCharSetCopy FcCharSetCopy_dylibloader_orig_fontconfig +#define FcCharSetEqual FcCharSetEqual_dylibloader_orig_fontconfig +#define FcCharSetIntersect FcCharSetIntersect_dylibloader_orig_fontconfig +#define FcCharSetUnion FcCharSetUnion_dylibloader_orig_fontconfig +#define FcCharSetSubtract FcCharSetSubtract_dylibloader_orig_fontconfig +#define FcCharSetMerge FcCharSetMerge_dylibloader_orig_fontconfig +#define FcCharSetHasChar FcCharSetHasChar_dylibloader_orig_fontconfig +#define FcCharSetCount FcCharSetCount_dylibloader_orig_fontconfig +#define FcCharSetIntersectCount FcCharSetIntersectCount_dylibloader_orig_fontconfig +#define FcCharSetSubtractCount FcCharSetSubtractCount_dylibloader_orig_fontconfig +#define FcCharSetIsSubset FcCharSetIsSubset_dylibloader_orig_fontconfig +#define FcCharSetCoverage FcCharSetCoverage_dylibloader_orig_fontconfig #define FcValuePrint FcValuePrint_dylibloader_orig_fontconfig #define FcPatternPrint FcPatternPrint_dylibloader_orig_fontconfig #define FcFontSetPrint FcFontSetPrint_dylibloader_orig_fontconfig @@ -61,6 +83,7 @@ #define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_orig_fontconfig #define FcDirCacheUnload FcDirCacheUnload_dylibloader_orig_fontconfig #define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_orig_fontconfig +#define FcFreeTypeQueryAll FcFreeTypeQueryAll_dylibloader_orig_fontconfig #define FcFontSetCreate FcFontSetCreate_dylibloader_orig_fontconfig #define FcFontSetDestroy FcFontSetDestroy_dylibloader_orig_fontconfig #define FcFontSetAdd FcFontSetAdd_dylibloader_orig_fontconfig @@ -131,6 +154,7 @@ #define FcValueEqual FcValueEqual_dylibloader_orig_fontconfig #define FcValueSave FcValueSave_dylibloader_orig_fontconfig #define FcPatternDestroy FcPatternDestroy_dylibloader_orig_fontconfig +#define FcPatternObjectCount FcPatternObjectCount_dylibloader_orig_fontconfig #define FcPatternEqual FcPatternEqual_dylibloader_orig_fontconfig #define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_orig_fontconfig #define FcPatternHash FcPatternHash_dylibloader_orig_fontconfig @@ -164,8 +188,18 @@ #define FcRangeDestroy FcRangeDestroy_dylibloader_orig_fontconfig #define FcRangeCopy FcRangeCopy_dylibloader_orig_fontconfig #define FcRangeGetDouble FcRangeGetDouble_dylibloader_orig_fontconfig +#define FcPatternIterStart FcPatternIterStart_dylibloader_orig_fontconfig +#define FcPatternIterNext FcPatternIterNext_dylibloader_orig_fontconfig +#define FcPatternIterEqual FcPatternIterEqual_dylibloader_orig_fontconfig +#define FcPatternFindIter FcPatternFindIter_dylibloader_orig_fontconfig +#define FcPatternIterIsValid FcPatternIterIsValid_dylibloader_orig_fontconfig +#define FcPatternIterGetObject FcPatternIterGetObject_dylibloader_orig_fontconfig +#define FcPatternIterValueCount FcPatternIterValueCount_dylibloader_orig_fontconfig +#define FcPatternIterGetValue FcPatternIterGetValue_dylibloader_orig_fontconfig #define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_orig_fontconfig +#define FcWeightFromOpenTypeDouble FcWeightFromOpenTypeDouble_dylibloader_orig_fontconfig #define FcWeightToOpenType FcWeightToOpenType_dylibloader_orig_fontconfig +#define FcWeightToOpenTypeDouble FcWeightToOpenTypeDouble_dylibloader_orig_fontconfig #define FcStrCopy FcStrCopy_dylibloader_orig_fontconfig #define FcStrCopyFilename FcStrCopyFilename_dylibloader_orig_fontconfig #define FcStrPlus FcStrPlus_dylibloader_orig_fontconfig @@ -209,6 +243,8 @@ #undef FcDirCacheValid #undef FcDirCacheClean #undef FcCacheCreateTagFile +#undef FcDirCacheCreateUUID +#undef FcDirCacheDeleteUUID #undef FcConfigHome #undef FcConfigEnableHome #undef FcConfigFilename @@ -235,6 +271,26 @@ #undef FcConfigSubstitute #undef FcConfigGetSysRoot #undef FcConfigSetSysRoot +#undef FcConfigFileInfoIterInit +#undef FcConfigFileInfoIterNext +#undef FcConfigFileInfoIterGet +#undef FcCharSetCreate +#undef FcCharSetNew +#undef FcCharSetDestroy +#undef FcCharSetAddChar +#undef FcCharSetDelChar +#undef FcCharSetCopy +#undef FcCharSetEqual +#undef FcCharSetIntersect +#undef FcCharSetUnion +#undef FcCharSetSubtract +#undef FcCharSetMerge +#undef FcCharSetHasChar +#undef FcCharSetCount +#undef FcCharSetIntersectCount +#undef FcCharSetSubtractCount +#undef FcCharSetIsSubset +#undef FcCharSetCoverage #undef FcValuePrint #undef FcPatternPrint #undef FcFontSetPrint @@ -250,6 +306,7 @@ #undef FcDirCacheLoadFile #undef FcDirCacheUnload #undef FcFreeTypeQuery +#undef FcFreeTypeQueryAll #undef FcFontSetCreate #undef FcFontSetDestroy #undef FcFontSetAdd @@ -320,6 +377,7 @@ #undef FcValueEqual #undef FcValueSave #undef FcPatternDestroy +#undef FcPatternObjectCount #undef FcPatternEqual #undef FcPatternEqualSubset #undef FcPatternHash @@ -353,8 +411,18 @@ #undef FcRangeDestroy #undef FcRangeCopy #undef FcRangeGetDouble +#undef FcPatternIterStart +#undef FcPatternIterNext +#undef FcPatternIterEqual +#undef FcPatternFindIter +#undef FcPatternIterIsValid +#undef FcPatternIterGetObject +#undef FcPatternIterValueCount +#undef FcPatternIterGetValue #undef FcWeightFromOpenType +#undef FcWeightFromOpenTypeDouble #undef FcWeightToOpenType +#undef FcWeightToOpenTypeDouble #undef FcStrCopy #undef FcStrCopyFilename #undef FcStrPlus @@ -400,6 +468,8 @@ extern "C" { #define FcDirCacheValid FcDirCacheValid_dylibloader_wrapper_fontconfig #define FcDirCacheClean FcDirCacheClean_dylibloader_wrapper_fontconfig #define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_wrapper_fontconfig +#define FcDirCacheCreateUUID FcDirCacheCreateUUID_dylibloader_wrapper_fontconfig +#define FcDirCacheDeleteUUID FcDirCacheDeleteUUID_dylibloader_wrapper_fontconfig #define FcConfigHome FcConfigHome_dylibloader_wrapper_fontconfig #define FcConfigEnableHome FcConfigEnableHome_dylibloader_wrapper_fontconfig #define FcConfigFilename FcConfigFilename_dylibloader_wrapper_fontconfig @@ -426,6 +496,26 @@ extern "C" { #define FcConfigSubstitute FcConfigSubstitute_dylibloader_wrapper_fontconfig #define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_wrapper_fontconfig #define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_wrapper_fontconfig +#define FcConfigFileInfoIterInit FcConfigFileInfoIterInit_dylibloader_wrapper_fontconfig +#define FcConfigFileInfoIterNext FcConfigFileInfoIterNext_dylibloader_wrapper_fontconfig +#define FcConfigFileInfoIterGet FcConfigFileInfoIterGet_dylibloader_wrapper_fontconfig +#define FcCharSetCreate FcCharSetCreate_dylibloader_wrapper_fontconfig +#define FcCharSetNew FcCharSetNew_dylibloader_wrapper_fontconfig +#define FcCharSetDestroy FcCharSetDestroy_dylibloader_wrapper_fontconfig +#define FcCharSetAddChar FcCharSetAddChar_dylibloader_wrapper_fontconfig +#define FcCharSetDelChar FcCharSetDelChar_dylibloader_wrapper_fontconfig +#define FcCharSetCopy FcCharSetCopy_dylibloader_wrapper_fontconfig +#define FcCharSetEqual FcCharSetEqual_dylibloader_wrapper_fontconfig +#define FcCharSetIntersect FcCharSetIntersect_dylibloader_wrapper_fontconfig +#define FcCharSetUnion FcCharSetUnion_dylibloader_wrapper_fontconfig +#define FcCharSetSubtract FcCharSetSubtract_dylibloader_wrapper_fontconfig +#define FcCharSetMerge FcCharSetMerge_dylibloader_wrapper_fontconfig +#define FcCharSetHasChar FcCharSetHasChar_dylibloader_wrapper_fontconfig +#define FcCharSetCount FcCharSetCount_dylibloader_wrapper_fontconfig +#define FcCharSetIntersectCount FcCharSetIntersectCount_dylibloader_wrapper_fontconfig +#define FcCharSetSubtractCount FcCharSetSubtractCount_dylibloader_wrapper_fontconfig +#define FcCharSetIsSubset FcCharSetIsSubset_dylibloader_wrapper_fontconfig +#define FcCharSetCoverage FcCharSetCoverage_dylibloader_wrapper_fontconfig #define FcValuePrint FcValuePrint_dylibloader_wrapper_fontconfig #define FcPatternPrint FcPatternPrint_dylibloader_wrapper_fontconfig #define FcFontSetPrint FcFontSetPrint_dylibloader_wrapper_fontconfig @@ -441,6 +531,7 @@ extern "C" { #define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_wrapper_fontconfig #define FcDirCacheUnload FcDirCacheUnload_dylibloader_wrapper_fontconfig #define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_wrapper_fontconfig +#define FcFreeTypeQueryAll FcFreeTypeQueryAll_dylibloader_wrapper_fontconfig #define FcFontSetCreate FcFontSetCreate_dylibloader_wrapper_fontconfig #define FcFontSetDestroy FcFontSetDestroy_dylibloader_wrapper_fontconfig #define FcFontSetAdd FcFontSetAdd_dylibloader_wrapper_fontconfig @@ -511,6 +602,7 @@ extern "C" { #define FcValueEqual FcValueEqual_dylibloader_wrapper_fontconfig #define FcValueSave FcValueSave_dylibloader_wrapper_fontconfig #define FcPatternDestroy FcPatternDestroy_dylibloader_wrapper_fontconfig +#define FcPatternObjectCount FcPatternObjectCount_dylibloader_wrapper_fontconfig #define FcPatternEqual FcPatternEqual_dylibloader_wrapper_fontconfig #define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_wrapper_fontconfig #define FcPatternHash FcPatternHash_dylibloader_wrapper_fontconfig @@ -544,8 +636,18 @@ extern "C" { #define FcRangeDestroy FcRangeDestroy_dylibloader_wrapper_fontconfig #define FcRangeCopy FcRangeCopy_dylibloader_wrapper_fontconfig #define FcRangeGetDouble FcRangeGetDouble_dylibloader_wrapper_fontconfig +#define FcPatternIterStart FcPatternIterStart_dylibloader_wrapper_fontconfig +#define FcPatternIterNext FcPatternIterNext_dylibloader_wrapper_fontconfig +#define FcPatternIterEqual FcPatternIterEqual_dylibloader_wrapper_fontconfig +#define FcPatternFindIter FcPatternFindIter_dylibloader_wrapper_fontconfig +#define FcPatternIterIsValid FcPatternIterIsValid_dylibloader_wrapper_fontconfig +#define FcPatternIterGetObject FcPatternIterGetObject_dylibloader_wrapper_fontconfig +#define FcPatternIterValueCount FcPatternIterValueCount_dylibloader_wrapper_fontconfig +#define FcPatternIterGetValue FcPatternIterGetValue_dylibloader_wrapper_fontconfig #define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_wrapper_fontconfig +#define FcWeightFromOpenTypeDouble FcWeightFromOpenTypeDouble_dylibloader_wrapper_fontconfig #define FcWeightToOpenType FcWeightToOpenType_dylibloader_wrapper_fontconfig +#define FcWeightToOpenTypeDouble FcWeightToOpenTypeDouble_dylibloader_wrapper_fontconfig #define FcStrCopy FcStrCopy_dylibloader_wrapper_fontconfig #define FcStrCopyFilename FcStrCopyFilename_dylibloader_wrapper_fontconfig #define FcStrPlus FcStrPlus_dylibloader_wrapper_fontconfig @@ -588,6 +690,8 @@ extern FcBool (*FcDirCacheUnlink_dylibloader_wrapper_fontconfig)(const FcChar8*, extern FcBool (*FcDirCacheValid_dylibloader_wrapper_fontconfig)(const FcChar8*); extern FcBool (*FcDirCacheClean_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool); extern void (*FcCacheCreateTagFile_dylibloader_wrapper_fontconfig)(const FcConfig*); +extern FcBool (*FcDirCacheCreateUUID_dylibloader_wrapper_fontconfig)( FcChar8*, FcBool, FcConfig*); +extern FcBool (*FcDirCacheDeleteUUID_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); extern FcChar8* (*FcConfigHome_dylibloader_wrapper_fontconfig)( void); extern FcBool (*FcConfigEnableHome_dylibloader_wrapper_fontconfig)( FcBool); extern FcChar8* (*FcConfigFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); @@ -614,6 +718,26 @@ extern FcBool (*FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig)( FcCon extern FcBool (*FcConfigSubstitute_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcMatchKind); extern const FcChar8* (*FcConfigGetSysRoot_dylibloader_wrapper_fontconfig)(const FcConfig*); extern void (*FcConfigSetSysRoot_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +extern void (*FcConfigFileInfoIterInit_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*); +extern FcBool (*FcConfigFileInfoIterNext_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*); +extern FcBool (*FcConfigFileInfoIterGet_dylibloader_wrapper_fontconfig)( FcConfig*, FcConfigFileInfoIter*, FcChar8**, FcChar8**, FcBool*); +extern FcCharSet* (*FcCharSetCreate_dylibloader_wrapper_fontconfig)( void); +extern FcCharSet* (*FcCharSetNew_dylibloader_wrapper_fontconfig)( void); +extern void (*FcCharSetDestroy_dylibloader_wrapper_fontconfig)( FcCharSet*); +extern FcBool (*FcCharSetAddChar_dylibloader_wrapper_fontconfig)( FcCharSet*, FcChar32); +extern FcBool (*FcCharSetDelChar_dylibloader_wrapper_fontconfig)( FcCharSet*, FcChar32); +extern FcCharSet* (*FcCharSetCopy_dylibloader_wrapper_fontconfig)( FcCharSet*); +extern FcBool (*FcCharSetEqual_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcCharSet* (*FcCharSetIntersect_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcCharSet* (*FcCharSetUnion_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcCharSet* (*FcCharSetSubtract_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcBool (*FcCharSetMerge_dylibloader_wrapper_fontconfig)( FcCharSet*,const FcCharSet*, FcBool*); +extern FcBool (*FcCharSetHasChar_dylibloader_wrapper_fontconfig)(const FcCharSet*, FcChar32); +extern FcChar32 (*FcCharSetCount_dylibloader_wrapper_fontconfig)(const FcCharSet*); +extern FcChar32 (*FcCharSetIntersectCount_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcChar32 (*FcCharSetSubtractCount_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcBool (*FcCharSetIsSubset_dylibloader_wrapper_fontconfig)(const FcCharSet*,const FcCharSet*); +extern FcChar32 (*FcCharSetCoverage_dylibloader_wrapper_fontconfig)(const FcCharSet*, FcChar32, FcChar32*); extern void (*FcValuePrint_dylibloader_wrapper_fontconfig)(const FcValue); extern void (*FcPatternPrint_dylibloader_wrapper_fontconfig)(const FcPattern*); extern void (*FcFontSetPrint_dylibloader_wrapper_fontconfig)(const FcFontSet*); @@ -628,7 +752,8 @@ extern FcCache* (*FcDirCacheRescan_dylibloader_wrapper_fontconfig)(const FcChar8 extern FcCache* (*FcDirCacheRead_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool, FcConfig*); extern FcCache* (*FcDirCacheLoadFile_dylibloader_wrapper_fontconfig)(const FcChar8*,struct stat*); extern void (*FcDirCacheUnload_dylibloader_wrapper_fontconfig)( FcCache*); -extern FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, int, FcBlanks*, int*); +extern FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, unsigned int, FcBlanks*, int*); +extern unsigned int (*FcFreeTypeQueryAll_dylibloader_wrapper_fontconfig)(const FcChar8*, unsigned int, FcBlanks*, int*, FcFontSet*); extern FcFontSet* (*FcFontSetCreate_dylibloader_wrapper_fontconfig)( void); extern void (*FcFontSetDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); extern FcBool (*FcFontSetAdd_dylibloader_wrapper_fontconfig)( FcFontSet*, FcPattern*); @@ -699,6 +824,7 @@ extern void (*FcValueDestroy_dylibloader_wrapper_fontconfig)( FcValue); extern FcBool (*FcValueEqual_dylibloader_wrapper_fontconfig)( FcValue, FcValue); extern FcValue (*FcValueSave_dylibloader_wrapper_fontconfig)( FcValue); extern void (*FcPatternDestroy_dylibloader_wrapper_fontconfig)( FcPattern*); +extern int (*FcPatternObjectCount_dylibloader_wrapper_fontconfig)(const FcPattern*); extern FcBool (*FcPatternEqual_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*); extern FcBool (*FcPatternEqualSubset_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*,const FcObjectSet*); extern FcChar32 (*FcPatternHash_dylibloader_wrapper_fontconfig)(const FcPattern*); @@ -732,8 +858,18 @@ extern FcRange* (*FcRangeCreateInteger_dylibloader_wrapper_fontconfig)( FcChar32 extern void (*FcRangeDestroy_dylibloader_wrapper_fontconfig)( FcRange*); extern FcRange* (*FcRangeCopy_dylibloader_wrapper_fontconfig)(const FcRange*); extern FcBool (*FcRangeGetDouble_dylibloader_wrapper_fontconfig)(const FcRange*, double*, double*); +extern void (*FcPatternIterStart_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +extern FcBool (*FcPatternIterNext_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +extern FcBool (*FcPatternIterEqual_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*,const FcPattern*, FcPatternIter*); +extern FcBool (*FcPatternFindIter_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*,const char*); +extern FcBool (*FcPatternIterIsValid_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +extern const char* (*FcPatternIterGetObject_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +extern int (*FcPatternIterValueCount_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*); +extern FcResult (*FcPatternIterGetValue_dylibloader_wrapper_fontconfig)(const FcPattern*, FcPatternIter*, int, FcValue*, FcValueBinding*); extern int (*FcWeightFromOpenType_dylibloader_wrapper_fontconfig)( int); +extern double (*FcWeightFromOpenTypeDouble_dylibloader_wrapper_fontconfig)( double); extern int (*FcWeightToOpenType_dylibloader_wrapper_fontconfig)( int); +extern double (*FcWeightToOpenTypeDouble_dylibloader_wrapper_fontconfig)( double); extern FcChar8* (*FcStrCopy_dylibloader_wrapper_fontconfig)(const FcChar8*); extern FcChar8* (*FcStrCopyFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); extern FcChar8* (*FcStrPlus_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index e14e4fb52d..25cb575199 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -56,10 +56,6 @@ #include <sys/utsname.h> #include <unistd.h> -#ifdef FONTCONFIG_ENABLED -#include "fontconfig-so_wrap.h" -#endif - void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; @@ -585,15 +581,9 @@ Vector<String> OS_LinuxBSD::get_system_fonts() const { if (!font_config_initialized) { ERR_FAIL_V_MSG(Vector<String>(), "Unable to load fontconfig, system font support is disabled."); } + HashSet<String> font_names; Vector<String> ret; - - FcConfig *config = FcInitLoadConfigAndFonts(); - ERR_FAIL_COND_V(!config, ret); - - FcObjectSet *object_set = FcObjectSetBuild(FC_FAMILY, nullptr); - ERR_FAIL_COND_V(!object_set, ret); - static const char *allowed_formats[] = { "TrueType", "CFF" }; for (size_t i = 0; i < sizeof(allowed_formats) / sizeof(const char *); i++) { FcPattern *pattern = FcPatternCreate(); @@ -616,8 +606,6 @@ Vector<String> OS_LinuxBSD::get_system_fonts() const { } FcPatternDestroy(pattern); } - FcObjectSetDestroy(object_set); - FcConfigDestroy(config); for (const String &E : font_names) { ret.push_back(E); @@ -628,27 +616,120 @@ Vector<String> OS_LinuxBSD::get_system_fonts() const { #endif } -String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { +int OS_LinuxBSD::_weight_to_fc(int p_weight) const { + if (p_weight < 150) { + return FC_WEIGHT_THIN; + } else if (p_weight < 250) { + return FC_WEIGHT_EXTRALIGHT; + } else if (p_weight < 325) { + return FC_WEIGHT_LIGHT; + } else if (p_weight < 375) { + return FC_WEIGHT_DEMILIGHT; + } else if (p_weight < 390) { + return FC_WEIGHT_BOOK; + } else if (p_weight < 450) { + return FC_WEIGHT_REGULAR; + } else if (p_weight < 550) { + return FC_WEIGHT_MEDIUM; + } else if (p_weight < 650) { + return FC_WEIGHT_DEMIBOLD; + } else if (p_weight < 750) { + return FC_WEIGHT_BOLD; + } else if (p_weight < 850) { + return FC_WEIGHT_EXTRABOLD; + } else if (p_weight < 925) { + return FC_WEIGHT_BLACK; + } else { + return FC_WEIGHT_EXTRABLACK; + } +} + +int OS_LinuxBSD::_stretch_to_fc(int p_stretch) const { + if (p_stretch < 56) { + return FC_WIDTH_ULTRACONDENSED; + } else if (p_stretch < 69) { + return FC_WIDTH_EXTRACONDENSED; + } else if (p_stretch < 81) { + return FC_WIDTH_CONDENSED; + } else if (p_stretch < 93) { + return FC_WIDTH_SEMICONDENSED; + } else if (p_stretch < 106) { + return FC_WIDTH_NORMAL; + } else if (p_stretch < 137) { + return FC_WIDTH_SEMIEXPANDED; + } else if (p_stretch < 144) { + return FC_WIDTH_EXPANDED; + } else if (p_stretch < 162) { + return FC_WIDTH_EXTRAEXPANDED; + } else { + return FC_WIDTH_ULTRAEXPANDED; + } +} + +Vector<String> OS_LinuxBSD::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { #ifdef FONTCONFIG_ENABLED if (!font_config_initialized) { - ERR_FAIL_V_MSG(String(), "Unable to load fontconfig, system font support is disabled."); + ERR_FAIL_V_MSG(Vector<String>(), "Unable to load fontconfig, system font support is disabled."); } - bool allow_substitutes = (p_font_name.to_lower() == "sans-serif") || (p_font_name.to_lower() == "serif") || (p_font_name.to_lower() == "monospace") || (p_font_name.to_lower() == "cursive") || (p_font_name.to_lower() == "fantasy"); + Vector<String> ret; + FcPattern *pattern = FcPatternCreate(); + if (pattern) { + FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); + FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); + FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); + FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); - String ret; + FcCharSet *char_set = FcCharSetCreate(); + for (int i = 0; i < p_text.size(); i++) { + FcCharSetAddChar(char_set, p_text[i]); + } + FcPatternAddCharSet(pattern, FC_CHARSET, char_set); - FcConfig *config = FcInitLoadConfigAndFonts(); - ERR_FAIL_COND_V(!config, ret); + FcLangSet *lang_set = FcLangSetCreate(); + FcLangSetAdd(lang_set, reinterpret_cast<const FcChar8 *>(p_locale.utf8().get_data())); + FcPatternAddLangSet(pattern, FC_LANG, lang_set); - FcObjectSet *object_set = FcObjectSetBuild(FC_FAMILY, FC_FILE, nullptr); - ERR_FAIL_COND_V(!object_set, ret); + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + FcResult result; + FcPattern *match = FcFontMatch(0, pattern, &result); + if (match) { + char *file_name = nullptr; + if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { + if (file_name) { + ret.push_back(String::utf8(file_name)); + } + } + FcPatternDestroy(match); + } + FcPatternDestroy(pattern); + FcCharSetDestroy(char_set); + FcLangSetDestroy(lang_set); + } + + return ret; +#else + ERR_FAIL_V_MSG(Vector<String>(), "Godot was compiled without fontconfig, system font support is disabled."); +#endif +} + +String OS_LinuxBSD::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { +#ifdef FONTCONFIG_ENABLED + if (!font_config_initialized) { + ERR_FAIL_V_MSG(String(), "Unable to load fontconfig, system font support is disabled."); + } + + String ret; FcPattern *pattern = FcPatternCreate(); if (pattern) { + bool allow_substitutes = (p_font_name.to_lower() == "sans-serif") || (p_font_name.to_lower() == "serif") || (p_font_name.to_lower() == "monospace") || (p_font_name.to_lower() == "cursive") || (p_font_name.to_lower() == "fantasy"); + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); - FcPatternAddInteger(pattern, FC_WEIGHT, p_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); + FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); + FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); FcConfigSubstitute(0, pattern, FcMatchPattern); @@ -663,8 +744,6 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold, if (family_name && String::utf8(family_name).to_lower() != p_font_name.to_lower()) { FcPatternDestroy(match); FcPatternDestroy(pattern); - FcObjectSetDestroy(object_set); - FcConfigDestroy(config); return String(); } @@ -681,8 +760,6 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold, } FcPatternDestroy(pattern); } - FcObjectSetDestroy(object_set); - FcConfigDestroy(config); return ret; #else @@ -1008,5 +1085,26 @@ OS_LinuxBSD::OS_LinuxBSD() { int dylibloader_verbose = 0; #endif font_config_initialized = (initialize_fontconfig(dylibloader_verbose) == 0); + if (font_config_initialized) { + config = FcInitLoadConfigAndFonts(); + if (!config) { + font_config_initialized = false; + } + object_set = FcObjectSetBuild(FC_FAMILY, FC_FILE, nullptr); + if (!object_set) { + font_config_initialized = false; + } + } +#endif // FONTCONFIG_ENABLED +} + +OS_LinuxBSD::~OS_LinuxBSD() { +#ifdef FONTCONFIG_ENABLED + if (object_set) { + FcObjectSetDestroy(object_set); + } + if (config) { + FcConfigDestroy(config); + } #endif // FONTCONFIG_ENABLED } diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index aa7af92aa1..ef830a069b 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -40,11 +40,17 @@ #include "joypad_linux.h" #include "servers/audio_server.h" +#ifdef FONTCONFIG_ENABLED +#include "fontconfig-so_wrap.h" +#endif + class OS_LinuxBSD : public OS_Unix { virtual void delete_main_loop() override; #ifdef FONTCONFIG_ENABLED bool font_config_initialized = false; + FcConfig *config = nullptr; + FcObjectSet *object_set = nullptr; #endif #ifdef JOYDEV_ENABLED @@ -67,6 +73,9 @@ class OS_LinuxBSD : public OS_Unix { MainLoop *main_loop = nullptr; + int _weight_to_fc(int p_weight) const; + int _stretch_to_fc(int p_stretch) const; + String get_systemd_os_release_info_value(const String &key) const; Vector<String> lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const; @@ -94,7 +103,8 @@ public: virtual uint64_t get_embedded_pck_offset() const override; virtual Vector<String> get_system_fonts() const override; - virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; virtual String get_config_path() const override; virtual String get_data_path() const override; @@ -119,6 +129,7 @@ public: virtual Error move_to_trash(const String &p_path) override; OS_LinuxBSD(); + ~OS_LinuxBSD(); }; #endif // OS_LINUXBSD_H diff --git a/platform/macos/export/plist.cpp b/platform/macos/export/plist.cpp index cad014e65b..82ecd41d9c 100644 --- a/platform/macos/export/plist.cpp +++ b/platform/macos/export/plist.cpp @@ -353,7 +353,7 @@ bool PList::load_file(const String &p_filename) { } else { // Load text plist. Error err; - Vector<uint8_t> array = FileAccess::get_file_as_array(p_filename, &err); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(p_filename, &err); ERR_FAIL_COND_V(err != OK, false); String ret; diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h index 46e7c17ebe..b2734e57cc 100644 --- a/platform/macos/os_macos.h +++ b/platform/macos/os_macos.h @@ -57,6 +57,10 @@ class OS_MacOS : public OS_Unix { List<String> launch_service_args; + CGFloat _weight_to_ct(int p_weight) const; + CGFloat _stretch_to_ct(int p_stretch) const; + String _get_default_fontname(const String &p_font_name) const; + static _FORCE_INLINE_ String get_framework_executable(const String &p_path); static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); @@ -98,7 +102,8 @@ public: virtual String get_locale() const override; virtual Vector<String> get_system_fonts() const override; - virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; virtual String get_executable_path() const override; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index e620b058d3..ebba96ceb1 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -336,9 +336,7 @@ Vector<String> OS_MacOS::get_system_fonts() const { return ret; } -String OS_MacOS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { - String ret; - +String OS_MacOS::_get_default_fontname(const String &p_font_name) const { String font_name = p_font_name; if (font_name.to_lower() == "sans-serif") { font_name = "Helvetica"; @@ -351,21 +349,153 @@ String OS_MacOS::get_system_font_path(const String &p_font_name, bool p_bold, bo } else if (font_name.to_lower() == "cursive") { font_name = "Apple Chancery"; }; + return font_name; +} + +CGFloat OS_MacOS::_weight_to_ct(int p_weight) const { + if (p_weight < 150) { + return -0.80; + } else if (p_weight < 250) { + return -0.60; + } else if (p_weight < 350) { + return -0.40; + } else if (p_weight < 450) { + return 0.0; + } else if (p_weight < 550) { + return 0.23; + } else if (p_weight < 650) { + return 0.30; + } else if (p_weight < 750) { + return 0.40; + } else if (p_weight < 850) { + return 0.56; + } else if (p_weight < 925) { + return 0.62; + } else { + return 1.00; + } +} + +CGFloat OS_MacOS::_stretch_to_ct(int p_stretch) const { + if (p_stretch < 56) { + return -0.5; + } else if (p_stretch < 69) { + return -0.37; + } else if (p_stretch < 81) { + return -0.25; + } else if (p_stretch < 93) { + return -0.13; + } else if (p_stretch < 106) { + return 0.0; + } else if (p_stretch < 137) { + return 0.13; + } else if (p_stretch < 144) { + return 0.25; + } else if (p_stretch < 162) { + return 0.37; + } else { + return 0.5; + } +} + +Vector<String> OS_MacOS::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { + Vector<String> ret; + String font_name = _get_default_fontname(p_font_name); + + CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); + CTFontSymbolicTraits traits = 0; + if (p_weight >= 700) { + traits |= kCTFontBoldTrait; + } + if (p_italic) { + traits |= kCTFontItalicTrait; + } + if (p_stretch < 100) { + traits |= kCTFontCondensedTrait; + } else if (p_stretch > 100) { + traits |= kCTFontExpandedTrait; + } + + CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); + CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + + CGFloat weight = _weight_to_ct(p_weight); + CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight); + CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight); + + CGFloat stretch = _stretch_to_ct(p_stretch); + CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch); + CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch); + + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); + CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); + + CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes); + if (font) { + CTFontRef family = CTFontCreateWithFontDescriptor(font, 0, nullptr); + CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, p_text.utf8().get_data(), kCFStringEncodingUTF8); + CFRange range = CFRangeMake(0, CFStringGetLength(string)); + CTFontRef fallback_family = CTFontCreateForString(family, string, range); + if (fallback_family) { + CTFontDescriptorRef fallback_font = CTFontCopyFontDescriptor(fallback_family); + if (fallback_font) { + CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fallback_font, kCTFontURLAttribute); + if (url) { + NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]]; + ret.push_back(String::utf8([font_path UTF8String])); + CFRelease(url); + } + CFRelease(fallback_font); + } + CFRelease(fallback_family); + } + CFRelease(string); + CFRelease(font); + } + + CFRelease(attributes); + CFRelease(traits_dict); + CFRelease(sym_traits); + CFRelease(font_stretch); + CFRelease(font_weight); + CFRelease(name); + + return ret; +} + +String OS_MacOS::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { + String ret; + String font_name = _get_default_fontname(p_font_name); CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); CTFontSymbolicTraits traits = 0; - if (p_bold) { + if (p_weight > 700) { traits |= kCTFontBoldTrait; } if (p_italic) { traits |= kCTFontItalicTrait; } + if (p_stretch < 100) { + traits |= kCTFontCondensedTrait; + } else if (p_stretch > 100) { + traits |= kCTFontExpandedTrait; + } CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + CGFloat weight = _weight_to_ct(p_weight); + CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight); + CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight); + + CGFloat stretch = _stretch_to_ct(p_stretch); + CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch); + CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch); + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); @@ -384,6 +514,8 @@ String OS_MacOS::get_system_font_path(const String &p_font_name, bool p_bold, bo CFRelease(attributes); CFRelease(traits_dict); CFRelease(sym_traits); + CFRelease(font_stretch); + CFRelease(font_weight); CFRelease(name); return ret; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index d8548eb545..e957a25e87 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -43,12 +43,12 @@ #include "platform/windows/display_server_windows.h" #include "servers/audio_server.h" #include "servers/rendering/rendering_server_default.h" +#include "servers/text_server.h" #include "windows_terminal_logger.h" #include <avrt.h> #include <bcrypt.h> #include <direct.h> -#include <dwrite.h> #include <knownfolders.h> #include <process.h> #include <regstr.h> @@ -189,6 +189,27 @@ void OS_Windows::initialize() { IPUnix::make_default(); main_loop = nullptr; + + CoInitialize(nullptr); + HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory)); + if (SUCCEEDED(hr)) { + hr = dwrite_factory->GetSystemFontCollection(&font_collection, false); + if (SUCCEEDED(hr)) { + dwrite_init = true; + hr = dwrite_factory->QueryInterface(&dwrite_factory2); + if (SUCCEEDED(hr)) { + hr = dwrite_factory2->GetSystemFontFallback(&system_font_fallback); + if (SUCCEEDED(hr)) { + dwrite2_init = true; + } + } + } + } + if (!dwrite_init) { + print_verbose("Unable to load IDWriteFactory, system font support is disabled."); + } else if (!dwrite2_init) { + print_verbose("Unable to load IDWriteFactory2, automatic system font fallback is disabled."); + } } void OS_Windows::delete_main_loop() { @@ -203,6 +224,22 @@ void OS_Windows::set_main_loop(MainLoop *p_main_loop) { } void OS_Windows::finalize() { + if (dwrite_factory2) { + dwrite_factory2->Release(); + dwrite_factory2 = nullptr; + } + if (font_collection) { + font_collection->Release(); + font_collection = nullptr; + } + if (system_font_fallback) { + system_font_fallback->Release(); + system_font_fallback = nullptr; + } + if (dwrite_factory) { + dwrite_factory->Release(); + dwrite_factory = nullptr; + } #ifdef WINMIDI_ENABLED driver_midi.close(); #endif @@ -726,21 +763,17 @@ Error OS_Windows::set_cwd(const String &p_cwd) { } Vector<String> OS_Windows::get_system_fonts() const { + if (!dwrite_init) { + return Vector<String>(); + } + Vector<String> ret; HashSet<String> font_names; - ComAutoreleaseRef<IDWriteFactory> dwrite_factory; - HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference)); - ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), ret); - - ComAutoreleaseRef<IDWriteFontCollection> font_collection; - hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false); - ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), ret); - UINT32 family_count = font_collection->GetFontFamilyCount(); for (UINT32 i = 0; i < family_count; i++) { ComAutoreleaseRef<IDWriteFontFamily> family; - hr = font_collection->GetFontFamily(i, &family.reference); + HRESULT hr = font_collection->GetFontFamily(i, &family.reference); ERR_CONTINUE(FAILED(hr) || family.is_null()); ComAutoreleaseRef<IDWriteLocalizedStrings> family_names; @@ -771,7 +804,98 @@ Vector<String> OS_Windows::get_system_fonts() const { return ret; } -String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +class FallbackTextAnalysisSource : public IDWriteTextAnalysisSource { + LONG _cRef = 1; + + bool rtl = false; + Char16String string; + Char16String locale; + IDWriteNumberSubstitution *n_sub = nullptr; + +public: + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown *)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient *)this; + } else { + *ppvInterface = nullptr; + return E_NOINTERFACE; + } + return S_OK; + } + + ULONG STDMETHODCALLTYPE AddRef() { + return InterlockedIncrement(&_cRef); + } + + ULONG STDMETHODCALLTYPE Release() { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE GetTextAtPosition(UINT32 p_text_position, WCHAR const **r_text_string, UINT32 *r_text_length) override { + if (p_text_position >= (UINT32)string.length()) { + *r_text_string = nullptr; + *r_text_length = 0; + return S_OK; + } + *r_text_string = reinterpret_cast<const wchar_t *>(string.get_data()) + p_text_position; + *r_text_length = string.length() - p_text_position; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetTextBeforePosition(UINT32 p_text_position, WCHAR const **r_text_string, UINT32 *r_text_length) override { + if (p_text_position < 1 || p_text_position >= (UINT32)string.length()) { + *r_text_string = nullptr; + *r_text_length = 0; + return S_OK; + } + *r_text_string = reinterpret_cast<const wchar_t *>(string.get_data()); + *r_text_length = p_text_position; + return S_OK; + } + + DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() override { + return (rtl) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; + } + + HRESULT STDMETHODCALLTYPE GetLocaleName(UINT32 p_text_position, UINT32 *r_text_length, WCHAR const **r_locale_name) override { + *r_locale_name = reinterpret_cast<const wchar_t *>(locale.get_data()); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetNumberSubstitution(UINT32 p_text_position, UINT32 *r_text_length, IDWriteNumberSubstitution **r_number_substitution) override { + *r_number_substitution = n_sub; + return S_OK; + } + + FallbackTextAnalysisSource(const Char16String &p_text, const Char16String &p_locale, bool p_rtl, IDWriteNumberSubstitution *p_nsub) { + _cRef = 1; + string = p_text; + locale = p_locale; + n_sub = p_nsub; + rtl = p_rtl; + }; + + virtual ~FallbackTextAnalysisSource() {} +}; + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +String OS_Windows::_get_default_fontname(const String &p_font_name) const { String font_name = p_font_name; if (font_name.to_lower() == "sans-serif") { font_name = "Arial"; @@ -784,18 +908,157 @@ String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, } else if (font_name.to_lower() == "fantasy") { font_name = "Gabriola"; } + return font_name; +} + +DWRITE_FONT_WEIGHT OS_Windows::_weight_to_dw(int p_weight) const { + if (p_weight < 150) { + return DWRITE_FONT_WEIGHT_THIN; + } else if (p_weight < 250) { + return DWRITE_FONT_WEIGHT_EXTRA_LIGHT; + } else if (p_weight < 325) { + return DWRITE_FONT_WEIGHT_LIGHT; + } else if (p_weight < 375) { + return DWRITE_FONT_WEIGHT_SEMI_LIGHT; + } else if (p_weight < 450) { + return DWRITE_FONT_WEIGHT_NORMAL; + } else if (p_weight < 550) { + return DWRITE_FONT_WEIGHT_MEDIUM; + } else if (p_weight < 650) { + return DWRITE_FONT_WEIGHT_DEMI_BOLD; + } else if (p_weight < 750) { + return DWRITE_FONT_WEIGHT_BOLD; + } else if (p_weight < 850) { + return DWRITE_FONT_WEIGHT_EXTRA_BOLD; + } else if (p_weight < 925) { + return DWRITE_FONT_WEIGHT_BLACK; + } else { + return DWRITE_FONT_WEIGHT_EXTRA_BLACK; + } +} + +DWRITE_FONT_STRETCH OS_Windows::_stretch_to_dw(int p_stretch) const { + if (p_stretch < 56) { + return DWRITE_FONT_STRETCH_ULTRA_CONDENSED; + } else if (p_stretch < 69) { + return DWRITE_FONT_STRETCH_EXTRA_CONDENSED; + } else if (p_stretch < 81) { + return DWRITE_FONT_STRETCH_CONDENSED; + } else if (p_stretch < 93) { + return DWRITE_FONT_STRETCH_SEMI_CONDENSED; + } else if (p_stretch < 106) { + return DWRITE_FONT_STRETCH_NORMAL; + } else if (p_stretch < 137) { + return DWRITE_FONT_STRETCH_SEMI_EXPANDED; + } else if (p_stretch < 144) { + return DWRITE_FONT_STRETCH_EXPANDED; + } else if (p_stretch < 162) { + return DWRITE_FONT_STRETCH_EXTRA_EXPANDED; + } else { + return DWRITE_FONT_STRETCH_ULTRA_EXPANDED; + } +} + +Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { + if (!dwrite2_init) { + return Vector<String>(); + } + + String font_name = _get_default_fontname(p_font_name); + + bool rtl = TS->is_locale_right_to_left(p_locale); + Char16String text = p_text.utf16(); + Char16String locale = p_locale.utf16(); + + ComAutoreleaseRef<IDWriteNumberSubstitution> number_substitution; + HRESULT hr = dwrite_factory->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, reinterpret_cast<const wchar_t *>(locale.get_data()), true, &number_substitution.reference); + ERR_FAIL_COND_V(FAILED(hr) || number_substitution.is_null(), Vector<String>()); + + FallbackTextAnalysisSource fs = FallbackTextAnalysisSource(text, locale, rtl, number_substitution.reference); + UINT32 mapped_length = 0; + FLOAT scale = 0.0; + ComAutoreleaseRef<IDWriteFont> dwrite_font; + hr = system_font_fallback->MapCharacters( + &fs, + 0, + (UINT32)text.length(), + font_collection, + reinterpret_cast<const wchar_t *>(font_name.utf16().get_data()), + _weight_to_dw(p_weight), + p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + _stretch_to_dw(p_stretch), + &mapped_length, + &dwrite_font.reference, + &scale); + + if (FAILED(hr) || dwrite_font.is_null()) { + return Vector<String>(); + } + + ComAutoreleaseRef<IDWriteFontFace> dwrite_face; + hr = dwrite_font->CreateFontFace(&dwrite_face.reference); + if (FAILED(hr) || dwrite_face.is_null()) { + return Vector<String>(); + } + + UINT32 number_of_files = 0; + hr = dwrite_face->GetFiles(&number_of_files, nullptr); + if (FAILED(hr)) { + return Vector<String>(); + } + Vector<ComAutoreleaseRef<IDWriteFontFile>> files; + files.resize(number_of_files); + hr = dwrite_face->GetFiles(&number_of_files, (IDWriteFontFile **)files.ptrw()); + if (FAILED(hr)) { + return Vector<String>(); + } + + Vector<String> ret; + for (UINT32 i = 0; i < number_of_files; i++) { + void const *reference_key = nullptr; + UINT32 reference_key_size = 0; + ComAutoreleaseRef<IDWriteLocalFontFileLoader> loader; + + hr = files.write[i]->GetLoader((IDWriteFontFileLoader **)&loader.reference); + if (FAILED(hr) || loader.is_null()) { + continue; + } + hr = files.write[i]->GetReferenceKey(&reference_key, &reference_key_size); + if (FAILED(hr)) { + continue; + } + + WCHAR file_path[MAX_PATH]; + hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], MAX_PATH); + if (FAILED(hr)) { + continue; + } + String fpath = String::utf16((const char16_t *)&file_path[0]); + + WIN32_FIND_DATAW d; + HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); + if (fnd != INVALID_HANDLE_VALUE) { + String fname = String::utf16((const char16_t *)d.cFileName); + if (!fname.is_empty()) { + fpath = fpath.get_base_dir().path_join(fname); + } + FindClose(fnd); + } + ret.push_back(fpath); + } + return ret; +} - ComAutoreleaseRef<IDWriteFactory> dwrite_factory; - HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference)); - ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), String()); +String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { + if (!dwrite_init) { + return String(); + } - ComAutoreleaseRef<IDWriteFontCollection> font_collection; - hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false); - ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), String()); + String font_name = _get_default_fontname(p_font_name); UINT32 index = 0; BOOL exists = false; - font_collection->FindFamilyName((const WCHAR *)font_name.utf16().get_data(), &index, &exists); + HRESULT hr = font_collection->FindFamilyName((const WCHAR *)font_name.utf16().get_data(), &index, &exists); if (FAILED(hr)) { return String(); } @@ -807,7 +1070,7 @@ String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, } ComAutoreleaseRef<IDWriteFont> dwrite_font; - hr = family->GetFirstMatchingFont(p_bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, &dwrite_font.reference); + hr = family->GetFirstMatchingFont(_weight_to_dw(p_weight), _stretch_to_dw(p_stretch), p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, &dwrite_font.reference); if (FAILED(hr) || dwrite_font.is_null()) { return String(); } @@ -1192,7 +1455,7 @@ String OS_Windows::get_unique_id() const { bool OS_Windows::_check_internal_feature_support(const String &p_feature) { if (p_feature == "system_fonts") { - return true; + return dwrite_init; } if (p_feature == "pc") { return true; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 6f89be699a..1db2b5880d 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -55,6 +55,8 @@ #include <stdio.h> #define WIN32_LEAN_AND_MEAN +#include <dwrite.h> +#include <dwrite_2.h> #include <windows.h> #include <windowsx.h> @@ -79,6 +81,9 @@ public: _FORCE_INLINE_ bool is_valid() const { return reference != nullptr; } _FORCE_INLINE_ bool is_null() const { return reference == nullptr; } ComAutoreleaseRef() {} + ComAutoreleaseRef(T *p_ref) { + reference = p_ref; + } ~ComAutoreleaseRef() { if (reference != nullptr) { reference->Release(); @@ -114,6 +119,18 @@ class OS_Windows : public OS { HWND main_window; + IDWriteFactory *dwrite_factory = nullptr; + IDWriteFactory2 *dwrite_factory2 = nullptr; + IDWriteFontCollection *font_collection = nullptr; + IDWriteFontFallback *system_font_fallback = nullptr; + + bool dwrite_init = false; + bool dwrite2_init = false; + + String _get_default_fontname(const String &p_font_name) const; + DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const; + DWRITE_FONT_STRETCH _stretch_to_dw(int p_stretch) const; + // functions used by main to initialize/deinitialize the OS protected: virtual void initialize() override; @@ -172,7 +189,8 @@ public: virtual bool set_environment(const String &p_var, const String &p_value) const override; virtual Vector<String> get_system_fonts() const override; - virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; + virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override; virtual String get_executable_path() const override; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index af51d6539e..584a7e7eac 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -63,6 +63,8 @@ void Font::_bind_methods() { ClassDB::bind_method(D_METHOD("get_font_name"), &Font::get_font_name); ClassDB::bind_method(D_METHOD("get_font_style_name"), &Font::get_font_style_name); ClassDB::bind_method(D_METHOD("get_font_style"), &Font::get_font_style); + ClassDB::bind_method(D_METHOD("get_font_weight"), &Font::get_font_weight); + ClassDB::bind_method(D_METHOD("get_font_stretch"), &Font::get_font_stretch); ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing); ClassDB::bind_method(D_METHOD("get_opentype_features"), &Font::get_opentype_features); @@ -249,6 +251,14 @@ BitField<TextServer::FontStyle> Font::get_font_style() const { return TS->font_get_style(_get_rid()); } +int Font::get_font_weight() const { + return TS->font_get_weight(_get_rid()); +} + +int Font::get_font_stretch() const { + return TS->font_get_stretch(_get_rid()); +} + Dictionary Font::get_opentype_features() const { return Dictionary(); } @@ -590,6 +600,7 @@ _FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const { TS->font_set_msdf_size(cache[p_cache_index], msdf_size); TS->font_set_fixed_size(cache[p_cache_index], fixed_size); TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter); + TS->font_set_allow_system_fallback(cache[p_cache_index], allow_system_fallback); TS->font_set_hinting(cache[p_cache_index], hinting); TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning); TS->font_set_oversampling(cache[p_cache_index], oversampling); @@ -881,6 +892,8 @@ void FontFile::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontFile::set_font_name); ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name); ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style); + ClassDB::bind_method(D_METHOD("set_font_weight", "weight"), &FontFile::set_font_weight); + ClassDB::bind_method(D_METHOD("set_font_stretch", "stretch"), &FontFile::set_font_stretch); ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &FontFile::set_antialiasing); ClassDB::bind_method(D_METHOD("get_antialiasing"), &FontFile::get_antialiasing); @@ -900,6 +913,9 @@ void FontFile::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontFile::set_fixed_size); ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontFile::get_fixed_size); + ClassDB::bind_method(D_METHOD("set_allow_system_fallback", "allow_system_fallback"), &FontFile::set_allow_system_fallback); + ClassDB::bind_method(D_METHOD("is_allow_system_fallback"), &FontFile::is_allow_system_fallback); + ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontFile::set_force_autohinter); ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontFile::is_force_autohinter); @@ -1007,10 +1023,14 @@ void FontFile::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic,Fixed Size", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_weight", PROPERTY_HINT_RANGE, "100,999,25", PROPERTY_USAGE_STORAGE), "set_font_weight", "get_font_weight"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_stretch", PROPERTY_HINT_RANGE, "50,200,25", PROPERTY_USAGE_STORAGE), "set_font_stretch", "get_font_stretch"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_allow_system_fallback", "is_allow_system_fallback"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling"); @@ -1329,6 +1349,7 @@ void FontFile::reset_state() { mipmaps = false; msdf = false; force_autohinter = false; + allow_system_fallback = true; hinting = TextServer::HINTING_LIGHT; subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED; msdf_pixel_range = 14; @@ -1361,6 +1382,7 @@ Error FontFile::load_bitmap_font(const String &p_path) { mipmaps = false; msdf = false; force_autohinter = false; + allow_system_fallback = true; hinting = TextServer::HINTING_NONE; oversampling = 1.0f; @@ -1937,6 +1959,9 @@ Error FontFile::load_bitmap_font(const String &p_path) { set_font_name(font_name); set_font_style(st_flags); + if (st_flags & TextServer::FONT_BOLD) { + set_font_weight(700); + } set_cache_ascent(0, base_size, ascent); set_cache_descent(0, base_size, height - ascent); @@ -1946,7 +1971,7 @@ Error FontFile::load_bitmap_font(const String &p_path) { Error FontFile::load_dynamic_font(const String &p_path) { reset_state(); - Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> font_data = FileAccess::get_file_as_bytes(p_path); set_data(font_data); return OK; @@ -2000,6 +2025,16 @@ void FontFile::set_font_style(BitField<TextServer::FontStyle> p_style) { TS->font_set_style(cache[0], p_style); } +void FontFile::set_font_weight(int p_weight) { + _ensure_rid(0); + TS->font_set_weight(cache[0], p_weight); +} + +void FontFile::set_font_stretch(int p_stretch) { + _ensure_rid(0); + TS->font_set_stretch(cache[0], p_stretch); +} + void FontFile::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) { if (antialiasing != p_antialiasing) { antialiasing = p_antialiasing; @@ -2090,6 +2125,21 @@ int FontFile::get_fixed_size() const { return fixed_size; } +void FontFile::set_allow_system_fallback(bool p_allow_system_fallback) { + if (allow_system_fallback != p_allow_system_fallback) { + allow_system_fallback = p_allow_system_fallback; + for (int i = 0; i < cache.size(); i++) { + _ensure_rid(i); + TS->font_set_allow_system_fallback(cache[i], allow_system_fallback); + } + emit_changed(); + } +} + +bool FontFile::is_allow_system_fallback() const { + return allow_system_fallback; +} + void FontFile::set_force_autohinter(bool p_force_autohinter) { if (force_autohinter != p_force_autohinter) { force_autohinter = p_force_autohinter; @@ -2839,6 +2889,9 @@ void SystemFont::_bind_methods() { ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &SystemFont::set_generate_mipmaps); ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &SystemFont::get_generate_mipmaps); + ClassDB::bind_method(D_METHOD("set_allow_system_fallback", "allow_system_fallback"), &SystemFont::set_allow_system_fallback); + ClassDB::bind_method(D_METHOD("is_allow_system_fallback"), &SystemFont::is_allow_system_fallback); + ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &SystemFont::set_force_autohinter); ClassDB::bind_method(D_METHOD("is_force_autohinter"), &SystemFont::is_force_autohinter); @@ -2857,12 +2910,18 @@ void SystemFont::_bind_methods() { ClassDB::bind_method(D_METHOD("get_font_names"), &SystemFont::get_font_names); ClassDB::bind_method(D_METHOD("set_font_names", "names"), &SystemFont::set_font_names); - ClassDB::bind_method(D_METHOD("set_font_style", "style"), &SystemFont::set_font_style); + ClassDB::bind_method(D_METHOD("get_font_italic"), &SystemFont::get_font_italic); + ClassDB::bind_method(D_METHOD("set_font_italic", "italic"), &SystemFont::set_font_italic); + ClassDB::bind_method(D_METHOD("set_font_weight", "weight"), &SystemFont::set_font_weight); + ClassDB::bind_method(D_METHOD("set_font_stretch", "stretch"), &SystemFont::set_font_stretch); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "font_names"), "set_font_names", "get_font_names"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic"), "set_font_style", "get_font_style"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "font_italic"), "set_font_italic", "get_font_italic"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_weight", PROPERTY_HINT_RANGE, "100,999,25"), "set_font_weight", "get_font_weight"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "font_stretch", PROPERTY_HINT_RANGE, "50,200,25"), "set_font_stretch", "get_font_stretch"); 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, "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::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"); @@ -2899,13 +2958,14 @@ void SystemFont::_update_base_font() { face_indeces.clear(); ftr_weight = 0; + ftr_stretch = 0; ftr_italic = 0; for (const String &E : names) { if (E.is_empty()) { continue; } - String path = OS::get_singleton()->get_system_font_path(E, style & TextServer::FONT_BOLD, style & TextServer::FONT_ITALIC); + String path = OS::get_singleton()->get_system_font_path(E, weight, stretch, italic); if (path.is_empty()) { continue; } @@ -2917,9 +2977,22 @@ void SystemFont::_update_base_font() { } // If it's a font collection check all faces to match requested style. + int best_score = 0; for (int i = 0; i < file->get_face_count(); i++) { file->set_face_index(0, i); - if (((file->get_font_style() & TextServer::FONT_BOLD) == (style & TextServer::FONT_BOLD)) && ((file->get_font_style() & TextServer::FONT_ITALIC) == (style & TextServer::FONT_ITALIC))) { + BitField<TextServer::FontStyle> style = file->get_font_style(); + int font_weight = file->get_font_weight(); + int font_stretch = file->get_font_stretch(); + int score = (20 - Math::abs(font_weight - weight) / 50); + score += (20 - Math::abs(font_stretch - stretch) / 10); + if (bool(style & TextServer::FONT_ITALIC) == italic) { + score += 30; + } + if (score > best_score) { + face_indeces.clear(); + } + if (score >= best_score) { + best_score = score; face_indeces.push_back(i); } } @@ -2928,19 +3001,25 @@ void SystemFont::_update_base_font() { } file->set_face_index(0, face_indeces[0]); - // If it's a variable font, apply weight and italic coordinates to match requested style. - Dictionary ftr = file->get_supported_variation_list(); - if ((style & TextServer::FONT_BOLD) && ftr.has(TS->name_to_tag("weight"))) { - ftr_weight = 700; - } - if ((style & TextServer::FONT_ITALIC) && ftr.has(TS->name_to_tag("italic"))) { - ftr_italic = 1; + // If it's a variable font, apply weight, stretch and italic coordinates to match requested style. + if (best_score != 50) { + Dictionary ftr = file->get_supported_variation_list(); + if (ftr.has(TS->name_to_tag("width"))) { + ftr_stretch = stretch; + } + if (ftr.has(TS->name_to_tag("weight"))) { + ftr_weight = weight; + } + if (italic && ftr.has(TS->name_to_tag("italic"))) { + ftr_italic = 1; + } } // Apply font rendering settings. file->set_antialiasing(antialiasing); file->set_generate_mipmaps(mipmaps); file->set_force_autohinter(force_autohinter); + file->set_allow_system_fallback(allow_system_fallback); file->set_hinting(hinting); file->set_subpixel_positioning(subpixel_positioning); file->set_multichannel_signed_distance_field(msdf); @@ -2973,11 +3052,15 @@ void SystemFont::reset_state() { names.clear(); face_indeces.clear(); ftr_weight = 0; + ftr_stretch = 0; ftr_italic = 0; - style = 0; + italic = false; + weight = 400; + stretch = 100; antialiasing = TextServer::FONT_ANTIALIASING_GRAY; mipmaps = false; force_autohinter = false; + allow_system_fallback = true; hinting = TextServer::HINTING_LIGHT; subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED; oversampling = 0.f; @@ -3069,6 +3152,20 @@ bool SystemFont::get_generate_mipmaps() const { return mipmaps; } +void SystemFont::set_allow_system_fallback(bool p_allow_system_fallback) { + if (allow_system_fallback != p_allow_system_fallback) { + allow_system_fallback = p_allow_system_fallback; + if (base_font.is_valid()) { + base_font->set_allow_system_fallback(allow_system_fallback); + } + emit_changed(); + } +} + +bool SystemFont::is_allow_system_fallback() const { + return allow_system_fallback; +} + void SystemFont::set_force_autohinter(bool p_force_autohinter) { if (force_autohinter != p_force_autohinter) { force_autohinter = p_force_autohinter; @@ -3150,15 +3247,37 @@ PackedStringArray SystemFont::get_font_names() const { return names; } -void SystemFont::set_font_style(BitField<TextServer::FontStyle> p_style) { - if (style != p_style) { - style = p_style; +void SystemFont::set_font_italic(bool p_italic) { + if (italic != p_italic) { + italic = p_italic; _update_base_font(); } } -BitField<TextServer::FontStyle> SystemFont::get_font_style() const { - return style; +bool SystemFont::get_font_italic() const { + return italic; +} + +void SystemFont::set_font_weight(int p_weight) { + if (weight != p_weight) { + weight = CLAMP(p_weight, 100, 999); + _update_base_font(); + } +} + +int SystemFont::get_font_weight() const { + return weight; +} + +void SystemFont::set_font_stretch(int p_stretch) { + if (stretch != p_stretch) { + stretch = CLAMP(p_stretch, 50, 200); + _update_base_font(); + } +} + +int SystemFont::get_font_stretch() const { + return stretch; } int SystemFont::get_spacing(TextServer::SpacingType p_spacing) const { @@ -3176,6 +3295,9 @@ RID SystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_ if (ftr_weight > 0 && !var.has(TS->name_to_tag("weight"))) { var[TS->name_to_tag("weight")] = ftr_weight; } + if (ftr_stretch > 0 && !var.has(TS->name_to_tag("width"))) { + var[TS->name_to_tag("width")] = ftr_stretch; + } if (ftr_italic > 0 && !var.has(TS->name_to_tag("italic"))) { var[TS->name_to_tag("italic")] = ftr_italic; } @@ -3198,6 +3320,9 @@ RID SystemFont::_get_rid() const { if (ftr_weight > 0) { var[TS->name_to_tag("weight")] = ftr_weight; } + if (ftr_stretch > 0) { + var[TS->name_to_tag("width")] = ftr_stretch; + } if (ftr_italic > 0) { var[TS->name_to_tag("italic")] = ftr_italic; } diff --git a/scene/resources/font.h b/scene/resources/font.h index 5cf596b41d..e9f7507652 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -92,6 +92,8 @@ public: virtual String get_font_name() const; virtual String get_font_style_name() const; virtual BitField<TextServer::FontStyle> get_font_style() const; + virtual int get_font_weight() const; + virtual int get_font_stretch() const; virtual int get_spacing(TextServer::SpacingType p_spacing) const { return 0; }; virtual Dictionary get_opentype_features() const; @@ -148,6 +150,7 @@ class FontFile : public Font { int msdf_size = 48; int fixed_size = 0; bool force_autohinter = false; + bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; real_t oversampling = 0.f; @@ -191,6 +194,8 @@ public: virtual void set_font_name(const String &p_name); virtual void set_font_style_name(const String &p_name); virtual void set_font_style(BitField<TextServer::FontStyle> p_style); + virtual void set_font_weight(int p_weight); + virtual void set_font_stretch(int p_stretch); virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing); virtual TextServer::FontAntialiasing get_antialiasing() const; @@ -210,6 +215,9 @@ public: virtual void set_fixed_size(int p_fixed_size); virtual int get_fixed_size() 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; @@ -389,18 +397,22 @@ class SystemFont : public Font { GDCLASS(SystemFont, Font); PackedStringArray names; - BitField<TextServer::FontStyle> style = 0; + bool italic = false; + int weight = 400; + int stretch = 100; mutable Ref<Font> theme_font; Ref<FontFile> base_font; Vector<int> face_indeces; int ftr_weight = 0; + int ftr_stretch = 0; int ftr_italic = 0; TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY; bool mipmaps = false; bool force_autohinter = false; + bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; real_t oversampling = 0.f; @@ -423,6 +435,9 @@ public: 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; @@ -441,8 +456,14 @@ public: virtual void set_font_names(const PackedStringArray &p_names); virtual PackedStringArray get_font_names() const; - virtual void set_font_style(BitField<TextServer::FontStyle> p_style); - virtual BitField<TextServer::FontStyle> get_font_style() const override; + 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; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 354373ef3c..36e4a8ea37 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1356,7 +1356,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) { wf->seek_end(); - Vector<uint8_t> data = FileAccess::get_file_as_array(temp_file); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(temp_file); wf->store_buffer(data.ptr(), data.size()); { Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir()); diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 3a671edeea..48ec084b02 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -221,7 +221,7 @@ Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const Strin Ref<Shader> shader; shader.instantiate(); - Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> buffer = FileAccess::get_file_as_bytes(p_path); String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index fe628dd323..a680e66a50 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -81,7 +81,7 @@ Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, cons Ref<ShaderInclude> shader_inc; shader_inc.instantiate(); - Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> buffer = FileAccess::get_file_as_bytes(p_path); String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index dd4cb5accb..64e8b1b5f7 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -69,6 +69,12 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_style_name, "font_rid", "name_style"); GDVIRTUAL_BIND(_font_get_style_name, "font_rid"); + GDVIRTUAL_BIND(_font_set_weight, "font_rid", "weight"); + GDVIRTUAL_BIND(_font_get_weight, "font_rid"); + + GDVIRTUAL_BIND(_font_set_stretch, "font_rid", "stretch"); + GDVIRTUAL_BIND(_font_get_stretch, "font_rid"); + GDVIRTUAL_BIND(_font_set_antialiasing, "font_rid", "antialiasing"); GDVIRTUAL_BIND(_font_get_antialiasing, "font_rid"); @@ -87,6 +93,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_fixed_size, "font_rid", "fixed_size"); GDVIRTUAL_BIND(_font_get_fixed_size, "font_rid"); + GDVIRTUAL_BIND(_font_set_allow_system_fallback, "font_rid", "allow_system_fallback"); + GDVIRTUAL_BIND(_font_is_allow_system_fallback, "font_rid"); + GDVIRTUAL_BIND(_font_set_force_autohinter, "font_rid", "force_autohinter"); GDVIRTUAL_BIND(_font_is_force_autohinter, "font_rid"); @@ -308,6 +317,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_string_to_lower, "string", "language"); GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text"); + + GDVIRTUAL_BIND(_cleanup); } bool TextServerExtension::has_feature(Feature p_feature) const { @@ -434,6 +445,26 @@ String TextServerExtension::font_get_style_name(const RID &p_font_rid) const { return ret; } +void TextServerExtension::font_set_weight(const RID &p_font_rid, int64_t p_weight) { + GDVIRTUAL_CALL(_font_set_weight, p_font_rid, p_weight); +} + +int64_t TextServerExtension::font_get_weight(const RID &p_font_rid) const { + int64_t ret = 400; + GDVIRTUAL_CALL(_font_get_weight, p_font_rid, ret); + return ret; +} + +void TextServerExtension::font_set_stretch(const RID &p_font_rid, int64_t p_stretch) { + GDVIRTUAL_CALL(_font_set_stretch, p_font_rid, p_stretch); +} + +int64_t TextServerExtension::font_get_stretch(const RID &p_font_rid) const { + int64_t ret = 100; + GDVIRTUAL_CALL(_font_get_stretch, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_name(const RID &p_font_rid, const String &p_name) { GDVIRTUAL_CALL(_font_set_name, p_font_rid, p_name); } @@ -504,6 +535,16 @@ int64_t TextServerExtension::font_get_fixed_size(const RID &p_font_rid) const { return ret; } +void TextServerExtension::font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) { + GDVIRTUAL_CALL(_font_set_allow_system_fallback, p_font_rid, p_allow_system_fallback); +} + +bool TextServerExtension::font_is_allow_system_fallback(const RID &p_font_rid) const { + bool ret = false; + GDVIRTUAL_CALL(_font_is_allow_system_fallback, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { GDVIRTUAL_CALL(_font_set_force_autohinter, p_font_rid, p_force_autohinter); } @@ -1360,6 +1401,10 @@ bool TextServerExtension::spoof_check(const String &p_string) const { return TextServer::spoof_check(p_string); } +void TextServerExtension::cleanup() { + GDVIRTUAL_CALL(_cleanup); +} + TextServerExtension::TextServerExtension() { //NOP } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 992b708045..46ed43e9c8 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -109,6 +109,16 @@ public: GDVIRTUAL2(_font_set_style_name, RID, const String &); GDVIRTUAL1RC(String, _font_get_style_name, RID); + virtual void font_set_weight(const RID &p_font_rid, int64_t p_weight) override; + virtual int64_t font_get_weight(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_weight, RID, int); + GDVIRTUAL1RC(int64_t, _font_get_weight, RID); + + virtual void font_set_stretch(const RID &p_font_rid, int64_t p_stretch) override; + virtual int64_t font_get_stretch(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_stretch, RID, int); + GDVIRTUAL1RC(int64_t, _font_get_stretch, RID); + virtual void font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; virtual TextServer::FontAntialiasing font_get_antialiasing(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_antialiasing, RID, TextServer::FontAntialiasing); @@ -154,6 +164,11 @@ public: GDVIRTUAL2(_font_set_transform, RID, Transform2D); GDVIRTUAL1RC(Transform2D, _font_get_transform, RID); + virtual void font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) override; + virtual bool font_is_allow_system_fallback(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_allow_system_fallback, RID, bool); + GDVIRTUAL1RC(bool, _font_is_allow_system_fallback, RID); + virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_force_autohinter, RID, bool); @@ -514,6 +529,9 @@ public: GDVIRTUAL2RC(int64_t, _is_confusable, const String &, const PackedStringArray &); GDVIRTUAL1RC(bool, _spoof_check, const String &); + virtual void cleanup() override; + GDVIRTUAL0(_cleanup); + TextServerExtension(); ~TextServerExtension(); }; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index dfeb5cb70c..1b9cd28cfb 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -223,6 +223,12 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_style_name", "font_rid", "name"), &TextServer::font_set_style_name); ClassDB::bind_method(D_METHOD("font_get_style_name", "font_rid"), &TextServer::font_get_style_name); + ClassDB::bind_method(D_METHOD("font_set_weight", "font_rid", "weight"), &TextServer::font_set_weight); + ClassDB::bind_method(D_METHOD("font_get_weight", "font_rid"), &TextServer::font_get_weight); + + ClassDB::bind_method(D_METHOD("font_set_stretch", "font_rid", "weight"), &TextServer::font_set_stretch); + ClassDB::bind_method(D_METHOD("font_get_stretch", "font_rid"), &TextServer::font_get_stretch); + ClassDB::bind_method(D_METHOD("font_set_antialiasing", "font_rid", "antialiasing"), &TextServer::font_set_antialiasing); ClassDB::bind_method(D_METHOD("font_get_antialiasing", "font_rid"), &TextServer::font_get_antialiasing); @@ -241,6 +247,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_fixed_size", "font_rid", "fixed_size"), &TextServer::font_set_fixed_size); ClassDB::bind_method(D_METHOD("font_get_fixed_size", "font_rid"), &TextServer::font_get_fixed_size); + ClassDB::bind_method(D_METHOD("font_set_allow_system_fallback", "font_rid", "allow_system_fallback"), &TextServer::font_set_allow_system_fallback); + ClassDB::bind_method(D_METHOD("font_is_allow_system_fallback", "font_rid"), &TextServer::font_is_allow_system_fallback); + ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font_rid", "force_autohinter"), &TextServer::font_set_force_autohinter); ClassDB::bind_method(D_METHOD("font_is_force_autohinter", "font_rid"), &TextServer::font_is_force_autohinter); diff --git a/servers/text_server.h b/servers/text_server.h index a4e6080fd0..5da38a627a 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -250,6 +250,12 @@ public: virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) = 0; virtual String font_get_style_name(const RID &p_font_rid) const = 0; + virtual void font_set_weight(const RID &p_font_rid, int64_t p_weight) = 0; + virtual int64_t font_get_weight(const RID &p_font_rid) const = 0; + + virtual void font_set_stretch(const RID &p_font_rid, int64_t p_stretch) = 0; + virtual int64_t font_get_stretch(const RID &p_font_rid) const = 0; + virtual void font_set_antialiasing(const RID &p_font_rid, FontAntialiasing p_antialiasing) = 0; virtual FontAntialiasing font_get_antialiasing(const RID &p_font_rid) const = 0; @@ -268,6 +274,9 @@ public: virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) = 0; virtual int64_t font_get_fixed_size(const RID &p_font_rid) const = 0; + virtual void font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) = 0; + virtual bool font_is_allow_system_fallback(const RID &p_font_rid) const = 0; + virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) = 0; virtual bool font_is_force_autohinter(const RID &p_font_rid) const = 0; @@ -498,6 +507,8 @@ public: TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + virtual void cleanup() {} + TextServer(); ~TextServer(); }; diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h index 9ebd0f34b4..297f7d2068 100644 --- a/tests/servers/test_text_server.h +++ b/tests/servers/test_text_server.h @@ -68,8 +68,10 @@ TEST_SUITE("[TextServer]") { RID font1 = ts->create_font(); ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + ts->font_set_allow_system_fallback(font1, false); RID font2 = ts->create_font(); ts->font_set_data_ptr(font2, _font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); + ts->font_set_allow_system_fallback(font2, false); Array font; font.push_back(font1); |