Coverage Report

Created: 2026-11-10 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/src/cairo-surface-wrapper.c
Line
Count
Source
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2005 Red Hat, Inc
5
 * Copyright © 2007 Adrian Johnson
6
 * Copyright © 2009 Chris Wilson
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it either under the terms of the GNU Lesser General Public
10
 * License version 2.1 as published by the Free Software Foundation
11
 * (the "LGPL") or, at your option, under the terms of the Mozilla
12
 * Public License Version 1.1 (the "MPL"). If you do not alter this
13
 * notice, a recipient may use your version of this file under either
14
 * the MPL or the LGPL.
15
 *
16
 * You should have received a copy of the LGPL along with this library
17
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19
 * You should have received a copy of the MPL along with this library
20
 * in the file COPYING-MPL-1.1
21
 *
22
 * The contents of this file are subject to the Mozilla Public License
23
 * Version 1.1 (the "License"); you may not use this file except in
24
 * compliance with the License. You may obtain a copy of the License at
25
 * http://www.mozilla.org/MPL/
26
 *
27
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29
 * the specific language governing rights and limitations.
30
 *
31
 * The Original Code is the cairo graphics library.
32
 *
33
 * The Initial Developer of the Original Code is Red Hat, Inc.
34
 *
35
 * Contributor(s):
36
 *      Chris Wilson <chris@chris-wilson.co.uk>
37
 */
38
39
#include "cairoint.h"
40
41
#include "cairo-clip-inline.h"
42
#include "cairo-error-private.h"
43
#include "cairo-pattern-private.h"
44
#include "cairo-surface-wrapper-private.h"
45
46
/* A collection of routines to facilitate surface wrapping */
47
48
static void
49
_copy_transformed_pattern (cairo_pattern_t *pattern,
50
         const cairo_pattern_t *original,
51
         const cairo_matrix_t  *ctm_inverse,
52
         unsigned int region_id)
53
17.8k
{
54
17.8k
    _cairo_pattern_init_static_copy (pattern, original);
55
56
17.8k
    if (! _cairo_matrix_is_identity (ctm_inverse))
57
13.6k
  _cairo_pattern_transform (pattern, ctm_inverse);
58
59
17.8k
    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
60
8.72k
  cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
61
8.72k
  surface_pattern->region_array_id = region_id;
62
8.72k
    }
63
17.8k
}
64
65
cairo_status_t
66
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
67
               cairo_image_surface_t  **image_out,
68
               void                   **image_extra)
69
0
{
70
0
    if (unlikely (wrapper->target->status))
71
0
  return wrapper->target->status;
72
73
0
    return _cairo_surface_acquire_source_image (wrapper->target,
74
0
            image_out, image_extra);
75
0
}
76
77
void
78
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
79
               cairo_image_surface_t  *image,
80
               void                   *image_extra)
81
0
{
82
0
    _cairo_surface_release_source_image (wrapper->target, image, image_extra);
83
0
}
84
85
static void
86
_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
87
              cairo_matrix_t *m)
88
3.07M
{
89
3.07M
    cairo_matrix_init_identity (m);
90
91
3.07M
    if (! _cairo_matrix_is_identity (&wrapper->transform))
92
9.73k
  cairo_matrix_multiply (m, &wrapper->transform, m);
93
94
3.07M
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
95
8.18k
  cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
96
3.07M
}
97
98
static void
99
_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
100
                cairo_matrix_t *m)
101
6.04k
{
102
6.04k
    cairo_matrix_init_identity (m);
103
104
6.04k
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse))
105
3.90k
  cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m);
106
107
6.04k
    if (! _cairo_matrix_is_identity (&wrapper->transform)) {
108
2.14k
  cairo_matrix_t inv;
109
2.14k
  cairo_status_t status;
110
111
2.14k
  inv = wrapper->transform;
112
2.14k
  status = cairo_matrix_invert (&inv);
113
2.14k
  assert (status == CAIRO_STATUS_SUCCESS);
114
2.14k
  cairo_matrix_multiply (m, &inv, m);
115
2.14k
    }
116
6.04k
}
117
118
static cairo_clip_t *
119
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
120
         const cairo_clip_t *clip)
121
3.06M
{
122
3.06M
    cairo_clip_t *copy;
123
3.06M
    cairo_matrix_t m;
124
125
3.06M
    copy = _cairo_clip_copy (clip);
126
3.06M
    if (wrapper->has_extents) {
127
3.05M
  copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
128
3.05M
    }
129
3.06M
    _cairo_surface_wrapper_get_transform (wrapper, &m);
130
3.06M
    copy = _cairo_clip_transform (copy, &m);
131
3.06M
    if (wrapper->clip)
132
0
  copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
133
134
3.06M
    return copy;
135
3.06M
}
136
137
cairo_status_t
138
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
139
            cairo_operator_t         op,
140
            const cairo_pattern_t   *source,
141
            unsigned int             source_region_id,
142
            const cairo_clip_t      *clip)
143
19.2k
{
144
19.2k
    cairo_status_t status;
145
19.2k
    cairo_clip_t *dev_clip;
146
19.2k
    cairo_pattern_union_t source_copy;
147
148
19.2k
    if (unlikely (wrapper->target->status))
149
0
  return wrapper->target->status;
150
151
19.2k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
152
19.2k
    if (_cairo_clip_is_all_clipped (dev_clip))
153
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
154
155
19.2k
    if (wrapper->needs_transform || source_region_id != 0) {
156
1.51k
  cairo_matrix_t m;
157
158
1.51k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
159
160
1.51k
  status = cairo_matrix_invert (&m);
161
1.51k
  assert (status == CAIRO_STATUS_SUCCESS);
162
163
1.51k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
164
1.51k
  source = &source_copy.base;
165
1.51k
    }
166
167
19.2k
    status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
168
169
19.2k
    _cairo_clip_destroy (dev_clip);
170
19.2k
    return status;
171
19.2k
}
172
173
cairo_status_t
174
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
175
           cairo_operator_t       op,
176
           const cairo_pattern_t   *source,
177
                             unsigned int             source_region_id,
178
           const cairo_pattern_t   *mask,
179
                             unsigned int             mask_region_id,
180
           const cairo_clip_t      *clip)
181
13.9k
{
182
13.9k
    cairo_status_t status;
183
13.9k
    cairo_clip_t *dev_clip;
184
13.9k
    cairo_pattern_union_t source_copy;
185
13.9k
    cairo_pattern_union_t mask_copy;
186
187
13.9k
    if (unlikely (wrapper->target->status))
188
0
  return wrapper->target->status;
189
190
13.9k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
191
13.9k
    if (_cairo_clip_is_all_clipped (dev_clip))
192
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
193
194
13.9k
    if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) {
195
5.64k
  cairo_matrix_t m;
196
197
5.64k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
198
199
5.64k
  status = cairo_matrix_invert (&m);
200
5.64k
  assert (status == CAIRO_STATUS_SUCCESS);
201
202
5.64k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
203
5.64k
  source = &source_copy.base;
204
205
5.64k
  _copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id);
206
5.64k
  mask = &mask_copy.base;
207
5.64k
    }
208
209
13.9k
    status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
210
211
13.9k
    _cairo_clip_destroy (dev_clip);
212
13.9k
    return status;
213
13.9k
}
214
215
cairo_status_t
216
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t    *wrapper,
217
             cairo_operator_t      op,
218
             const cairo_pattern_t    *source,
219
             unsigned int                source_region_id,
220
             const cairo_path_fixed_t   *path,
221
             const cairo_stroke_style_t *stroke_style,
222
             const cairo_matrix_t   *ctm,
223
             const cairo_matrix_t   *ctm_inverse,
224
             double        tolerance,
225
             cairo_antialias_t     antialias,
226
             const cairo_clip_t   *clip)
227
344k
{
228
344k
    cairo_status_t status;
229
344k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
230
344k
    cairo_clip_t *dev_clip;
231
344k
    cairo_matrix_t dev_ctm = *ctm;
232
344k
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
233
344k
    cairo_pattern_union_t source_copy;
234
235
344k
    if (unlikely (wrapper->target->status))
236
0
  return wrapper->target->status;
237
238
344k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
239
344k
    if (_cairo_clip_is_all_clipped (dev_clip))
240
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
241
242
344k
    if (wrapper->needs_transform || source_region_id != 0) {
243
2.20k
  cairo_matrix_t m;
244
245
2.20k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
246
247
2.20k
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
248
2.20k
  if (unlikely (status))
249
0
      goto FINISH;
250
251
2.20k
  _cairo_path_fixed_transform (&path_copy, &m);
252
2.20k
  dev_path = &path_copy;
253
254
2.20k
  cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
255
256
2.20k
  status = cairo_matrix_invert (&m);
257
2.20k
  assert (status == CAIRO_STATUS_SUCCESS);
258
259
2.20k
  cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
260
261
2.20k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
262
2.20k
  source = &source_copy.base;
263
2.20k
    }
264
265
344k
    status = _cairo_surface_stroke (wrapper->target, op, source,
266
344k
            dev_path, stroke_style,
267
344k
            &dev_ctm, &dev_ctm_inverse,
268
344k
            tolerance, antialias,
269
344k
            dev_clip);
270
271
344k
 FINISH:
272
344k
    if (dev_path != path)
273
2.20k
  _cairo_path_fixed_fini (dev_path);
274
344k
    _cairo_clip_destroy (dev_clip);
275
344k
    return status;
276
344k
}
277
278
cairo_status_t
279
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t    *wrapper,
280
            cairo_operator_t          fill_op,
281
            const cairo_pattern_t      *fill_source,
282
            unsigned int                fill_region_id,
283
            cairo_fill_rule_t         fill_rule,
284
            double            fill_tolerance,
285
            cairo_antialias_t         fill_antialias,
286
            const cairo_path_fixed_t   *path,
287
            cairo_operator_t          stroke_op,
288
            const cairo_pattern_t      *stroke_source,
289
            unsigned int                stroke_region_id,
290
            const cairo_stroke_style_t *stroke_style,
291
            const cairo_matrix_t       *stroke_ctm,
292
            const cairo_matrix_t       *stroke_ctm_inverse,
293
            double            stroke_tolerance,
294
            cairo_antialias_t         stroke_antialias,
295
            const cairo_clip_t         *clip)
296
23.3k
{
297
23.3k
    cairo_status_t status;
298
23.3k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
299
23.3k
    cairo_matrix_t dev_ctm = *stroke_ctm;
300
23.3k
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
301
23.3k
    cairo_clip_t *dev_clip;
302
23.3k
    cairo_pattern_union_t stroke_source_copy;
303
23.3k
    cairo_pattern_union_t fill_source_copy;
304
305
23.3k
    if (unlikely (wrapper->target->status))
306
0
  return wrapper->target->status;
307
308
23.3k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
309
23.3k
    if (_cairo_clip_is_all_clipped (dev_clip))
310
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
311
312
23.3k
    if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) {
313
34
  cairo_matrix_t m;
314
315
34
  _cairo_surface_wrapper_get_transform (wrapper, &m);
316
317
34
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
318
34
  if (unlikely (status))
319
0
      goto FINISH;
320
321
34
  _cairo_path_fixed_transform (&path_copy, &m);
322
34
  dev_path = &path_copy;
323
324
34
  cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
325
326
34
  status = cairo_matrix_invert (&m);
327
34
  assert (status == CAIRO_STATUS_SUCCESS);
328
329
34
  cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
330
331
34
  _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id);
332
34
  stroke_source = &stroke_source_copy.base;
333
334
34
  _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id);
335
34
  fill_source = &fill_source_copy.base;
336
34
    }
337
338
23.3k
    status = _cairo_surface_fill_stroke (wrapper->target,
339
23.3k
           fill_op, fill_source, fill_rule,
340
23.3k
           fill_tolerance, fill_antialias,
341
23.3k
           dev_path,
342
23.3k
           stroke_op, stroke_source,
343
23.3k
           stroke_style,
344
23.3k
           &dev_ctm, &dev_ctm_inverse,
345
23.3k
           stroke_tolerance, stroke_antialias,
346
23.3k
           dev_clip);
347
348
23.3k
  FINISH:
349
23.3k
    if (dev_path != path)
350
34
  _cairo_path_fixed_fini (dev_path);
351
23.3k
    _cairo_clip_destroy (dev_clip);
352
23.3k
    return status;
353
23.3k
}
354
355
cairo_status_t
356
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t  *wrapper,
357
           cairo_operator_t        op,
358
           const cairo_pattern_t    *source,
359
           unsigned int              source_region_id,
360
           const cairo_path_fixed_t *path,
361
           cairo_fill_rule_t         fill_rule,
362
           double          tolerance,
363
           cairo_antialias_t         antialias,
364
           const cairo_clip_t       *clip)
365
187k
{
366
187k
    cairo_status_t status;
367
187k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
368
187k
    cairo_pattern_union_t source_copy;
369
187k
    cairo_clip_t *dev_clip;
370
371
187k
    if (unlikely (wrapper->target->status))
372
0
  return wrapper->target->status;
373
374
187k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
375
187k
    if (_cairo_clip_is_all_clipped (dev_clip))
376
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
377
378
187k
    if (wrapper->needs_transform || source_region_id != 0) {
379
2.64k
  cairo_matrix_t m;
380
381
2.64k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
382
383
2.64k
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
384
2.64k
  if (unlikely (status))
385
0
      goto FINISH;
386
387
2.64k
  _cairo_path_fixed_transform (&path_copy, &m);
388
2.64k
  dev_path = &path_copy;
389
390
2.64k
  status = cairo_matrix_invert (&m);
391
2.64k
  assert (status == CAIRO_STATUS_SUCCESS);
392
393
2.64k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
394
2.64k
  source = &source_copy.base;
395
2.64k
    }
396
397
187k
    status = _cairo_surface_fill (wrapper->target, op, source,
398
187k
          dev_path, fill_rule,
399
187k
          tolerance, antialias,
400
187k
          dev_clip);
401
402
187k
 FINISH:
403
187k
    if (dev_path != path)
404
2.64k
  _cairo_path_fixed_fini (dev_path);
405
187k
    _cairo_clip_destroy (dev_clip);
406
187k
    return status;
407
187k
}
408
409
cairo_status_t
410
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t    *wrapper,
411
           cairo_operator_t      op,
412
           const cairo_pattern_t      *source,
413
           unsigned int                source_region_id,
414
           const char       *utf8,
415
           int           utf8_len,
416
           const cairo_glyph_t      *glyphs,
417
           int           num_glyphs,
418
           const cairo_text_cluster_t *clusters,
419
           int           num_clusters,
420
           cairo_text_cluster_flags_t  cluster_flags,
421
           cairo_scaled_font_t      *scaled_font,
422
           const cairo_clip_t     *clip)
423
2.47M
{
424
2.47M
    cairo_status_t status;
425
2.47M
    cairo_clip_t *dev_clip;
426
2.47M
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
427
2.47M
    cairo_glyph_t *dev_glyphs = stack_glyphs;
428
2.47M
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
429
2.47M
    cairo_pattern_union_t source_copy;
430
2.47M
    cairo_font_options_t options;
431
432
2.47M
    if (unlikely (wrapper->target->status))
433
0
  return wrapper->target->status;
434
435
2.47M
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
436
2.47M
    if (_cairo_clip_is_all_clipped (dev_clip))
437
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
438
439
2.47M
    cairo_surface_get_font_options (wrapper->target, &options);
440
2.47M
    cairo_font_options_merge (&options, &scaled_font->options);
441
442
2.47M
    if (wrapper->needs_transform || source_region_id != 0) {
443
139
  cairo_matrix_t m;
444
139
  int i;
445
446
139
  _cairo_surface_wrapper_get_transform (wrapper, &m);
447
448
139
  if (! _cairo_matrix_is_translation (&m)) {
449
18
      cairo_matrix_t ctm;
450
451
18
      _cairo_matrix_multiply (&ctm,
452
18
            &m,
453
18
            &scaled_font->ctm);
454
18
      dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
455
18
              &scaled_font->font_matrix,
456
18
              &ctm, &options);
457
18
  }
458
459
139
  if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
460
0
      dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
461
0
      if (unlikely (dev_glyphs == NULL)) {
462
0
    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
463
0
    goto FINISH;
464
0
      }
465
0
  }
466
467
663
  for (i = 0; i < num_glyphs; i++) {
468
524
      dev_glyphs[i] = glyphs[i];
469
524
      cairo_matrix_transform_point (&m,
470
524
            &dev_glyphs[i].x,
471
524
            &dev_glyphs[i].y);
472
524
  }
473
474
139
  status = cairo_matrix_invert (&m);
475
139
  assert (status == CAIRO_STATUS_SUCCESS);
476
477
139
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
478
139
  source = &source_copy.base;
479
2.47M
    } else {
480
2.47M
  if (! cairo_font_options_equal (&options, &scaled_font->options)) {
481
0
      dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
482
0
              &scaled_font->font_matrix,
483
0
              &scaled_font->ctm,
484
0
              &options);
485
0
  }
486
487
  /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
488
   * to modify the glyph array that's passed in.  We must always
489
   * copy the array before handing it to the backend.
490
   */
491
2.47M
  if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
492
1.88k
      dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
493
1.88k
      if (unlikely (dev_glyphs == NULL)) {
494
0
    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
495
0
    goto FINISH;
496
0
      }
497
1.88k
  }
498
499
2.47M
  memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
500
2.47M
    }
501
502
2.47M
    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
503
2.47M
                utf8, utf8_len,
504
2.47M
                dev_glyphs, num_glyphs,
505
2.47M
                clusters, num_clusters,
506
2.47M
                cluster_flags,
507
2.47M
                dev_scaled_font,
508
2.47M
                dev_clip);
509
2.47M
 FINISH:
510
2.47M
    _cairo_clip_destroy (dev_clip);
511
2.47M
    if (dev_glyphs != stack_glyphs)
512
1.88k
  free (dev_glyphs);
513
2.47M
    if (dev_scaled_font != scaled_font)
514
18
  cairo_scaled_font_destroy (dev_scaled_font);
515
2.47M
    return status;
516
2.47M
}
517
518
cairo_status_t
519
_cairo_surface_wrapper_tag (cairo_surface_wrapper_t     *wrapper,
520
          cairo_bool_t                 begin,
521
          const char                  *tag_name,
522
          const char                  *attributes)
523
0
{
524
0
    if (unlikely (wrapper->target->status))
525
0
  return wrapper->target->status;
526
527
528
0
    return _cairo_surface_tag (wrapper->target, begin, tag_name, attributes);
529
0
}
530
531
cairo_surface_t *
532
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
533
               cairo_content_t  content,
534
               int    width,
535
               int    height)
536
0
{
537
0
    return _cairo_surface_create_scratch (wrapper->target,
538
0
            content, width, height, NULL);
539
0
}
540
541
cairo_bool_t
542
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
543
            cairo_rectangle_int_t   *extents)
544
0
{
545
0
    if (wrapper->has_extents) {
546
0
  if (_cairo_surface_get_extents (wrapper->target, extents))
547
0
      _cairo_rectangle_intersect (extents, &wrapper->extents);
548
0
  else
549
0
      *extents = wrapper->extents;
550
551
0
  return TRUE;
552
0
    } else {
553
0
  return _cairo_surface_get_extents (wrapper->target, extents);
554
0
    }
555
0
}
556
557
static cairo_bool_t
558
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
559
29.0k
{
560
29.0k
    return
561
29.0k
  (wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
562
29.0k
  ! _cairo_matrix_is_identity (&wrapper->transform) ||
563
29.0k
  ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
564
29.0k
}
565
566
void
567
_cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper,
568
            const cairo_rectangle_int_t *extents)
569
12.6k
{
570
12.6k
    if (! wrapper->has_extents) {
571
12.6k
  wrapper->extents = *extents;
572
12.6k
  wrapper->has_extents = TRUE;
573
12.6k
    } else
574
0
  _cairo_rectangle_intersect (&wrapper->extents, extents);
575
576
12.6k
    wrapper->needs_transform =
577
12.6k
  _cairo_surface_wrapper_needs_device_transform (wrapper);
578
12.6k
}
579
580
void
581
_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
582
                const cairo_matrix_t *transform)
583
19.1k
{
584
19.1k
    cairo_status_t status;
585
586
19.1k
    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
587
16.3k
  cairo_matrix_init_identity (&wrapper->transform);
588
589
16.3k
  wrapper->needs_transform =
590
16.3k
      _cairo_surface_wrapper_needs_device_transform (wrapper);
591
16.3k
    } else {
592
2.82k
  wrapper->transform = *transform;
593
2.82k
  status = cairo_matrix_invert (&wrapper->transform);
594
  /* should always be invertible unless given pathological input */
595
2.82k
  assert (status == CAIRO_STATUS_SUCCESS);
596
597
2.82k
  wrapper->needs_transform = TRUE;
598
2.82k
    }
599
19.1k
}
600
601
void
602
_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
603
         const cairo_clip_t *clip)
604
19.1k
{
605
19.1k
    wrapper->clip = clip;
606
19.1k
}
607
608
void
609
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t    *wrapper,
610
           cairo_font_options_t     *options)
611
0
{
612
0
    cairo_surface_get_font_options (wrapper->target, options);
613
0
}
614
615
cairo_surface_t *
616
_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
617
0
{
618
0
    if (wrapper->target->backend->snapshot)
619
0
  return wrapper->target->backend->snapshot (wrapper->target);
620
621
0
    return NULL;
622
0
}
623
624
cairo_bool_t
625
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
626
0
{
627
0
    return cairo_surface_has_show_text_glyphs (wrapper->target);
628
0
}
629
630
void
631
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
632
           cairo_surface_t *target)
633
19.1k
{
634
19.1k
    wrapper->target = cairo_surface_reference (target);
635
19.1k
    cairo_matrix_init_identity (&wrapper->transform);
636
19.1k
    wrapper->has_extents = FALSE;
637
19.1k
    wrapper->extents.x = wrapper->extents.y = 0;
638
19.1k
    wrapper->clip = NULL;
639
19.1k
    wrapper->source_region_id = 0;
640
19.1k
    wrapper->mask_region_id = 0;
641
642
19.1k
    wrapper->needs_transform = FALSE;
643
19.1k
    if (target) {
644
19.1k
  wrapper->needs_transform =
645
19.1k
      ! _cairo_matrix_is_identity (&target->device_transform);
646
19.1k
    }
647
19.1k
}
648
649
void
650
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
651
19.1k
{
652
19.1k
    cairo_surface_destroy (wrapper->target);
653
19.1k
}
654
655
cairo_bool_t
656
_cairo_surface_wrapper_get_target_extents (cairo_surface_wrapper_t *wrapper,
657
             cairo_bool_t surface_is_unbounded,
658
             cairo_rectangle_int_t *extents)
659
19.1k
{
660
19.1k
    cairo_rectangle_int_t clip;
661
19.1k
    cairo_bool_t has_clip = FALSE;
662
663
19.1k
    if (!surface_is_unbounded)
664
18.5k
  has_clip = _cairo_surface_get_extents (wrapper->target, &clip);
665
666
19.1k
    if (wrapper->clip) {
667
0
  if (has_clip) {
668
0
      if (! _cairo_rectangle_intersect (&clip,
669
0
                _cairo_clip_get_extents (wrapper->clip)))
670
0
    return FALSE;
671
0
  } else {
672
0
      has_clip = TRUE;
673
0
      clip = *_cairo_clip_get_extents (wrapper->clip);
674
0
  }
675
0
    }
676
677
19.1k
    if (has_clip && wrapper->needs_transform) {
678
6.04k
  cairo_matrix_t m;
679
6.04k
  double x1, y1, x2, y2;
680
681
6.04k
  _cairo_surface_wrapper_get_inverse_transform (wrapper, &m);
682
683
6.04k
  x1 = clip.x;
684
6.04k
  y1 = clip.y;
685
6.04k
  x2 = clip.x + clip.width;
686
6.04k
  y2 = clip.y + clip.height;
687
688
6.04k
  _cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL);
689
690
6.04k
  clip.x = floor (x1);
691
6.04k
  clip.y = floor (y1);
692
6.04k
  clip.width  = ceil (x2) - clip.x;
693
6.04k
  clip.height = ceil (y2) - clip.y;
694
6.04k
    }
695
696
19.1k
    if (has_clip) {
697
15.4k
  if (wrapper->has_extents) {
698
11.5k
      *extents = wrapper->extents;
699
11.5k
      return _cairo_rectangle_intersect (extents, &clip);
700
11.5k
  } else {
701
3.89k
      *extents = clip;
702
3.89k
      return TRUE;
703
3.89k
  }
704
15.4k
    } else if (wrapper->has_extents) {
705
1.10k
  *extents = wrapper->extents;
706
1.10k
  return TRUE;
707
2.60k
    } else {
708
2.60k
  _cairo_unbounded_rectangle_init (extents);
709
2.60k
  return TRUE;
710
2.60k
    }
711
19.1k
}