From e81a2afbc49715eea0f82875721b1cc5f99414a9 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:14:11 +0200 Subject: [PATCH] [TextServer] Reset subpixel shift on blank glyphs and import option to enable/disable it. --- doc/classes/FontFile.xml | 3 ++ doc/classes/ResourceImporterDynamicFont.xml | 3 ++ doc/classes/SystemFont.xml | 3 ++ doc/classes/TextServer.xml | 15 +++++++ doc/classes/TextServerExtension.xml | 17 ++++++++ .../import/dynamic_font_import_settings.cpp | 5 +++ .../import/resource_importer_dynamic_font.cpp | 6 +++ editor/import/resource_importer_imagefont.cpp | 1 + modules/text_server_adv/text_server_adv.cpp | 28 ++++++++++++- modules/text_server_adv/text_server_adv.h | 10 ++++- modules/text_server_fb/text_server_fb.cpp | 17 ++++++++ modules/text_server_fb/text_server_fb.h | 10 ++++- scene/resources/font.cpp | 41 +++++++++++++++++++ scene/resources/font.h | 8 ++++ servers/text/text_server_extension.cpp | 13 ++++++ servers/text/text_server_extension.h | 5 +++ servers/text_server.cpp | 3 ++ servers/text_server.h | 3 ++ 18 files changed, 185 insertions(+), 6 deletions(-) diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index c230bf5ad2..e7a724cecd 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -631,6 +631,9 @@ Font hinting mode. Used by dynamic fonts only. + + If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct. diff --git a/doc/classes/ResourceImporterDynamicFont.xml b/doc/classes/ResourceImporterDynamicFont.xml index 3727bed8e5..ee7504aed8 100644 --- a/doc/classes/ResourceImporterDynamicFont.xml +++ b/doc/classes/ResourceImporterDynamicFont.xml @@ -44,6 +44,9 @@ [b]Light:[/b] Sharp result by snapping glyph edges to pixels on the Y axis only. [b]Full:[/b] Sharpest by snapping glyph edges to pixels on both X and Y axes. + + If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + Override the list of languages supported by this font. If left empty, this is supplied by the font metadata. There is usually no need to change this. See also [member script_support]. diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml index 38d6e27c85..b91ae74eae 100644 --- a/doc/classes/SystemFont.xml +++ b/doc/classes/SystemFont.xml @@ -43,6 +43,9 @@ Font hinting mode. + + If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index d76e65b618..309d9e6939 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -317,6 +317,13 @@ Returns the font hinting mode. Used by dynamic fonts only. + + + + + Returns glyph position rounding behavior. If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + + @@ -824,6 +831,14 @@ Sets font hinting mode. Used by dynamic fonts only. + + + + + + Sets glyph position rounding behavior. If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + + diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 3c27404f8e..fc0749c748 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -329,6 +329,14 @@ Returns the font hinting mode. Used by dynamic fonts only. + + + + + [b]Optional.[/b] + Returns glyph position rounding behavior. If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + + @@ -904,6 +912,15 @@ Sets font hinting mode. Used by dynamic fonts only. + + + + + + [b]Optional.[/b] + Sets glyph position rounding behavior. If set to [code]true[/code], when aligning glyphs to the pixel boundaries rounding remainders are accumulated to ensure more uniform glyph distribution. This setting has no effect if subpixel positioning is enabled. + + diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 8bbad91b68..19dafb7c42 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -494,6 +494,8 @@ void DynamicFontImportSettingsDialog::_main_prop_changed(const String &p_edited_ font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); } else if (p_edited_property == "subpixel_positioning") { font_preview->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); + } else if (p_edited_property == "keep_rounding_remainders") { + font_preview->set_keep_rounding_remainders(import_settings_data->get("keep_rounding_remainders")); } else if (p_edited_property == "oversampling") { font_preview->set_oversampling(import_settings_data->get("oversampling")); } @@ -960,6 +962,7 @@ void DynamicFontImportSettingsDialog::_re_import() { 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"); + main_settings["keep_rounding_remainders"] = import_settings_data->get("keep_rounding_remainders"); main_settings["oversampling"] = import_settings_data->get("oversampling"); main_settings["fallbacks"] = import_settings_data->get("fallbacks"); main_settings["compress"] = import_settings_data->get("compress"); @@ -1236,6 +1239,7 @@ void DynamicFontImportSettingsDialog::open_settings(const String &p_path) { 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()); + font_preview->set_keep_rounding_remainders(import_settings_data->get("keep_rounding_remainders")); font_preview->set_oversampling(import_settings_data->get("oversampling")); } font_preview_label->add_theme_font_override(SceneStringName(font), font_preview); @@ -1268,6 +1272,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { 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)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Metadata Overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index fa222b2790..21fe9b4faa 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -85,6 +85,9 @@ bool ResourceImporterDynamicFont::get_option_visibility(const String &p_path, co if (p_option == "subpixel_positioning" && bool(p_options["multichannel_signed_distance_field"])) { return false; } + if (p_option == "keep_rounding_remainders" && bool(p_options["multichannel_signed_distance_field"])) { + return false; + } return true; } @@ -119,6 +122,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< 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,Auto (Except Pixel Fonts)"), 4)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); @@ -156,6 +160,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str bool allow_system_fallback = p_options["allow_system_fallback"]; int hinting = p_options["hinting"]; int subpixel_positioning = p_options["subpixel_positioning"]; + bool keep_rounding_remainders = p_options["keep_rounding_remainders"]; real_t oversampling = p_options["oversampling"]; Array fallbacks = p_options["fallbacks"]; @@ -213,6 +218,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str } } font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning); + font->set_keep_rounding_remainders(keep_rounding_remainders); Dictionary langs = p_options["language_support"]; for (int i = 0; i < langs.size(); i++) { diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index f01381904d..01b3935fe4 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -112,6 +112,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin font->set_multichannel_signed_distance_field(false); font->set_fixed_size(chr_height); font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED); + font->set_keep_rounding_remainders(true); font->set_force_autohinter(false); font->set_allow_system_fallback(false); font->set_hinting(TextServer::HINTING_NONE); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 1c6e62650a..7c50dc6c6e 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2467,6 +2467,22 @@ TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioni return fd->subpixel_positioning; } +void TextServerAdvanced::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) { + FontAdvanced *fd = _get_font_data(p_font_rid); + ERR_FAIL_NULL(fd); + + MutexLock lock(fd->mutex); + fd->keep_rounding_remainders = p_keep_rounding_remainders; +} + +bool TextServerAdvanced::_font_get_keep_rounding_remainders(const RID &p_font_rid) const { + FontAdvanced *fd = _get_font_data(p_font_rid); + ERR_FAIL_NULL_V(fd, false); + + MutexLock lock(fd->mutex); + return fd->keep_rounding_remainders; +} + void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) { FontAdvanced *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -5195,6 +5211,7 @@ RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String _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_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders); _font_set_variation_coordinates(sysf.rid, var); _font_set_oversampling(sysf.rid, key.oversampling); _font_set_embolden(sysf.rid, key.embolden); @@ -6233,6 +6250,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star #endif gl.index = glyph_info[i].codepoint; + if ((p_sd->text[glyph_info[i].cluster] == 0x0009) || u_isblank(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster])) { + adv_rem = 0.0; // Reset on blank. + } if (gl.index != 0) { FontGlyph fgl; _ensure_glyph(fd, fss, gl.index | mod, fgl); @@ -6254,12 +6274,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star } else { double full_adv = adv_rem + ((double)glyph_pos[i].x_advance / (64.0 / scale) + ea); gl.advance = Math::round(full_adv); - adv_rem = full_adv - gl.advance; + if (fd->keep_rounding_remainders) { + adv_rem = full_adv - gl.advance; + } } } else { double full_adv = adv_rem + ((double)glyph_pos[i].y_advance / (64.0 / scale)); gl.advance = -Math::round(full_adv); - adv_rem = full_adv + gl.advance; + if (fd->keep_rounding_remainders) { + adv_rem = full_adv + gl.advance; + } } if (p_sd->orientation == ORIENTATION_HORIZONTAL) { gl.y_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size)); diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index def57b9372..4f08356ca7 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -328,6 +328,7 @@ class TextServerAdvanced : public TextServerExtension { bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; Dictionary variation_coordinates; double oversampling = 0.0; double embolden = 0.0; @@ -588,6 +589,7 @@ class TextServerAdvanced : public TextServerExtension { int fixed_size = 0; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; Dictionary variation_coordinates; double oversampling = 0.0; double embolden = 0.0; @@ -596,7 +598,7 @@ class TextServerAdvanced : public TextServerExtension { double baseline_offset = 0.0; bool operator==(const SystemFontKey &p_b) const { - return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (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) && (keep_rounding_remainders == p_b.keep_rounding_remainders) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); } SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerAdvanced *p_fb) { @@ -614,6 +616,7 @@ class TextServerAdvanced : public TextServerExtension { 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); + keep_rounding_remainders = p_fb->_font_get_keep_rounding_remainders(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); @@ -656,7 +659,7 @@ class TextServerAdvanced : public TextServerExtension { hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_SPACE], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_GLYPH], hash); hash = hash_murmur3_one_double(p_a.baseline_offset, hash); - return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12) | ((int)p_a.disable_embedded_bitmaps << 14), 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) | ((int)p_a.disable_embedded_bitmaps << 14) | ((int)p_a.keep_rounding_remainders << 15), hash)); } }; mutable HashMap system_fonts; @@ -800,6 +803,9 @@ public: MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning); MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &); + MODBIND2(font_set_keep_rounding_remainders, const RID &, bool); + MODBIND1RC(bool, font_get_keep_rounding_remainders, const RID &); + MODBIND2(font_set_embolden, const RID &, double); MODBIND1RC(double, font_get_embolden, const RID &); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index d30b2aae19..e2d89ba3df 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -1468,6 +1468,22 @@ TextServer::SubpixelPositioning TextServerFallback::_font_get_subpixel_positioni return fd->subpixel_positioning; } +void TextServerFallback::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) { + FontFallback *fd = _get_font_data(p_font_rid); + ERR_FAIL_NULL(fd); + + MutexLock lock(fd->mutex); + fd->keep_rounding_remainders = p_keep_rounding_remainders; +} + +bool TextServerFallback::_font_get_keep_rounding_remainders(const RID &p_font_rid) const { + FontFallback *fd = _get_font_data(p_font_rid); + ERR_FAIL_NULL_V(fd, false); + + MutexLock lock(fd->mutex); + return fd->keep_rounding_remainders; +} + void TextServerFallback::_font_set_embolden(const RID &p_font_rid, double p_strength) { FontFallback *fd = _get_font_data(p_font_rid); ERR_FAIL_NULL(fd); @@ -4007,6 +4023,7 @@ RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String _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_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders); _font_set_variation_coordinates(sysf.rid, var); _font_set_oversampling(sysf.rid, key.oversampling); _font_set_embolden(sysf.rid, key.embolden); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 56626c1f6c..62b003a1ec 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -270,6 +270,7 @@ class TextServerFallback : public TextServerExtension { bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; Dictionary variation_coordinates; double oversampling = 0.0; double embolden = 0.0; @@ -495,6 +496,7 @@ class TextServerFallback : public TextServerExtension { int fixed_size = 0; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; Dictionary variation_coordinates; double oversampling = 0.0; double embolden = 0.0; @@ -503,7 +505,7 @@ class TextServerFallback : public TextServerExtension { double baseline_offset = 0.0; bool operator==(const SystemFontKey &p_b) const { - return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); + return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (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) && (keep_rounding_remainders == p_b.keep_rounding_remainders) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset); } SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerFallback *p_fb) { @@ -521,6 +523,7 @@ class TextServerFallback : public TextServerExtension { 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); + keep_rounding_remainders = p_fb->_font_get_keep_rounding_remainders(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); @@ -563,7 +566,7 @@ class TextServerFallback : public TextServerExtension { hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_SPACE], hash); hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_GLYPH], hash); hash = hash_murmur3_one_double(p_a.baseline_offset, hash); - return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12) | ((int)p_a.disable_embedded_bitmaps << 14), 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) | ((int)p_a.disable_embedded_bitmaps << 14) | ((int)p_a.keep_rounding_remainders << 15), hash)); } }; mutable HashMap system_fonts; @@ -659,6 +662,9 @@ public: MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning); MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &); + MODBIND2(font_set_keep_rounding_remainders, const RID &, bool); + MODBIND1RC(bool, font_get_keep_rounding_remainders, const RID &); + MODBIND2(font_set_embolden, const RID &, double); MODBIND1RC(double, font_get_embolden, const RID &); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 5e4136f449..ce429ae8d4 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -605,6 +605,7 @@ _FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index, int p_make_linked_f 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_keep_rounding_remainders(cache[p_cache_index], keep_rounding_remainders); TS->font_set_oversampling(cache[p_cache_index], oversampling); } } @@ -934,6 +935,9 @@ void FontFile::_bind_methods() { ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontFile::set_subpixel_positioning); ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontFile::get_subpixel_positioning); + ClassDB::bind_method(D_METHOD("set_keep_rounding_remainders", "keep_rounding_remainders"), &FontFile::set_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("get_keep_rounding_remainders"), &FontFile::get_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontFile::set_oversampling); ClassDB::bind_method(D_METHOD("get_oversampling"), &FontFile::get_oversampling); @@ -1044,6 +1048,7 @@ void FontFile::_bind_methods() { 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, "keep_rounding_remainders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_keep_rounding_remainders", "get_keep_rounding_remainders"); 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"); @@ -1411,6 +1416,7 @@ void FontFile::reset_state() { allow_system_fallback = true; hinting = TextServer::HINTING_LIGHT; subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED; + keep_rounding_remainders = true; msdf_pixel_range = 14; msdf_size = 128; fixed_size = 0; @@ -2296,6 +2302,21 @@ TextServer::SubpixelPositioning FontFile::get_subpixel_positioning() const { return subpixel_positioning; } +void FontFile::set_keep_rounding_remainders(bool p_keep_rounding_remainders) { + if (keep_rounding_remainders != p_keep_rounding_remainders) { + keep_rounding_remainders = p_keep_rounding_remainders; + for (int i = 0; i < cache.size(); i++) { + _ensure_rid(i); + TS->font_set_keep_rounding_remainders(cache[i], keep_rounding_remainders); + } + emit_changed(); + } +} + +bool FontFile::get_keep_rounding_remainders() const { + return keep_rounding_remainders; +} + void FontFile::set_oversampling(real_t p_oversampling) { if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -3085,6 +3106,9 @@ void SystemFont::_bind_methods() { ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &SystemFont::set_subpixel_positioning); ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &SystemFont::get_subpixel_positioning); + ClassDB::bind_method(D_METHOD("set_keep_rounding_remainders", "keep_rounding_remainders"), &SystemFont::set_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("get_keep_rounding_remainders"), &SystemFont::get_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field); ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field); @@ -3116,6 +3140,7 @@ void SystemFont::_bind_methods() { 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"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), "set_keep_rounding_remainders", "get_keep_rounding_remainders"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range"), "set_msdf_pixel_range", "get_msdf_pixel_range"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size"), "set_msdf_size", "get_msdf_size"); @@ -3220,6 +3245,7 @@ void SystemFont::_update_base_font() { file->set_allow_system_fallback(allow_system_fallback); file->set_hinting(hinting); file->set_subpixel_positioning(subpixel_positioning); + file->set_keep_rounding_remainders(keep_rounding_remainders); file->set_multichannel_signed_distance_field(msdf); file->set_msdf_pixel_range(msdf_pixel_range); file->set_msdf_size(msdf_size); @@ -3263,6 +3289,7 @@ void SystemFont::reset_state() { allow_system_fallback = true; hinting = TextServer::HINTING_LIGHT; subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED; + keep_rounding_remainders = true; oversampling = 0.f; msdf = false; @@ -3416,6 +3443,20 @@ TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const { return subpixel_positioning; } +void SystemFont::set_keep_rounding_remainders(bool p_keep_rounding_remainders) { + if (keep_rounding_remainders != p_keep_rounding_remainders) { + keep_rounding_remainders = p_keep_rounding_remainders; + if (base_font.is_valid()) { + base_font->set_keep_rounding_remainders(keep_rounding_remainders); + } + emit_changed(); + } +} + +bool SystemFont::get_keep_rounding_remainders() const { + return keep_rounding_remainders; +} + void SystemFont::set_multichannel_signed_distance_field(bool p_msdf) { if (msdf != p_msdf) { msdf = p_msdf; diff --git a/scene/resources/font.h b/scene/resources/font.h index 68c391c35e..9e31b8fd8e 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -197,6 +197,7 @@ class FontFile : public Font { bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; real_t oversampling = 0.f; #ifndef DISABLE_DEPRECATED @@ -280,6 +281,9 @@ public: virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel); virtual TextServer::SubpixelPositioning get_subpixel_positioning() const; + virtual void set_keep_rounding_remainders(bool p_keep_rounding_remainders); + virtual bool get_keep_rounding_remainders() const; + virtual void set_oversampling(real_t p_oversampling); virtual real_t get_oversampling() const; @@ -480,6 +484,7 @@ class SystemFont : public Font { bool allow_system_fallback = true; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; + bool keep_rounding_remainders = true; real_t oversampling = 0.f; bool msdf = false; int msdf_pixel_range = 16; @@ -518,6 +523,9 @@ public: virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel); virtual TextServer::SubpixelPositioning get_subpixel_positioning() const; + virtual void set_keep_rounding_remainders(bool p_keep_rounding_remainders); + virtual bool get_keep_rounding_remainders() const; + virtual void set_oversampling(real_t p_oversampling); virtual real_t get_oversampling() const; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 1c0d518e75..17e92b8c8a 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -113,6 +113,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_subpixel_positioning, "font_rid", "subpixel_positioning"); GDVIRTUAL_BIND(_font_get_subpixel_positioning, "font_rid"); + GDVIRTUAL_BIND(_font_set_keep_rounding_remainders, "font_rid", "keep_rounding_remainders"); + GDVIRTUAL_BIND(_font_get_keep_rounding_remainders, "font_rid"); + GDVIRTUAL_BIND(_font_set_embolden, "font_rid", "strength"); GDVIRTUAL_BIND(_font_get_embolden, "font_rid"); @@ -640,6 +643,16 @@ TextServer::SubpixelPositioning TextServerExtension::font_get_subpixel_positioni return ret; } +void TextServerExtension::font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) { + GDVIRTUAL_CALL(_font_set_keep_rounding_remainders, p_font_rid, p_keep_rounding_remainders); +} + +bool TextServerExtension::font_get_keep_rounding_remainders(const RID &p_font_rid) const { + bool ret = true; + GDVIRTUAL_CALL(_font_get_keep_rounding_remainders, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_embolden(const RID &p_font_rid, double p_strength) { GDVIRTUAL_CALL(_font_set_embolden, p_font_rid, p_strength); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index bd803be8aa..fd668ab4e5 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -168,6 +168,11 @@ public: GDVIRTUAL2(_font_set_subpixel_positioning, RID, SubpixelPositioning); GDVIRTUAL1RC(SubpixelPositioning, _font_get_subpixel_positioning, RID); + virtual void font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) override; + virtual bool font_get_keep_rounding_remainders(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_keep_rounding_remainders, RID, bool); + GDVIRTUAL1RC(bool, _font_get_keep_rounding_remainders, RID); + virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; virtual double font_get_embolden(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_embolden, RID, double); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index d2cf4674ae..8e4f3fd21f 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -269,6 +269,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_subpixel_positioning", "font_rid", "subpixel_positioning"), &TextServer::font_set_subpixel_positioning); ClassDB::bind_method(D_METHOD("font_get_subpixel_positioning", "font_rid"), &TextServer::font_get_subpixel_positioning); + ClassDB::bind_method(D_METHOD("font_set_keep_rounding_remainders", "font_rid", "keep_rounding_remainders"), &TextServer::font_set_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("font_get_keep_rounding_remainders", "font_rid"), &TextServer::font_get_keep_rounding_remainders); + ClassDB::bind_method(D_METHOD("font_set_embolden", "font_rid", "strength"), &TextServer::font_set_embolden); ClassDB::bind_method(D_METHOD("font_get_embolden", "font_rid"), &TextServer::font_get_embolden); diff --git a/servers/text_server.h b/servers/text_server.h index f448d62cb2..46b263c54e 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -315,6 +315,9 @@ public: virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) = 0; virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const = 0; + virtual void font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) = 0; + virtual bool font_get_keep_rounding_remainders(const RID &p_font_rid) const = 0; + virtual void font_set_embolden(const RID &p_font_rid, double p_strength) = 0; virtual double font_get_embolden(const RID &p_font_rid) const = 0;