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-07-07 22:59:16 +0300
committerHarley Acheson <harley.acheson@gmail.com>2022-07-07 22:59:16 +0300
commitb9c0eed206b0d7d1b6af6809c6d2cb6c2187bcc8 (patch)
treea84d8653a5e2c1e9a40d4f37877b2f5672ab142e /source/blender/blenfont
parentfc06b4c03356b5b9a272df8a2b96b6c4f9254ee7 (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')
-rw-r--r--source/blender/blenfont/intern/blf_font.c15
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c181
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h26
3 files changed, 214 insertions, 8 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 2eb43e3df43..4db083366c3 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -18,7 +18,8 @@
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BITMAP_H
-#include FT_ADVANCES_H /* For FT_Get_Advance. */
+#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
* \{ */
@@ -682,9 +779,7 @@ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
*
* \param factor: -1 (min stroke width) <= 0 (normal) => 1 (max boldness).
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_weight)(FT_GlyphSlot glyph,
- float factor,
- bool monospaced)
+static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
/* Fake bold if the font does not have this variable axis. */
@@ -713,7 +808,7 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_weight)(FT_GlyphSlot glyph,
*
* \note that left-leaning italics are possible in some RTL writing systems.
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_slant)(FT_GlyphSlot glyph, float factor)
+static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
FT_Matrix transform = {to_16dot16(1), to_16dot16(factor / 2.0f), 0, to_16dot16(1)};
@@ -728,7 +823,7 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_slant)(FT_GlyphSlot glyph, float
*
* \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 */
@@ -741,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)
@@ -791,6 +901,48 @@ 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, 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);
+ /* 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;
@@ -800,6 +952,21 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width);
}
+ /* Fallback glyph transforms, but only if required and not yet done. */
+
+ 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)) {
return glyph;
}
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 998093dae70..5b55f4af0b8 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -10,6 +10,19 @@
#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. */
+
+#define MAKE_DVAR_TAG(a, b, c, d) \
+ (((uint32_t)a << 24u) | ((uint32_t)b << 16u) | ((uint32_t)c << 8u) | ((uint32_t)d))
+
+#define blf_variation_axis_weight MAKE_DVAR_TAG('w', 'g', 'h', 't') /* 'wght' weight axis. */
+#define blf_variation_axis_slant MAKE_DVAR_TAG('s', 'l', 'n', 't') /* 'slnt' slant axis. */
+#define blf_variation_axis_width MAKE_DVAR_TAG('w', 'd', 't', 'h') /* 'wdth' width axis. */
+#define blf_variation_axis_spacing MAKE_DVAR_TAG('s', 'p', 'a', 'c') /* 'spac' spacing axis. */
+#define blf_variation_axis_optsize MAKE_DVAR_TAG('o', 'p', 's', 'z') /* 'opsz' optical size. */
+
/* -------------------------------------------------------------------- */
/** \name Sub-Pixel Offset & Utilities
*
@@ -125,6 +138,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 +292,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;