Merge branch 'font-variations'

This commit is contained in:
Behdad Esfahbod 2018-01-03 12:35:12 +00:00
commit a7a0085713
10 changed files with 486 additions and 19 deletions

View file

@ -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, [

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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 {

View file

@ -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. */

View file

@ -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);

View file

@ -158,6 +158,7 @@ ps-features \
svg-clip \
svg-surface \
toy-font-face \
font-variations \
user-data
# A target to summarise the failures

View file

@ -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
View 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)