Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-colr-glyph-render.c
Line
Count
Source
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2022 Matthias Clasen
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * Contributor(s):
32
 *      Matthias Clasen <mclasen@redhat.com>
33
 */
34
35
#include "cairoint.h"
36
#include "cairo-array-private.h"
37
#include "cairo-ft-private.h"
38
#include "cairo-path-private.h"
39
#include "cairo-pattern-private.h"
40
41
#include <assert.h>
42
#include <math.h>
43
#include <stdio.h>
44
#include <string.h>
45
46
#ifdef _MSC_VER
47
#include <malloc.h>
48
#endif
49
50
#ifdef HAVE_ALLOCA_H
51
#include <alloca.h>
52
#endif
53
54
#if HAVE_FT_COLR_V1
55
56
#include <ft2build.h>
57
#include FT_CONFIG_OPTIONS_H
58
#include FT_COLOR_H
59
#include FT_GLYPH_H
60
#include FT_OUTLINE_H
61
#include FT_SIZES_H
62
63
/* #define DEBUG_COLR 1 */
64
65
typedef struct _cairo_colr_glyph_render {
66
    FT_Face face;
67
    FT_Color *palette;
68
    unsigned int num_palette_entries;
69
    cairo_pattern_t *foreground_marker;
70
    cairo_pattern_t *foreground_source;
71
    cairo_bool_t foreground_source_used;
72
    int level;
73
} cairo_colr_glyph_render_t;
74
75
static cairo_status_t
76
draw_paint (cairo_colr_glyph_render_t *render,
77
      FT_OpaquePaint            *paint,
78
      cairo_t                   *cr);
79
80
81
static inline double
82
double_from_16_16 (FT_Fixed f)
83
0
{
84
0
    return f / (double) (1 << 16);
85
0
}
86
87
static inline double
88
double_from_26_6 (FT_F26Dot6 f)
89
0
{
90
0
    return f / (double) (1 << 6);
91
0
}
92
93
static inline double
94
double_from_2_14 (FT_F2Dot14 f)
95
0
{
96
0
    return f / (double) (1 << 14);
97
0
}
98
99
static inline double
100
interpolate (double f0, double f1, double f)
101
0
{
102
0
    return f0 + f * (f1 - f0);
103
0
}
104
105
static inline void
106
interpolate_points (cairo_point_double_t *p0,
107
        cairo_point_double_t *p1,
108
        double                f,
109
        cairo_point_double_t *out)
110
0
{
111
0
  out->x = interpolate (p0->x, p1->x, f);
112
0
  out->y = interpolate (p0->y, p1->y, f);
113
0
}
114
115
static inline void
116
interpolate_colors (cairo_color_t *c0,
117
        cairo_color_t *c1,
118
        double         f,
119
        cairo_color_t *out)
120
0
{
121
0
    out->red = interpolate (c0->red, c1->red, f);
122
0
    out->green = interpolate (c0->green, c1->green, f);
123
0
    out->blue = interpolate (c0->blue, c1->blue, f);
124
0
    out->alpha = interpolate (c0->alpha, c1->alpha, f);
125
0
}
126
127
static inline double
128
dot (cairo_point_double_t p, cairo_point_double_t q)
129
0
{
130
0
    return p.x * q.x + p.y * q.y;
131
0
}
132
133
static inline cairo_point_double_t
134
normalize (cairo_point_double_t p)
135
0
{
136
0
    double len = sqrt (dot (p, p));
137
138
0
    return (cairo_point_double_t) { p.x / len, p.y / len };
139
0
}
140
141
static inline cairo_point_double_t
142
sum (cairo_point_double_t p, cairo_point_double_t q)
143
0
{
144
0
    return (cairo_point_double_t) { p.x + q.x, p.y + q.y };
145
0
}
146
147
static inline cairo_point_double_t
148
difference (cairo_point_double_t p, cairo_point_double_t q)
149
0
{
150
0
    return (cairo_point_double_t) { p.x - q.x, p.y - q.y };
151
0
}
152
153
static inline cairo_point_double_t
154
scale (cairo_point_double_t p, double f)
155
0
{
156
0
    return (cairo_point_double_t) { p.x * f, p.y * f };
157
0
}
158
159
static cairo_operator_t
160
cairo_operator_from_ft_composite_mode (FT_Composite_Mode mode)
161
0
{
162
0
    switch (mode)
163
0
    {
164
0
  case FT_COLR_COMPOSITE_CLEAR: return CAIRO_OPERATOR_CLEAR;
165
0
  case FT_COLR_COMPOSITE_SRC: return CAIRO_OPERATOR_SOURCE;
166
0
  case FT_COLR_COMPOSITE_DEST: return CAIRO_OPERATOR_DEST;
167
0
  case FT_COLR_COMPOSITE_SRC_OVER: return CAIRO_OPERATOR_OVER;
168
0
  case FT_COLR_COMPOSITE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
169
0
  case FT_COLR_COMPOSITE_SRC_IN: return CAIRO_OPERATOR_IN;
170
0
  case FT_COLR_COMPOSITE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
171
0
  case FT_COLR_COMPOSITE_SRC_OUT: return CAIRO_OPERATOR_OUT;
172
0
  case FT_COLR_COMPOSITE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
173
0
  case FT_COLR_COMPOSITE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
174
0
  case FT_COLR_COMPOSITE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
175
0
  case FT_COLR_COMPOSITE_XOR: return CAIRO_OPERATOR_XOR;
176
0
  case FT_COLR_COMPOSITE_PLUS: return CAIRO_OPERATOR_ADD;
177
0
  case FT_COLR_COMPOSITE_SCREEN: return CAIRO_OPERATOR_SCREEN;
178
0
  case FT_COLR_COMPOSITE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
179
0
  case FT_COLR_COMPOSITE_DARKEN: return CAIRO_OPERATOR_DARKEN;
180
0
  case FT_COLR_COMPOSITE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
181
0
  case FT_COLR_COMPOSITE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
182
0
  case FT_COLR_COMPOSITE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
183
0
  case FT_COLR_COMPOSITE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
184
0
  case FT_COLR_COMPOSITE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
185
0
  case FT_COLR_COMPOSITE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
186
0
  case FT_COLR_COMPOSITE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
187
0
  case FT_COLR_COMPOSITE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
188
0
  case FT_COLR_COMPOSITE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
189
0
  case FT_COLR_COMPOSITE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
190
0
  case FT_COLR_COMPOSITE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
191
0
  case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
192
0
  case FT_COLR_COMPOSITE_MAX:
193
0
  default:
194
0
      ASSERT_NOT_REACHED;
195
0
    }
196
0
}
197
198
static cairo_extend_t
199
cairo_extend_from_ft_paint_extend (FT_PaintExtend extend)
200
0
{
201
0
    switch (extend)
202
0
    {
203
0
  case FT_COLR_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
204
0
  case FT_COLR_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
205
0
  case FT_COLR_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
206
0
  default:
207
0
      ASSERT_NOT_REACHED;
208
0
    }
209
0
}
210
211
static cairo_status_t
212
draw_paint_colr_layers (cairo_colr_glyph_render_t *render,
213
                        FT_PaintColrLayers        *colr_layers,
214
                        cairo_t                   *cr)
215
0
{
216
0
    FT_OpaquePaint paint;
217
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
218
219
#if DEBUG_COLR
220
    printf ("%*sDraw PaintColrLayers\n", 2 * render->level, "");
221
#endif
222
223
0
    while (FT_Get_Paint_Layers (render->face, &colr_layers->layer_iterator, &paint)) {
224
0
  cairo_push_group (cr);
225
0
  status = draw_paint (render, &paint, cr);
226
0
  cairo_pop_group_to_source (cr);
227
0
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
228
0
  cairo_paint (cr);
229
230
0
  if (unlikely (status))
231
0
      break;
232
0
    }
233
234
0
    return status;
235
0
}
236
237
static void
238
get_palette_color (cairo_colr_glyph_render_t *render,
239
       FT_ColorIndex             *ci,
240
       cairo_color_t             *color,
241
       double                    *colr_alpha,
242
       cairo_bool_t              *is_foreground_color)
243
0
{
244
0
    cairo_bool_t foreground = FALSE;
245
246
0
    if (ci->palette_index == 0xffff || ci->palette_index >= render->num_palette_entries) {
247
0
  color->red = 0;
248
0
  color->green = 0;
249
0
  color->blue = 0;
250
0
  color->alpha = 1;
251
0
  foreground = TRUE;
252
0
    } else {
253
0
  FT_Color c = render->palette[ci->palette_index];
254
0
  color->red = c.red / 255.0;
255
0
  color->green = c.green / 255.0;
256
0
  color->blue = c.blue / 255.0;
257
0
  color->alpha = c.alpha / 255.0;
258
0
    }
259
260
0
    *colr_alpha = double_from_2_14 (ci->alpha);
261
0
    *is_foreground_color = foreground;
262
0
}
263
264
static cairo_status_t
265
draw_paint_solid (cairo_colr_glyph_render_t *render,
266
                  FT_PaintSolid             *solid,
267
                  cairo_t                   *cr)
268
0
{
269
0
    cairo_color_t color;
270
0
    double colr_alpha;
271
0
    cairo_bool_t is_foreground_color;
272
273
#if DEBUG_COLR
274
    printf ("%*sDraw PaintSolid\n", 2 * render->level, "");
275
#endif
276
277
0
    get_palette_color (render, &solid->color, &color, &colr_alpha, &is_foreground_color);
278
0
    if (is_foreground_color) {
279
0
  cairo_set_source (cr, render->foreground_marker);
280
0
  cairo_paint_with_alpha (cr, colr_alpha);
281
0
    } else {
282
0
  cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * colr_alpha);
283
0
  cairo_paint (cr);
284
0
    }
285
286
0
    return CAIRO_STATUS_SUCCESS;
287
0
}
288
289
typedef struct _cairo_colr_color_stop {
290
    cairo_color_t color;
291
    double position;
292
} cairo_colr_color_stop_t;
293
294
typedef struct _cairo_colr_color_line {
295
    int n_stops;
296
    cairo_colr_color_stop_t *stops;
297
} cairo_colr_color_line_t;
298
299
static void
300
free_colorline (cairo_colr_color_line_t *cl)
301
0
{
302
0
    free (cl->stops);
303
0
    free (cl);
304
0
}
305
306
static int
307
_compare_stops (const void *p1, const void *p2)
308
0
{
309
0
    const cairo_colr_color_stop_t *c1 = p1;
310
0
    const cairo_colr_color_stop_t *c2 = p2;
311
312
0
    if (c1->position < c2->position)
313
0
  return -1;
314
0
    else if (c1->position > c2->position)
315
0
  return 1;
316
0
    else
317
0
  return 0;
318
0
}
319
320
static cairo_colr_color_line_t *
321
read_colorline (cairo_colr_glyph_render_t *render,
322
                FT_ColorLine              *colorline)
323
0
{
324
0
    cairo_colr_color_line_t *cl;
325
0
    FT_ColorStop stop;
326
0
    int i;
327
0
    double colr_alpha;
328
0
    cairo_bool_t is_foreground_color;
329
330
0
    cl = _cairo_calloc (sizeof (cairo_colr_color_line_t));
331
0
    if (unlikely (cl == NULL))
332
0
  return NULL;
333
334
0
    cl->n_stops = colorline->color_stop_iterator.num_color_stops;
335
0
    cl->stops = _cairo_calloc_ab (cl->n_stops, sizeof (cairo_colr_color_stop_t));
336
0
    if (unlikely (cl->stops == NULL)) {
337
0
  free (cl);
338
0
  return NULL;
339
0
    }
340
341
0
    i = 0;
342
0
    while (FT_Get_Colorline_Stops (render->face, &stop, &colorline->color_stop_iterator)) {
343
0
  cl->stops[i].position = double_from_16_16 (stop.stop_offset);
344
0
  get_palette_color (render, &stop.color, &cl->stops[i].color, &colr_alpha, &is_foreground_color);
345
0
  if (is_foreground_color) {
346
0
      double red, green, blue, alpha;
347
0
      if (cairo_pattern_get_rgba (render->foreground_source,
348
0
          &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS)
349
0
      {
350
0
    cl->stops[i].color.red = red;
351
0
    cl->stops[i].color.green = green;
352
0
    cl->stops[i].color.blue = blue;
353
0
    cl->stops[i].color.alpha = alpha * colr_alpha;
354
0
    render->foreground_source_used = TRUE;
355
0
      }
356
0
      else
357
0
      {
358
0
    cl->stops[i].color.red = 0;
359
0
    cl->stops[i].color.green = 0;
360
0
    cl->stops[i].color.blue = 0;
361
0
    cl->stops[i].color.alpha = colr_alpha;
362
0
      }
363
0
  } else {
364
0
      cl->stops[i].color.alpha *= colr_alpha;
365
0
  }
366
0
  i++;
367
0
    }
368
369
0
    qsort (cl->stops, cl->n_stops, sizeof (cairo_colr_color_stop_t), _compare_stops);
370
371
0
    return cl;
372
0
}
373
374
static void
375
reduce_anchors (FT_PaintLinearGradient *gradient,
376
                cairo_point_double_t   *pp0,
377
                cairo_point_double_t   *pp1)
378
0
{
379
0
    cairo_point_double_t p0, p1, p2;
380
0
    cairo_point_double_t q1, q2;
381
0
    double s;
382
0
    double k;
383
384
0
    p0.x = double_from_16_16 (gradient->p0.x);
385
0
    p0.y = double_from_16_16 (gradient->p0.y);
386
0
    p1.x = double_from_16_16 (gradient->p1.x);
387
0
    p1.y = double_from_16_16 (gradient->p1.y);
388
0
    p2.x = double_from_16_16 (gradient->p2.x);
389
0
    p2.y = double_from_16_16 (gradient->p2.y);
390
391
0
    q2.x = p2.x - p0.x;
392
0
    q2.y = p2.y - p0.y;
393
0
    q1.x = p1.x - p0.x;
394
0
    q1.y = p1.y - p0.y;
395
396
0
    s = q2.x * q2.x + q2.y * q2.y;
397
0
    if (s < 0.000001)
398
0
    {
399
0
  pp0->x = p0.x; pp0->y = p0.y;
400
0
  pp1->x = p1.x; pp1->y = p1.y;
401
0
  return;
402
0
    }
403
404
0
    k = (q2.x * q1.x + q2.y * q1.y) / s;
405
0
    pp0->x = p0.x;
406
0
    pp0->y = p0.y;
407
0
    pp1->x = p1.x - k * q2.x;
408
0
    pp1->y = p1.y - k * q2.y;
409
0
}
410
411
static void
412
normalize_colorline (cairo_colr_color_line_t *cl,
413
                     double                  *out_min,
414
                     double                  *out_max)
415
0
{
416
0
    double min, max;
417
418
0
    *out_min = 0.;
419
0
    *out_max = 1.;
420
421
0
    min = max = cl->stops[0].position;
422
0
    for (int i = 0; i < cl->n_stops; i++) {
423
0
  cairo_colr_color_stop_t *stop = &cl->stops[i];
424
0
  min = MIN (min, stop->position);
425
0
  max = MAX (max, stop->position);
426
0
    }
427
428
0
    if (min != max) {
429
0
  for (int i = 0; i < cl->n_stops; i++) {
430
0
      cairo_colr_color_stop_t *stop = &cl->stops[i];
431
0
      stop->position = (stop->position - min) / (max - min);
432
0
        }
433
0
  *out_min = min;
434
0
  *out_max = max;
435
0
    }
436
0
}
437
438
static cairo_status_t
439
draw_paint_linear_gradient (cairo_colr_glyph_render_t *render,
440
                            FT_PaintLinearGradient    *gradient,
441
                            cairo_t                   *cr)
442
0
{
443
0
    cairo_colr_color_line_t *cl;
444
0
    cairo_point_double_t p0, p1;
445
0
    cairo_point_double_t pp0, pp1;
446
0
    cairo_pattern_t *pattern;
447
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
448
0
    double min, max;
449
450
#if DEBUG_COLR
451
    printf ("%*sDraw PaintLinearGradient\n", 2 * render->level, "");
452
#endif
453
454
0
    cl = read_colorline (render, &gradient->colorline);
455
0
    if (unlikely (cl == NULL))
456
0
  return CAIRO_STATUS_NO_MEMORY;
457
458
    /* cairo only allows stop positions between 0 and 1 */
459
0
    normalize_colorline (cl, &min, &max);
460
0
    reduce_anchors (gradient, &p0, &p1);
461
0
    interpolate_points (&p0, &p1, min, &pp0);
462
0
    interpolate_points (&p0, &p1, max, &pp1);
463
464
0
    pattern = cairo_pattern_create_linear (pp0.x, pp0.y, pp1.x, pp1.y);
465
466
0
    cairo_pattern_set_extend (pattern, cairo_extend_from_ft_paint_extend (gradient->colorline.extend));
467
468
0
    for (int i = 0; i < cl->n_stops; i++) {
469
0
  cairo_colr_color_stop_t *stop = &cl->stops[i];
470
0
  cairo_pattern_add_color_stop_rgba (pattern, stop->position,
471
0
             stop->color.red, stop->color.green, stop->color.blue, stop->color.alpha);
472
0
    }
473
474
0
    cairo_set_source (cr, pattern);
475
0
    cairo_paint (cr);
476
477
0
    cairo_pattern_destroy (pattern);
478
479
0
    free_colorline (cl);
480
481
0
    return status;
482
0
}
483
484
static cairo_status_t
485
draw_paint_radial_gradient (cairo_colr_glyph_render_t *render,
486
                            FT_PaintRadialGradient *gradient,
487
                            cairo_t *cr)
488
0
{
489
0
    cairo_colr_color_line_t *cl;
490
0
    cairo_point_double_t start, end;
491
0
    cairo_point_double_t start1, end1;
492
0
    double start_radius, end_radius;
493
0
    double start_radius1, end_radius1;
494
0
    double min, max;
495
0
    cairo_pattern_t *pattern;
496
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
497
498
#if DEBUG_COLR
499
    printf ("%*sDraw PaintRadialGradient\n", 2 * render->level, "");
500
#endif
501
502
0
    cl = read_colorline (render, &gradient->colorline);
503
0
    if (unlikely (cl == NULL))
504
0
  return CAIRO_STATUS_NO_MEMORY;
505
506
0
    start.x = double_from_16_16 (gradient->c0.x);
507
0
    start.y = double_from_16_16 (gradient->c0.y);
508
0
    end.x = double_from_16_16 (gradient->c1.x);
509
0
    end.y = double_from_16_16 (gradient->c1.y);
510
511
0
    start_radius = double_from_16_16 (gradient->r0);
512
0
    end_radius = double_from_16_16 (gradient->r1);
513
514
    /* cairo only allows stop positions between 0 and 1 */
515
0
    normalize_colorline (cl, &min, &max);
516
0
    interpolate_points (&start, &end, min, &start1);
517
0
    interpolate_points (&start, &end, max, &end1);
518
0
    start_radius1 = interpolate (start_radius, end_radius, min);
519
0
    end_radius1 = interpolate (start_radius, end_radius, max);
520
521
0
    pattern = cairo_pattern_create_radial (start1.x, start1.y, start_radius1,
522
0
             end1.x, end1.y, end_radius1);
523
524
0
    cairo_pattern_set_extend (pattern, cairo_extend_from_ft_paint_extend (gradient->colorline.extend));
525
526
0
    for (int i = 0; i < cl->n_stops; i++) {
527
0
  cairo_colr_color_stop_t *stop = &cl->stops[i];
528
0
  cairo_pattern_add_color_stop_rgba (pattern, stop->position,
529
0
             stop->color.red, stop->color.green, stop->color.blue, stop->color.alpha);
530
0
    }
531
532
0
    cairo_set_source (cr, pattern);
533
0
    cairo_paint (cr);
534
535
0
    cairo_pattern_destroy (pattern);
536
537
0
    free_colorline (cl);
538
539
0
    return status;
540
0
}
541
542
typedef struct {
543
    cairo_point_double_t center, p0, c0, c1, p1;
544
    cairo_color_t color0, color1;
545
} cairo_colr_gradient_patch_t;
546
547
static void
548
add_patch (cairo_pattern_t             *pattern,
549
     cairo_point_double_t        *center,
550
     cairo_colr_gradient_patch_t *p)
551
0
{
552
0
    cairo_mesh_pattern_begin_patch (pattern);
553
0
    cairo_mesh_pattern_move_to (pattern, center->x, center->y);
554
0
    cairo_mesh_pattern_line_to (pattern, p->p0.x, p->p0.y);
555
0
    cairo_mesh_pattern_curve_to (pattern,
556
0
         p->c0.x, p->c0.y,
557
0
         p->c1.x, p->c1.y,
558
0
         p->p1.x, p->p1.y);
559
0
    cairo_mesh_pattern_line_to (pattern, center->x, center->y);
560
0
    cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
561
0
                p->color0.red,
562
0
                p->color0.green,
563
0
                p->color0.blue,
564
0
                p->color0.alpha);
565
0
    cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
566
0
                p->color0.red,
567
0
                p->color0.green,
568
0
                p->color0.blue,
569
0
                p->color0.alpha);
570
0
    cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
571
0
                p->color1.red,
572
0
                p->color1.green,
573
0
                p->color1.blue,
574
0
                p->color1.alpha);
575
0
    cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
576
0
                p->color1.red,
577
0
                p->color1.green,
578
0
                p->color1.blue,
579
0
                p->color1.alpha);
580
0
    cairo_mesh_pattern_end_patch (pattern);
581
0
}
582
583
0
#define MAX_ANGLE (M_PI / 8.)
584
585
static void
586
add_sweep_gradient_patches1 (cairo_point_double_t *center,
587
           double                radius,
588
                             double                a0,
589
           cairo_color_t        *c0,
590
                             double                a1,
591
           cairo_color_t        *c1,
592
                             cairo_pattern_t      *pattern)
593
0
{
594
595
0
    int num_splits;
596
0
    cairo_point_double_t p0;
597
0
    cairo_color_t color0, color1;
598
599
0
    num_splits = ceilf (fabs (a1 - a0) / MAX_ANGLE);
600
0
    p0 = (cairo_point_double_t) { cosf (a0), sinf (a0) };
601
0
    color0 = *c0;
602
603
0
    for (int a = 0; a < num_splits; a++) {
604
0
  double k = (a + 1.) / num_splits;
605
0
  double angle1;
606
0
  cairo_point_double_t p1;
607
0
  cairo_point_double_t A, U;
608
0
  cairo_point_double_t C0, C1;
609
0
  cairo_colr_gradient_patch_t patch;
610
611
0
  angle1 = interpolate (a0, a1, k);
612
0
  interpolate_colors (c0, c1, k, &color1);
613
614
0
  patch.color0 = color0;
615
0
  patch.color1 = color1;
616
617
0
  p1 = (cairo_point_double_t) { cosf (angle1), sinf (angle1) };
618
0
  patch.p0 = sum (*center, scale (p0, radius));
619
0
  patch.p1 = sum (*center, scale (p1, radius));
620
621
0
  A = normalize (sum (p0, p1));
622
0
  U = (cairo_point_double_t) { -A.y, A.x };
623
0
  C0 = sum (A, scale (U, dot (difference (p0, A), p0) / dot (U, p0)));
624
0
  C1 = sum (A, scale (U, dot (difference (p1, A), p1) / dot (U, p1)));
625
0
  patch.c0 = sum (*center, scale (sum (C0, scale (difference (C0, p0), 0.33333)), radius));
626
0
  patch.c1 = sum (*center, scale (sum (C1, scale (difference (C1, p1), 0.33333)), radius));
627
628
0
  add_patch (pattern, center, &patch);
629
630
0
  p0 = p1;
631
0
  color0 = color1;
632
0
    }
633
0
}
634
635
static void
636
add_sweep_gradient_patches (cairo_colr_color_line_t *cl,
637
                            cairo_extend_t           extend,
638
                            cairo_point_double_t    *center,
639
                            double                   radius,
640
                            double                   start_angle,
641
                            double                   end_angle,
642
                            cairo_pattern_t         *pattern)
643
0
{
644
0
    double *angles;
645
0
    cairo_color_t color0, color1;
646
647
0
    if (start_angle == end_angle) {
648
0
  if (extend == CAIRO_EXTEND_PAD) {
649
0
      if (start_angle > 0)
650
0
    add_sweep_gradient_patches1 (center, radius,
651
0
               0.,          &cl->stops[0].color,
652
0
               start_angle, &cl->stops[0].color,
653
0
               pattern);
654
0
      if (end_angle < 2 * M_PI)
655
0
    add_sweep_gradient_patches1 (center, radius,
656
0
               end_angle, &cl->stops[cl->n_stops - 1].color,
657
0
               2 * M_PI,  &cl->stops[cl->n_stops - 1].color,
658
0
               pattern);
659
0
        }
660
0
  return;
661
0
    }
662
663
0
    assert (start_angle != end_angle);
664
665
0
    angles = alloca (sizeof (double) * cl->n_stops);
666
667
0
    for (int i = 0; i < cl->n_stops; i++)
668
0
  angles[i] = start_angle + cl->stops[i].position * (end_angle - start_angle);
669
670
    /* handle directions */
671
0
    if (end_angle < start_angle) {
672
0
  for (int i = 0; i < cl->n_stops - 1 - i; i++) {
673
0
      cairo_colr_color_stop_t stop = cl->stops[i];
674
0
      double a = angles[i];
675
0
      cl->stops[i] = cl->stops[cl->n_stops - 1 - i];
676
0
      cl->stops[cl->n_stops - 1 - i] = stop;
677
0
      angles[i] = angles[cl->n_stops - 1 - i];
678
0
      angles[cl->n_stops - 1 - i] = a;
679
0
        }
680
0
    }
681
682
0
    if (extend == CAIRO_EXTEND_PAD)
683
0
    {
684
0
  int pos;
685
686
0
  color0 = cl->stops[0].color;
687
0
  for (pos = 0; pos < cl->n_stops; pos++) {
688
0
      if (angles[pos] >= 0) {
689
0
    if (pos > 0) {
690
0
        double k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
691
0
        interpolate_colors (&cl->stops[pos - 1].color, &cl->stops[pos].color, k, &color0);
692
0
                }
693
0
    break;
694
0
            }
695
0
        }
696
0
  if (pos == cl->n_stops) {
697
      /* everything is below 0 */
698
0
      color0 = cl->stops[cl->n_stops - 1].color;
699
0
      add_sweep_gradient_patches1 (center, radius,
700
0
           0.,       &color0,
701
0
           2 * M_PI, &color0,
702
0
           pattern);
703
0
      return;
704
0
        }
705
706
0
  add_sweep_gradient_patches1 (center, radius,
707
0
             0.,          &color0,
708
0
             angles[pos], &cl->stops[pos].color,
709
0
             pattern);
710
711
0
  for (pos++; pos < cl->n_stops; pos++) {
712
0
      if (angles[pos] <= 2 * M_PI) {
713
0
    add_sweep_gradient_patches1 (center, radius,
714
0
               angles[pos - 1], &cl->stops[pos - 1].color,
715
0
               angles[pos],     &cl->stops[pos].color,
716
0
               pattern);
717
0
            } else {
718
0
    double k = (2 * M_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
719
0
    interpolate_colors (&cl->stops[pos - 1].color, &cl->stops[pos].color, k, &color1);
720
0
    add_sweep_gradient_patches1 (center, radius,
721
0
               angles[pos - 1], &cl->stops[pos - 1].color,
722
0
               2 * M_PI,        &color1,
723
0
               pattern);
724
0
    break;
725
0
            }
726
0
        }
727
728
0
  if (pos == cl->n_stops) {
729
      /* everything is below 2*M_PI */
730
0
      color0 = cl->stops[cl->n_stops - 1].color;
731
0
      add_sweep_gradient_patches1 (center, radius,
732
0
           angles[cl->n_stops - 1], &color0,
733
0
           2 * M_PI,                &color0,
734
0
           pattern);
735
0
      return;
736
0
        }
737
0
    } else {
738
0
  int k;
739
0
  double span;
740
741
0
  span = angles[cl->n_stops - 1] - angles[0];
742
0
  k = 0;
743
0
  if (angles[0] >= 0) {
744
0
      double ss = angles[0];
745
0
      while (ss > 0) {
746
0
    if (span > 0) {
747
0
        ss -= span;
748
0
        k--;
749
0
                } else {
750
0
        ss += span;
751
0
        k++;
752
0
                }
753
0
            }
754
0
        }
755
0
  else if (angles[0] < 0)
756
0
        {
757
0
      double ee = angles[cl->n_stops - 1];
758
0
      while (ee < 0) {
759
0
    if (span > 0) {
760
0
        ee += span;
761
0
        k++;
762
0
                } else {
763
0
        ee -= span;
764
0
        k--;
765
0
                }
766
0
            }
767
0
        }
768
769
  //assert (angles[0] + k * span <= 0 && 0 < angles[cl->n_stops - 1] + k * span);
770
771
0
  for (int l = k; TRUE; l++) {
772
0
      for (int i = 1; i < cl->n_stops; i++) {
773
0
    double a0, a1;
774
0
    cairo_color_t *c0, *c1;
775
776
0
    if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT)) {
777
0
        a0 = angles[0] + angles[cl->n_stops - 1] - angles[cl->n_stops - 1 - (i-1)] + l * span;
778
0
        a1 = angles[0] + angles[cl->n_stops - 1] - angles[cl->n_stops - 1 - i] + l * span;
779
0
        c0 = &cl->stops[cl->n_stops - 1 - (i-1)].color;
780
0
        c1 = &cl->stops[cl->n_stops - 1 - i].color;
781
0
                } else {
782
0
        a0 = angles[i-1] + l * span;
783
0
        a1 = angles[i] + l * span;
784
0
        c0 = &cl->stops[i-1].color;
785
0
        c1 = &cl->stops[i].color;
786
0
                }
787
788
0
    if (a1 < 0)
789
0
        continue;
790
791
0
    if (a0 < 0) {
792
0
        cairo_color_t color;
793
0
        double f = (0 - a0)/(a1 - a0);
794
0
        interpolate_colors (c0, c1, f, &color);
795
0
        add_sweep_gradient_patches1 (center, radius,
796
0
             0,  &color,
797
0
             a1, c1,
798
0
             pattern);
799
0
                } else if (a1 >= 2 * M_PI) {
800
0
        cairo_color_t color;
801
0
        double f = (2 * M_PI - a0)/(a1 - a0);
802
0
        interpolate_colors (c0, c1, f, &color);
803
0
        add_sweep_gradient_patches1 (center, radius,
804
0
             a0,       c0,
805
0
             2 * M_PI, &color,
806
0
             pattern);
807
0
        return;
808
0
                } else {
809
0
        add_sweep_gradient_patches1 (center, radius,
810
0
             a0, c0,
811
0
             a1, c1,
812
0
             pattern);
813
0
                }
814
0
            }
815
0
        }
816
0
    }
817
0
}
818
819
static cairo_status_t
820
draw_paint_sweep_gradient (cairo_colr_glyph_render_t *render,
821
                           FT_PaintSweepGradient     *gradient,
822
                           cairo_t                   *cr)
823
0
{
824
0
    cairo_colr_color_line_t *cl;
825
0
    cairo_point_double_t center;
826
0
    double start_angle, end_angle;
827
0
    double x1, y1, x2, y2;
828
0
    double max_x, max_y, R;
829
0
    cairo_pattern_t *pattern;
830
0
    cairo_extend_t extend;
831
832
#if DEBUG_COLR
833
    printf ("%*sDraw PaintSweepGradient\n", 2 * render->level, "");
834
#endif
835
836
0
    cl = read_colorline (render, &gradient->colorline);
837
0
    if (unlikely (cl == NULL))
838
0
  return CAIRO_STATUS_NO_MEMORY;
839
840
0
    center.x = double_from_16_16 (gradient->center.x);
841
0
    center.y = double_from_16_16 (gradient->center.y);
842
0
    start_angle = (double_from_16_16 (gradient->start_angle) + 1) * M_PI;
843
0
    end_angle = (double_from_16_16 (gradient->end_angle) + 1) * M_PI;
844
845
0
    pattern = cairo_pattern_create_mesh ();
846
847
0
    cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
848
0
    max_x = MAX ((x1 - center.x) * (x1 - center.x), (x2 - center.x) * (x2 - center.x));
849
0
    max_y = MAX ((y1 - center.y) * (y1 - center.y), (y2 - center.y) * (y2 - center.y));
850
0
    R = sqrt (max_x + max_y);
851
852
0
    extend = cairo_extend_from_ft_paint_extend (gradient->colorline.extend);
853
854
0
    add_sweep_gradient_patches (cl, extend, &center, R, start_angle, end_angle, pattern);
855
856
0
    cairo_set_source (cr, pattern);
857
0
    cairo_paint (cr);
858
859
0
    cairo_pattern_destroy (pattern);
860
861
0
    free_colorline (cl);
862
863
0
    return CAIRO_STATUS_SUCCESS;
864
0
}
865
866
static cairo_status_t
867
draw_paint_glyph (cairo_colr_glyph_render_t *render,
868
                  FT_PaintGlyph             *glyph,
869
                  cairo_t                   *cr)
870
0
{
871
0
    cairo_path_fixed_t *path_fixed;
872
0
    cairo_path_t *path;
873
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
874
0
    FT_Error error;
875
876
#if DEBUG_COLR
877
    printf ("%*sDraw PaintGlyph\n", 2 * render->level, "");
878
#endif
879
880
0
    error = FT_Load_Glyph (render->face, glyph->glyphID, FT_LOAD_DEFAULT);
881
0
    status = _cairo_ft_to_cairo_error (error);
882
0
    if (unlikely (status))
883
0
        return status;
884
885
0
    status = _cairo_ft_face_decompose_glyph_outline (render->face, &path_fixed);
886
0
    if (unlikely (status))
887
0
        return status;
888
889
0
    cairo_save (cr);
890
0
    cairo_identity_matrix (cr);
891
0
    path = _cairo_path_create (path_fixed, cr);
892
0
    _cairo_path_fixed_destroy (path_fixed);
893
0
    cairo_restore (cr);
894
895
0
    cairo_save (cr);
896
897
0
    cairo_new_path (cr);
898
0
    cairo_append_path (cr, path);
899
0
    cairo_path_destroy (path);
900
0
    cairo_clip (cr);
901
902
0
    status = draw_paint (render, &glyph->paint, cr);
903
904
0
    cairo_restore (cr);
905
906
0
    return status;
907
0
}
908
909
static cairo_status_t draw_colr_glyph (cairo_colr_glyph_render_t *render,
910
               unsigned long              glyph,
911
                                       FT_Color_Root_Transform    root,
912
                                       cairo_t                   *cr);
913
914
static cairo_status_t
915
draw_paint_colr_glyph (cairo_colr_glyph_render_t *render,
916
                       FT_PaintColrGlyph *colr_glyph,
917
                       cairo_t *cr)
918
0
{
919
#if DEBUG_COLR
920
    printf ("%*sDraw PaintColrGlyph\n", 2 * render->level, "");
921
#endif
922
923
0
    return draw_colr_glyph (render, colr_glyph->glyphID, FT_COLOR_NO_ROOT_TRANSFORM, cr);
924
0
}
925
926
static cairo_status_t
927
draw_paint_transform (cairo_colr_glyph_render_t *render,
928
                      FT_PaintTransform *transform,
929
                      cairo_t *cr)
930
0
{
931
0
    cairo_matrix_t t;
932
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
933
934
#if DEBUG_COLR
935
    printf ("%*sDraw PaintTransform\n", 2 * render->level, "");
936
#endif
937
938
0
    cairo_matrix_init (&t,
939
0
           double_from_16_16 (transform->affine.xx),
940
0
           double_from_16_16 (transform->affine.yx),
941
0
           double_from_16_16 (transform->affine.xy),
942
0
           double_from_16_16 (transform->affine.yy),
943
0
           double_from_16_16 (transform->affine.dx),
944
0
           double_from_16_16 (transform->affine.dy));
945
946
0
    cairo_save (cr);
947
948
0
    cairo_transform (cr, &t);
949
0
    status = draw_paint (render, &transform->paint, cr);
950
951
0
    cairo_restore (cr);
952
953
0
    return status;
954
0
}
955
956
static cairo_status_t
957
draw_paint_translate (cairo_colr_glyph_render_t *render,
958
                      FT_PaintTranslate *translate,
959
                      cairo_t *cr)
960
0
{
961
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
962
963
#if DEBUG_COLR
964
    printf ("%*sDraw PaintTranslate\n", 2 * render->level, "");
965
#endif
966
967
0
    cairo_save (cr);
968
969
0
    cairo_translate (cr, double_from_16_16 (translate->dx), double_from_16_16 (translate->dy));
970
0
    status = draw_paint (render, &translate->paint, cr);
971
972
0
    cairo_restore (cr);
973
974
0
    return status;
975
0
}
976
977
static cairo_status_t
978
draw_paint_rotate (cairo_colr_glyph_render_t *render,
979
                   FT_PaintRotate *rotate,
980
                   cairo_t *cr)
981
0
{
982
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
983
984
#if DEBUG_COLR
985
    printf ("%*sDraw PaintRotate\n", 2 * render->level, "");
986
#endif
987
988
0
    cairo_save (cr);
989
990
0
    cairo_translate (cr, double_from_16_16 (rotate->center_x), double_from_16_16 (rotate->center_y));
991
0
    cairo_rotate (cr, double_from_16_16 (rotate->angle) * M_PI);
992
0
    cairo_translate (cr, - double_from_16_16 (rotate->center_x), - double_from_16_16 (rotate->center_y));
993
0
    status = draw_paint (render, &rotate->paint, cr);
994
995
0
    cairo_restore (cr);
996
997
0
    return status;
998
0
}
999
1000
static cairo_status_t
1001
draw_paint_scale (cairo_colr_glyph_render_t *render,
1002
                  FT_PaintScale *scale,
1003
                  cairo_t *cr)
1004
0
{
1005
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1006
1007
#if DEBUG_COLR
1008
    printf ("%*sDraw PaintScale\n", 2 * render->level, "");
1009
#endif
1010
1011
0
    cairo_save (cr);
1012
1013
0
    cairo_translate (cr, double_from_16_16 (scale->center_x), double_from_16_16 (scale->center_y));
1014
0
    cairo_scale (cr, double_from_16_16 (scale->scale_x), double_from_16_16 (scale->scale_y));
1015
0
    cairo_translate (cr, - double_from_16_16 (scale->center_x), - double_from_16_16 (scale->center_y));
1016
0
    status = draw_paint (render, &scale->paint, cr);
1017
1018
0
    cairo_restore (cr);
1019
1020
0
    return status;
1021
0
}
1022
1023
static cairo_status_t
1024
draw_paint_skew (cairo_colr_glyph_render_t *render,
1025
                 FT_PaintSkew              *skew,
1026
                 cairo_t                   *cr)
1027
0
{
1028
0
    cairo_matrix_t s;
1029
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1030
1031
#if DEBUG_COLR
1032
    printf ("%*sDraw PaintSkew\n", 2 * render->level, "");
1033
#endif
1034
1035
0
    cairo_save (cr);
1036
1037
0
    cairo_translate (cr, double_from_16_16 (skew->center_x), double_from_16_16 (skew->center_y));
1038
0
    cairo_matrix_init (&s, 1., tan (double_from_16_16 (skew->y_skew_angle) * M_PI), - tan (double_from_16_16 (skew->x_skew_angle) * M_PI), 1., 0., 0.);
1039
0
    cairo_transform (cr, &s);
1040
0
    cairo_translate (cr, - double_from_16_16 (skew->center_x), - double_from_16_16 (skew->center_y));
1041
0
    status = draw_paint (render, &skew->paint, cr);
1042
1043
0
    cairo_restore (cr);
1044
1045
0
    return status;
1046
0
}
1047
1048
static cairo_status_t
1049
draw_paint_composite (cairo_colr_glyph_render_t *render,
1050
                      FT_PaintComposite         *composite,
1051
                      cairo_t                   *cr)
1052
0
{
1053
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1054
1055
1056
#if DEBUG_COLR
1057
    printf ("%*sDraw PaintComposite\n", 2 * render->level, "");
1058
#endif
1059
1060
0
    cairo_save (cr);
1061
1062
0
    status = draw_paint (render, &composite->backdrop_paint, cr);
1063
0
    if (unlikely (status)) {
1064
0
  cairo_pattern_destroy (cairo_pop_group (cr));
1065
0
  goto cleanup;
1066
0
    }
1067
1068
0
    cairo_push_group (cr);
1069
0
    status = draw_paint (render, &composite->source_paint, cr);
1070
0
    if (unlikely (status)) {
1071
0
  cairo_pattern_destroy (cairo_pop_group (cr));
1072
0
  cairo_pattern_destroy (cairo_pop_group (cr));
1073
0
  goto cleanup;
1074
0
    }
1075
1076
0
    cairo_pop_group_to_source (cr);
1077
0
    cairo_set_operator (cr, cairo_operator_from_ft_composite_mode (composite->composite_mode));
1078
0
    cairo_paint (cr);
1079
1080
0
  cleanup:
1081
0
    cairo_restore (cr);
1082
1083
0
    return status;
1084
0
}
1085
1086
static cairo_status_t
1087
draw_paint (cairo_colr_glyph_render_t *render,
1088
            FT_OpaquePaint *paint,
1089
            cairo_t *cr)
1090
0
{
1091
0
    FT_COLR_Paint p;
1092
0
    FT_Size orig_size;
1093
0
    FT_Size unscaled_size;
1094
0
    FT_Matrix orig_transform;
1095
0
    FT_Vector orig_delta;
1096
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1097
1098
0
    assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS);
1099
1100
0
    if (!FT_Get_Paint (render->face, *paint, &p))
1101
0
  return CAIRO_STATUS_NO_MEMORY;
1102
1103
0
    if (render->level == 0) {
1104
  /* Now that the FT_Get_Paint call has applied the root transform,
1105
   * make the face unscaled and untransformed, so we can load glyph
1106
   * contours.
1107
   */
1108
1109
0
  FT_Matrix transform;
1110
0
  FT_Vector delta;
1111
1112
0
  orig_size = render->face->size;
1113
0
  FT_New_Size (render->face, &unscaled_size);
1114
0
  FT_Activate_Size (unscaled_size);
1115
0
  FT_Set_Char_Size (render->face, render->face->units_per_EM << 6, 0, 0, 0);
1116
1117
0
  transform.xx = transform.yy = 1 << 16;
1118
0
  transform.xy = transform.yx = 0;
1119
0
  delta.x = delta.y = 0;
1120
1121
0
  FT_Get_Transform (render->face, &orig_transform, &orig_delta);
1122
0
  FT_Set_Transform (render->face, &transform, &delta);
1123
0
    }
1124
1125
0
    render->level++;
1126
1127
0
    switch (p.format) {
1128
0
  case FT_COLR_PAINTFORMAT_COLR_LAYERS:
1129
0
      status = draw_paint_colr_layers (render, &p.u.colr_layers, cr);
1130
0
      break;
1131
0
  case FT_COLR_PAINTFORMAT_SOLID:
1132
0
      status = draw_paint_solid (render, &p.u.solid, cr);
1133
0
      break;
1134
0
  case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1135
0
      status = draw_paint_linear_gradient (render, &p.u.linear_gradient, cr);
1136
0
      break;
1137
0
  case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1138
0
      status = draw_paint_radial_gradient (render, &p.u.radial_gradient, cr);
1139
0
      break;
1140
0
  case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT:
1141
0
      status = draw_paint_sweep_gradient (render, &p.u.sweep_gradient, cr);
1142
0
      break;
1143
0
  case FT_COLR_PAINTFORMAT_GLYPH:
1144
0
      status = draw_paint_glyph (render, &p.u.glyph, cr);
1145
0
      break;
1146
0
  case FT_COLR_PAINTFORMAT_COLR_GLYPH:
1147
0
      status = draw_paint_colr_glyph (render, &p.u.colr_glyph, cr);
1148
0
      break;
1149
0
  case FT_COLR_PAINTFORMAT_TRANSFORM:
1150
0
      status = draw_paint_transform (render, &p.u.transform, cr);
1151
0
      break;
1152
0
  case FT_COLR_PAINTFORMAT_TRANSLATE:
1153
0
      status = draw_paint_translate (render, &p.u.translate, cr);
1154
0
      break;
1155
0
  case FT_COLR_PAINTFORMAT_ROTATE:
1156
0
      status = draw_paint_rotate (render, &p.u.rotate, cr);
1157
0
      break;
1158
0
  case FT_COLR_PAINTFORMAT_SCALE:
1159
0
      status = draw_paint_scale (render, &p.u.scale, cr);
1160
0
      break;
1161
0
  case FT_COLR_PAINTFORMAT_SKEW:
1162
0
      status = draw_paint_skew (render, &p.u.skew, cr);
1163
0
      break;
1164
0
  case FT_COLR_PAINTFORMAT_COMPOSITE:
1165
0
      status = draw_paint_composite (render, &p.u.composite, cr);
1166
0
      break;
1167
0
  case FT_COLR_PAINT_FORMAT_MAX:
1168
0
  case FT_COLR_PAINTFORMAT_UNSUPPORTED:
1169
0
  default:
1170
0
      ASSERT_NOT_REACHED;
1171
0
    }
1172
1173
0
    render->level--;
1174
1175
0
    if (render->level == 0) {
1176
0
  FT_Set_Transform (render->face, &orig_transform, &orig_delta);
1177
0
  FT_Activate_Size (orig_size);
1178
0
  FT_Done_Size (unscaled_size);
1179
0
    }
1180
1181
0
    return status;
1182
0
}
1183
1184
static cairo_status_t
1185
draw_colr_glyph (cairo_colr_glyph_render_t *render,
1186
     unsigned long              glyph,
1187
                 FT_Color_Root_Transform    root,
1188
                 cairo_t                   *cr)
1189
0
{
1190
0
    FT_OpaquePaint paint = { NULL, 0 };
1191
0
    FT_ClipBox box;
1192
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1193
1194
0
    cairo_save (cr);
1195
1196
0
    if (FT_Get_Color_Glyph_ClipBox (render->face, glyph, &box)) {
1197
0
  double xmin, ymin, xmax, ymax;
1198
1199
0
  xmin = double_from_26_6 (box.bottom_left.x);
1200
0
  ymin = double_from_26_6 (box.bottom_left.y);
1201
0
  xmax = double_from_26_6 (box.top_right.x);
1202
0
  ymax = double_from_26_6 (box.top_right.y);
1203
1204
0
  cairo_new_path (cr);
1205
0
  cairo_rectangle (cr, xmin, ymin, xmax - xmin, ymax - ymin);
1206
0
  cairo_clip (cr);
1207
0
    }
1208
1209
0
    if (FT_Get_Color_Glyph_Paint (render->face, glyph, root, &paint))
1210
0
  status = draw_paint (render, &paint, cr);
1211
1212
0
    cairo_restore (cr);
1213
1214
0
    return status;
1215
0
}
1216
1217
/* Create an image surface and render the glyph onto it,
1218
 * using the given colors.
1219
 */
1220
cairo_status_t
1221
_cairo_render_colr_v1_glyph (FT_Face               face,
1222
                             unsigned long         glyph,
1223
                             FT_Color             *palette,
1224
                             int                   num_palette_entries,
1225
                             cairo_t              *cr,
1226
                             cairo_pattern_t      *foreground_source,
1227
                             cairo_bool_t         *foreground_source_used)
1228
0
{
1229
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1230
0
    cairo_colr_glyph_render_t colr_render;
1231
1232
#if DEBUG_COLR
1233
    printf ("_cairo_render_colr_glyph  glyph index: %ld\n", glyph);
1234
#endif
1235
1236
0
    colr_render.face = face;
1237
0
    colr_render.palette = palette;
1238
0
    colr_render.num_palette_entries = num_palette_entries;
1239
0
    colr_render.foreground_marker = _cairo_pattern_create_foreground_marker ();
1240
0
    colr_render.foreground_source = cairo_pattern_reference (foreground_source);;
1241
0
    colr_render.foreground_source_used = FALSE;
1242
0
    colr_render.level = 0;
1243
1244
0
    status = draw_colr_glyph (&colr_render,
1245
0
            glyph,
1246
0
            FT_COLOR_INCLUDE_ROOT_TRANSFORM,
1247
0
            cr);
1248
  
1249
0
    cairo_pattern_destroy (colr_render.foreground_marker);
1250
0
    cairo_pattern_destroy (colr_render.foreground_source);
1251
0
    *foreground_source_used = colr_render.foreground_source_used;
1252
1253
0
    return status;
1254
0
}
1255
1256
#endif /* HAVE_FT_COLR_V1 */