Skip to content

Commit 06314c1

Browse files
authored
Merge pull request godotengine#43030 from bruvzg/ctl_var_font
[Complex Text Layouts] Add variable fonts support.
2 parents bbf7bb3 + c1d261f commit 06314c1

16 files changed

+279
-4
lines changed

doc/classes/FontData.xml

+28
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,23 @@
179179
Returns underline thickness in pixels.
180180
</description>
181181
</method>
182+
<method name="get_variation" qualifiers="const">
183+
<return type="float">
184+
</return>
185+
<argument index="0" name="tag" type="String">
186+
</argument>
187+
<description>
188+
Returns variation coordinate [code]tag[/code].
189+
</description>
190+
</method>
191+
<method name="get_variation_list" qualifiers="const">
192+
<return type="Dictionary">
193+
</return>
194+
<description>
195+
Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code].
196+
Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
197+
</description>
198+
</method>
182199
<method name="has_char" qualifiers="const">
183200
<return type="bool">
184201
</return>
@@ -279,6 +296,17 @@
279296
Adds override for [method is_script_supported].
280297
</description>
281298
</method>
299+
<method name="set_variation">
300+
<return type="void">
301+
</return>
302+
<argument index="0" name="tag" type="String">
303+
</argument>
304+
<argument index="1" name="value" type="float">
305+
</argument>
306+
<description>
307+
Sets variation coordinate [code]tag[/code].
308+
</description>
309+
</method>
282310
</methods>
283311
<members>
284312
<member name="antialiased" type="bool" setter="set_antialiased" getter="get_antialiased" default="false">

doc/classes/TextServer.xml

+38-1
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,27 @@
326326
Returns underline thickness in pixels.
327327
</description>
328328
</method>
329+
<method name="font_get_variation" qualifiers="const">
330+
<return type="float">
331+
</return>
332+
<argument index="0" name="font" type="RID">
333+
</argument>
334+
<argument index="1" name="tag" type="String">
335+
</argument>
336+
<description>
337+
Returns variation coordinate [code]tag[/code].
338+
</description>
339+
</method>
340+
<method name="font_get_variation_list" qualifiers="const">
341+
<return type="Dictionary">
342+
</return>
343+
<argument index="0" name="font" type="RID">
344+
</argument>
345+
<description>
346+
Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code].
347+
Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
348+
</description>
349+
</method>
329350
<method name="font_has_char" qualifiers="const">
330351
<return type="bool">
331352
</return>
@@ -469,6 +490,19 @@
469490
Adds override for [method font_is_script_supported].
470491
</description>
471492
</method>
493+
<method name="font_set_variation">
494+
<return type="void">
495+
</return>
496+
<argument index="0" name="font" type="RID">
497+
</argument>
498+
<argument index="1" name="tag" type="String">
499+
</argument>
500+
<argument index="2" name="value" type="float">
501+
</argument>
502+
<description>
503+
Sets variation coordinate [code]name[/code]. Unsupported coordinates will be silently ignored.
504+
</description>
505+
</method>
472506
<method name="format_number" qualifiers="const">
473507
<return type="String">
474508
</return>
@@ -1160,7 +1194,10 @@
11601194
<constant name="FEATURE_FONT_SYSTEM" value="32" enum="Feature">
11611195
TextServer supports loading system fonts.
11621196
</constant>
1163-
<constant name="FEATURE_USE_SUPPORT_DATA" value="64" enum="Feature">
1197+
<constant name="FEATURE_FONT_VARIABLE" value="64" enum="Feature">
1198+
TextServer supports variable fonts.
1199+
</constant>
1200+
<constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
11641201
TextServer require external data file for some features.
11651202
</constant>
11661203
</constants>

editor/editor_fonts.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,14 @@ void editor_register_fonts(Ref<Theme> p_theme) {
161161
CustomFontSource->load_resource(custom_font_path_source, default_font_size);
162162
CustomFontSource->set_antialiased(font_antialiased);
163163
CustomFontSource->set_hinting(font_hinting);
164+
165+
Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
166+
for (int i = 0; i < subtag.size(); i++) {
167+
Vector<String> subtag_a = subtag[i].split("=");
168+
if (subtag_a.size() == 2) {
169+
CustomFontSource->set_variation(subtag_a[0], subtag_a[1].to_float());
170+
}
171+
}
164172
} else {
165173
EditorSettings::get_singleton()->set_manually("interface/editor/code_font", "");
166174
}
@@ -282,6 +290,15 @@ void editor_register_fonts(Ref<Theme> p_theme) {
282290
dfmono->set_antialiased(font_antialiased);
283291
dfmono->set_hinting(font_hinting);
284292

293+
Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
294+
Dictionary ftrs;
295+
for (int i = 0; i < subtag.size(); i++) {
296+
Vector<String> subtag_a = subtag[i].split("=");
297+
if (subtag_a.size() == 2) {
298+
dfmono->set_variation(subtag_a[0], subtag_a[1].to_float());
299+
}
300+
}
301+
285302
// Default font
286303
MAKE_DEFAULT_FONT(df);
287304
p_theme->set_default_theme_font(df); // Default theme font

editor/editor_settings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
336336
_initial_set("interface/editor/code_font_contextual_ligatures", 0);
337337
hints["interface/editor/code_font_contextual_ligatures"] = PropertyInfo(Variant::INT, "interface/editor/code_font_contextual_ligatures", PROPERTY_HINT_ENUM, "Default,Disable contextual alternates (coding ligatures),Use custom OpenType feature set", PROPERTY_USAGE_DEFAULT);
338338
_initial_set("interface/editor/code_font_custom_opentype_features", "");
339+
_initial_set("interface/editor/code_font_custom_variations", "");
339340
_initial_set("interface/editor/font_antialiased", true);
340341
_initial_set("interface/editor/font_hinting", 0);
341342
hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto,None,Light,Normal", PROPERTY_USAGE_DEFAULT);

modules/gdnative/include/text/godot_text.h

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ typedef struct {
8282
void (*font_set_antialiased)(void *, godot_rid *, bool);
8383
bool (*font_get_antialiased)(void *, godot_rid *);
8484
godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
85+
godot_dictionary (*font_get_variation_list)(void *, godot_rid *);
86+
void (*font_set_variation)(void *, godot_rid *, const godot_string *, double);
87+
double (*font_get_variation)(void *, godot_rid *, const godot_string *);
8588
void (*font_set_distance_field_hint)(void *, godot_rid *, bool);
8689
bool (*font_get_distance_field_hint)(void *, godot_rid *);
8790
void (*font_set_hinting)(void *, godot_rid *, godot_int);

modules/gdnative/text/text_server_gdnative.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const {
148148
return interface->font_get_antialiased(data, (godot_rid *)&p_font);
149149
}
150150

151+
Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const {
152+
ERR_FAIL_COND_V(interface == nullptr, Dictionary());
153+
godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font);
154+
Dictionary info = *(Dictionary *)&result;
155+
godot_dictionary_destroy(&result);
156+
157+
return info;
158+
}
159+
160+
void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) {
161+
ERR_FAIL_COND(interface == nullptr);
162+
interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value);
163+
}
164+
165+
double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const {
166+
return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name);
167+
}
168+
151169
void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
152170
ERR_FAIL_COND(interface == nullptr);
153171
interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting);

modules/gdnative/text/text_server_gdnative.h

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class TextServerGDNative : public TextServer {
7676
virtual bool font_get_antialiased(RID p_font) const override;
7777

7878
virtual Dictionary font_get_feature_list(RID p_font) const override;
79+
virtual Dictionary font_get_variation_list(RID p_font) const override;
80+
81+
virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
82+
virtual double font_get_variation(RID p_font, const String &p_name) const override;
7983

8084
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
8185
virtual Hinting font_get_hinting(RID p_font) const override;

modules/text_server_adv/dynamic_font_adv.cpp

+77-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include FT_STROKER_H
3434
#include FT_ADVANCES_H
35+
#include FT_MULTIPLE_MASTERS_H
3536

3637
DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
3738
ERR_FAIL_COND_V(!valid, nullptr);
@@ -134,16 +135,91 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
134135
memdelete(fds);
135136
ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
136137
}
138+
137139
if (p_outline_size != 0) {
138140
size_cache_outline[id] = fds;
139141
} else {
140142
size_cache[id] = fds;
141143
}
142-
}
143144

145+
// Write variations.
146+
if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
147+
FT_MM_Var *amaster;
148+
149+
FT_Get_MM_Var(fds->face, &amaster);
150+
151+
Vector<hb_variation_t> hb_vars;
152+
Vector<FT_Fixed> coords;
153+
coords.resize(amaster->num_axis);
154+
155+
FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
156+
157+
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
158+
hb_variation_t var;
159+
160+
// Reset to default.
161+
var.tag = amaster->axis[i].tag;
162+
var.value = (double)amaster->axis[i].def / 65536.f;
163+
coords.write[i] = amaster->axis[i].def;
164+
165+
if (variations.has(var.tag)) {
166+
var.value = variations[var.tag];
167+
coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
168+
}
169+
170+
hb_vars.push_back(var);
171+
}
172+
173+
FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
174+
hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size());
175+
176+
FT_Done_MM_Var(library, amaster);
177+
}
178+
}
144179
return fds;
145180
}
146181

182+
Dictionary DynamicFontDataAdvanced::get_variation_list() const {
183+
_THREAD_SAFE_METHOD_
184+
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
185+
if (fds == nullptr) {
186+
return Dictionary();
187+
}
188+
189+
Dictionary ret;
190+
// Read variations.
191+
if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
192+
FT_MM_Var *amaster;
193+
194+
FT_Get_MM_Var(fds->face, &amaster);
195+
196+
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
197+
ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
198+
}
199+
200+
FT_Done_MM_Var(library, amaster);
201+
}
202+
return ret;
203+
}
204+
205+
void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
206+
_THREAD_SAFE_METHOD_
207+
int32_t tag = TS->name_to_tag(p_name);
208+
if (!variations.has(tag) || (variations[tag] != p_value)) {
209+
variations[tag] = p_value;
210+
clear_cache();
211+
}
212+
}
213+
214+
double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
215+
_THREAD_SAFE_METHOD_
216+
int32_t tag = TS->name_to_tag(p_name);
217+
if (!variations.has(tag)) {
218+
return 0.f;
219+
}
220+
return variations[tag];
221+
}
222+
147223
Dictionary DynamicFontDataAdvanced::get_feature_list() const {
148224
_THREAD_SAFE_METHOD_
149225
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);

modules/text_server_adv/dynamic_font_adv.h

+6
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ struct DynamicFontDataAdvanced : public FontDataAdvanced {
118118
String font_path;
119119
Vector<uint8_t> font_mem_cache;
120120

121+
Map<int32_t, double> variations;
122+
121123
float rect_margin = 1.f;
122124
int base_size = 16;
123125
float oversampling = 1.f;
@@ -146,6 +148,10 @@ struct DynamicFontDataAdvanced : public FontDataAdvanced {
146148
virtual float get_descent(int p_size) const override;
147149

148150
virtual Dictionary get_feature_list() const override;
151+
virtual Dictionary get_variation_list() const override;
152+
153+
virtual void set_variation(const String &p_name, double p_value) override;
154+
virtual double get_variation(const String &p_name) const override;
149155

150156
virtual float get_underline_position(int p_size) const override;
151157
virtual float get_underline_thickness(int p_size) const override;

modules/text_server_adv/font_adv.h

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ struct FontDataAdvanced {
5050
virtual float get_descent(int p_size) const = 0;
5151

5252
virtual Dictionary get_feature_list() const { return Dictionary(); };
53+
virtual Dictionary get_variation_list() const { return Dictionary(); };
54+
55+
virtual void set_variation(const String &p_name, double p_value){};
56+
virtual double get_variation(const String &p_name) const { return 0; };
5357

5458
virtual float get_underline_position(int p_size) const = 0;
5559
virtual float get_underline_thickness(int p_size) const = 0;

modules/text_server_adv/text_server_adv.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
132132
/*************************************************************************/
133133

134134
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
135-
uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA;
135+
uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
136136

137137
bool TextServerAdvanced::has_feature(Feature p_feature) {
138138
return (interface_features & p_feature) == p_feature;
@@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
622622
return fd->get_antialiased();
623623
}
624624

625+
Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
626+
_THREAD_SAFE_METHOD_
627+
const FontDataAdvanced *fd = font_owner.getornull(p_font);
628+
ERR_FAIL_COND_V(!fd, Dictionary());
629+
return fd->get_variation_list();
630+
}
631+
632+
void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
633+
_THREAD_SAFE_METHOD_
634+
FontDataAdvanced *fd = font_owner.getornull(p_font);
635+
ERR_FAIL_COND(!fd);
636+
fd->set_variation(p_name, p_value);
637+
}
638+
639+
double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
640+
_THREAD_SAFE_METHOD_
641+
const FontDataAdvanced *fd = font_owner.getornull(p_font);
642+
ERR_FAIL_COND_V(!fd, 0);
643+
return fd->get_variation(p_name);
644+
}
645+
625646
void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
626647
_THREAD_SAFE_METHOD_
627648
FontDataAdvanced *fd = font_owner.getornull(p_font);

modules/text_server_adv/text_server_adv.h

+4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class TextServerAdvanced : public TextServer {
138138
virtual bool font_get_antialiased(RID p_font) const override;
139139

140140
virtual Dictionary font_get_feature_list(RID p_font) const override;
141+
virtual Dictionary font_get_variation_list(RID p_font) const override;
142+
143+
virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
144+
virtual double font_get_variation(RID p_font, const String &p_name) const override;
141145

142146
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
143147
virtual Hinting font_get_hinting(RID p_font) const override;

0 commit comments

Comments
 (0)