Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarley Acheson <harley.acheson@gmail.com>2022-06-27 16:05:46 +0300
committerHarley Acheson <harley.acheson@gmail.com>2022-06-27 16:07:55 +0300
commit6de0f299505a24969022cc2a63dd11db7b13b1be (patch)
treefb50036eb7b9bc3db510100d79ce2771ab49fcd2 /source/blender/blenfont/intern
parent151fc2fcd8461a9a28a2e912148718d51e8efd37 (diff)
BLF: Add Support for Variable Fonts
Add support for Variable/Multiple Master font features. These are fonts that contain a range of design variations along multiple axes. This contains no client-facing options. See D12977 for details and examples Differential Revision: https://developer.blender.org/D12977 Reviewed by Brecht Van Lommel
Diffstat (limited to 'source/blender/blenfont/intern')
-rw-r--r--source/blender/blenfont/intern/blf_font.c15
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c177
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h17
3 files changed, 194 insertions, 15 deletions
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 3e2927d581e..038e73cc928 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -18,7 +18,8 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
-#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
#include "MEM_guardedalloc.h"
@@ -1285,6 +1286,10 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
MEM_freeN(mfile);
}
+ if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
+ FT_Get_MM_Var(font->face, &(font->variations));
+ }
+
font->name = BLI_strdup(name);
font->filepath = BLI_strdup(filepath);
blf_font_fill(font);
@@ -1351,6 +1356,10 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m
return NULL;
}
+ if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
+ FT_Get_MM_Var(font->face, &(font->variations));
+ }
+
font->name = BLI_strdup(name);
font->filepath = NULL;
blf_font_fill(font);
@@ -1365,6 +1374,10 @@ void blf_font_free(FontBLF *font)
MEM_freeN(font->kerning_cache);
}
+ if (font->variations) {
+ FT_Done_MM_Var(ft_lib, font->variations);
+ }
+
FT_Done_Face(font->face);
if (font->filepath) {
MEM_freeN(font->filepath);
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index ed30cca4da2..f1a9816c417 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -19,6 +19,7 @@
#include FT_OUTLINE_H
#include FT_BITMAP_H
#include FT_ADVANCES_H /* For FT_Get_Advance. */
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
#include "MEM_guardedalloc.h"
@@ -64,7 +65,9 @@ static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned i
GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
while (gc) {
if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
- (gc->italic == ((font->flags & BLF_ITALIC) != 0))) {
+ (gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
+ (gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
+ (gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing)) {
return gc;
}
gc = gc->next;
@@ -82,6 +85,10 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
gc->dpi = font->dpi;
gc->bold = ((font->flags & BLF_BOLD) != 0);
gc->italic = ((font->flags & BLF_ITALIC) != 0);
+ gc->char_weight = font->char_weight;
+ gc->char_slant = font->char_slant;
+ gc->char_width = font->char_width;
+ gc->char_spacing = font->char_spacing;
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
@@ -674,6 +681,96 @@ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Variations (Multiple Masters) support
+ * \{ */
+
+/**
+ * Return a design axis that matches an identifying tag.
+ *
+ * \param variations: Variation descriptors from `FT_Get_MM_Var`.
+ * \param tag: Axis tag (4-character string as uint), like 'wght'
+ * \param axis_index: returns index of axis in variations array.
+ */
+static FT_Var_Axis *blf_var_axis_by_tag(FT_MM_Var *variations, uint tag, int *axis_index)
+{
+ *axis_index = -1;
+ if (!variations) {
+ return NULL;
+ }
+ for (int i = 0; i < (int)variations->num_axis; i++) {
+ if (variations->axis[i].tag == tag) {
+ *axis_index = i;
+ return &(variations->axis)[i];
+ break;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Convert a float factor to a fixed-point design coordinate.
+ *
+ * \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(FT_Var_Axis *axis, float factor)
+{
+ FT_Fixed value = axis->def;
+ if (factor > 0) {
+ /* Map 0-1 to axis->def - axis->maximum */
+ value += (FT_Fixed)((double)(axis->maximum - axis->def) * factor);
+ }
+ else if (factor < 0) {
+ /* Map -1-0 to axis->minimum - axis->def */
+ value += (FT_Fixed)((double)(axis->def - axis->minimum) * factor);
+ }
+ return value;
+}
+
+/**
+ * Alter a face variation axis by a factor
+ *
+ * \param coords: array of design coordinates, per axis.
+ * \param tag: Axis tag (4-character string as uint), like 'wght'
+ * \param factor: -1 to 1 with 0 meaning "default"
+ */
+static bool blf_glyph_set_variation_normalized(FontBLF *font,
+ FT_Fixed coords[],
+ uint tag,
+ float factor)
+{
+ int axis_index;
+ FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
+ if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
+ coords[axis_index] = blf_factor_to_coordinate(axis, factor);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Set a face variation axis to an exact float value
+ *
+ * \param coords: array of design coordinates, per axis.
+ * \param tag: Axis tag (4-character string as uint), like 'opsz'
+ * \param value: New float value. Converted to 16.16 and clamped within allowed range.
+ */
+static bool blf_glyph_set_variation_float(FontBLF *font, FT_Fixed coords[], uint tag, float value)
+{
+ int axis_index;
+ 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);
+ CLAMP(int_value, axis->minimum, axis->maximum);
+ coords[axis_index] = int_value;
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Glyph Transformations
* \{ */
@@ -726,7 +823,7 @@ static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
*
* \param factor: -1 (min width) <= 0 (normal) => 1 (max width).
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor)
+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 */
@@ -739,6 +836,21 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float
}
/**
+ * Change glyph advance to alter letter-spacing (tracking).
+ *
+ * \param factor: -1 (min tightness) <= 0 (normal) => 1 (max looseness).
+ */
+static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
+{
+ if (glyph->advance.x > 0) {
+ const int size = glyph->face->size->metrics.height;
+ glyph->advance.x += (FT_Pos)(factor * (float)size / 6.0f);
+ return true;
+ }
+ return false;
+}
+
+/**
* Transform glyph to fit nicely within a fixed column width.
*/
static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
@@ -789,6 +901,43 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
glyph_font->dpi = settings_font->dpi;
}
+ /* 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;
+
+ /* 70% of maximum weight results in the same amount of boldness and horizontal
+ * expansion as the bold version (DejaVuSans-Bold.ttf) of our default font.
+ * Worth reevaluating if we change default font. */
+ float weight = (settings_font->flags & BLF_BOLD) ? 0.7f : settings_font->char_weight;
+
+ /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic
+ * version (DejaVuSans-Oblique.ttf) of our current font. But a nice median when
+ * checking others. Worth reevaluating if we change default font. We could also
+ * narrow the glyph slightly as most italics do, but this one does not. */
+ float slant = (settings_font->flags & BLF_ITALIC) ? 0.375f : settings_font->char_slant;
+
+ float width = settings_font->char_width;
+ float spacing = settings_font->char_spacing;
+
+ /* Font variations need to be set before glyph loading. Even if new value is zero. */
+
+ if (glyph_font->variations) {
+ FT_Fixed coords[BLF_VARIATIONS_MAX];
+ /* 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, 'wght', weight);
+ slant_done = blf_glyph_set_variation_normalized(glyph_font, coords, 'slnt', slant);
+ width_done = blf_glyph_set_variation_normalized(glyph_font, coords, 'wdth', width);
+ spacing_done = blf_glyph_set_variation_normalized(glyph_font, coords, 'spac', spacing);
+ /* Optical size, if available, is set to current font size. */
+ blf_glyph_set_variation_float(glyph_font, coords, 'opsz', settings_font->size);
+ /* Save updated design coordinates. */
+ FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
+ }
+
FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index);
if (!glyph) {
return NULL;
@@ -798,19 +947,19 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width);
}
- if ((settings_font->flags & BLF_ITALIC) != 0) {
- /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic
- * version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when
- * checking others. Worth reevaluating if we change default font. We could also
- * narrow the glyph slightly as most italics do, but this one does not. */
- blf_glyph_transform_slant(glyph, 0.375f);
- }
+ /* Fallback glyph transforms, but only if required and not yet done. */
- if ((settings_font->flags & BLF_BOLD) != 0) {
- /* 70% of maximum weight results in the same amount of boldness and horizontal
- * expansion as the bold version (`DejaVuSans-Bold.ttf`) of our default font.
- * Worth reevaluating if we change default font. */
- blf_glyph_transform_weight(glyph, 0.7f, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
+ if (weight != 0.0f && !weight_done) {
+ blf_glyph_transform_weight(glyph, weight, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
+ }
+ if (slant != 0.0f && !slant_done) {
+ blf_glyph_transform_slant(glyph, slant);
+ }
+ if (width != 0.0f && !width_done) {
+ blf_glyph_transform_width(glyph, width);
+ }
+ if (spacing != 0.0f && !spacing_done) {
+ blf_glyph_transform_spacing(glyph, spacing);
}
if (blf_glyph_render_bitmap(glyph_font, glyph)) {
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 998093dae70..238301b9c4d 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -10,6 +10,10 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
+
+#define BLF_VARIATIONS_MAX 16 /* Maximum variation axes per font. */
+
/* -------------------------------------------------------------------- */
/** \name Sub-Pixel Offset & Utilities
*
@@ -125,6 +129,10 @@ typedef struct GlyphCacheBLF {
/* and DPI. */
unsigned int dpi;
+ float char_weight;
+ float char_slant;
+ float char_width;
+ float char_spacing;
bool bold;
bool italic;
@@ -275,6 +283,15 @@ typedef struct FontBLF {
/* font size. */
float size;
+ /* 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;
+
/* max texture size. */
int tex_size_max;