UI: Configurable UI Font Weight #112454

Merged
Harley Acheson merged 36 commits from Harley/blender:TextUiStyles into main 2023-10-21 00:28:37 +02:00
11 changed files with 221 additions and 63 deletions

View File

@ -1076,6 +1076,7 @@ class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel):
col = flow.column()
col.prop(font_style, "points")
col.prop(font_style, "character_weight", text="Weight")
col = flow.column(align=True)
col.prop(font_style, "shadow_offset_x", text="Shadow Offset X")

View File

@ -85,6 +85,11 @@ void BLF_aspect(int fontid, float x, float y, float z);
void BLF_position(int fontid, float x, float y, float z);
void BLF_size(int fontid, float size);
/**
* Weight class: 100 (Thin) - 400 (Normal) - 900 (Heavy).
*/
void BLF_character_weight(int fontid, int weight);
/* Goal: small but useful color API. */
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);

View File

@ -324,6 +324,14 @@ void BLF_disable(int fontid, int option)
}
}
void BLF_character_weight(int fontid, int weight)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->char_weight = weight;
}
}
void BLF_aspect(int fontid, float x, float y, float z)
{
FontBLF *font = blf_get(fontid);

View File

@ -1347,6 +1347,11 @@ static void blf_font_fill(FontBLF *font)
font->clip_rec.ymax = 0;
font->flags = 0;
font->size = 0;
font->char_weight = 400;
font->char_slant = 0.0f;
font->char_width = 1.0f;
font->char_spacing = 0.0f;
BLI_listbase_clear(&font->cache);
font->kerning_cache = nullptr;
#if BLF_BLUR_ENABLE
@ -1372,7 +1377,6 @@ static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
/* Members with non-zero defaults. */
metrics->weight = 400;
metrics->width = 1.0f;
metrics->spacing = 1.0f;
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
if (os2_table) {
@ -1625,6 +1629,11 @@ bool blf_ensure_face(FontBLF *font)
blf_ensure_size(font);
blf_font_metrics(font->face, &font->metrics);
font->char_weight = font->metrics.weight;
font->char_slant = font->metrics.slant;
font->char_width = font->metrics.width;
font->char_spacing = font->metrics.spacing;
/* Save TrueType table with bits to quickly test most unicode block coverage. */
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
if (os2_table) {

View File

@ -58,6 +58,14 @@ static FT_Fixed to_16dot16(double val)
return (FT_Fixed)lround(val * 65536.0);
}
/**
* Convert a floating point value to a FreeType 16.16 fixed point value.
*/
static float from_16dot16(FT_Fixed value)
{
return float(value) / 65536.0f;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -813,11 +821,15 @@ static const FT_Var_Axis *blf_var_axis_by_tag(const FT_MM_Var *variations,
/**
* Convert a float factor to a fixed-point design coordinate.
* Currently unused because we are only dealing with known axes
* with specific functions, but this would be needed for unregistered,
* custom, or private tags. These are all uppercase axis tags.
*
* \param axis: Pointer to a design space axis structure.
* \param factor: -1 to 1 with 0 meaning "default"
*/
static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis, const float factor)
[[maybe_unused]] static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis,
const float factor)
{
FT_Fixed value = axis->def;
if (factor > 0) {
@ -832,16 +844,20 @@ static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis, const float fa
}
/**
* Alter a face variation axis by a factor
* Alter a face variation axis by a factor.
* Currently unused because we are only dealing with known axes
* with specific functions, but this would be needed for unregistered,
* custom, or private tags. These are all uppercase axis tags.
*
* \param coords: array of design coordinates, per axis.
* \param tag: Axis tag, e.g. #BLF_VARIATION_AXIS_WEIGHT.
* \param factor: -1 to 1 with 0 meaning "default"
* \return success if able to set this value.
*/
static bool blf_glyph_set_variation_normalized(const FontBLF *font,
FT_Fixed coords[],
const uint32_t tag,
const float factor)
[[maybe_unused]] static bool blf_glyph_set_variation_normalized(const FontBLF *font,
FT_Fixed coords[],
const uint32_t tag,
const float factor)
{
int axis_index;
const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
@ -858,23 +874,116 @@ static bool blf_glyph_set_variation_normalized(const FontBLF *font,
* \param coords: Array of design coordinates, per axis.
* \param tag: Axis tag, e.g. #BLF_VARIATION_AXIS_OPTSIZE.
* \param value: New float value. Converted to 16.16 and clamped within allowed range.
* \return success if able to set this value.
*/
static bool blf_glyph_set_variation_float(FontBLF *font,
FT_Fixed coords[],
uint32_t tag,
float value)
float *value)
{
int axis_index;
const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
FT_Fixed int_value = to_16dot16(value);
FT_Fixed int_value = to_16dot16(*value);
CLAMP(int_value, axis->minimum, axis->maximum);
coords[axis_index] = int_value;
*value = from_16dot16(int_value);
return true;
}
return false;
}
/**
* Set the "wght" (Weight) axis to a specific weight value.
*
* \param coords: Array of design coordinates, per axis.
* \param weight: Weight class value (1-1000 allowed, 100-900 typical).
* \return value set (could be clamped), or current weight if the axis does not exist.
*/
static float blf_glyph_set_variation_weight(FontBLF *font,
FT_Fixed coords[],
float current_weight,
float target_weight)
{
float value = target_weight;
if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_WEIGHT, &value)) {
return value;
}
return current_weight;
}
/**
* Set the "slnt" (Slant) axis to a specific slant value.
*
* \param coords: Array of design coordinates, per axis.
* \param degrees: Slant in clockwise (opposite to spec) degrees.
* \return value set (could be clamped), or current slant if the axis does not exist.
*/
static float blf_glyph_set_variation_slant(FontBLF *font,
FT_Fixed coords[],
float current_degrees,
float target_degrees)
{
float value = -target_degrees;
if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_SLANT, &value)) {
return -value;
}
return current_degrees;
}
/**
* Set the "wdth" (Width) axis to a specific width value.
*
* \param coords: Array of design coordinates, per axis.
* \param width: Glyph width value. 1.0 is normal, as per spec (which uses percent).
* \return value set (could be clamped), or current width if the axis does not exist.
*/
static float blf_glyph_set_variation_width(FontBLF *font,
FT_Fixed coords[],
float current_width,
float target_width)
{
float value = target_width * 100.0f;
if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_WIDTH, &value)) {
return value / 100.0f;
}
return current_width;
}
/**
* Set the proposed "spac" (Spacing) axis to a specific value.
*
* \param coords: Array of design coordinates, per axis.
* \param spacing: Glyph spacing value. 0.0 is normal, as per spec.
* \return value set (could be clamped), or current spacing if the axis does not exist.
*/
static float blf_glyph_set_variation_spacing(FontBLF *font,
FT_Fixed coords[],
float current_spacing,
float target_spacing)
{
float value = target_spacing;
if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_SPACING, &value)) {
return value;
}
return current_spacing;
}
/**
* Set the "opsz" (Optical Size) axis to a specific size value.
*
* \param coords: Array of design coordinates, per axis.
* \param points: Non-zero size in typographic points.
* \return success if able to set this value.
*/
static bool blf_glyph_set_variation_optical_size(FontBLF *font,
FT_Fixed coords[],
const float points)
{
float value = points;
return blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_OPTSIZE, &value);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -885,14 +994,15 @@ static bool blf_glyph_set_variation_float(FontBLF *font,
* Adjust the glyph's weight by a factor.
* Used for fonts without #BLF_VARIATION_AXIS_WEIGHT variable axis.
*
* \param factor: -1 (min stroke width) <= 0 (normal) => 1 (max boldness).
* \param width: -500 (make thinner) <= 0 (normal) => 500 (add boldness).
*/
static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced)
static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float width, bool monospaced)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
const FontBLF *font = (FontBLF *)glyph->face->generic.data;
const FT_Pos average_width = font->ft_size->metrics.height;
FT_Pos change = (FT_Pos)(float(average_width) * factor * 0.12f);
float factor = width * 0.000225f;
FT_Pos change = (FT_Pos)(float(average_width) * factor);
FT_Outline_EmboldenXY(&glyph->outline, change, 0);
if (monospaced) {
/* Widened fixed-pitch font needs a nudge left. */
@ -908,19 +1018,23 @@ static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool mo
}
/**
* Adjust the glyph's slant by a factor.
* Adjust the glyph's slant by a number of degrees.
* Used for fonts without #BLF_VARIATION_AXIS_SLANT variable axis.
*
* \param factor: -1 (max right-leaning) <= 0 (no slant) => 1 (max left-leaning).
*
* \note that left-leaning italics are possible in some RTL writing systems.
* \param degrees: amount of tilt to add in clockwise degrees.
*/
static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float degrees)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
/* Slant angle is counter-clockwise as per OTF specs. */
FT_Matrix transform = {to_16dot16(1), to_16dot16(-factor / 4.0f), 0, to_16dot16(1)};
FT_Matrix transform = {to_16dot16(1), to_16dot16(degrees * 0.0225f), 0, to_16dot16(1)};
FT_Outline_Transform(&glyph->outline, &transform);
if (degrees < 0.0f) {
/* Leftward slant could interfere with prior characters to nudge right. */
const FontBLF *font = (FontBLF *)glyph->face->generic.data;
const FT_Pos average_width = font->ft_size->metrics.height;
FT_Pos change = (FT_Pos)(float(average_width) * degrees * -0.01f);
FT_Outline_Translate(&glyph->outline, change, 0);
}
return true;
}
return false;
@ -930,12 +1044,12 @@ static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
* Adjust the glyph width by factor.
* Used for fonts without #BLF_VARIATION_AXIS_WIDTH variable axis.
*
* \param factor: -1 (min width) <= 0 (normal) => 1 (max width).
* \param factor: -1 (subtract width) <= 0 (normal) => 1 (add width).
*/
static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
float scale = (factor * 0.4f) + 1.0f; /* 0.6f - 1.4f */
float scale = factor + 1.0f;
FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
FT_Outline_Transform(&glyph->outline, &matrix);
glyph->advance.x = (FT_Pos)(double(glyph->advance.x) * scale);
@ -948,7 +1062,7 @@ static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor)
* Adjust the glyph spacing by factor.
* Used for fonts without #BLF_VARIATION_AXIS_SPACING variable axis.
*
* \param factor: -1 (min tightness) <= 0 (normal) => 1 (max looseness).
* \param factor: -1 (make tighter) <= 0 (normal) => 1 (add space).
*/
static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
{
@ -1011,21 +1125,23 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
blf_ensure_size(glyph_font);
/* We need to keep track if changes are still needed. */
bool weight_done = false;
bool slant_done = false;
bool width_done = false;
bool spacing_done = false;
/* Default style values of the font containing the glyph. */
float weight = glyph_font->metrics.weight;
float slant = glyph_font->metrics.slant;
float width = glyph_font->metrics.width;
float spacing = glyph_font->metrics.spacing;
/* Treat bold as 75% of maximum weight. */
float weight = (settings_font->flags & BLF_BOLD) ? 0.75f : settings_font->char_weight;
/* Treat italics as 75% of maximum rightward slant. Note that slant angle is in
* counter-clockwise degrees per OTF spec, so negative. */
float slant = (settings_font->flags & BLF_ITALIC) ? -0.75f : settings_font->char_slant;
float width = settings_font->char_width;
float spacing = settings_font->char_spacing;
/* Style targets are on the settings_font. */
float weight_target = float(settings_font->char_weight);
if (settings_font->flags & BLF_BOLD) {
weight_target = MIN2(weight_target + 300.0f, 900.0f);
}
float slant_target = settings_font->char_slant;
if (settings_font->flags & BLF_ITALIC) {
slant_target = MIN2(slant_target + 8.0f, 15.0f);
}
float width_target = settings_font->char_width;
float spacing_target = settings_font->char_spacing;
/* Font variations need to be set before glyph loading. Even if new value is zero. */
@ -1034,17 +1150,13 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
/* Load current design coordinates. */
FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
/* Update design coordinates with new values. */
weight_done = blf_glyph_set_variation_normalized(
glyph_font, coords, BLF_VARIATION_AXIS_WEIGHT, weight);
slant_done = blf_glyph_set_variation_normalized(
glyph_font, coords, BLF_VARIATION_AXIS_SLANT, slant);
width_done = blf_glyph_set_variation_normalized(
glyph_font, coords, BLF_VARIATION_AXIS_WIDTH, width);
spacing_done = blf_glyph_set_variation_normalized(
glyph_font, coords, BLF_VARIATION_AXIS_SPACING, spacing);
/* Optical size, if available, is set to current font size. */
blf_glyph_set_variation_float(
glyph_font, coords, BLF_VARIATION_AXIS_OPTSIZE, settings_font->size);
weight = blf_glyph_set_variation_weight(glyph_font, coords, weight, weight_target);
slant = blf_glyph_set_variation_slant(glyph_font, coords, slant, slant_target);
width = blf_glyph_set_variation_width(glyph_font, coords, width, width_target);
spacing = blf_glyph_set_variation_spacing(glyph_font, coords, spacing, spacing_target);
blf_glyph_set_variation_optical_size(glyph_font, coords, settings_font->size);
/* Save updated design coordinates. */
FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
}
@ -1063,17 +1175,17 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
/* Fallback glyph transforms, but only if required and not yet done. */
if (weight != 0.0f && !weight_done) {
blf_glyph_transform_weight(glyph, weight, FT_IS_FIXED_WIDTH(glyph_font));
if (weight != weight_target) {
blf_glyph_transform_weight(glyph, weight_target - weight, FT_IS_FIXED_WIDTH(glyph_font));
}
if (slant != 0.0f && !slant_done) {
blf_glyph_transform_slant(glyph, slant);
if (slant != slant_target) {
blf_glyph_transform_slant(glyph, slant_target - slant);
}
if (width != 0.0f && !width_done) {
blf_glyph_transform_width(glyph, width);
if (width != width_target) {
blf_glyph_transform_width(glyph, width_target - width);
}
if (spacing != 0.0f && !spacing_done) {
blf_glyph_transform_spacing(glyph, spacing);
if (spacing != spacing_target) {
blf_glyph_transform_spacing(glyph, spacing_target - spacing);
}
FT_Outline_Translate(&glyph->outline, (FT_Pos)subpixel, 0);

View File

@ -116,7 +116,7 @@ typedef struct GlyphCacheBLF {
/** Font size. */
float size;
float char_weight;
int char_weight;
float char_slant;
float char_width;
float char_spacing;
@ -343,11 +343,11 @@ typedef struct FontBLF {
/** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */
FT_MM_Var *variations;
/** Character variation; 0=default, -1=min, +1=max. */
float char_weight;
float char_slant;
float char_width;
float char_spacing;
/** Character variations. */
int char_weight; /* 100 - 900, 400 = normal. */
float char_slant; /* Slant in clockwise degrees. 0.0 = upright. */
float char_width; /* Factor of normal character width. 1.0 = normal. */
float char_spacing; /* Factor of normal normal spacing. 0.0 = normal. */
/** Max texture size. */
int tex_size_max;

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 2
#define BLENDER_FILE_SUBVERSION 3
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -885,6 +885,15 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->text_render |= USER_TEXT_RENDER_SUBPIXELAA;
}
if (!USER_VERSION_ATLEAST(401, 3)) {
LISTBASE_FOREACH (uiStyle *, style, &userdef->uistyles) {
style->paneltitle.character_weight = 400;
style->grouplabel.character_weight = 400;
style->widgetlabel.character_weight = 400;
style->widget.character_weight = 400;
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -69,6 +69,7 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->paneltitle.uifont_id = uifont_id;
style->paneltitle.points = UI_DEFAULT_TITLE_POINTS;
style->paneltitle.character_weight = 400;
style->paneltitle.shadow = 3;
style->paneltitle.shadx = 0;
style->paneltitle.shady = -1;
@ -77,6 +78,7 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->grouplabel.uifont_id = uifont_id;
style->grouplabel.points = UI_DEFAULT_TITLE_POINTS;
style->grouplabel.character_weight = 400;
style->grouplabel.shadow = 3;
style->grouplabel.shadx = 0;
style->grouplabel.shady = -1;
@ -85,6 +87,7 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->widgetlabel.uifont_id = uifont_id;
style->widgetlabel.points = UI_DEFAULT_TEXT_POINTS;
style->widgetlabel.character_weight = 400;
style->widgetlabel.shadow = 3;
style->widgetlabel.shadx = 0;
style->widgetlabel.shady = -1;
@ -93,6 +96,7 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->widget.uifont_id = uifont_id;
style->widget.points = UI_DEFAULT_TEXT_POINTS;
style->widget.character_weight = 400;
style->widget.shadow = 1;
style->widget.shady = -1;
style->widget.shadowalpha = 0.5f;
@ -492,6 +496,7 @@ static void fontstyle_set_ex(const uiFontStyle *fs, const float dpi_fac)
uiFont *font = uifont_to_blfont(fs->uifont_id);
BLF_size(font->blf_id, fs->points * dpi_fac);
BLF_character_weight(fs->uifont_id, fs->character_weight);
}
void UI_fontstyle_set(const uiFontStyle *fs)

View File

@ -81,7 +81,8 @@ typedef struct uiFontStyle {
float shadowalpha;
/** 1 value, typically white or black anyway. */
float shadowcolor;
char _pad2[4];
/** Weight class 100-900, 400 is normal. */
int character_weight;
} uiFontStyle;
/* this is fed to the layout engine and widget code */

View File

@ -1294,6 +1294,14 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Points", "Font size in points");
RNA_def_property_update(prop, 0, "rna_userdef_gpu_update");
prop = RNA_def_property(srna, "character_weight", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 400);
RNA_def_property_range(prop, 100.0f, 900.0f);
RNA_def_property_ui_range(prop, 100.0f, 900.0f, 50, 0);
RNA_def_property_ui_text(
prop, "Character Weight", "Weight of the characters. 100-900, 400 is normal");
RNA_def_property_update(prop, 0, "rna_userdef_text_update");
prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 0, 5);
RNA_def_property_ui_text(prop, "Shadow Size", "Shadow size (0, 3 and 5 supported)");