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-gstate.c
Line
Count
Source
1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2002 University of Southern California
4
 * Copyright © 2005 Red Hat, Inc.
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
 * The Initial Developer of the Original Code is University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *  Carl D. Worth <cworth@cworth.org>
36
 */
37
38
#include "cairoint.h"
39
40
#include "cairo-clip-inline.h"
41
#include "cairo-clip-private.h"
42
#include "cairo-error-private.h"
43
#include "cairo-list-inline.h"
44
#include "cairo-gstate-private.h"
45
#include "cairo-pattern-private.h"
46
#include "cairo-traps-private.h"
47
48
static cairo_status_t
49
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
50
51
static cairo_status_t
52
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
53
54
static cairo_status_t
55
_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
56
57
static void
58
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
59
60
static void
61
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
62
                                           const cairo_glyph_t *glyphs,
63
                                           int                  num_glyphs,
64
             const cairo_text_cluster_t *clusters,
65
             int       num_clusters,
66
             cairo_text_cluster_flags_t cluster_flags,
67
                                           cairo_glyph_t       *transformed_glyphs,
68
             int      *num_transformed_glyphs,
69
             cairo_text_cluster_t *transformed_clusters,
70
             cairo_bool_t          perform_early_clip);
71
72
static void
73
_cairo_gstate_update_device_transform (cairo_observer_t *observer,
74
               void *arg)
75
0
{
76
0
    cairo_gstate_t *gstate = cairo_container_of (observer,
77
0
             cairo_gstate_t,
78
0
             device_transform_observer);
79
80
0
    gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
81
0
         _cairo_matrix_is_identity (&gstate->target->device_transform));
82
0
}
83
84
cairo_status_t
85
_cairo_gstate_init (cairo_gstate_t  *gstate,
86
        cairo_surface_t *target)
87
14.5M
{
88
14.5M
    VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
89
90
14.5M
    gstate->next = NULL;
91
92
14.5M
    gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
93
14.5M
    gstate->opacity = 1.;
94
95
14.5M
    gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
96
14.5M
    gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
97
98
14.5M
    _cairo_stroke_style_init (&gstate->stroke_style);
99
100
14.5M
    gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
101
102
14.5M
    gstate->font_face = NULL;
103
14.5M
    gstate->scaled_font = NULL;
104
14.5M
    gstate->previous_scaled_font = NULL;
105
106
14.5M
    cairo_matrix_init_scale (&gstate->font_matrix,
107
14.5M
           CAIRO_GSTATE_DEFAULT_FONT_SIZE,
108
14.5M
           CAIRO_GSTATE_DEFAULT_FONT_SIZE);
109
110
14.5M
    _cairo_font_options_init_default (&gstate->font_options);
111
112
14.5M
    gstate->clip = NULL;
113
114
14.5M
    gstate->target = cairo_surface_reference (target);
115
14.5M
    gstate->parent_target = NULL;
116
14.5M
    gstate->original_target = cairo_surface_reference (target);
117
118
14.5M
    gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
119
14.5M
    cairo_list_add (&gstate->device_transform_observer.link,
120
14.5M
        &gstate->target->device_transform_observers);
121
122
14.5M
    gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
123
14.5M
    cairo_matrix_init_identity (&gstate->ctm);
124
14.5M
    gstate->ctm_inverse = gstate->ctm;
125
14.5M
    gstate->source_ctm_inverse = gstate->ctm;
126
127
14.5M
    gstate->source = (cairo_pattern_t *) &_cairo_pattern_black.base;
128
129
    /* Now that the gstate is fully initialized and ready for the eventual
130
     * _cairo_gstate_fini(), we can check for errors (and not worry about
131
     * the resource deallocation). */
132
14.5M
    return target->status;
133
14.5M
}
134
135
/**
136
 * _cairo_gstate_init_copy:
137
 *
138
 * Initialize @gstate by performing a deep copy of state fields from
139
 * @other. Note that gstate->next is not copied but is set to %NULL by
140
 * this function.
141
 **/
142
static cairo_status_t
143
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
144
18.3k
{
145
18.3k
    cairo_status_t status;
146
147
18.3k
    VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
148
149
18.3k
    gstate->op = other->op;
150
18.3k
    gstate->opacity = other->opacity;
151
152
18.3k
    gstate->tolerance = other->tolerance;
153
18.3k
    gstate->antialias = other->antialias;
154
155
18.3k
    status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
156
18.3k
              &other->stroke_style);
157
18.3k
    if (unlikely (status))
158
0
  return status;
159
160
18.3k
    gstate->fill_rule = other->fill_rule;
161
162
18.3k
    gstate->font_face = cairo_font_face_reference (other->font_face);
163
18.3k
    gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font);
164
18.3k
    gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font);
165
166
18.3k
    gstate->font_matrix = other->font_matrix;
167
168
18.3k
    _cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
169
170
18.3k
    gstate->clip = _cairo_clip_copy (other->clip);
171
172
18.3k
    gstate->target = cairo_surface_reference (other->target);
173
    /* parent_target is always set to NULL; it's only ever set by redirect_target */
174
18.3k
    gstate->parent_target = NULL;
175
18.3k
    gstate->original_target = cairo_surface_reference (other->original_target);
176
177
18.3k
    gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
178
18.3k
    cairo_list_add (&gstate->device_transform_observer.link,
179
18.3k
        &gstate->target->device_transform_observers);
180
181
18.3k
    gstate->is_identity = other->is_identity;
182
18.3k
    gstate->ctm = other->ctm;
183
18.3k
    gstate->ctm_inverse = other->ctm_inverse;
184
18.3k
    gstate->source_ctm_inverse = other->source_ctm_inverse;
185
186
18.3k
    gstate->source = cairo_pattern_reference (other->source);
187
188
18.3k
    gstate->next = NULL;
189
190
18.3k
    return CAIRO_STATUS_SUCCESS;
191
18.3k
}
192
193
void
194
_cairo_gstate_fini (cairo_gstate_t *gstate)
195
14.6M
{
196
14.6M
    _cairo_stroke_style_fini (&gstate->stroke_style);
197
14.6M
    _cairo_font_options_fini (&gstate->font_options);
198
199
14.6M
    cairo_font_face_destroy (gstate->font_face);
200
14.6M
    gstate->font_face = NULL;
201
202
14.6M
    cairo_scaled_font_destroy (gstate->previous_scaled_font);
203
14.6M
    gstate->previous_scaled_font = NULL;
204
205
14.6M
    cairo_scaled_font_destroy (gstate->scaled_font);
206
14.6M
    gstate->scaled_font = NULL;
207
208
14.6M
    _cairo_clip_destroy (gstate->clip);
209
210
14.6M
    cairo_list_del (&gstate->device_transform_observer.link);
211
212
14.6M
    cairo_surface_destroy (gstate->target);
213
14.6M
    gstate->target = NULL;
214
215
14.6M
    cairo_surface_destroy (gstate->parent_target);
216
14.6M
    gstate->parent_target = NULL;
217
218
14.6M
    cairo_surface_destroy (gstate->original_target);
219
14.6M
    gstate->original_target = NULL;
220
221
14.6M
    cairo_pattern_destroy (gstate->source);
222
14.6M
    gstate->source = NULL;
223
224
14.6M
    VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
225
14.6M
}
226
227
/**
228
 * _cairo_gstate_save:
229
 * @gstate: input/output gstate pointer
230
 *
231
 * Makes a copy of the current state of @gstate and saves it
232
 * to @gstate->next, then put the address of the newly allcated
233
 * copy into @gstate.  _cairo_gstate_restore() reverses this.
234
 **/
235
cairo_status_t
236
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
237
18.3k
{
238
18.3k
    cairo_gstate_t *top;
239
18.3k
    cairo_status_t status;
240
241
18.3k
    if (CAIRO_INJECT_FAULT ())
242
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
243
244
18.3k
    top = *freelist;
245
18.3k
    if (top == NULL) {
246
1
  top = _cairo_calloc (sizeof (cairo_gstate_t));
247
1
  if (unlikely (top == NULL))
248
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
249
1
    } else
250
18.3k
  *freelist = top->next;
251
252
18.3k
    status = _cairo_gstate_init_copy (top, *gstate);
253
18.3k
    if (unlikely (status)) {
254
0
  top->next = *freelist;
255
0
  *freelist = top;
256
0
  return status;
257
0
    }
258
259
18.3k
    top->next = *gstate;
260
18.3k
    *gstate = top;
261
262
18.3k
    return CAIRO_STATUS_SUCCESS;
263
18.3k
}
264
265
/**
266
 * _cairo_gstate_restore:
267
 * @gstate: input/output gstate pointer
268
 *
269
 * Reverses the effects of one _cairo_gstate_save() call.
270
 **/
271
cairo_status_t
272
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
273
18.3k
{
274
18.3k
    cairo_gstate_t *top;
275
276
18.3k
    top = *gstate;
277
18.3k
    if (top->next == NULL)
278
0
  return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
279
280
18.3k
    *gstate = top->next;
281
282
18.3k
    _cairo_gstate_fini (top);
283
18.3k
    VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *)));
284
18.3k
    top->next = *freelist;
285
18.3k
    *freelist = top;
286
287
18.3k
    return CAIRO_STATUS_SUCCESS;
288
18.3k
}
289
290
/**
291
 * _cairo_gstate_redirect_target:
292
 * @gstate: a #cairo_gstate_t
293
 * @child: the new child target
294
 *
295
 * Redirect @gstate rendering to a "child" target. The original
296
 * "parent" target with which the gstate was created will not be
297
 * affected. See _cairo_gstate_get_target().
298
 **/
299
cairo_status_t
300
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
301
0
{
302
    /* If this gstate is already redirected, this is an error; we need a
303
     * new gstate to be able to redirect */
304
0
    assert (gstate->parent_target == NULL);
305
306
    /* Set up our new parent_target based on our current target;
307
     * gstate->parent_target will take the ref that is held by gstate->target
308
     */
309
0
    gstate->parent_target = gstate->target;
310
311
    /* Now set up our new target; we overwrite gstate->target directly,
312
     * since its ref is now owned by gstate->parent_target */
313
0
    gstate->target = cairo_surface_reference (child);
314
0
    gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
315
0
    cairo_list_move (&gstate->device_transform_observer.link,
316
0
         &gstate->target->device_transform_observers);
317
318
    /* The clip is in surface backend coordinates for the previous target;
319
     * translate it into the child's backend coordinates. */
320
0
    _cairo_clip_destroy (gstate->clip);
321
0
    gstate->clip = _cairo_clip_copy_with_translation (gstate->next->clip,
322
0
                  child->device_transform.x0 - gstate->parent_target->device_transform.x0,
323
0
                  child->device_transform.y0 - gstate->parent_target->device_transform.y0);
324
325
0
    return CAIRO_STATUS_SUCCESS;
326
0
}
327
328
/**
329
 * _cairo_gstate_is_group:
330
 * @gstate: a #cairo_gstate_t
331
 *
332
 * Check if _cairo_gstate_redirect_target has been called on the head
333
 * of the stack.
334
 *
335
 * Return value: %TRUE if @gstate is redirected to a target different
336
 * than the previous state in the stack, %FALSE otherwise.
337
 **/
338
cairo_bool_t
339
_cairo_gstate_is_group (cairo_gstate_t *gstate)
340
18.3k
{
341
18.3k
    return gstate->parent_target != NULL;
342
18.3k
}
343
344
/**
345
 * _cairo_gstate_get_target:
346
 * @gstate: a #cairo_gstate_t
347
 *
348
 * Return the current drawing target; if drawing is not redirected,
349
 * this will be the same as _cairo_gstate_get_original_target().
350
 *
351
 * Return value: the current target surface
352
 **/
353
cairo_surface_t *
354
_cairo_gstate_get_target (cairo_gstate_t *gstate)
355
0
{
356
0
    return gstate->target;
357
0
}
358
359
/**
360
 * _cairo_gstate_get_original_target:
361
 * @gstate: a #cairo_gstate_t
362
 *
363
 * Return the original target with which @gstate was created. This
364
 * function always returns the original target independent of any
365
 * child target that may have been set with
366
 * _cairo_gstate_redirect_target.
367
 *
368
 * Return value: the original target surface
369
 **/
370
cairo_surface_t *
371
_cairo_gstate_get_original_target (cairo_gstate_t *gstate)
372
13.8M
{
373
13.8M
    return gstate->original_target;
374
13.8M
}
375
376
/**
377
 * _cairo_gstate_get_clip:
378
 * @gstate: a #cairo_gstate_t
379
 *
380
 * This space left intentionally blank.
381
 *
382
 * Return value: a pointer to the gstate's #cairo_clip_t structure.
383
 **/
384
cairo_clip_t *
385
_cairo_gstate_get_clip (cairo_gstate_t *gstate)
386
0
{
387
0
    return gstate->clip;
388
0
}
389
390
cairo_status_t
391
_cairo_gstate_set_source (cairo_gstate_t  *gstate,
392
        cairo_pattern_t *source)
393
12.1M
{
394
12.1M
    if (source->status)
395
0
  return source->status;
396
397
12.1M
    source = cairo_pattern_reference (source);
398
12.1M
    cairo_pattern_destroy (gstate->source);
399
12.1M
    gstate->source = source;
400
12.1M
    gstate->source_ctm_inverse = gstate->ctm_inverse;
401
402
12.1M
    return CAIRO_STATUS_SUCCESS;
403
12.1M
}
404
405
cairo_pattern_t *
406
_cairo_gstate_get_source (cairo_gstate_t *gstate)
407
19.2k
{
408
19.2k
    if (gstate->source == &_cairo_pattern_black.base) {
409
  /* do not expose the static object to the user */
410
0
        gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
411
0
    }
412
413
19.2k
    return gstate->source;
414
19.2k
}
415
416
cairo_status_t
417
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op)
418
24.7M
{
419
24.7M
    gstate->op = op;
420
421
24.7M
    return CAIRO_STATUS_SUCCESS;
422
24.7M
}
423
424
cairo_operator_t
425
_cairo_gstate_get_operator (cairo_gstate_t *gstate)
426
0
{
427
0
    return gstate->op;
428
0
}
429
430
cairo_status_t
431
_cairo_gstate_set_opacity (cairo_gstate_t *gstate, double op)
432
0
{
433
0
    gstate->opacity = op;
434
435
0
    return CAIRO_STATUS_SUCCESS;
436
0
}
437
438
double
439
_cairo_gstate_get_opacity (cairo_gstate_t *gstate)
440
0
{
441
0
    return gstate->opacity;
442
0
}
443
444
cairo_status_t
445
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
446
0
{
447
0
    gstate->tolerance = tolerance;
448
449
0
    return CAIRO_STATUS_SUCCESS;
450
0
}
451
452
double
453
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
454
551
{
455
551
    return gstate->tolerance;
456
551
}
457
458
cairo_status_t
459
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
460
12.6M
{
461
12.6M
    gstate->fill_rule = fill_rule;
462
463
12.6M
    return CAIRO_STATUS_SUCCESS;
464
12.6M
}
465
466
cairo_fill_rule_t
467
_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
468
0
{
469
0
    return gstate->fill_rule;
470
0
}
471
472
cairo_status_t
473
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
474
12.8M
{
475
12.8M
    if (gstate->stroke_style.is_hairline)
476
0
  gstate->stroke_style.pre_hairline_line_width = width;
477
12.8M
  else
478
12.8M
  gstate->stroke_style.line_width = width;
479
480
12.8M
    return CAIRO_STATUS_SUCCESS;
481
12.8M
}
482
483
double
484
_cairo_gstate_get_line_width (cairo_gstate_t *gstate)
485
228M
{
486
228M
    return gstate->stroke_style.line_width;
487
228M
}
488
489
cairo_status_t
490
_cairo_gstate_set_hairline (cairo_gstate_t *gstate, cairo_bool_t set_hairline)
491
0
{
492
0
    if (gstate->stroke_style.is_hairline != set_hairline) {
493
0
        gstate->stroke_style.is_hairline = set_hairline;
494
495
0
        if (set_hairline) {
496
0
            gstate->stroke_style.pre_hairline_line_width = gstate->stroke_style.line_width;
497
0
            gstate->stroke_style.line_width = 0.0;
498
0
        } else {
499
0
            gstate->stroke_style.line_width = gstate->stroke_style.pre_hairline_line_width;
500
0
        }
501
0
    }
502
503
0
    return CAIRO_STATUS_SUCCESS;
504
0
}
505
506
cairo_bool_t
507
_cairo_gstate_get_hairline (cairo_gstate_t *gstate)
508
0
{
509
0
    return gstate->stroke_style.is_hairline;
510
0
}
511
512
cairo_status_t
513
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
514
270k
{
515
270k
    gstate->stroke_style.line_cap = line_cap;
516
517
270k
    return CAIRO_STATUS_SUCCESS;
518
270k
}
519
520
cairo_line_cap_t
521
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
522
0
{
523
0
    return gstate->stroke_style.line_cap;
524
0
}
525
526
cairo_status_t
527
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
528
270k
{
529
270k
    gstate->stroke_style.line_join = line_join;
530
531
270k
    return CAIRO_STATUS_SUCCESS;
532
270k
}
533
534
cairo_line_join_t
535
_cairo_gstate_get_line_join (cairo_gstate_t *gstate)
536
0
{
537
0
    return gstate->stroke_style.line_join;
538
0
}
539
540
cairo_status_t
541
_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset)
542
0
{
543
0
    double dash_total, on_total, off_total;
544
0
    int i, j;
545
546
0
    free (gstate->stroke_style.dash);
547
548
0
    gstate->stroke_style.num_dashes = num_dashes;
549
550
0
    if (gstate->stroke_style.num_dashes == 0) {
551
0
  gstate->stroke_style.dash = NULL;
552
0
  gstate->stroke_style.dash_offset = 0.0;
553
0
  return CAIRO_STATUS_SUCCESS;
554
0
    }
555
556
0
    gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
557
0
    if (unlikely (gstate->stroke_style.dash == NULL)) {
558
0
  gstate->stroke_style.num_dashes = 0;
559
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
560
0
    }
561
562
0
    on_total = off_total = dash_total = 0.0;
563
0
    for (i = j = 0; i < num_dashes; i++) {
564
0
  if (dash[i] < 0)
565
0
      return _cairo_error (CAIRO_STATUS_INVALID_DASH);
566
567
0
  if (dash[i] == 0 && i > 0 && i < num_dashes - 1) {
568
0
      if (dash[++i] < 0)
569
0
    return _cairo_error (CAIRO_STATUS_INVALID_DASH);
570
571
0
      gstate->stroke_style.dash[j-1] += dash[i];
572
0
      gstate->stroke_style.num_dashes -= 2;
573
0
  } else
574
0
      gstate->stroke_style.dash[j++] = dash[i];
575
576
0
  if (dash[i]) {
577
0
      dash_total += dash[i];
578
0
      if ((i & 1) == 0)
579
0
    on_total += dash[i];
580
0
      else
581
0
    off_total += dash[i];
582
0
  }
583
0
    }
584
585
0
    if (dash_total == 0.0)
586
0
  return _cairo_error (CAIRO_STATUS_INVALID_DASH);
587
588
    /* An odd dash value indicate symmetric repeating, so the total
589
     * is twice as long. */
590
0
    if (gstate->stroke_style.num_dashes & 1) {
591
0
  dash_total *= 2;
592
0
  on_total += off_total;
593
0
    }
594
595
0
    if (dash_total - on_total < CAIRO_FIXED_ERROR_DOUBLE) {
596
  /* Degenerate dash -> solid line */
597
0
  free (gstate->stroke_style.dash);
598
0
  gstate->stroke_style.dash = NULL;
599
0
  gstate->stroke_style.num_dashes = 0;
600
0
  gstate->stroke_style.dash_offset = 0.0;
601
0
  return CAIRO_STATUS_SUCCESS;
602
0
    }
603
604
    /* The dashing code doesn't like a negative offset or a big positive
605
     * offset, so we compute an equivalent offset which is guaranteed to be
606
     * positive and less than twice the pattern length. */
607
0
    offset = fmod (offset, dash_total);
608
0
    if (offset < 0.0)
609
0
  offset += dash_total;
610
0
    if (offset <= 0.0)   /* Take care of -0 */
611
0
  offset = 0.0;
612
0
    gstate->stroke_style.dash_offset = offset;
613
614
0
    return CAIRO_STATUS_SUCCESS;
615
0
}
616
617
void
618
_cairo_gstate_get_dash (cairo_gstate_t *gstate,
619
      double         *dashes,
620
      int            *num_dashes,
621
      double         *offset)
622
0
{
623
0
    if (dashes) {
624
0
  memcpy (dashes,
625
0
    gstate->stroke_style.dash,
626
0
    sizeof (double) * gstate->stroke_style.num_dashes);
627
0
    }
628
629
0
    if (num_dashes)
630
0
  *num_dashes = gstate->stroke_style.num_dashes;
631
632
0
    if (offset)
633
0
  *offset = gstate->stroke_style.dash_offset;
634
0
}
635
636
cairo_status_t
637
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
638
270k
{
639
270k
    gstate->stroke_style.miter_limit = limit;
640
641
270k
    return CAIRO_STATUS_SUCCESS;
642
270k
}
643
644
double
645
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
646
0
{
647
0
    return gstate->stroke_style.miter_limit;
648
0
}
649
650
void
651
_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
652
0
{
653
0
    *matrix = gstate->ctm;
654
0
}
655
656
cairo_status_t
657
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
658
19.2k
{
659
19.2k
    cairo_matrix_t tmp;
660
661
19.2k
    if (! ISFINITE (tx) || ! ISFINITE (ty))
662
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
663
664
19.2k
    _cairo_gstate_unset_scaled_font (gstate);
665
666
19.2k
    cairo_matrix_init_translate (&tmp, tx, ty);
667
19.2k
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
668
19.2k
    gstate->is_identity = FALSE;
669
670
    /* paranoid check against gradual numerical instability */
671
19.2k
    if (! _cairo_matrix_is_invertible (&gstate->ctm))
672
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
673
674
19.2k
    cairo_matrix_init_translate (&tmp, -tx, -ty);
675
19.2k
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
676
677
19.2k
    return CAIRO_STATUS_SUCCESS;
678
19.2k
}
679
680
cairo_status_t
681
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
682
19.2k
{
683
19.2k
    cairo_matrix_t tmp;
684
685
19.2k
    if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
686
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
687
19.2k
    if (! ISFINITE (sx) || ! ISFINITE (sy))
688
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
689
690
19.2k
    _cairo_gstate_unset_scaled_font (gstate);
691
692
19.2k
    cairo_matrix_init_scale (&tmp, sx, sy);
693
19.2k
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
694
19.2k
    gstate->is_identity = FALSE;
695
696
    /* paranoid check against gradual numerical instability */
697
19.2k
    if (! _cairo_matrix_is_invertible (&gstate->ctm))
698
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
699
700
19.2k
    cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
701
19.2k
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
702
703
19.2k
    return CAIRO_STATUS_SUCCESS;
704
19.2k
}
705
706
cairo_status_t
707
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
708
0
{
709
0
    cairo_matrix_t tmp;
710
711
0
    if (angle == 0.)
712
0
  return CAIRO_STATUS_SUCCESS;
713
714
0
    if (! ISFINITE (angle))
715
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
716
717
0
    _cairo_gstate_unset_scaled_font (gstate);
718
719
0
    cairo_matrix_init_rotate (&tmp, angle);
720
0
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
721
0
    gstate->is_identity = FALSE;
722
723
    /* paranoid check against gradual numerical instability */
724
0
    if (! _cairo_matrix_is_invertible (&gstate->ctm))
725
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
726
727
0
    cairo_matrix_init_rotate (&tmp, -angle);
728
0
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
729
730
0
    return CAIRO_STATUS_SUCCESS;
731
0
}
732
733
cairo_status_t
734
_cairo_gstate_transform (cairo_gstate_t       *gstate,
735
       const cairo_matrix_t *matrix)
736
0
{
737
0
    cairo_matrix_t tmp;
738
0
    cairo_status_t status;
739
740
0
    if (! _cairo_matrix_is_invertible (matrix))
741
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
742
743
0
    if (_cairo_matrix_is_identity (matrix))
744
0
  return CAIRO_STATUS_SUCCESS;
745
746
0
    tmp = *matrix;
747
0
    status = cairo_matrix_invert (&tmp);
748
0
    if (unlikely (status))
749
0
  return status;
750
751
0
    _cairo_gstate_unset_scaled_font (gstate);
752
753
0
    cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
754
0
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
755
0
    gstate->is_identity = FALSE;
756
757
    /* paranoid check against gradual numerical instability */
758
0
    if (! _cairo_matrix_is_invertible (&gstate->ctm))
759
0
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
760
761
0
    return CAIRO_STATUS_SUCCESS;
762
0
}
763
764
cairo_status_t
765
_cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
766
        const cairo_matrix_t *matrix)
767
1.04M
{
768
1.04M
    cairo_status_t status;
769
770
1.04M
    if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0)
771
0
  return CAIRO_STATUS_SUCCESS;
772
773
1.04M
    if (! _cairo_matrix_is_invertible (matrix))
774
977
  return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
775
776
1.04M
    if (_cairo_matrix_is_identity (matrix)) {
777
0
  _cairo_gstate_identity_matrix (gstate);
778
0
  return CAIRO_STATUS_SUCCESS;
779
0
    }
780
781
1.04M
    _cairo_gstate_unset_scaled_font (gstate);
782
783
1.04M
    gstate->ctm = *matrix;
784
1.04M
    gstate->ctm_inverse = *matrix;
785
1.04M
    status = cairo_matrix_invert (&gstate->ctm_inverse);
786
1.04M
    assert (status == CAIRO_STATUS_SUCCESS);
787
1.04M
    gstate->is_identity = FALSE;
788
789
1.04M
    return CAIRO_STATUS_SUCCESS;
790
1.04M
}
791
792
void
793
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
794
12.6M
{
795
12.6M
    if (_cairo_matrix_is_identity (&gstate->ctm))
796
12.6M
  return;
797
798
1
    _cairo_gstate_unset_scaled_font (gstate);
799
800
1
    cairo_matrix_init_identity (&gstate->ctm);
801
1
    cairo_matrix_init_identity (&gstate->ctm_inverse);
802
1
    gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
803
1
}
804
805
void
806
_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
807
0
{
808
0
    cairo_matrix_transform_point (&gstate->ctm, x, y);
809
0
}
810
811
void
812
_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
813
               double *dx, double *dy)
814
0
{
815
0
    cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
816
0
}
817
818
void
819
_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
820
0
{
821
0
    cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
822
0
}
823
824
void
825
_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
826
               double *dx, double *dy)
827
0
{
828
0
    cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
829
0
}
830
831
void
832
_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
833
6.70M
{
834
6.70M
    cairo_matrix_transform_point (&gstate->ctm, x, y);
835
6.70M
    cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
836
6.70M
}
837
838
void
839
_do_cairo_gstate_user_to_backend_distance (cairo_gstate_t *gstate, double *x, double *y)
840
0
{
841
0
    cairo_matrix_transform_distance (&gstate->ctm, x, y);
842
0
    cairo_matrix_transform_distance (&gstate->target->device_transform, x, y);
843
0
}
844
845
void
846
_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
847
0
{
848
0
    cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
849
0
    cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
850
0
}
851
852
void
853
_do_cairo_gstate_backend_to_user_distance (cairo_gstate_t *gstate, double *x, double *y)
854
0
{
855
0
    cairo_matrix_transform_distance (&gstate->target->device_transform_inverse, x, y);
856
0
    cairo_matrix_transform_distance (&gstate->ctm_inverse, x, y);
857
0
}
858
859
void
860
_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
861
                                         double *x1, double *y1,
862
                                         double *x2, double *y2,
863
                                         cairo_bool_t *is_tight)
864
23.2M
{
865
23.2M
    cairo_matrix_t matrix_inverse;
866
867
23.2M
    if (! _cairo_matrix_is_identity (&gstate->target->device_transform_inverse) ||
868
23.2M
    ! _cairo_matrix_is_identity (&gstate->ctm_inverse))
869
2.09M
    {
870
2.09M
  cairo_matrix_multiply (&matrix_inverse,
871
2.09M
             &gstate->target->device_transform_inverse,
872
2.09M
             &gstate->ctm_inverse);
873
2.09M
  _cairo_matrix_transform_bounding_box (&matrix_inverse,
874
2.09M
                x1, y1, x2, y2, is_tight);
875
2.09M
    }
876
877
21.1M
    else
878
21.1M
    {
879
21.1M
  if (is_tight)
880
0
      *is_tight = TRUE;
881
21.1M
    }
882
23.2M
}
883
884
/* XXX: NYI
885
cairo_status_t
886
_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
887
{
888
    cairo_status_t status;
889
890
    _cairo_pen_init (&gstate);
891
    return CAIRO_STATUS_SUCCESS;
892
}
893
*/
894
895
void
896
_cairo_gstate_path_extents (cairo_gstate_t     *gstate,
897
          cairo_path_fixed_t *path,
898
          double *x1, double *y1,
899
          double *x2, double *y2)
900
12.5M
{
901
12.5M
    cairo_box_t box;
902
12.5M
    double px1, py1, px2, py2;
903
904
12.5M
    if (_cairo_path_fixed_extents (path, &box)) {
905
10.6M
  px1 = _cairo_fixed_to_double (box.p1.x);
906
10.6M
  py1 = _cairo_fixed_to_double (box.p1.y);
907
10.6M
  px2 = _cairo_fixed_to_double (box.p2.x);
908
10.6M
  py2 = _cairo_fixed_to_double (box.p2.y);
909
910
10.6M
  _cairo_gstate_backend_to_user_rectangle (gstate,
911
10.6M
             &px1, &py1, &px2, &py2,
912
10.6M
             NULL);
913
10.6M
    } else {
914
1.91M
  px1 = 0.0;
915
1.91M
  py1 = 0.0;
916
1.91M
  px2 = 0.0;
917
1.91M
  py2 = 0.0;
918
1.91M
    }
919
920
12.5M
    if (x1)
921
12.5M
  *x1 = px1;
922
12.5M
    if (y1)
923
12.5M
  *y1 = py1;
924
12.5M
    if (x2)
925
12.5M
  *x2 = px2;
926
12.5M
    if (y2)
927
12.5M
  *y2 = py2;
928
12.5M
}
929
930
static void
931
_cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
932
          const cairo_pattern_t *original)
933
13.2M
{
934
    /* First check if the we can replace the original with a much simpler
935
     * pattern. For example, gradients that are uniform or just have a single
936
     * stop can sometimes be replaced with a solid.
937
     */
938
939
13.2M
    if (_cairo_pattern_is_clear (original)) {
940
21.8k
        _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
941
21.8k
           CAIRO_COLOR_TRANSPARENT);
942
21.8k
  return;
943
21.8k
    }
944
945
13.1M
    if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
946
13.1M
  original->type == CAIRO_PATTERN_TYPE_RADIAL)
947
6.23k
    {
948
6.23k
        cairo_color_t color;
949
6.23k
  if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
950
6.23k
                NULL,
951
6.23k
                &color))
952
3.72k
  {
953
3.72k
      _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
954
3.72k
               &color);
955
3.72k
      return;
956
3.72k
  }
957
6.23k
    }
958
959
13.1M
    _cairo_pattern_init_static_copy (pattern, original);
960
13.1M
}
961
962
static void
963
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t  *gstate,
964
          cairo_pattern_t *pattern,
965
          const cairo_pattern_t *original,
966
          const cairo_matrix_t  *ctm_inverse)
967
13.2M
{
968
    /*
969
     * What calculations below do can be described in pseudo-code (so using nonexistent fields) as (using column vectors):
970
     * pattern->matrix = surface->device_transform *
971
     *       pattern->matrix *
972
     *       ctm_inverse *
973
     *       gstate->target->device_transform_inverse
974
     *
975
     * The inverse of which is:
976
     * pattern->matrix_inverse = gstate->target->device_transform *
977
     *         ctm *
978
     *         pattern->matrix_inverse *
979
     *         surface->device_transform_inverse
980
     */
981
982
13.2M
    _cairo_gstate_copy_pattern (pattern, original);
983
984
13.2M
    if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
985
515k
  cairo_surface_pattern_t *surface_pattern;
986
515k
  cairo_surface_t *surface;
987
988
515k
        surface_pattern = (cairo_surface_pattern_t *) original;
989
515k
        surface = surface_pattern->surface;
990
991
515k
  if (_cairo_surface_has_device_transform (surface))
992
1
      _cairo_pattern_pretransform (pattern, &surface->device_transform);
993
515k
    }
994
995
13.2M
    if (! _cairo_matrix_is_identity (ctm_inverse))
996
79.2k
  _cairo_pattern_transform (pattern, ctm_inverse);
997
998
13.2M
    if (_cairo_surface_has_device_transform (gstate->target)) {
999
0
        _cairo_pattern_transform (pattern,
1000
0
                                  &gstate->target->device_transform_inverse);
1001
0
    }
1002
13.2M
}
1003
1004
static void
1005
_cairo_gstate_copy_transformed_source (cairo_gstate_t   *gstate,
1006
               cairo_pattern_t  *pattern)
1007
13.2M
{
1008
13.2M
    _cairo_gstate_copy_transformed_pattern (gstate, pattern,
1009
13.2M
              gstate->source,
1010
13.2M
              &gstate->source_ctm_inverse);
1011
13.2M
}
1012
1013
static void
1014
_cairo_gstate_copy_transformed_mask (cairo_gstate_t   *gstate,
1015
             cairo_pattern_t  *pattern,
1016
             cairo_pattern_t  *mask)
1017
0
{
1018
0
    _cairo_gstate_copy_transformed_pattern (gstate, pattern,
1019
0
              mask,
1020
0
              &gstate->ctm_inverse);
1021
0
}
1022
1023
static cairo_operator_t
1024
_reduce_op (cairo_gstate_t *gstate)
1025
12.1M
{
1026
12.1M
    cairo_operator_t op;
1027
12.1M
    const cairo_pattern_t *pattern;
1028
1029
12.1M
    op = gstate->op;
1030
12.1M
    if (op != CAIRO_OPERATOR_SOURCE)
1031
4.31M
  return op;
1032
1033
7.83M
    pattern = gstate->source;
1034
7.83M
    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
1035
7.82M
  const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
1036
7.82M
  if (solid->color.alpha_short <= 0x00ff) {
1037
57
      op = CAIRO_OPERATOR_CLEAR;
1038
7.82M
  } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
1039
0
      if ((solid->color.red_short |
1040
0
     solid->color.green_short |
1041
0
     solid->color.blue_short) <= 0x00ff)
1042
0
      {
1043
0
    op = CAIRO_OPERATOR_CLEAR;
1044
0
      }
1045
0
  }
1046
7.82M
    } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1047
17.3k
  const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
1048
17.3k
  if (surface->surface->is_clear &&
1049
0
      surface->surface->content & CAIRO_CONTENT_ALPHA)
1050
0
  {
1051
0
      op = CAIRO_OPERATOR_CLEAR;
1052
0
  }
1053
17.3k
    } else {
1054
0
  const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
1055
0
  if (gradient->n_stops == 0)
1056
0
      op = CAIRO_OPERATOR_CLEAR;
1057
0
    }
1058
1059
7.83M
    return op;
1060
12.1M
}
1061
1062
static cairo_status_t
1063
_cairo_gstate_get_pattern_status (const cairo_pattern_t *pattern)
1064
16.7M
{
1065
16.7M
    if (unlikely (pattern->type == CAIRO_PATTERN_TYPE_MESH &&
1066
16.7M
      ((const cairo_mesh_pattern_t *) pattern)->current_patch))
1067
0
    {
1068
  /* If current patch != NULL, the pattern is under construction
1069
   * and cannot be used as a source */
1070
0
  return CAIRO_STATUS_INVALID_MESH_CONSTRUCTION;
1071
0
    }
1072
1073
16.7M
    return pattern->status;
1074
16.7M
}
1075
1076
cairo_status_t
1077
_cairo_gstate_paint (cairo_gstate_t *gstate)
1078
516k
{
1079
516k
    cairo_pattern_union_t source_pattern;
1080
516k
    const cairo_pattern_t *pattern;
1081
516k
    cairo_status_t status;
1082
516k
    cairo_operator_t op;
1083
1084
516k
    status = _cairo_gstate_get_pattern_status (gstate->source);
1085
516k
    if (unlikely (status))
1086
0
  return status;
1087
1088
516k
    if (gstate->op == CAIRO_OPERATOR_DEST)
1089
0
  return CAIRO_STATUS_SUCCESS;
1090
1091
516k
    if (_cairo_clip_is_all_clipped (gstate->clip))
1092
501
  return CAIRO_STATUS_SUCCESS;
1093
1094
515k
    op = _reduce_op (gstate);
1095
515k
    if (op == CAIRO_OPERATOR_CLEAR) {
1096
0
  pattern = &_cairo_pattern_clear.base;
1097
515k
    } else {
1098
515k
  _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1099
515k
  pattern = &source_pattern.base;
1100
515k
    }
1101
1102
515k
    return _cairo_surface_paint (gstate->target,
1103
515k
         op, pattern,
1104
515k
         gstate->clip);
1105
516k
}
1106
1107
cairo_status_t
1108
_cairo_gstate_mask (cairo_gstate_t  *gstate,
1109
        cairo_pattern_t *mask)
1110
0
{
1111
0
    cairo_pattern_union_t source_pattern, mask_pattern;
1112
0
    const cairo_pattern_t *source;
1113
0
    cairo_operator_t op;
1114
0
    cairo_status_t status;
1115
1116
0
    status = _cairo_gstate_get_pattern_status (mask);
1117
0
    if (unlikely (status))
1118
0
  return status;
1119
1120
0
    status = _cairo_gstate_get_pattern_status (gstate->source);
1121
0
    if (unlikely (status))
1122
0
  return status;
1123
1124
0
    if (gstate->op == CAIRO_OPERATOR_DEST)
1125
0
  return CAIRO_STATUS_SUCCESS;
1126
1127
0
    if (_cairo_clip_is_all_clipped (gstate->clip))
1128
0
  return CAIRO_STATUS_SUCCESS;
1129
1130
0
    assert (gstate->opacity == 1.0);
1131
1132
0
    if (_cairo_pattern_is_opaque (mask, NULL))
1133
0
  return _cairo_gstate_paint (gstate);
1134
1135
0
    if (_cairo_pattern_is_clear (mask) &&
1136
0
  _cairo_operator_bounded_by_mask (gstate->op))
1137
0
    {
1138
0
  return CAIRO_STATUS_SUCCESS;
1139
0
    }
1140
1141
0
    op = _reduce_op (gstate);
1142
0
    if (op == CAIRO_OPERATOR_CLEAR) {
1143
0
  source = &_cairo_pattern_clear.base;
1144
0
    } else {
1145
0
  _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1146
0
  source = &source_pattern.base;
1147
0
    }
1148
0
    _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
1149
1150
0
    if (source->type == CAIRO_PATTERN_TYPE_SOLID && !source->is_foreground_marker &&
1151
0
  mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
1152
0
  _cairo_operator_bounded_by_source (op))
1153
0
    {
1154
0
  const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1155
0
  cairo_color_t combined;
1156
1157
0
  if (mask_pattern.base.has_component_alpha) {
1158
0
#define M(R, A, B, c) R.c = A.c * B.c
1159
0
      M(combined, solid->color, mask_pattern.solid.color, red);
1160
0
      M(combined, solid->color, mask_pattern.solid.color, green);
1161
0
      M(combined, solid->color, mask_pattern.solid.color, blue);
1162
0
      M(combined, solid->color, mask_pattern.solid.color, alpha);
1163
0
#undef M
1164
0
  } else {
1165
0
      combined = solid->color;
1166
0
      _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
1167
0
  }
1168
1169
0
  _cairo_pattern_init_solid (&source_pattern.solid, &combined);
1170
1171
0
  status = _cairo_surface_paint (gstate->target, op,
1172
0
               &source_pattern.base,
1173
0
               gstate->clip);
1174
0
    }
1175
0
    else
1176
0
    {
1177
0
  status = _cairo_surface_mask (gstate->target, op,
1178
0
              source,
1179
0
              &mask_pattern.base,
1180
0
              gstate->clip);
1181
0
    }
1182
1183
0
    return status;
1184
0
}
1185
1186
cairo_status_t
1187
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1188
1.04M
{
1189
1.04M
    cairo_pattern_union_t source_pattern;
1190
1.04M
    cairo_stroke_style_t style;
1191
1.04M
    double dash[2];
1192
1.04M
    cairo_status_t status;
1193
1.04M
    cairo_matrix_t aggregate_transform;
1194
1.04M
    cairo_matrix_t aggregate_transform_inverse;
1195
1196
1.04M
    status = _cairo_gstate_get_pattern_status (gstate->source);
1197
1.04M
    if (unlikely (status))
1198
0
  return status;
1199
1200
1.04M
    if (gstate->op == CAIRO_OPERATOR_DEST)
1201
0
  return CAIRO_STATUS_SUCCESS;
1202
1203
1.04M
    if (gstate->stroke_style.line_width <= 0.0 && !gstate->stroke_style.is_hairline)
1204
214
  return CAIRO_STATUS_SUCCESS;
1205
1206
1.04M
    if (_cairo_clip_is_all_clipped (gstate->clip))
1207
0
  return CAIRO_STATUS_SUCCESS;
1208
1209
1.04M
    assert (gstate->opacity == 1.0);
1210
1211
1.04M
    cairo_matrix_multiply (&aggregate_transform,
1212
1.04M
                           &gstate->ctm,
1213
1.04M
                           &gstate->target->device_transform);
1214
1.04M
    cairo_matrix_multiply (&aggregate_transform_inverse,
1215
1.04M
                           &gstate->target->device_transform_inverse,
1216
1.04M
                           &gstate->ctm_inverse);
1217
1218
1.04M
    memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
1219
1.04M
    if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &aggregate_transform, gstate->tolerance)) {
1220
0
        style.dash = dash;
1221
0
        _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
1222
0
                &style.dash_offset,
1223
0
                style.dash,
1224
0
                &style.num_dashes);
1225
0
    }
1226
1227
1.04M
    _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1228
1229
1.04M
    return _cairo_surface_stroke (gstate->target,
1230
1.04M
          gstate->op,
1231
1.04M
          &source_pattern.base,
1232
1.04M
          path,
1233
1.04M
          &style,
1234
1.04M
          &aggregate_transform,
1235
1.04M
          &aggregate_transform_inverse,
1236
1.04M
          gstate->tolerance,
1237
1.04M
          gstate->antialias,
1238
1.04M
          gstate->clip);
1239
1.04M
}
1240
1241
cairo_status_t
1242
_cairo_gstate_in_stroke (cairo_gstate_t     *gstate,
1243
       cairo_path_fixed_t *path,
1244
       double        x,
1245
       double        y,
1246
       cairo_bool_t     *inside_ret)
1247
0
{
1248
0
    cairo_status_t status;
1249
0
    cairo_rectangle_int_t extents;
1250
0
    cairo_box_t limit;
1251
0
    cairo_traps_t traps;
1252
1253
0
    if (gstate->stroke_style.line_width <= 0.0) {
1254
0
  *inside_ret = FALSE;
1255
0
  return CAIRO_STATUS_SUCCESS;
1256
0
    }
1257
1258
0
    _cairo_gstate_user_to_backend (gstate, &x, &y);
1259
1260
    /* Before we perform the expensive stroke analysis,
1261
     * check whether the point is within the extents of the path.
1262
     */
1263
0
    _cairo_path_fixed_approximate_stroke_extents (path,
1264
0
              &gstate->stroke_style,
1265
0
              &gstate->ctm,
1266
0
              gstate->target->is_vector,
1267
0
              &extents);
1268
0
    if (x < extents.x || x > extents.x + extents.width ||
1269
0
  y < extents.y || y > extents.y + extents.height)
1270
0
    {
1271
0
  *inside_ret = FALSE;
1272
0
  return CAIRO_STATUS_SUCCESS;
1273
0
    }
1274
1275
0
    limit.p1.x = _cairo_fixed_from_double (x) - 1;
1276
0
    limit.p1.y = _cairo_fixed_from_double (y) - 1;
1277
0
    limit.p2.x = limit.p1.x + 2;
1278
0
    limit.p2.y = limit.p1.y + 2;
1279
1280
0
    _cairo_traps_init (&traps);
1281
0
    _cairo_traps_limit (&traps, &limit, 1);
1282
1283
0
    status = _cairo_path_fixed_stroke_polygon_to_traps (path,
1284
0
              &gstate->stroke_style,
1285
0
              &gstate->ctm,
1286
0
              &gstate->ctm_inverse,
1287
0
              gstate->tolerance,
1288
0
              &traps);
1289
0
    if (unlikely (status))
1290
0
  goto BAIL;
1291
1292
0
    *inside_ret = _cairo_traps_contain (&traps, x, y);
1293
1294
0
BAIL:
1295
0
    _cairo_traps_fini (&traps);
1296
1297
0
    return status;
1298
0
}
1299
1300
cairo_status_t
1301
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1302
12.9M
{
1303
12.9M
    cairo_status_t status;
1304
1305
12.9M
    status = _cairo_gstate_get_pattern_status (gstate->source);
1306
12.9M
    if (unlikely (status))
1307
0
  return status;
1308
1309
12.9M
    if (gstate->op == CAIRO_OPERATOR_DEST)
1310
0
  return CAIRO_STATUS_SUCCESS;
1311
1312
12.9M
    if (_cairo_clip_is_all_clipped (gstate->clip))
1313
0
  return CAIRO_STATUS_SUCCESS;
1314
1315
12.9M
    assert (gstate->opacity == 1.0);
1316
1317
12.9M
    if (_cairo_path_fixed_fill_is_empty (path)) {
1318
1.78M
  if (_cairo_operator_bounded_by_mask (gstate->op))
1319
1.78M
      return CAIRO_STATUS_SUCCESS;
1320
1321
0
  status = _cairo_surface_paint (gstate->target,
1322
0
               CAIRO_OPERATOR_CLEAR,
1323
0
               &_cairo_pattern_clear.base,
1324
0
               gstate->clip);
1325
11.2M
    } else {
1326
11.2M
  cairo_pattern_union_t source_pattern;
1327
11.2M
  const cairo_pattern_t *pattern;
1328
11.2M
  cairo_operator_t op;
1329
11.2M
  cairo_rectangle_int_t extents;
1330
11.2M
  cairo_box_t box;
1331
1332
11.2M
  op = _reduce_op (gstate);
1333
11.2M
  if (op == CAIRO_OPERATOR_CLEAR) {
1334
57
      pattern = &_cairo_pattern_clear.base;
1335
11.2M
  } else {
1336
11.2M
      _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1337
11.2M
      pattern = &source_pattern.base;
1338
11.2M
  }
1339
1340
  /* Toolkits often paint the entire background with a fill */
1341
11.2M
  if (_cairo_surface_get_extents (gstate->target, &extents) &&
1342
11.2M
      _cairo_path_fixed_is_box (path, &box) &&
1343
5.97M
      box.p1.x <= _cairo_fixed_from_int (extents.x) &&
1344
4.28M
      box.p1.y <= _cairo_fixed_from_int (extents.y) &&
1345
3.08M
      box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
1346
2.23M
      box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
1347
1.54M
  {
1348
1.54M
      status = _cairo_surface_paint (gstate->target, op, pattern,
1349
1.54M
             gstate->clip);
1350
1.54M
  }
1351
9.66M
  else
1352
9.66M
  {
1353
9.66M
      status = _cairo_surface_fill (gstate->target, op, pattern,
1354
9.66M
            path,
1355
9.66M
            gstate->fill_rule,
1356
9.66M
            gstate->tolerance,
1357
9.66M
            gstate->antialias,
1358
9.66M
            gstate->clip);
1359
9.66M
  }
1360
11.2M
    }
1361
1362
11.2M
    return status;
1363
12.9M
}
1364
1365
cairo_bool_t
1366
_cairo_gstate_in_fill (cairo_gstate_t   *gstate,
1367
           cairo_path_fixed_t *path,
1368
           double      x,
1369
           double      y)
1370
0
{
1371
0
    _cairo_gstate_user_to_backend (gstate, &x, &y);
1372
1373
0
    return _cairo_path_fixed_in_fill (path,
1374
0
              gstate->fill_rule,
1375
0
              gstate->tolerance,
1376
0
              x, y);
1377
0
}
1378
1379
cairo_bool_t
1380
_cairo_gstate_in_clip (cairo_gstate_t   *gstate,
1381
           double      x,
1382
           double      y)
1383
0
{
1384
0
    cairo_clip_t *clip = gstate->clip;
1385
0
    int i;
1386
1387
0
    if (_cairo_clip_is_all_clipped (clip))
1388
0
  return FALSE;
1389
1390
0
    if (clip == NULL)
1391
0
  return TRUE;
1392
1393
0
    _cairo_gstate_user_to_backend (gstate, &x, &y);
1394
1395
0
    if (x <  clip->extents.x ||
1396
0
  x >= clip->extents.x + clip->extents.width ||
1397
0
  y <  clip->extents.y ||
1398
0
  y >= clip->extents.y + clip->extents.height)
1399
0
    {
1400
0
  return FALSE;
1401
0
    }
1402
1403
0
    if (clip->num_boxes) {
1404
0
  int fx, fy;
1405
1406
0
  fx = _cairo_fixed_from_double (x);
1407
0
  fy = _cairo_fixed_from_double (y);
1408
0
  for (i = 0; i < clip->num_boxes; i++) {
1409
0
      if (fx >= clip->boxes[i].p1.x && fx <= clip->boxes[i].p2.x &&
1410
0
    fy >= clip->boxes[i].p1.y && fy <= clip->boxes[i].p2.y)
1411
0
    break;
1412
0
  }
1413
0
  if (i == clip->num_boxes)
1414
0
      return FALSE;
1415
0
    }
1416
1417
0
    if (clip->path) {
1418
0
  cairo_clip_path_t *clip_path = clip->path;
1419
0
  do {
1420
0
      if (! _cairo_path_fixed_in_fill (&clip_path->path,
1421
0
               clip_path->fill_rule,
1422
0
               clip_path->tolerance,
1423
0
               x, y))
1424
0
    return FALSE;
1425
0
  } while ((clip_path = clip_path->prev) != NULL);
1426
0
    }
1427
1428
0
    return TRUE;
1429
0
}
1430
1431
cairo_status_t
1432
_cairo_gstate_copy_page (cairo_gstate_t *gstate)
1433
0
{
1434
0
    cairo_surface_copy_page (gstate->target);
1435
0
    return cairo_surface_status (gstate->target);
1436
0
}
1437
1438
cairo_status_t
1439
_cairo_gstate_show_page (cairo_gstate_t *gstate)
1440
0
{
1441
0
    cairo_surface_show_page (gstate->target);
1442
0
    return cairo_surface_status (gstate->target);
1443
0
}
1444
1445
static void
1446
_cairo_gstate_extents_to_user_rectangle (cairo_gstate_t   *gstate,
1447
           const cairo_box_t *extents,
1448
           double *x1, double *y1,
1449
           double *x2, double *y2)
1450
0
{
1451
0
    double px1, py1, px2, py2;
1452
1453
0
    px1 = _cairo_fixed_to_double (extents->p1.x);
1454
0
    py1 = _cairo_fixed_to_double (extents->p1.y);
1455
0
    px2 = _cairo_fixed_to_double (extents->p2.x);
1456
0
    py2 = _cairo_fixed_to_double (extents->p2.y);
1457
1458
0
    _cairo_gstate_backend_to_user_rectangle (gstate,
1459
0
               &px1, &py1, &px2, &py2,
1460
0
               NULL);
1461
0
    if (x1)
1462
0
  *x1 = px1;
1463
0
    if (y1)
1464
0
  *y1 = py1;
1465
0
    if (x2)
1466
0
  *x2 = px2;
1467
0
    if (y2)
1468
0
  *y2 = py2;
1469
0
}
1470
1471
cairo_status_t
1472
_cairo_gstate_stroke_extents (cairo_gstate_t   *gstate,
1473
            cairo_path_fixed_t *path,
1474
                              double *x1, double *y1,
1475
            double *x2, double *y2)
1476
0
{
1477
0
    cairo_int_status_t status;
1478
0
    cairo_box_t extents;
1479
0
    cairo_bool_t empty;
1480
1481
0
    if (x1)
1482
0
  *x1 = 0.0;
1483
0
    if (y1)
1484
0
  *y1 = 0.0;
1485
0
    if (x2)
1486
0
  *x2 = 0.0;
1487
0
    if (y2)
1488
0
  *y2 = 0.0;
1489
1490
0
    if (gstate->stroke_style.line_width <= 0.0)
1491
0
  return CAIRO_STATUS_SUCCESS;
1492
1493
0
    status = CAIRO_INT_STATUS_UNSUPPORTED;
1494
0
    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
1495
0
  cairo_boxes_t boxes;
1496
1497
0
  _cairo_boxes_init (&boxes);
1498
0
  status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
1499
0
                &gstate->stroke_style,
1500
0
                &gstate->ctm,
1501
0
                gstate->antialias,
1502
0
                &boxes);
1503
0
  empty = boxes.num_boxes == 0;
1504
0
  if (! empty)
1505
0
      _cairo_boxes_extents (&boxes, &extents);
1506
0
  _cairo_boxes_fini (&boxes);
1507
0
    }
1508
1509
0
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1510
0
  cairo_polygon_t polygon;
1511
1512
0
  _cairo_polygon_init (&polygon, NULL, 0);
1513
0
  status = _cairo_path_fixed_stroke_to_polygon (path,
1514
0
                  &gstate->stroke_style,
1515
0
                  &gstate->ctm,
1516
0
                  &gstate->ctm_inverse,
1517
0
                  gstate->tolerance,
1518
0
                  &polygon);
1519
0
  empty = polygon.num_edges == 0;
1520
0
  if (! empty)
1521
0
      extents = polygon.extents;
1522
0
  _cairo_polygon_fini (&polygon);
1523
0
    }
1524
0
    if (! empty) {
1525
0
  _cairo_gstate_extents_to_user_rectangle (gstate, &extents,
1526
0
             x1, y1, x2, y2);
1527
0
    }
1528
1529
0
    return status;
1530
0
}
1531
1532
cairo_status_t
1533
_cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
1534
          cairo_path_fixed_t *path,
1535
                            double *x1, double *y1,
1536
          double *x2, double *y2)
1537
0
{
1538
0
    cairo_status_t status;
1539
0
    cairo_box_t extents;
1540
0
    cairo_bool_t empty;
1541
1542
0
    if (x1)
1543
0
  *x1 = 0.0;
1544
0
    if (y1)
1545
0
  *y1 = 0.0;
1546
0
    if (x2)
1547
0
  *x2 = 0.0;
1548
0
    if (y2)
1549
0
  *y2 = 0.0;
1550
1551
0
    if (_cairo_path_fixed_fill_is_empty (path))
1552
0
  return CAIRO_STATUS_SUCCESS;
1553
1554
0
    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
1555
0
  cairo_boxes_t boxes;
1556
1557
0
  _cairo_boxes_init (&boxes);
1558
0
  status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
1559
0
                    gstate->fill_rule,
1560
0
                    gstate->antialias,
1561
0
                    &boxes);
1562
0
  empty = boxes.num_boxes == 0;
1563
0
  if (! empty)
1564
0
      _cairo_boxes_extents (&boxes, &extents);
1565
1566
0
  _cairo_boxes_fini (&boxes);
1567
0
    } else {
1568
0
  cairo_traps_t traps;
1569
1570
0
  _cairo_traps_init (&traps);
1571
1572
0
  status = _cairo_path_fixed_fill_to_traps (path,
1573
0
              gstate->fill_rule,
1574
0
              gstate->tolerance,
1575
0
              &traps);
1576
0
  empty = traps.num_traps == 0;
1577
0
  if (! empty)
1578
0
      _cairo_traps_extents (&traps, &extents);
1579
1580
0
  _cairo_traps_fini (&traps);
1581
0
    }
1582
1583
0
    if (! empty) {
1584
0
  _cairo_gstate_extents_to_user_rectangle (gstate, &extents,
1585
0
             x1, y1, x2, y2);
1586
0
    }
1587
1588
0
    return status;
1589
0
}
1590
1591
cairo_status_t
1592
_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
1593
1
{
1594
1
    _cairo_clip_destroy (gstate->clip);
1595
1
    gstate->clip = NULL;
1596
1597
1
    return CAIRO_STATUS_SUCCESS;
1598
1
}
1599
1600
cairo_status_t
1601
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1602
1.48M
{
1603
1.48M
    gstate->clip =
1604
1.48M
  _cairo_clip_intersect_path (gstate->clip,
1605
1.48M
            path,
1606
1.48M
            gstate->fill_rule,
1607
1.48M
            gstate->tolerance,
1608
1.48M
            gstate->antialias);
1609
    /* XXX */
1610
1.48M
    return CAIRO_STATUS_SUCCESS;
1611
1.48M
}
1612
1613
static cairo_bool_t
1614
_cairo_gstate_int_clip_extents (cairo_gstate_t        *gstate,
1615
        cairo_rectangle_int_t *extents)
1616
14.8M
{
1617
14.8M
    cairo_bool_t is_bounded;
1618
1619
14.8M
    is_bounded = _cairo_surface_get_extents (gstate->target, extents);
1620
1621
14.8M
    if (gstate->clip) {
1622
1.58M
  _cairo_rectangle_intersect (extents,
1623
1.58M
            _cairo_clip_get_extents (gstate->clip));
1624
1.58M
  is_bounded = TRUE;
1625
1.58M
    }
1626
1627
14.8M
    return is_bounded;
1628
14.8M
}
1629
1630
cairo_bool_t
1631
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
1632
                double         *x1,
1633
                double         *y1,
1634
          double         *x2,
1635
          double         *y2)
1636
12.5M
{
1637
12.5M
    cairo_rectangle_int_t extents;
1638
12.5M
    double px1, py1, px2, py2;
1639
1640
12.5M
    if (! _cairo_gstate_int_clip_extents (gstate, &extents))
1641
0
  return FALSE;
1642
1643
12.5M
    px1 = extents.x;
1644
12.5M
    py1 = extents.y;
1645
12.5M
    px2 = extents.x + (int) extents.width;
1646
12.5M
    py2 = extents.y + (int) extents.height;
1647
1648
12.5M
    _cairo_gstate_backend_to_user_rectangle (gstate,
1649
12.5M
               &px1, &py1, &px2, &py2,
1650
12.5M
               NULL);
1651
1652
12.5M
    if (x1)
1653
12.5M
  *x1 = px1;
1654
12.5M
    if (y1)
1655
12.5M
  *y1 = py1;
1656
12.5M
    if (x2)
1657
12.5M
  *x2 = px2;
1658
12.5M
    if (y2)
1659
12.5M
  *y2 = py2;
1660
1661
12.5M
    return TRUE;
1662
12.5M
}
1663
1664
cairo_rectangle_list_t*
1665
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
1666
0
{
1667
0
    cairo_rectangle_int_t extents;
1668
0
    cairo_rectangle_list_t *list;
1669
0
    cairo_clip_t *clip;
1670
1671
0
    if (_cairo_surface_get_extents (gstate->target, &extents))
1672
0
  clip = _cairo_clip_copy_intersect_rectangle (gstate->clip, &extents);
1673
0
    else
1674
0
  clip = gstate->clip;
1675
1676
0
    list = _cairo_clip_copy_rectangle_list (clip, gstate);
1677
1678
0
    if (clip != gstate->clip)
1679
0
  _cairo_clip_destroy (clip);
1680
1681
0
    return list;
1682
0
}
1683
1684
cairo_status_t
1685
_cairo_gstate_tag_begin (cairo_gstate_t *gstate,
1686
       const char *tag_name, const char *attributes)
1687
0
{
1688
0
    return _cairo_surface_tag (gstate->target,
1689
0
             TRUE, /* begin */
1690
0
             tag_name,
1691
0
             attributes ? attributes : "");
1692
0
}
1693
1694
cairo_status_t
1695
_cairo_gstate_tag_end (cairo_gstate_t *gstate,
1696
           const char *tag_name)
1697
0
{
1698
0
    return _cairo_surface_tag (gstate->target,
1699
0
             FALSE, /* begin */
1700
0
             tag_name,
1701
0
             NULL); /* attributes */
1702
0
}
1703
1704
static void
1705
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
1706
5.55M
{
1707
5.55M
    if (gstate->scaled_font == NULL)
1708
3.34M
  return;
1709
1710
2.20M
    if (gstate->previous_scaled_font != NULL)
1711
2.20M
  cairo_scaled_font_destroy (gstate->previous_scaled_font);
1712
1713
2.20M
    gstate->previous_scaled_font = gstate->scaled_font;
1714
2.20M
    gstate->scaled_font = NULL;
1715
2.20M
}
1716
1717
cairo_status_t
1718
_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
1719
           double          size)
1720
2.22M
{
1721
2.22M
    _cairo_gstate_unset_scaled_font (gstate);
1722
1723
2.22M
    cairo_matrix_init_scale (&gstate->font_matrix, size, size);
1724
1725
2.22M
    return CAIRO_STATUS_SUCCESS;
1726
2.22M
}
1727
1728
cairo_status_t
1729
_cairo_gstate_set_font_matrix (cairo_gstate_t     *gstate,
1730
             const cairo_matrix_t *matrix)
1731
2.22M
{
1732
2.22M
    if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0)
1733
34.3k
  return CAIRO_STATUS_SUCCESS;
1734
1735
2.19M
    _cairo_gstate_unset_scaled_font (gstate);
1736
1737
2.19M
    gstate->font_matrix = *matrix;
1738
1739
2.19M
    return CAIRO_STATUS_SUCCESS;
1740
2.22M
}
1741
1742
void
1743
_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
1744
             cairo_matrix_t *matrix)
1745
0
{
1746
0
    *matrix = gstate->font_matrix;
1747
0
}
1748
1749
void
1750
_cairo_gstate_set_font_options (cairo_gstate_t             *gstate,
1751
        const cairo_font_options_t *options)
1752
21.7k
{
1753
21.7k
    if (_cairo_font_options_compare (options, &gstate->font_options))
1754
0
  return;
1755
1756
21.7k
    _cairo_gstate_unset_scaled_font (gstate);
1757
1758
21.7k
    _cairo_font_options_fini (&gstate->font_options);
1759
21.7k
    _cairo_font_options_init_copy (&gstate->font_options, options);
1760
21.7k
}
1761
1762
void
1763
_cairo_gstate_get_font_options (cairo_gstate_t       *gstate,
1764
        cairo_font_options_t *options)
1765
0
{
1766
0
    _cairo_font_options_fini (options);
1767
0
    _cairo_font_options_init_copy (options, &gstate->font_options);
1768
0
}
1769
1770
cairo_status_t
1771
_cairo_gstate_get_font_face (cairo_gstate_t     *gstate,
1772
           cairo_font_face_t **font_face)
1773
0
{
1774
0
    cairo_status_t status;
1775
1776
0
    status = _cairo_gstate_ensure_font_face (gstate);
1777
0
    if (unlikely (status))
1778
0
  return status;
1779
1780
0
    *font_face = gstate->font_face;
1781
1782
0
    return CAIRO_STATUS_SUCCESS;
1783
0
}
1784
1785
cairo_status_t
1786
_cairo_gstate_get_scaled_font (cairo_gstate_t       *gstate,
1787
             cairo_scaled_font_t **scaled_font)
1788
0
{
1789
0
    cairo_status_t status;
1790
1791
0
    status = _cairo_gstate_ensure_scaled_font (gstate);
1792
0
    if (unlikely (status))
1793
0
  return status;
1794
1795
0
    *scaled_font = gstate->scaled_font;
1796
1797
0
    return CAIRO_STATUS_SUCCESS;
1798
0
}
1799
1800
/*
1801
 * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
1802
 * it is easy to get confused about what's going on.
1803
 *
1804
 * The user's view
1805
 * ---------------
1806
 *
1807
 * Users ask for things in user space. When cairo starts, a user space unit
1808
 * is about 1/96 inch, which is similar to (but importantly different from)
1809
 * the normal "point" units most users think in terms of. When a user
1810
 * selects a font, its scale is set to "one user unit". The user can then
1811
 * independently scale the user coordinate system *or* the font matrix, in
1812
 * order to adjust the rendered size of the font.
1813
 *
1814
 * Metrics are returned in user space, whether they are obtained from
1815
 * the currently selected font in a  #cairo_t or from a #cairo_scaled_font_t
1816
 * which is a font specialized to a particular scale matrix, CTM, and target
1817
 * surface.
1818
 *
1819
 * The font's view
1820
 * ---------------
1821
 *
1822
 * Fonts are designed and stored (in say .ttf files) in "font space", which
1823
 * describes an "EM Square" (a design tile) and has some abstract number
1824
 * such as 1000, 1024, or 2048 units per "EM". This is basically an
1825
 * uninteresting space for us, but we need to remember that it exists.
1826
 *
1827
 * Font resources (from libraries or operating systems) render themselves
1828
 * to a particular device. Since they do not want to make most programmers
1829
 * worry about the font design space, the scaling API is simplified to
1830
 * involve just telling the font the required pixel size of the EM square
1831
 * (that is, in device space).
1832
 *
1833
 *
1834
 * Cairo's gstate view
1835
 * -------------------
1836
 *
1837
 * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
1838
 * called the "font matrix" which describes the user's most recent
1839
 * font-scaling or font-transforming request. This is kept in terms of an
1840
 * abstract scale factor, composed with the CTM and used to set the font's
1841
 * pixel size. So if the user asks to "scale the font by 12", the matrix
1842
 * is:
1843
 *
1844
 *   [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
1845
 *
1846
 * It is an affine matrix, like all cairo matrices, where its tx and ty
1847
 * components are used to "nudging" fonts around and are handled in gstate
1848
 * and then ignored by the "scaled-font" layer.
1849
 *
1850
 * In order to perform any action on a font, we must build an object
1851
 * called a #cairo_font_scale_t; this contains the central 2x2 matrix
1852
 * resulting from "font matrix * CTM" (sans the font matrix translation
1853
 * components as stated in the previous paragraph).
1854
 *
1855
 * We pass this to the font when making requests of it, which causes it to
1856
 * reply for a particular [user request, device] combination, under the CTM
1857
 * (to accommodate the "zoom in" == "bigger fonts" issue above).
1858
 *
1859
 * The other terms in our communication with the font are therefore in
1860
 * device space. When we ask it to perform text->glyph conversion, it will
1861
 * produce a glyph string in device space. Glyph vectors we pass to it for
1862
 * measuring or rendering should be in device space. The metrics which we
1863
 * get back from the font will be in device space. The contents of the
1864
 * global glyph image cache will be in device space.
1865
 *
1866
 *
1867
 * Cairo's public view
1868
 * -------------------
1869
 *
1870
 * Since the values entering and leaving via public API calls are in user
1871
 * space, the gstate functions typically need to multiply arguments by the
1872
 * CTM (for user-input glyph vectors), and return values by the CTM inverse
1873
 * (for font responses such as metrics or glyph vectors).
1874
 *
1875
 */
1876
1877
static cairo_status_t
1878
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
1879
2.22M
{
1880
2.22M
    cairo_font_face_t *font_face;
1881
1882
2.22M
    if (gstate->font_face != NULL)
1883
2.22M
  return gstate->font_face->status;
1884
1885
1886
0
    font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
1887
0
              CAIRO_FONT_SLANT_DEFAULT,
1888
0
              CAIRO_FONT_WEIGHT_DEFAULT);
1889
0
    if (font_face->status)
1890
0
  return font_face->status;
1891
1892
0
    gstate->font_face = font_face;
1893
1894
0
    return CAIRO_STATUS_SUCCESS;
1895
0
}
1896
1897
static cairo_status_t
1898
_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
1899
2.22M
{
1900
2.22M
    cairo_status_t status;
1901
2.22M
    cairo_font_options_t options;
1902
2.22M
    cairo_scaled_font_t *scaled_font;
1903
2.22M
    cairo_matrix_t font_ctm;
1904
1905
2.22M
    if (gstate->scaled_font != NULL)
1906
0
  return gstate->scaled_font->status;
1907
1908
2.22M
    status = _cairo_gstate_ensure_font_face (gstate);
1909
2.22M
    if (unlikely (status))
1910
0
  return status;
1911
1912
2.22M
    cairo_surface_get_font_options (gstate->target, &options);
1913
2.22M
    cairo_font_options_merge (&options, &gstate->font_options);
1914
1915
2.22M
    cairo_matrix_multiply (&font_ctm,
1916
2.22M
         &gstate->ctm,
1917
2.22M
         &gstate->target->device_transform);
1918
1919
2.22M
    scaled_font = cairo_scaled_font_create (gstate->font_face,
1920
2.22M
                    &gstate->font_matrix,
1921
2.22M
              &font_ctm,
1922
2.22M
              &options);
1923
1924
2.22M
    _cairo_font_options_fini (&options);
1925
1926
2.22M
    status = cairo_scaled_font_status (scaled_font);
1927
2.22M
    if (unlikely (status))
1928
0
  return status;
1929
1930
2.22M
    gstate->scaled_font = scaled_font;
1931
1932
2.22M
    return CAIRO_STATUS_SUCCESS;
1933
2.22M
}
1934
1935
cairo_status_t
1936
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
1937
        cairo_font_extents_t *extents)
1938
0
{
1939
0
    cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
1940
0
    if (unlikely (status))
1941
0
  return status;
1942
1943
0
    cairo_scaled_font_extents (gstate->scaled_font, extents);
1944
1945
0
    return cairo_scaled_font_status (gstate->scaled_font);
1946
0
}
1947
1948
cairo_status_t
1949
_cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
1950
           cairo_font_face_t *font_face)
1951
2.22M
{
1952
2.22M
    if (font_face && font_face->status)
1953
0
  return _cairo_error (font_face->status);
1954
1955
2.22M
    if (font_face == gstate->font_face)
1956
2.20M
  return CAIRO_STATUS_SUCCESS;
1957
1958
21.7k
    cairo_font_face_destroy (gstate->font_face);
1959
21.7k
    gstate->font_face = cairo_font_face_reference (font_face);
1960
1961
21.7k
    _cairo_gstate_unset_scaled_font (gstate);
1962
1963
21.7k
    return CAIRO_STATUS_SUCCESS;
1964
2.22M
}
1965
1966
cairo_status_t
1967
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
1968
           const cairo_glyph_t *glyphs,
1969
           int num_glyphs,
1970
           cairo_text_extents_t *extents)
1971
0
{
1972
0
    cairo_status_t status;
1973
1974
0
    status = _cairo_gstate_ensure_scaled_font (gstate);
1975
0
    if (unlikely (status))
1976
0
  return status;
1977
1978
0
    cairo_scaled_font_glyph_extents (gstate->scaled_font,
1979
0
             glyphs, num_glyphs,
1980
0
             extents);
1981
1982
0
    return cairo_scaled_font_status (gstate->scaled_font);
1983
0
}
1984
1985
cairo_status_t
1986
_cairo_gstate_show_text_glyphs (cairo_gstate_t       *gstate,
1987
        const cairo_glyph_t    *glyphs,
1988
        int         num_glyphs,
1989
        cairo_glyph_text_info_t    *info)
1990
2.22M
{
1991
2.22M
    cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
1992
2.22M
    cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
1993
2.22M
    cairo_pattern_union_t source_pattern;
1994
2.22M
    cairo_glyph_t *transformed_glyphs;
1995
2.22M
    const cairo_pattern_t *pattern;
1996
2.22M
    cairo_text_cluster_t *transformed_clusters;
1997
2.22M
    cairo_operator_t op;
1998
2.22M
    cairo_status_t status;
1999
2000
2.22M
    status = _cairo_gstate_get_pattern_status (gstate->source);
2001
2.22M
    if (unlikely (status))
2002
0
  return status;
2003
2004
2.22M
    if (gstate->op == CAIRO_OPERATOR_DEST)
2005
0
  return CAIRO_STATUS_SUCCESS;
2006
2007
2.22M
    if (_cairo_clip_is_all_clipped (gstate->clip))
2008
0
  return CAIRO_STATUS_SUCCESS;
2009
2010
2.22M
    status = _cairo_gstate_ensure_scaled_font (gstate);
2011
2.22M
    if (unlikely (status))
2012
0
  return status;
2013
2014
2.22M
    transformed_glyphs = stack_transformed_glyphs;
2015
2.22M
    transformed_clusters = stack_transformed_clusters;
2016
2017
2.22M
    if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
2018
7.17k
  transformed_glyphs = cairo_glyph_allocate (num_glyphs);
2019
7.17k
  if (unlikely (transformed_glyphs == NULL))
2020
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2021
7.17k
    }
2022
2023
2.22M
    if (info != NULL) {
2024
0
  if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
2025
0
      transformed_clusters = cairo_text_cluster_allocate (info->num_clusters);
2026
0
      if (unlikely (transformed_clusters == NULL)) {
2027
0
    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2028
0
    goto CLEANUP_GLYPHS;
2029
0
      }
2030
0
  }
2031
2032
0
  _cairo_gstate_transform_glyphs_to_backend (gstate,
2033
0
               glyphs, num_glyphs,
2034
0
               info->clusters,
2035
0
               info->num_clusters,
2036
0
               info->cluster_flags,
2037
0
               transformed_glyphs,
2038
0
               &num_glyphs,
2039
0
               transformed_clusters,
2040
0
               TRUE);
2041
2.22M
    } else {
2042
2.22M
  _cairo_gstate_transform_glyphs_to_backend (gstate,
2043
2.22M
               glyphs, num_glyphs,
2044
2.22M
               NULL, 0, 0,
2045
2.22M
               transformed_glyphs,
2046
2.22M
               &num_glyphs,
2047
2.22M
               NULL,
2048
2.22M
               TRUE);
2049
2.22M
    }
2050
2051
2.22M
    if (num_glyphs == 0)
2052
1.79M
  goto CLEANUP_GLYPHS;
2053
2054
429k
    op = _reduce_op (gstate);
2055
429k
    if (op == CAIRO_OPERATOR_CLEAR) {
2056
0
  pattern = &_cairo_pattern_clear.base;
2057
429k
    } else {
2058
429k
  _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
2059
429k
  pattern = &source_pattern.base;
2060
429k
    }
2061
2062
    /* For really huge font sizes, we can just do path;fill instead of
2063
     * show_glyphs, as show_glyphs would put excess pressure on the cache,
2064
     * and moreover, not all components below us correctly handle huge font
2065
     * sizes.  I wanted to set the limit at 256.  But alas, seems like cairo's
2066
     * rasterizer is something like ten times slower than freetype's for huge
2067
     * sizes.  So, no win just yet.  For now, do it for insanely-huge sizes,
2068
     * just to make sure we don't make anyone unhappy.  When we get a really
2069
     * fast rasterizer in cairo, we may want to readjust this.
2070
     *
2071
     * Needless to say, do this only if show_text_glyphs is not available. */
2072
429k
    if (cairo_surface_has_show_text_glyphs (gstate->target) ||
2073
429k
  _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
2074
429k
    {
2075
2076
429k
  if (info != NULL) {
2077
0
      status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
2078
0
                  info->utf8, info->utf8_len,
2079
0
                  transformed_glyphs, num_glyphs,
2080
0
                  transformed_clusters, info->num_clusters,
2081
0
                  info->cluster_flags,
2082
0
                  gstate->scaled_font,
2083
0
                  gstate->clip);
2084
429k
  } else {
2085
429k
      status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
2086
429k
                  NULL, 0,
2087
429k
                  transformed_glyphs, num_glyphs,
2088
429k
                  NULL, 0, 0,
2089
429k
                  gstate->scaled_font,
2090
429k
                  gstate->clip);
2091
429k
  }
2092
429k
    }
2093
0
    else
2094
0
    {
2095
0
  cairo_path_fixed_t path;
2096
2097
0
  _cairo_path_fixed_init (&path);
2098
2099
0
  status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2100
0
            transformed_glyphs, num_glyphs,
2101
0
            &path);
2102
2103
0
  if (status == CAIRO_STATUS_SUCCESS) {
2104
0
      status = _cairo_surface_fill (gstate->target, op, pattern,
2105
0
            &path,
2106
0
            CAIRO_FILL_RULE_WINDING,
2107
0
            gstate->tolerance,
2108
0
            gstate->scaled_font->options.antialias,
2109
0
            gstate->clip);
2110
0
  }
2111
2112
0
  _cairo_path_fixed_fini (&path);
2113
0
    }
2114
2115
2.22M
CLEANUP_GLYPHS:
2116
2.22M
    if (transformed_glyphs != stack_transformed_glyphs)
2117
7.17k
      cairo_glyph_free (transformed_glyphs);
2118
2.22M
    if (transformed_clusters != stack_transformed_clusters)
2119
0
      cairo_text_cluster_free (transformed_clusters);
2120
2121
2.22M
    return status;
2122
429k
}
2123
2124
cairo_status_t
2125
_cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
2126
        const cairo_glyph_t *glyphs,
2127
        int          num_glyphs,
2128
        cairo_path_fixed_t  *path)
2129
0
{
2130
0
    cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
2131
0
    cairo_glyph_t *transformed_glyphs;
2132
0
    cairo_status_t status;
2133
2134
0
    status = _cairo_gstate_ensure_scaled_font (gstate);
2135
0
    if (unlikely (status))
2136
0
  return status;
2137
2138
0
    if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
2139
0
  transformed_glyphs = stack_transformed_glyphs;
2140
0
    } else {
2141
0
  transformed_glyphs = cairo_glyph_allocate (num_glyphs);
2142
0
  if (unlikely (transformed_glyphs == NULL))
2143
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2144
0
    }
2145
2146
0
    _cairo_gstate_transform_glyphs_to_backend (gstate,
2147
0
                 glyphs, num_glyphs,
2148
0
                 NULL, 0, 0,
2149
0
                 transformed_glyphs,
2150
0
                 &num_glyphs, NULL, FALSE);
2151
2152
0
    status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2153
0
              transformed_glyphs, num_glyphs,
2154
0
              path);
2155
2156
0
    if (transformed_glyphs != stack_transformed_glyphs)
2157
0
      cairo_glyph_free (transformed_glyphs);
2158
2159
0
    return status;
2160
0
}
2161
2162
cairo_status_t
2163
_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
2164
           cairo_antialias_t antialias)
2165
12.6M
{
2166
12.6M
    gstate->antialias = antialias;
2167
2168
12.6M
    return CAIRO_STATUS_SUCCESS;
2169
12.6M
}
2170
2171
cairo_antialias_t
2172
_cairo_gstate_get_antialias (cairo_gstate_t *gstate)
2173
0
{
2174
0
    return gstate->antialias;
2175
0
}
2176
2177
/**
2178
 * _cairo_gstate_transform_glyphs_to_backend:
2179
 * @gstate: a #cairo_gstate_t
2180
 * @glyphs: the array of #cairo_glyph_t objects to be transformed
2181
 * @num_glyphs: the number of elements in @glyphs
2182
 * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
2183
 * #cairo_glyph_t objects
2184
 * @num_transformed_glyphs: the number of elements in @transformed_glyphs
2185
 * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
2186
 * dropped
2187
 *
2188
 * Transform an array of glyphs to backend space by first adding the offset
2189
 * of the font matrix, then transforming from user space to backend space.
2190
 * The result of the transformation is placed in @transformed_glyphs.
2191
 *
2192
 * This also uses information from the scaled font and the surface to
2193
 * cull/drop glyphs that will not be visible.
2194
 **/
2195
static void
2196
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
2197
                                           const cairo_glyph_t  *glyphs,
2198
                                           int       num_glyphs,
2199
             const cairo_text_cluster_t *clusters,
2200
             int       num_clusters,
2201
             cairo_text_cluster_flags_t cluster_flags,
2202
                                           cairo_glyph_t  *transformed_glyphs,
2203
             int      *num_transformed_glyphs,
2204
             cairo_text_cluster_t *transformed_clusters,
2205
             cairo_bool_t         perform_early_clip)
2206
2.22M
{
2207
2.22M
    cairo_rectangle_int_t surface_extents;
2208
2.22M
    cairo_matrix_t *ctm = &gstate->ctm;
2209
2.22M
    cairo_matrix_t *font_matrix = &gstate->font_matrix;
2210
2.22M
    cairo_matrix_t *device_transform = &gstate->target->device_transform;
2211
2.22M
    cairo_bool_t drop = FALSE;
2212
2.22M
    double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
2213
2.22M
    int i, j, k;
2214
2215
2.22M
    drop = TRUE;
2216
2.22M
    if (!perform_early_clip || !_cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
2217
0
  drop = FALSE; /* unbounded surface */
2218
2.22M
    } else {
2219
2.22M
  double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
2220
2.22M
  if (surface_extents.width == 0 || surface_extents.height == 0) {
2221
    /* No visible area.  Don't draw anything */
2222
0
    *num_transformed_glyphs = 0;
2223
0
    return;
2224
0
  }
2225
  /* XXX We currently drop any glyphs that have their position outside
2226
   * of the surface boundaries by a safety margin depending on the
2227
   * font scale.  This however can fail in extreme cases where the
2228
   * font has really long swashes for example...  We can correctly
2229
   * handle that by looking the glyph up and using its device bbox
2230
   * to device if it's going to be visible, but I'm not inclined to
2231
   * do that now.
2232
   */
2233
2.22M
  x1 = surface_extents.x - scale10;
2234
2.22M
  y1 = surface_extents.y - scale10;
2235
2.22M
  x2 = surface_extents.x + (int) surface_extents.width  + scale10;
2236
2.22M
  y2 = surface_extents.y + (int) surface_extents.height + scale10;
2237
2.22M
    }
2238
2239
2.22M
    if (!drop)
2240
0
  *num_transformed_glyphs = num_glyphs;
2241
2242
11.1M
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
2243
2244
2.22M
    j = 0;
2245
2.22M
    if (_cairo_matrix_is_identity (ctm) &&
2246
2.22M
        _cairo_matrix_is_identity (device_transform) &&
2247
2.22M
  font_matrix->x0 == 0 && font_matrix->y0 == 0)
2248
2.22M
    {
2249
2.22M
  if (! drop) {
2250
0
      memcpy (transformed_glyphs, glyphs,
2251
0
        num_glyphs * sizeof (cairo_glyph_t));
2252
0
      memcpy (transformed_clusters, clusters,
2253
0
        num_clusters * sizeof (cairo_text_cluster_t));
2254
0
      j = num_glyphs;
2255
2.22M
  } else if (num_clusters == 0) {
2256
13.3M
      for (i = 0; i < num_glyphs; i++) {
2257
11.1M
    transformed_glyphs[j].index = glyphs[i].index;
2258
11.1M
    transformed_glyphs[j].x = glyphs[i].x;
2259
11.1M
    transformed_glyphs[j].y = glyphs[i].y;
2260
11.1M
    if (KEEP_GLYPH (transformed_glyphs[j]))
2261
3.69M
        j++;
2262
11.1M
      }
2263
2.22M
  } else {
2264
0
      const cairo_glyph_t *cur_glyph;
2265
2266
0
      if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2267
0
    cur_glyph = glyphs + num_glyphs - 1;
2268
0
      else
2269
0
    cur_glyph = glyphs;
2270
2271
0
      for (i = 0; i < num_clusters; i++) {
2272
0
    cairo_bool_t cluster_visible = FALSE;
2273
2274
0
    for (k = 0; k < clusters[i].num_glyphs; k++) {
2275
0
        transformed_glyphs[j+k].index = cur_glyph->index;
2276
0
        transformed_glyphs[j+k].x = cur_glyph->x;
2277
0
        transformed_glyphs[j+k].y = cur_glyph->y;
2278
0
        if (KEEP_GLYPH (transformed_glyphs[j+k]))
2279
0
      cluster_visible = TRUE;
2280
2281
0
        if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2282
0
      cur_glyph--;
2283
0
        else
2284
0
      cur_glyph++;
2285
0
    }
2286
2287
0
    transformed_clusters[i] = clusters[i];
2288
0
    if (cluster_visible)
2289
0
        j += k;
2290
0
    else
2291
0
        transformed_clusters[i].num_glyphs = 0;
2292
0
      }
2293
0
  }
2294
2.22M
    }
2295
0
    else if (_cairo_matrix_is_translation (ctm) &&
2296
0
             _cairo_matrix_is_translation (device_transform))
2297
0
    {
2298
0
        double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
2299
0
        double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
2300
2301
0
  if (! drop || num_clusters == 0) {
2302
0
      for (i = 0; i < num_glyphs; i++) {
2303
0
    transformed_glyphs[j].index = glyphs[i].index;
2304
0
    transformed_glyphs[j].x = glyphs[i].x + tx;
2305
0
    transformed_glyphs[j].y = glyphs[i].y + ty;
2306
0
    if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
2307
0
        j++;
2308
0
      }
2309
0
        if (num_clusters != 0)
2310
0
            memcpy (transformed_clusters, clusters,
2311
0
                num_clusters * sizeof (cairo_text_cluster_t));
2312
0
  } else {
2313
0
      const cairo_glyph_t *cur_glyph;
2314
2315
0
      if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2316
0
    cur_glyph = glyphs + num_glyphs - 1;
2317
0
      else
2318
0
    cur_glyph = glyphs;
2319
2320
0
      for (i = 0; i < num_clusters; i++) {
2321
0
    cairo_bool_t cluster_visible = FALSE;
2322
2323
0
    for (k = 0; k < clusters[i].num_glyphs; k++) {
2324
0
        transformed_glyphs[j+k].index = cur_glyph->index;
2325
0
        transformed_glyphs[j+k].x = cur_glyph->x + tx;
2326
0
        transformed_glyphs[j+k].y = cur_glyph->y + ty;
2327
0
        if (KEEP_GLYPH (transformed_glyphs[j+k]))
2328
0
      cluster_visible = TRUE;
2329
2330
0
        if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2331
0
      cur_glyph--;
2332
0
        else
2333
0
      cur_glyph++;
2334
0
    }
2335
2336
0
    transformed_clusters[i] = clusters[i];
2337
0
    if (cluster_visible)
2338
0
        j += k;
2339
0
    else
2340
0
        transformed_clusters[i].num_glyphs = 0;
2341
0
      }
2342
0
  }
2343
0
    }
2344
0
    else
2345
0
    {
2346
0
        cairo_matrix_t aggregate_transform;
2347
2348
0
        cairo_matrix_init_translate (&aggregate_transform,
2349
0
                                     gstate->font_matrix.x0,
2350
0
                                     gstate->font_matrix.y0);
2351
0
        cairo_matrix_multiply (&aggregate_transform,
2352
0
                               &aggregate_transform, ctm);
2353
0
        cairo_matrix_multiply (&aggregate_transform,
2354
0
                               &aggregate_transform, device_transform);
2355
2356
0
  if (! drop || num_clusters == 0) {
2357
0
      for (i = 0; i < num_glyphs; i++) {
2358
0
    transformed_glyphs[j] = glyphs[i];
2359
0
    cairo_matrix_transform_point (&aggregate_transform,
2360
0
                &transformed_glyphs[j].x,
2361
0
                &transformed_glyphs[j].y);
2362
0
    if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
2363
0
        j++;
2364
0
      }
2365
0
        if (num_clusters)
2366
0
            memcpy (transformed_clusters, clusters,
2367
0
                num_clusters * sizeof (cairo_text_cluster_t));
2368
0
  } else {
2369
0
      const cairo_glyph_t *cur_glyph;
2370
2371
0
      if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2372
0
    cur_glyph = glyphs + num_glyphs - 1;
2373
0
      else
2374
0
    cur_glyph = glyphs;
2375
2376
0
      for (i = 0; i < num_clusters; i++) {
2377
0
    cairo_bool_t cluster_visible = FALSE;
2378
0
    for (k = 0; k < clusters[i].num_glyphs; k++) {
2379
0
        transformed_glyphs[j+k] = *cur_glyph;
2380
0
        cairo_matrix_transform_point (&aggregate_transform,
2381
0
              &transformed_glyphs[j+k].x,
2382
0
              &transformed_glyphs[j+k].y);
2383
0
        if (KEEP_GLYPH (transformed_glyphs[j+k]))
2384
0
      cluster_visible = TRUE;
2385
2386
0
        if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2387
0
      cur_glyph--;
2388
0
        else
2389
0
      cur_glyph++;
2390
0
    }
2391
2392
0
    transformed_clusters[i] = clusters[i];
2393
0
    if (cluster_visible)
2394
0
        j += k;
2395
0
    else
2396
0
        transformed_clusters[i].num_glyphs = 0;
2397
0
      }
2398
0
  }
2399
0
    }
2400
2.22M
    *num_transformed_glyphs = j;
2401
2402
2.22M
    if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
2403
0
  for (i = 0; i < --j; i++) {
2404
0
      cairo_glyph_t tmp;
2405
2406
0
      tmp = transformed_glyphs[i];
2407
0
      transformed_glyphs[i] = transformed_glyphs[j];
2408
0
      transformed_glyphs[j] = tmp;
2409
0
  }
2410
0
    }
2411
2.22M
}