Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Complex Text Layouts] Add variable fonts support. #43030

Merged
merged 1 commit into from
Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions doc/classes/FontData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,23 @@
Returns underline thickness in pixels.
</description>
</method>
<method name="get_variation" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="tag" type="String">
</argument>
<description>
Returns variation coordinate [code]tag[/code].
</description>
</method>
<method name="get_variation_list" qualifiers="const">
<return type="Dictionary">
</return>
<description>
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].
Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
</description>
</method>
<method name="has_char" qualifiers="const">
<return type="bool">
</return>
Expand Down Expand Up @@ -279,6 +296,17 @@
Adds override for [method is_script_supported].
</description>
</method>
<method name="set_variation">
<return type="void">
</return>
<argument index="0" name="tag" type="String">
</argument>
<argument index="1" name="value" type="float">
</argument>
<description>
Sets variation coordinate [code]tag[/code].
</description>
</method>
</methods>
<members>
<member name="antialiased" type="bool" setter="set_antialiased" getter="get_antialiased" default="false">
Expand Down
39 changes: 38 additions & 1 deletion doc/classes/TextServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,27 @@
Returns underline thickness in pixels.
</description>
</method>
<method name="font_get_variation" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="font" type="RID">
</argument>
<argument index="1" name="tag" type="String">
</argument>
<description>
Returns variation coordinate [code]tag[/code].
</description>
</method>
<method name="font_get_variation_list" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="font" type="RID">
</argument>
<description>
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].
Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
</description>
</method>
<method name="font_has_char" qualifiers="const">
<return type="bool">
</return>
Expand Down Expand Up @@ -469,6 +490,19 @@
Adds override for [method font_is_script_supported].
</description>
</method>
<method name="font_set_variation">
<return type="void">
</return>
<argument index="0" name="font" type="RID">
</argument>
<argument index="1" name="tag" type="String">
</argument>
<argument index="2" name="value" type="float">
</argument>
<description>
Sets variation coordinate [code]name[/code]. Unsupported coordinates will be silently ignored.
</description>
</method>
<method name="format_number" qualifiers="const">
<return type="String">
</return>
Expand Down Expand Up @@ -1160,7 +1194,10 @@
<constant name="FEATURE_FONT_SYSTEM" value="32" enum="Feature">
TextServer supports loading system fonts.
</constant>
<constant name="FEATURE_USE_SUPPORT_DATA" value="64" enum="Feature">
<constant name="FEATURE_FONT_VARIABLE" value="64" enum="Feature">
TextServer supports variable fonts.
</constant>
<constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
TextServer require external data file for some features.
</constant>
</constants>
Expand Down
17 changes: 17 additions & 0 deletions editor/editor_fonts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ void editor_register_fonts(Ref<Theme> p_theme) {
CustomFontSource->load_resource(custom_font_path_source, default_font_size);
CustomFontSource->set_antialiased(font_antialiased);
CustomFontSource->set_hinting(font_hinting);

Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
if (subtag_a.size() == 2) {
CustomFontSource->set_variation(subtag_a[0], subtag_a[1].to_float());
}
}
} else {
EditorSettings::get_singleton()->set_manually("interface/editor/code_font", "");
}
Expand Down Expand Up @@ -282,6 +290,15 @@ void editor_register_fonts(Ref<Theme> p_theme) {
dfmono->set_antialiased(font_antialiased);
dfmono->set_hinting(font_hinting);

Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(",");
Dictionary ftrs;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
if (subtag_a.size() == 2) {
dfmono->set_variation(subtag_a[0], subtag_a[1].to_float());
}
}

// Default font
MAKE_DEFAULT_FONT(df);
p_theme->set_default_theme_font(df); // Default theme font
Expand Down
1 change: 1 addition & 0 deletions editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/code_font_contextual_ligatures", 0);
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);
_initial_set("interface/editor/code_font_custom_opentype_features", "");
_initial_set("interface/editor/code_font_custom_variations", "");
_initial_set("interface/editor/font_antialiased", true);
_initial_set("interface/editor/font_hinting", 0);
hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto,None,Light,Normal", PROPERTY_USAGE_DEFAULT);
Expand Down
3 changes: 3 additions & 0 deletions modules/gdnative/include/text/godot_text.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ typedef struct {
void (*font_set_antialiased)(void *, godot_rid *, bool);
bool (*font_get_antialiased)(void *, godot_rid *);
godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
godot_dictionary (*font_get_variation_list)(void *, godot_rid *);
void (*font_set_variation)(void *, godot_rid *, const godot_string *, double);
double (*font_get_variation)(void *, godot_rid *, const godot_string *);
void (*font_set_distance_field_hint)(void *, godot_rid *, bool);
bool (*font_get_distance_field_hint)(void *, godot_rid *);
void (*font_set_hinting)(void *, godot_rid *, godot_int);
Expand Down
18 changes: 18 additions & 0 deletions modules/gdnative/text/text_server_gdnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const {
return interface->font_get_antialiased(data, (godot_rid *)&p_font);
}

Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const {
ERR_FAIL_COND_V(interface == nullptr, Dictionary());
godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font);
Dictionary info = *(Dictionary *)&result;
godot_dictionary_destroy(&result);

return info;
}

void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) {
ERR_FAIL_COND(interface == nullptr);
interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value);
}

double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const {
return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name);
}

void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) {
ERR_FAIL_COND(interface == nullptr);
interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting);
Expand Down
4 changes: 4 additions & 0 deletions modules/gdnative/text/text_server_gdnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ class TextServerGDNative : public TextServer {
virtual bool font_get_antialiased(RID p_font) const override;

virtual Dictionary font_get_feature_list(RID p_font) const override;
virtual Dictionary font_get_variation_list(RID p_font) const override;

virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
virtual double font_get_variation(RID p_font, const String &p_name) const override;

virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
Expand Down
78 changes: 77 additions & 1 deletion modules/text_server_adv/dynamic_font_adv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include FT_STROKER_H
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H

DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
ERR_FAIL_COND_V(!valid, nullptr);
Expand Down Expand Up @@ -134,16 +135,91 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
memdelete(fds);
ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
}

if (p_outline_size != 0) {
size_cache_outline[id] = fds;
} else {
size_cache[id] = fds;
}
}

// Write variations.
if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
FT_MM_Var *amaster;

FT_Get_MM_Var(fds->face, &amaster);

Vector<hb_variation_t> hb_vars;
Vector<FT_Fixed> coords;
coords.resize(amaster->num_axis);

FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());

for (FT_UInt i = 0; i < amaster->num_axis; i++) {
hb_variation_t var;

// Reset to default.
var.tag = amaster->axis[i].tag;
var.value = (double)amaster->axis[i].def / 65536.f;
coords.write[i] = amaster->axis[i].def;

if (variations.has(var.tag)) {
var.value = variations[var.tag];
coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
}

hb_vars.push_back(var);
}

FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size());

FT_Done_MM_Var(library, amaster);
}
}
return fds;
}

Dictionary DynamicFontDataAdvanced::get_variation_list() const {
_THREAD_SAFE_METHOD_
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
if (fds == nullptr) {
return Dictionary();
}

Dictionary ret;
// Read variations.
if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
FT_MM_Var *amaster;

FT_Get_MM_Var(fds->face, &amaster);

for (FT_UInt i = 0; i < amaster->num_axis; i++) {
ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
}

FT_Done_MM_Var(library, amaster);
}
return ret;
}

void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
_THREAD_SAFE_METHOD_
int32_t tag = TS->name_to_tag(p_name);
if (!variations.has(tag) || (variations[tag] != p_value)) {
variations[tag] = p_value;
clear_cache();
}
}

double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
_THREAD_SAFE_METHOD_
int32_t tag = TS->name_to_tag(p_name);
if (!variations.has(tag)) {
return 0.f;
}
return variations[tag];
}

Dictionary DynamicFontDataAdvanced::get_feature_list() const {
_THREAD_SAFE_METHOD_
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
Expand Down
6 changes: 6 additions & 0 deletions modules/text_server_adv/dynamic_font_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ struct DynamicFontDataAdvanced : public FontDataAdvanced {
String font_path;
Vector<uint8_t> font_mem_cache;

Map<int32_t, double> variations;

float rect_margin = 1.f;
int base_size = 16;
float oversampling = 1.f;
Expand Down Expand Up @@ -146,6 +148,10 @@ struct DynamicFontDataAdvanced : public FontDataAdvanced {
virtual float get_descent(int p_size) const override;

virtual Dictionary get_feature_list() const override;
virtual Dictionary get_variation_list() const override;

virtual void set_variation(const String &p_name, double p_value) override;
virtual double get_variation(const String &p_name) const override;

virtual float get_underline_position(int p_size) const override;
virtual float get_underline_thickness(int p_size) const override;
Expand Down
4 changes: 4 additions & 0 deletions modules/text_server_adv/font_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ struct FontDataAdvanced {
virtual float get_descent(int p_size) const = 0;

virtual Dictionary get_feature_list() const { return Dictionary(); };
virtual Dictionary get_variation_list() const { return Dictionary(); };

virtual void set_variation(const String &p_name, double p_value){};
virtual double get_variation(const String &p_name) const { return 0; };

virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
Expand Down
23 changes: 22 additions & 1 deletion modules/text_server_adv/text_server_adv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
/*************************************************************************/

String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA;
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;

bool TextServerAdvanced::has_feature(Feature p_feature) {
return (interface_features & p_feature) == p_feature;
Expand Down Expand Up @@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
return fd->get_antialiased();
}

Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
_THREAD_SAFE_METHOD_
const FontDataAdvanced *fd = font_owner.getornull(p_font);
ERR_FAIL_COND_V(!fd, Dictionary());
return fd->get_variation_list();
}

void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
ERR_FAIL_COND(!fd);
fd->set_variation(p_name, p_value);
}

double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
_THREAD_SAFE_METHOD_
const FontDataAdvanced *fd = font_owner.getornull(p_font);
ERR_FAIL_COND_V(!fd, 0);
return fd->get_variation(p_name);
}

void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
Expand Down
4 changes: 4 additions & 0 deletions modules/text_server_adv/text_server_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ class TextServerAdvanced : public TextServer {
virtual bool font_get_antialiased(RID p_font) const override;

virtual Dictionary font_get_feature_list(RID p_font) const override;
virtual Dictionary font_get_variation_list(RID p_font) const override;

virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
virtual double font_get_variation(RID p_font, const String &p_name) const override;

virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;
Expand Down
Loading