1
/*
2
 * Copyright © 2017 Red Hat, Inc.
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software
5
 * and its documentation for any purpose is hereby granted without
6
 * fee, provided that the above copyright notice appear in all copies
7
 * and that both that copyright notice and this permission notice
8
 * appear in supporting documentation, and that the name of
9
 * Red Hat, Inc. not be used in advertising or publicity pertaining to
10
 * distribution of the software without specific, written prior
11
 * permission. Red Hat, Inc. makes no representations about the
12
 * suitability of this software for any purpose.  It is provided "as
13
 * is" without express or implied warranty.
14
 *
15
 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 *
23
 * Author: MAtthias Clasen <mclasen@redhat.com>
24
 */
25

            
26
#include "cairo-test.h"
27

            
28
#include <assert.h>
29

            
30
/* This test requires freetype2 */
31
#include <ft2build.h>
32
#include FT_FREETYPE_H
33
#include FT_MULTIPLE_MASTERS_H
34

            
35
#if CAIRO_HAS_FC_FONT
36
#include <fontconfig/fontconfig.h>
37
#endif
38

            
39
#include "cairo-ft.h"
40

            
41
#define FloatToFixed(f) ((FT_Fixed)((f)*65536))
42

            
43
static cairo_test_status_t
44
1
test_variation (cairo_test_context_t *ctx,
45
                const char           *input,
46
                const char           *tag,
47
                int                   def,
48
                float                 expected_value)
49
{
50
    cairo_font_face_t *font_face;
51
    cairo_scaled_font_t *scaled_font;
52
    cairo_matrix_t matrix;
53
    cairo_font_options_t *options;
54
    cairo_status_t status;
55

            
56
    FT_Face ft_face;
57
    FT_MM_Var *ft_mm_var;
58
    FT_Error ret;
59
    FT_Fixed coords[20];
60
    unsigned int i;
61

            
62
#if CAIRO_HAS_FC_FONT
63
    FcPattern *pattern;
64

            
65
    /* we need a font that has variations */
66
1
    pattern = FcPatternBuild (NULL,
67
                              FC_FAMILY, FcTypeString, (FcChar8*)"Adobe Variable Font Prototype",
68
                              NULL);
69
1
    font_face = cairo_ft_font_face_create_for_pattern (pattern);
70
1
    status = cairo_font_face_status (font_face);
71
1
    FcPatternDestroy (pattern);
72

            
73
1
    if (status != CAIRO_STATUS_SUCCESS) {
74
        cairo_test_log (ctx, "Failed to create font face");
75
        return CAIRO_TEST_FAILURE;
76
    }
77

            
78
1
    cairo_matrix_init_identity (&matrix);
79
1
    options = cairo_font_options_create ();
80
1
    if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) {
81
        cairo_test_log (ctx, "Failed to create font options");
82
        return CAIRO_TEST_FAILURE;
83
    }
84

            
85
1
    cairo_font_options_set_variations (options, input);
86
1
    if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) {
87
        cairo_test_log (ctx, "Failed to set variations");
88
        return CAIRO_TEST_FAILURE;
89
    }
90

            
91
1
    if (strcmp (cairo_font_options_get_variations (options), input) != 0) {
92
        cairo_test_log (ctx, "Failed to verify variations");
93
        return CAIRO_TEST_FAILURE;
94
    }
95

            
96
1
    scaled_font = cairo_scaled_font_create (font_face, &matrix, &matrix, options);
97
1
    status = cairo_scaled_font_status (scaled_font);
98

            
99
1
    if (status != CAIRO_STATUS_SUCCESS) {
100
        cairo_test_log (ctx, "Failed to create scaled font");
101
        return CAIRO_TEST_FAILURE;
102
    }
103

            
104
1
    ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
105
1
    if (cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS) {
106
        cairo_test_log (ctx, "Failed to get FT_Face");
107
        return CAIRO_TEST_FAILURE;
108
    }
109
1
    if (strcmp (ft_face->family_name, "Adobe Variable Font Prototype") != 0) {
110
1
        cairo_test_log (ctx, "This test requires the font \"Adobe Variable Font Prototype\" (https://github.com/adobe-fonts/adobe-variable-font-prototype/releases)");
111
1
        return CAIRO_TEST_UNTESTED;
112
    }
113

            
114
    ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
115
    if (ret != 0) {
116
        cairo_test_log (ctx, "Failed to get MM");
117
        return CAIRO_TEST_FAILURE;
118
    }
119

            
120
    ret = FT_Get_Var_Design_Coordinates (ft_face, 20, coords);
121
    if (ret != 0) {
122
        cairo_test_log (ctx, "Failed to get coords");
123
        return CAIRO_TEST_FAILURE;
124
    }
125

            
126
    for (i = 0; i < ft_mm_var->num_axis; i++) {
127
        FT_Var_Axis *axis = &ft_mm_var->axis[i];
128
        cairo_test_log (ctx, "axis %s, value %g\n", axis->name, coords[i] / 65536.);
129
    }
130
    for (i = 0; i < ft_mm_var->num_axis; i++) {
131
        FT_Var_Axis *axis = &ft_mm_var->axis[i];
132
        if (axis->tag == FT_MAKE_TAG(tag[0], tag[1], tag[2], tag[3])) {
133
            if (def) {
134
                if (coords[i] != axis->def) {
135
                    cairo_test_log (ctx, "Axis %s: not default value (%g != %g)",
136
                                    axis->name, coords[i] / 65536., axis->def / 65536.);
137
                    return CAIRO_TEST_FAILURE;
138
                }
139
            }
140
            else {
141
                if (coords[i] != FloatToFixed(expected_value)) {
142
                    cairo_test_log (ctx, "Axis %s: not expected value (%g != %g)",
143
                                    axis->name, coords[i] / 65536., expected_value);
144
                    return CAIRO_TEST_FAILURE;
145
                }
146
            }
147
        }
148
        else {
149
        }
150
    }
151

            
152
    cairo_ft_scaled_font_unlock_face (scaled_font);
153

            
154
    cairo_scaled_font_destroy (scaled_font);
155
    cairo_font_options_destroy (options);
156
    cairo_font_face_destroy (font_face);
157

            
158
    return CAIRO_TEST_SUCCESS;
159
#else
160
    return CAIRO_TEST_UNTESTED;
161
#endif
162
}
163

            
164
static cairo_test_status_t
165
1
preamble (cairo_test_context_t *ctx)
166
{
167
1
    cairo_test_status_t status = CAIRO_TEST_SUCCESS;
168
    struct { const char *input;
169
             const char *tag;
170
             int expected_default;
171
             float expected_value;
172
1
    } tests[] = {
173
      { "wdth=200,wght=300", "wght", 0, 300.0 }, // valid
174
      { "wdth=200.5,wght=300.5", "wght", 0, 300.5 }, // valid, using decimal dot
175
      { "wdth 200 , wght 300", "wght", 0, 300.0 }, // valid, without =
176
      { "wght = 200", "wght", 0, 200.0 }, // valid, whitespace and =
177
      { "CNTR=20", "wght", 1, 0.0 }, // valid, not setting wght
178
      { "weight=100", "wght", 1, 0.0 }, // not a valid tag
179
      { NULL, 0 }
180
    };
181
    int i;
182

            
183
1
    for (i = 0; tests[i].input; i++) {
184
1
       status = test_variation (ctx,
185
                                tests[i].input,
186
                                tests[i].tag,
187
                                tests[i].expected_default,
188
                                tests[i].expected_value);
189
1
       if (status != CAIRO_TEST_SUCCESS)
190
1
           return status;
191
    }
192

            
193
    return CAIRO_TEST_SUCCESS;
194
}
195

            
196
1
CAIRO_TEST (font_variations,
197
	    "Test font variations",
198
	    "fonts", /* keywords */
199
	    NULL, /* requirements */
200
	    9, 11,
201
	    preamble, NULL)