mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-06 04:38:04 +02:00
Merge branch 'font-variations'
This commit is contained in:
commit
a7a0085713
10 changed files with 486 additions and 19 deletions
|
|
@ -76,6 +76,9 @@ if test "x$have_dlsym" = "xyes"; then
|
|||
fi
|
||||
AM_CONDITIONAL(CAIRO_HAS_DLSYM, test "x$have_dlsym" = "xyes")
|
||||
|
||||
AC_CHECK_HEADERS(xlocale.h)
|
||||
AC_CHECK_FUNCS(newlocale strtod_l)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ static const cairo_font_options_t _cairo_font_options_nil = {
|
|||
CAIRO_LCD_FILTER_DEFAULT,
|
||||
CAIRO_HINT_STYLE_DEFAULT,
|
||||
CAIRO_HINT_METRICS_DEFAULT,
|
||||
CAIRO_ROUND_GLYPH_POS_DEFAULT
|
||||
CAIRO_ROUND_GLYPH_POS_DEFAULT,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -73,6 +74,7 @@ _cairo_font_options_init_default (cairo_font_options_t *options)
|
|||
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
|
||||
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
|
||||
options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT;
|
||||
options->variations = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -85,6 +87,7 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
|
|||
options->hint_style = other->hint_style;
|
||||
options->hint_metrics = other->hint_metrics;
|
||||
options->round_glyph_positions = other->round_glyph_positions;
|
||||
options->variations = other->variations ? strdup (other->variations) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -166,6 +169,7 @@ cairo_font_options_destroy (cairo_font_options_t *options)
|
|||
if (cairo_font_options_status (options))
|
||||
return;
|
||||
|
||||
free (options->variations);
|
||||
free (options);
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +230,24 @@ cairo_font_options_merge (cairo_font_options_t *options,
|
|||
options->hint_metrics = other->hint_metrics;
|
||||
if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT)
|
||||
options->round_glyph_positions = other->round_glyph_positions;
|
||||
|
||||
if (other->variations) {
|
||||
if (options->variations) {
|
||||
char *p;
|
||||
|
||||
/* 'merge' variations by concatenating - later entries win */
|
||||
p = malloc (strlen (other->variations) + strlen (options->variations) + 2);
|
||||
p[0] = 0;
|
||||
strcat (p, options->variations);
|
||||
strcat (p, ",");
|
||||
strcat (p, other->variations);
|
||||
free (options->variations);
|
||||
options->variations = p;
|
||||
}
|
||||
else {
|
||||
options->variations = strdup (other->variations);
|
||||
}
|
||||
}
|
||||
}
|
||||
slim_hidden_def (cairo_font_options_merge);
|
||||
|
||||
|
|
@ -259,7 +281,10 @@ cairo_font_options_equal (const cairo_font_options_t *options,
|
|||
options->lcd_filter == other->lcd_filter &&
|
||||
options->hint_style == other->hint_style &&
|
||||
options->hint_metrics == other->hint_metrics &&
|
||||
options->round_glyph_positions == other->round_glyph_positions);
|
||||
options->round_glyph_positions == other->round_glyph_positions &&
|
||||
((options->variations == NULL && other->variations == NULL) ||
|
||||
(options->variations != NULL && other->variations != NULL &&
|
||||
strcmp (options->variations, other->variations) == 0)));
|
||||
}
|
||||
slim_hidden_def (cairo_font_options_equal);
|
||||
|
||||
|
|
@ -280,14 +305,19 @@ slim_hidden_def (cairo_font_options_equal);
|
|||
unsigned long
|
||||
cairo_font_options_hash (const cairo_font_options_t *options)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
|
||||
if (cairo_font_options_status ((cairo_font_options_t *) options))
|
||||
options = &_cairo_font_options_nil; /* force default values */
|
||||
|
||||
if (options->variations)
|
||||
hash = _cairo_string_hash (options->variations, strlen (options->variations));
|
||||
|
||||
return ((options->antialias) |
|
||||
(options->subpixel_order << 4) |
|
||||
(options->lcd_filter << 8) |
|
||||
(options->hint_style << 12) |
|
||||
(options->hint_metrics << 16));
|
||||
(options->hint_metrics << 16)) ^ hash;
|
||||
}
|
||||
slim_hidden_def (cairo_font_options_hash);
|
||||
|
||||
|
|
@ -533,3 +563,54 @@ cairo_font_options_get_hint_metrics (const cairo_font_options_t *options)
|
|||
|
||||
return options->hint_metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_font_options_set_variations:
|
||||
* @options: a #cairo_font_options_t
|
||||
* @variations: the new font variations, or %NULL
|
||||
*
|
||||
* Sets the OpenType font variations for the font options object.
|
||||
* Font variations are specified as a string with a format that
|
||||
* is similar to the CSS font-variation-settings. The string contains
|
||||
* a comma-separated list of axis assignments, which each assignment
|
||||
* consists of a 4-character axis name and a value, separated by
|
||||
* whitespace and optional equals sign.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* wght=200,wdth=140.5
|
||||
*
|
||||
* wght 200 , wdth 140.5
|
||||
*
|
||||
* Since: 1.16
|
||||
**/
|
||||
void
|
||||
cairo_font_options_set_variations (cairo_font_options_t *options,
|
||||
const char *variations)
|
||||
{
|
||||
char *tmp = variations ? strdup (variations) : NULL;
|
||||
free (options->variations);
|
||||
options->variations = tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_font_options_get_variations:
|
||||
* @options: a #cairo_font_options_t
|
||||
*
|
||||
* Gets the OpenType font variations for the font options object.
|
||||
* See cairo_font_options_set_variations() for details about the
|
||||
* string format.
|
||||
*
|
||||
* Return value: the font variations for the font options object. The
|
||||
* returned string belongs to the @options and must not be modified.
|
||||
* It is valid until either the font options object is destroyed or
|
||||
* the font variations in this object is modified with
|
||||
* cairo_font_options_set_variations().
|
||||
*
|
||||
* Since: 1.16
|
||||
**/
|
||||
const char *
|
||||
cairo_font_options_get_variations (cairo_font_options_t *options)
|
||||
{
|
||||
return options->variations;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@
|
|||
#define FT_LCD_FILTER_LEGACY 16
|
||||
#endif
|
||||
|
||||
#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
|
||||
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
|
||||
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
|
||||
#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
|
||||
|
|
@ -169,8 +168,9 @@ struct _cairo_ft_unscaled_font {
|
|||
cairo_matrix_t current_shape;
|
||||
FT_Matrix Current_Shape;
|
||||
|
||||
unsigned int have_color_set : 1;
|
||||
unsigned int have_color : 1; /* true if the font contains color glyphs */
|
||||
unsigned int have_color_set : 1;
|
||||
unsigned int have_color : 1; /* true if the font contains color glyphs */
|
||||
FT_Fixed *variations; /* variation settings that FT_Face came */
|
||||
|
||||
cairo_mutex_t mutex;
|
||||
int lock_count;
|
||||
|
|
@ -426,12 +426,25 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
|
|||
_cairo_unscaled_font_init (&unscaled->base,
|
||||
&cairo_ft_unscaled_font_backend);
|
||||
|
||||
unscaled->variations = NULL;
|
||||
|
||||
if (from_face) {
|
||||
unscaled->from_face = TRUE;
|
||||
_cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face);
|
||||
_cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, face->face_index, face);
|
||||
|
||||
|
||||
unscaled->have_color = FT_HAS_COLOR (face) != 0;
|
||||
unscaled->have_color_set = TRUE;
|
||||
|
||||
{
|
||||
FT_MM_Var *ft_mm_var;
|
||||
if (0 == FT_Get_MM_Var (face, &ft_mm_var))
|
||||
{
|
||||
unscaled->variations = calloc (ft_mm_var->num_axis, sizeof (FT_Fixed));
|
||||
if (unscaled->variations)
|
||||
FT_Get_Var_Design_Coordinates (face, ft_mm_var->num_axis, unscaled->variations);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char *filename_copy;
|
||||
|
||||
|
|
@ -444,7 +457,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
|
|||
|
||||
_cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL);
|
||||
|
||||
unscaled->have_color_set = FALSE;
|
||||
unscaled->have_color_set = FALSE;
|
||||
}
|
||||
|
||||
unscaled->have_scale = FALSE;
|
||||
|
|
@ -475,6 +488,8 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
|
|||
free (unscaled->filename);
|
||||
unscaled->filename = NULL;
|
||||
|
||||
free (unscaled->variations);
|
||||
|
||||
CAIRO_MUTEX_FINI (unscaled->mutex);
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +502,7 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a,
|
|||
|
||||
if (unscaled_a->id == unscaled_b->id &&
|
||||
unscaled_a->from_face == unscaled_b->from_face)
|
||||
{
|
||||
{
|
||||
if (unscaled_a->from_face)
|
||||
return unscaled_a->face == unscaled_b->face;
|
||||
|
||||
|
|
@ -1714,6 +1729,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
|
|||
#ifdef FC_HINT_STYLE
|
||||
int hintstyle;
|
||||
#endif
|
||||
char *variations;
|
||||
|
||||
_cairo_font_options_init_default (&ft_options.base);
|
||||
ft_options.load_flags = FT_LOAD_DEFAULT;
|
||||
|
|
@ -1855,6 +1871,13 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
|
|||
if (embolden)
|
||||
ft_options.synth_flags |= CAIRO_FT_SYNTHESIZE_BOLD;
|
||||
|
||||
#ifndef FC_FONT_VARIATIONS
|
||||
#define FC_FONT_VARIATIONS "fontvariations"
|
||||
#endif
|
||||
if (FcPatternGetString (pattern, FC_FONT_VARIATIONS, 0, (FcChar8 **) &variations) == FcResultMatch) {
|
||||
ft_options.base.variations = strdup (variations);
|
||||
}
|
||||
|
||||
*ret = ft_options;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1932,6 +1955,24 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
|
|||
}
|
||||
}
|
||||
|
||||
if (other->base.variations) {
|
||||
if (options->base.variations) {
|
||||
char *p;
|
||||
|
||||
/* 'merge' variations by concatenating - later entries win */
|
||||
p = malloc (strlen (other->base.variations) + strlen (options->base.variations) + 2);
|
||||
p[0] = 0;
|
||||
strcat (p, other->base.variations);
|
||||
strcat (p, ",");
|
||||
strcat (p, options->base.variations);
|
||||
free (options->base.variations);
|
||||
options->base.variations = p;
|
||||
}
|
||||
else {
|
||||
options->base.variations = strdup (other->base.variations);
|
||||
}
|
||||
}
|
||||
|
||||
options->load_flags = load_flags | load_target;
|
||||
options->synth_flags = other->synth_flags;
|
||||
}
|
||||
|
|
@ -2234,6 +2275,96 @@ _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (void *abstract_font,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cairo_ft_apply_variations (FT_Face face,
|
||||
cairo_ft_scaled_font_t *scaled_font)
|
||||
{
|
||||
FT_MM_Var *ft_mm_var;
|
||||
FT_Error ret;
|
||||
unsigned int instance_id = scaled_font->unscaled->id >> 16;
|
||||
|
||||
ret = FT_Get_MM_Var (face, &ft_mm_var);
|
||||
if (ret == 0) {
|
||||
FT_Fixed *current_coords;
|
||||
FT_Fixed *coords;
|
||||
unsigned int i;
|
||||
const char *p;
|
||||
|
||||
coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis);
|
||||
/* FIXME check coords. */
|
||||
|
||||
if (scaled_font->unscaled->variations)
|
||||
{
|
||||
memcpy (coords, scaled_font->unscaled->variations, ft_mm_var->num_axis * sizeof (*coords));
|
||||
}
|
||||
else if (instance_id && instance_id <= ft_mm_var->num_namedstyles)
|
||||
{
|
||||
FT_Var_Named_Style *instance = &ft_mm_var->namedstyle[instance_id - 1];
|
||||
memcpy (coords, instance->coords, ft_mm_var->num_axis * sizeof (*coords));
|
||||
}
|
||||
else
|
||||
for (i = 0; i < ft_mm_var->num_axis; i++)
|
||||
coords[i] = ft_mm_var->axis[i].def;
|
||||
|
||||
p = scaled_font->ft_options.base.variations;
|
||||
while (p && *p) {
|
||||
const char *start;
|
||||
const char *end, *end2;
|
||||
FT_ULong tag;
|
||||
double value;
|
||||
|
||||
while (_cairo_isspace (*p)) p++;
|
||||
|
||||
start = p;
|
||||
end = strchr (p, ',');
|
||||
if (end && (end - p < 6))
|
||||
goto skip;
|
||||
|
||||
tag = FT_MAKE_TAG(p[0], p[1], p[2], p[3]);
|
||||
|
||||
p += 4;
|
||||
while (_cairo_isspace (*p)) p++;
|
||||
if (*p == '=') p++;
|
||||
|
||||
if (p - start < 5)
|
||||
goto skip;
|
||||
|
||||
value = _cairo_strtod (p, (char **) &end2);
|
||||
|
||||
while (end2 && _cairo_isspace (*end2)) end2++;
|
||||
|
||||
if (end2 && (*end2 != ',' && *end2 != '\0'))
|
||||
goto skip;
|
||||
|
||||
for (i = 0; i < ft_mm_var->num_axis; i++) {
|
||||
if (ft_mm_var->axis[i].tag == tag) {
|
||||
coords[i] = (FT_Fixed)(value*65536);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
p = end ? end + 1 : NULL;
|
||||
}
|
||||
|
||||
current_coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis);
|
||||
ret = FT_Get_Var_Design_Coordinates (face, ft_mm_var->num_axis, current_coords);
|
||||
if (ret == 0) {
|
||||
for (i = 0; i < ft_mm_var->num_axis; i++) {
|
||||
if (coords[i] != current_coords[i])
|
||||
break;
|
||||
}
|
||||
if (i == ft_mm_var->num_axis)
|
||||
goto done;
|
||||
}
|
||||
|
||||
FT_Set_Var_Design_Coordinates (face, ft_mm_var->num_axis, coords);
|
||||
done:
|
||||
free (coords);
|
||||
free (current_coords);
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font,
|
||||
cairo_scaled_glyph_t *scaled_glyph,
|
||||
|
|
@ -2256,6 +2387,8 @@ _cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
cairo_ft_apply_variations (face, scaled_font);
|
||||
|
||||
error = FT_Load_Glyph (face,
|
||||
_cairo_scaled_glyph_index(scaled_glyph),
|
||||
load_flags);
|
||||
|
|
@ -2678,17 +2811,17 @@ _cairo_ft_is_synthetic (void *abstract_font,
|
|||
}
|
||||
|
||||
#if FREETYPE_MAJOR > 2 || ( FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 8)
|
||||
/* If FT_Get_Var_Design_Coordinates() is available, we can check if the
|
||||
/* If FT_Get_Var_Blend_Coordinates() is available, we can check if the
|
||||
* current design coordinates are the default coordinates. In this case
|
||||
* the current outlines match the font tables.
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
|
||||
FT_Get_Var_Design_Coordinates (face, num_axis, coords);
|
||||
FT_Get_Var_Blend_Coordinates (face, num_axis, coords);
|
||||
*is_synthetic = FALSE;
|
||||
for (i = 0; i < num_axis; i++) {
|
||||
if (coords[i] != mm_var->axis[i].def) {
|
||||
if (coords[i]) {
|
||||
*is_synthetic = TRUE;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2851,8 +2984,7 @@ _cairo_ft_has_color_glyphs (void *scaled)
|
|||
cairo_ft_unscaled_font_t *unscaled = ((cairo_ft_scaled_font_t *)scaled)->unscaled;
|
||||
|
||||
if (!unscaled->have_color_set) {
|
||||
FT_Face face;
|
||||
face = _cairo_ft_unscaled_font_lock_face (unscaled);
|
||||
_cairo_ft_unscaled_font_lock_face (unscaled);
|
||||
_cairo_ft_unscaled_font_unlock_face (unscaled);
|
||||
}
|
||||
|
||||
|
|
@ -3628,7 +3760,8 @@ cairo_ft_font_face_get_synthesize (cairo_font_face_t *font_face)
|
|||
* cairo_ft_font_face_create_for_ft_face()).
|
||||
*
|
||||
* cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType
|
||||
* backend font and scales it appropriately for the font. You must
|
||||
* backend font and scales it appropriately for the font and applies OpenType
|
||||
* font variations if applicable. You must
|
||||
* release the face with cairo_ft_scaled_font_unlock_face()
|
||||
* when you are done using it. Since the #FT_Face object can be
|
||||
* shared between multiple #cairo_scaled_font_t objects, you must not
|
||||
|
|
@ -3681,6 +3814,8 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
cairo_ft_apply_variations (face, scaled_font);
|
||||
|
||||
/* Note: We deliberately release the unscaled font's mutex here,
|
||||
* so that we are not holding a lock across two separate calls to
|
||||
* cairo function, (which would give the application some
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED);
|
||||
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
|
||||
|
|
@ -789,6 +793,38 @@ _cairo_get_locale_decimal_point (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
|
||||
|
||||
static locale_t C_locale;
|
||||
|
||||
static locale_t
|
||||
get_C_locale (void)
|
||||
{
|
||||
locale_t C;
|
||||
|
||||
retry:
|
||||
C = (locale_t) _cairo_atomic_ptr_get (&C_locale);
|
||||
|
||||
if (unlikely (!C)) {
|
||||
C = newlocale (LC_ALL_MASK, "C", NULL);
|
||||
|
||||
if (!_cairo_atomic_ptr_cmpxchg (&C_locale, NULL, C)) {
|
||||
freelocale (C_locale);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
double
|
||||
_cairo_strtod (const char *nptr, char **endptr)
|
||||
{
|
||||
return strtod_l (nptr, endptr, get_C_locale ());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* strtod replacement that ignores locale and only accepts decimal points */
|
||||
double
|
||||
_cairo_strtod (const char *nptr, char **endptr)
|
||||
|
|
@ -844,6 +880,7 @@ _cairo_strtod (const char *nptr, char **endptr)
|
|||
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* _cairo_fopen:
|
||||
|
|
@ -980,13 +1017,13 @@ typedef struct _cairo_intern_string {
|
|||
|
||||
static cairo_hash_table_t *_cairo_intern_string_ht;
|
||||
|
||||
static unsigned long
|
||||
_intern_string_hash (const char *str, int len)
|
||||
unsigned long
|
||||
_cairo_string_hash (const char *str, int len)
|
||||
{
|
||||
const signed char *p = (const signed char *) str;
|
||||
unsigned int h = *p;
|
||||
|
||||
for (p += 1; --len; p++)
|
||||
for (p += 1; len > 0; len--, p++)
|
||||
h = (h << 5) - h + *p;
|
||||
|
||||
return h;
|
||||
|
|
@ -1016,7 +1053,7 @@ _cairo_intern_string (const char **str_inout, int len)
|
|||
|
||||
if (len < 0)
|
||||
len = strlen (str);
|
||||
tmpl.hash_entry.hash = _intern_string_hash (str, len);
|
||||
tmpl.hash_entry.hash = _cairo_string_hash (str, len);
|
||||
tmpl.len = len;
|
||||
tmpl.string = (char *) str;
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ struct _cairo_font_options {
|
|||
cairo_hint_style_t hint_style;
|
||||
cairo_hint_metrics_t hint_metrics;
|
||||
cairo_round_glyph_positions_t round_glyph_positions;
|
||||
char *variations;
|
||||
};
|
||||
|
||||
struct _cairo_glyph_text_info {
|
||||
|
|
|
|||
|
|
@ -1430,6 +1430,13 @@ cairo_font_options_set_hint_metrics (cairo_font_options_t *options,
|
|||
cairo_public cairo_hint_metrics_t
|
||||
cairo_font_options_get_hint_metrics (const cairo_font_options_t *options);
|
||||
|
||||
cairo_public const char *
|
||||
cairo_font_options_get_variations (cairo_font_options_t *options);
|
||||
|
||||
cairo_public void
|
||||
cairo_font_options_set_variations (cairo_font_options_t *options,
|
||||
const char *variations);
|
||||
|
||||
/* This interface is for dealing with text as text, not caring about the
|
||||
font object inside the the cairo_t. */
|
||||
|
||||
|
|
|
|||
|
|
@ -912,6 +912,9 @@ _cairo_validate_text_clusters (const char *utf8,
|
|||
int num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags);
|
||||
|
||||
cairo_private unsigned long
|
||||
_cairo_string_hash (const char *str, int len);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_intern_string (const char **str_inout, int len);
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ ps-features \
|
|||
svg-clip \
|
||||
svg-surface \
|
||||
toy-font-face \
|
||||
font-variations \
|
||||
user-data
|
||||
|
||||
# A target to summarise the failures
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ test_sources = \
|
|||
font-face-get-type.c \
|
||||
font-matrix-translation.c \
|
||||
font-options.c \
|
||||
font-variations.c \
|
||||
glyph-cache-pressure.c \
|
||||
get-and-set.c \
|
||||
get-clip.c \
|
||||
|
|
|
|||
198
test/font-variations.c
Normal file
198
test/font-variations.c
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of
|
||||
* Red Hat, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Red Hat, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: MAtthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if CAIRO_HAS_FC_FONT
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include "cairo-ft.h"
|
||||
#endif
|
||||
|
||||
#define FloatToFixed(f) ((FT_Fixed)((f)*65536))
|
||||
|
||||
static cairo_test_status_t
|
||||
test_variation (cairo_test_context_t *ctx,
|
||||
const char *input,
|
||||
const char *tag,
|
||||
int def,
|
||||
float expected_value)
|
||||
{
|
||||
cairo_font_face_t *font_face;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
cairo_matrix_t matrix;
|
||||
cairo_font_options_t *options;
|
||||
cairo_status_t status;
|
||||
|
||||
FT_Face ft_face;
|
||||
FT_MM_Var *ft_mm_var;
|
||||
FT_Error ret;
|
||||
FT_Fixed coords[20];
|
||||
unsigned int i;
|
||||
|
||||
#if CAIRO_HAS_FC_FONT
|
||||
FcPattern *pattern;
|
||||
|
||||
/* we need a font that has variations */
|
||||
pattern = FcPatternBuild (NULL,
|
||||
FC_FAMILY, FcTypeString, (FcChar8*)"Adobe Variable Font Prototype",
|
||||
NULL);
|
||||
font_face = cairo_ft_font_face_create_for_pattern (pattern);
|
||||
status = cairo_font_face_status (font_face);
|
||||
FcPatternDestroy (pattern);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log (ctx, "Failed to create font face");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
cairo_matrix_init_identity (&matrix);
|
||||
options = cairo_font_options_create ();
|
||||
if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log (ctx, "Failed to create font options");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
cairo_font_options_set_variations (options, input);
|
||||
if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log (ctx, "Failed to set variations");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
if (strcmp (cairo_font_options_get_variations (options), input) != 0) {
|
||||
cairo_test_log (ctx, "Failed to verify variations");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
scaled_font = cairo_scaled_font_create (font_face, &matrix, &matrix, options);
|
||||
status = cairo_scaled_font_status (scaled_font);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log (ctx, "Failed to create scaled font");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
|
||||
if (cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS) {
|
||||
cairo_test_log (ctx, "Failed to get FT_Face");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
if (strcmp (ft_face->family_name, "Adobe Variable Font Prototype") != 0) {
|
||||
cairo_test_log (ctx, "This test requires the font \"Adobe Variable Font Prototype\" (https://github.com/adobe-fonts/adobe-variable-font-prototype/releases)");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
|
||||
if (ret != 0) {
|
||||
cairo_test_log (ctx, "Failed to get MM");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
ret = FT_Get_Var_Design_Coordinates (ft_face, 20, coords);
|
||||
if (ret != 0) {
|
||||
cairo_test_log (ctx, "Failed to get coords");
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0; i < ft_mm_var->num_axis; i++) {
|
||||
FT_Var_Axis *axis = &ft_mm_var->axis[i];
|
||||
cairo_test_log (ctx, "axis %s, value %g\n", axis->name, coords[i] / 65536.);
|
||||
}
|
||||
for (i = 0; i < ft_mm_var->num_axis; i++) {
|
||||
FT_Var_Axis *axis = &ft_mm_var->axis[i];
|
||||
if (axis->tag == FT_MAKE_TAG(tag[0], tag[1], tag[2], tag[3])) {
|
||||
if (def) {
|
||||
if (coords[i] != axis->def) {
|
||||
cairo_test_log (ctx, "Axis %s: not default value (%g != %g)",
|
||||
axis->name, coords[i] / 65536., axis->def / 65536.);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (coords[i] != FloatToFixed(expected_value)) {
|
||||
cairo_test_log (ctx, "Axis %s: not expected value (%g != %g)",
|
||||
axis->name, coords[i] / 65536., expected_value);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
cairo_ft_scaled_font_unlock_face (scaled_font);
|
||||
|
||||
cairo_scaled_font_destroy (scaled_font);
|
||||
cairo_font_options_destroy (options);
|
||||
cairo_font_face_destroy (font_face);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
#else
|
||||
return CAIRO_TEST_UNTESTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
preamble (cairo_test_context_t *ctx)
|
||||
{
|
||||
cairo_test_status_t status = CAIRO_TEST_SUCCESS;
|
||||
struct { const char *input;
|
||||
const char *tag;
|
||||
int expected_default;
|
||||
float expected_value;
|
||||
} tests[] = {
|
||||
{ "wdth=200,wght=300", "wght", 0, 300.0 }, // valid
|
||||
{ "wdth=200.5,wght=300.5", "wght", 0, 300.5 }, // valid, using decimal dot
|
||||
{ "wdth 200 , wght 300", "wght", 0, 300.0 }, // valid, without =
|
||||
{ "wght = 200", "wght", 0, 200.0 }, // valid, whitespace and =
|
||||
{ "CNTR=20", "wght", 1, 0.0 }, // valid, not setting wght
|
||||
{ "weight=100", "wght", 1, 0.0 }, // not a valid tag
|
||||
{ NULL, 0 }
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; tests[i].input; i++) {
|
||||
status = test_variation (ctx,
|
||||
tests[i].input,
|
||||
tests[i].tag,
|
||||
tests[i].expected_default,
|
||||
tests[i].expected_value);
|
||||
if (status != CAIRO_TEST_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
CAIRO_TEST (font_variations,
|
||||
"Test font variations",
|
||||
"fonts", /* keywords */
|
||||
NULL, /* requirements */
|
||||
9, 11,
|
||||
preamble, NULL)
|
||||
Loading…
Add table
Reference in a new issue