Skip to content

Commit

Permalink
[TextServer] Reset subpixel shift on blank glyphs and import option t…
Browse files Browse the repository at this point in the history
…o enable/disable it.
  • Loading branch information
bruvzg committed Nov 1, 2024
1 parent c6c464c commit e81a2af
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 6 deletions.
3 changes: 3 additions & 0 deletions doc/classes/FontFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,9 @@
<member name="hinting" type="int" setter="set_hinting" getter="get_hinting" enum="TextServer.Hinting" default="1">
Font hinting mode. Used by dynamic fonts only.
</member>
<member name="keep_rounding_remainders" type="bool" setter="set_keep_rounding_remainders" getter="get_keep_rounding_remainders" default="true">
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.
</member>
<member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16">
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.
</member>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/ResourceImporterDynamicFont.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</member>
<member name="keep_rounding_remainders" type="bool" setter="" getter="" default="true">
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.
</member>
<member name="language_support" type="Dictionary" setter="" getter="" default="{}">
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].
</member>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/SystemFont.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
<member name="hinting" type="int" setter="set_hinting" getter="get_hinting" enum="TextServer.Hinting" default="1">
Font hinting mode.
</member>
<member name="keep_rounding_remainders" type="bool" setter="set_keep_rounding_remainders" getter="get_keep_rounding_remainders" default="true">
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.
</member>
<member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16">
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.
</member>
Expand Down
15 changes: 15 additions & 0 deletions doc/classes/TextServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@
Returns the font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_get_keep_rounding_remainders" qualifiers="const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
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.
</description>
</method>
<method name="font_get_kerning" qualifiers="const">
<return type="Vector2" />
<param index="0" name="font_rid" type="RID" />
Expand Down Expand Up @@ -824,6 +831,14 @@
Sets font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_set_keep_rounding_remainders">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="keep_rounding_remainders" type="bool" />
<description>
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.
</description>
</method>
<method name="font_set_kerning">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
Expand Down
17 changes: 17 additions & 0 deletions doc/classes/TextServerExtension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@
Returns the font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="_font_get_keep_rounding_remainders" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
[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.
</description>
</method>
<method name="_font_get_kerning" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="font_rid" type="RID" />
Expand Down Expand Up @@ -904,6 +912,15 @@
Sets font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="_font_set_keep_rounding_remainders" qualifiers="virtual">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="keep_rounding_remainders" type="bool" />
<description>
[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.
</description>
</method>
<method name="_font_set_kerning" qualifiers="virtual">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
Expand Down
5 changes: 5 additions & 0 deletions editor/import/dynamic_font_import_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()));
Expand Down
6 changes: 6 additions & 0 deletions editor/import/resource_importer_dynamic_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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"];

Expand Down Expand Up @@ -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++) {
Expand Down
1 change: 1 addition & 0 deletions editor/import/resource_importer_imagefont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
28 changes: 26 additions & 2 deletions modules/text_server_adv/text_server_adv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand Down
10 changes: 8 additions & 2 deletions modules/text_server_adv/text_server_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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<SystemFontKey, SystemFontCache, SystemFontKeyHasher> system_fonts;
Expand Down Expand Up @@ -800,6 +803,9 @@ class TextServerAdvanced : public TextServerExtension {
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 &);

Expand Down
Loading

0 comments on commit e81a2af

Please sign in to comment.