Coverage Report

Created: 2026-10-14 08:19

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
15.8k
{
54
15.8k
    _cairo_pattern_init_static_copy (pattern, original);
55
56
15.8k
    if (! _cairo_matrix_is_identity (ctm_inverse))
57
11.9k
  _cairo_pattern_transform (pattern, ctm_inverse);
58
59
15.8k
    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
60
7.52k
  cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
61
7.52k
  surface_pattern->region_array_id = region_id;
62
7.52k
    }
63
15.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
2.83M
{
89
2.83M
    cairo_matrix_init_identity (m);
90
91
2.83M
    if (! _cairo_matrix_is_identity (&wrapper->transform))
92
9.13k
  cairo_matrix_multiply (m, &wrapper->transform, m);
93
94
2.83M
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
95
6.82k
  cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
96
2.83M
}
97
98
static void
99
_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
100
                cairo_matrix_t *m)
101
5.15k
{
102
5.15k
    cairo_matrix_init_identity (m);
103
104
5.15k
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse))
105
3.22k
  cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m);
106
107
5.15k
    if (! _cairo_matrix_is_identity (&wrapper->transform)) {
108
1.93k
  cairo_matrix_t inv;
109
1.93k
  cairo_status_t status;
110
111
1.93k
  inv = wrapper->transform;
112
1.93k
  status = cairo_matrix_invert (&inv);
113
1.93k
  assert (status == CAIRO_STATUS_SUCCESS);
114
1.93k
  cairo_matrix_multiply (m, &inv, m);
115
1.93k
    }
116
5.15k
}
117
118
static cairo_clip_t *
119
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
120
         const cairo_clip_t *clip)
121
2.82M
{
122
2.82M
    cairo_clip_t *copy;
123
2.82M
    cairo_matrix_t m;
124
125
2.82M
    copy = _cairo_clip_copy (clip);
126
2.82M
    if (wrapper->has_extents) {
127
2.82M
  copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
128
2.82M
    }
129
2.82M
    _cairo_surface_wrapper_get_transform (wrapper, &m);
130
2.82M
    copy = _cairo_clip_transform (copy, &m);
131
2.82M
    if (wrapper->clip)
132
0
  copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
133
134
2.82M
    return copy;
135
2.82M
}
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
9.88k
{
144
9.88k
    cairo_status_t status;
145
9.88k
    cairo_clip_t *dev_clip;
146
9.88k
    cairo_pattern_union_t source_copy;
147
148
9.88k
    if (unlikely (wrapper->target->status))
149
0
  return wrapper->target->status;
150
151
9.88k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
152
9.88k
    if (_cairo_clip_is_all_clipped (dev_clip))
153
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
154
155
9.88k
    if (wrapper->needs_transform || source_region_id != 0) {
156
1.41k
  cairo_matrix_t m;
157
158
1.41k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
159
160
1.41k
  status = cairo_matrix_invert (&m);
161
1.41k
  assert (status == CAIRO_STATUS_SUCCESS);
162
163
1.41k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
164
1.41k
  source = &source_copy.base;
165
1.41k
    }
166
167
9.88k
    status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
168
169
9.88k
    _cairo_clip_destroy (dev_clip);
170
9.88k
    return status;
171
9.88k
}
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
12.5k
{
182
12.5k
    cairo_status_t status;
183
12.5k
    cairo_clip_t *dev_clip;
184
12.5k
    cairo_pattern_union_t source_copy;
185
12.5k
    cairo_pattern_union_t mask_copy;
186
187
12.5k
    if (unlikely (wrapper->target->status))
188
0
  return wrapper->target->status;
189
190
12.5k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
191
12.5k
    if (_cairo_clip_is_all_clipped (dev_clip))
192
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
193
194
12.5k
    if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) {
195
4.79k
  cairo_matrix_t m;
196
197
4.79k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
198
199
4.79k
  status = cairo_matrix_invert (&m);
200
4.79k
  assert (status == CAIRO_STATUS_SUCCESS);
201
202
4.79k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
203
4.79k
  source = &source_copy.base;
204
205
4.79k
  _copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id);
206
4.79k
  mask = &mask_copy.base;
207
4.79k
    }
208
209
12.5k
    status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
210
211
12.5k
    _cairo_clip_destroy (dev_clip);
212
12.5k
    return status;
213
12.5k
}
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
270k
{
228
270k
    cairo_status_t status;
229
270k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
230
270k
    cairo_clip_t *dev_clip;
231
270k
    cairo_matrix_t dev_ctm = *ctm;
232
270k
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
233
270k
    cairo_pattern_union_t source_copy;
234
235
270k
    if (unlikely (wrapper->target->status))
236
0
  return wrapper->target->status;
237
238
270k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
239
270k
    if (_cairo_clip_is_all_clipped (dev_clip))
240
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
241
242
270k
    if (wrapper->needs_transform || source_region_id != 0) {
243
2.15k
  cairo_matrix_t m;
244
245
2.15k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
246
247
2.15k
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
248
2.15k
  if (unlikely (status))
249
0
      goto FINISH;
250
251
2.15k
  _cairo_path_fixed_transform (&path_copy, &m);
252
2.15k
  dev_path = &path_copy;
253
254
2.15k
  cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
255
256
2.15k
  status = cairo_matrix_invert (&m);
257
2.15k
  assert (status == CAIRO_STATUS_SUCCESS);
258
259
2.15k
  cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
260
261
2.15k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
262
2.15k
  source = &source_copy.base;
263
2.15k
    }
264
265
270k
    status = _cairo_surface_stroke (wrapper->target, op, source,
266
270k
            dev_path, stroke_style,
267
270k
            &dev_ctm, &dev_ctm_inverse,
268
270k
            tolerance, antialias,
269
270k
            dev_clip);
270
271
270k
 FINISH:
272
270k
    if (dev_path != path)
273
2.15k
  _cairo_path_fixed_fini (dev_path);
274
270k
    _cairo_clip_destroy (dev_clip);
275
270k
    return status;
276
270k
}
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
4.95k
{
297
4.95k
    cairo_status_t status;
298
4.95k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
299
4.95k
    cairo_matrix_t dev_ctm = *stroke_ctm;
300
4.95k
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
301
4.95k
    cairo_clip_t *dev_clip;
302
4.95k
    cairo_pattern_union_t stroke_source_copy;
303
4.95k
    cairo_pattern_union_t fill_source_copy;
304
305
4.95k
    if (unlikely (wrapper->target->status))
306
0
  return wrapper->target->status;
307
308
4.95k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
309
4.95k
    if (_cairo_clip_is_all_clipped (dev_clip))
310
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
311
312
4.95k
    if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) {
313
35
  cairo_matrix_t m;
314
315
35
  _cairo_surface_wrapper_get_transform (wrapper, &m);
316
317
35
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
318
35
  if (unlikely (status))
319
0
      goto FINISH;
320
321
35
  _cairo_path_fixed_transform (&path_copy, &m);
322
35
  dev_path = &path_copy;
323
324
35
  cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
325
326
35
  status = cairo_matrix_invert (&m);
327
35
  assert (status == CAIRO_STATUS_SUCCESS);
328
329
35
  cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
330
331
35
  _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id);
332
35
  stroke_source = &stroke_source_copy.base;
333
334
35
  _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id);
335
35
  fill_source = &fill_source_copy.base;
336
35
    }
337
338
4.95k
    status = _cairo_surface_fill_stroke (wrapper->target,
339
4.95k
           fill_op, fill_source, fill_rule,
340
4.95k
           fill_tolerance, fill_antialias,
341
4.95k
           dev_path,
342
4.95k
           stroke_op, stroke_source,
343
4.95k
           stroke_style,
344
4.95k
           &dev_ctm, &dev_ctm_inverse,
345
4.95k
           stroke_tolerance, stroke_antialias,
346
4.95k
           dev_clip);
347
348
4.95k
  FINISH:
349
4.95k
    if (dev_path != path)
350
35
  _cairo_path_fixed_fini (dev_path);
351
4.95k
    _cairo_clip_destroy (dev_clip);
352
4.95k
    return status;
353
4.95k
}
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
100k
{
366
100k
    cairo_status_t status;
367
100k
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
368
100k
    cairo_pattern_union_t source_copy;
369
100k
    cairo_clip_t *dev_clip;
370
371
100k
    if (unlikely (wrapper->target->status))
372
0
  return wrapper->target->status;
373
374
100k
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
375
100k
    if (_cairo_clip_is_all_clipped (dev_clip))
376
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
377
378
100k
    if (wrapper->needs_transform || source_region_id != 0) {
379
2.52k
  cairo_matrix_t m;
380
381
2.52k
  _cairo_surface_wrapper_get_transform (wrapper, &m);
382
383
2.52k
  status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
384
2.52k
  if (unlikely (status))
385
0
      goto FINISH;
386
387
2.52k
  _cairo_path_fixed_transform (&path_copy, &m);
388
2.52k
  dev_path = &path_copy;
389
390
2.52k
  status = cairo_matrix_invert (&m);
391
2.52k
  assert (status == CAIRO_STATUS_SUCCESS);
392
393
2.52k
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
394
2.52k
  source = &source_copy.base;
395
2.52k
    }
396
397
100k
    status = _cairo_surface_fill (wrapper->target, op, source,
398
100k
          dev_path, fill_rule,
399
100k
          tolerance, antialias,
400
100k
          dev_clip);
401
402
100k
 FINISH:
403
100k
    if (dev_path != path)
404
2.52k
  _cairo_path_fixed_fini (dev_path);
405
100k
    _cairo_clip_destroy (dev_clip);
406
100k
    return status;
407
100k
}
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.42M
{
424
2.42M
    cairo_status_t status;
425
2.42M
    cairo_clip_t *dev_clip;
426
2.42M
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
427
2.42M
    cairo_glyph_t *dev_glyphs = stack_glyphs;
428
2.42M
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
429
2.42M
    cairo_pattern_union_t source_copy;
430
2.42M
    cairo_font_options_t options;
431
432
2.42M
    if (unlikely (wrapper->target->status))
433
0
  return wrapper->target->status;
434
435
2.42M
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
436
2.42M
    if (_cairo_clip_is_all_clipped (dev_clip))
437
0
  return CAIRO_INT_STATUS_NOTHING_TO_DO;
438
439
2.42M
    cairo_surface_get_font_options (wrapper->target, &options);
440
2.42M
    cairo_font_options_merge (&options, &scaled_font->options);
441
442
2.42M
    if (wrapper->needs_transform || source_region_id != 0) {
443
79
  cairo_matrix_t m;
444
79
  int i;
445
446
79
  _cairo_surface_wrapper_get_transform (wrapper, &m);
447
448
79
  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
79
  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
363
  for (i = 0; i < num_glyphs; i++) {
468
284
      dev_glyphs[i] = glyphs[i];
469
284
      cairo_matrix_transform_point (&m,
470
284
            &dev_glyphs[i].x,
471
284
            &dev_glyphs[i].y);
472
284
  }
473
474
79
  status = cairo_matrix_invert (&m);
475
79
  assert (status == CAIRO_STATUS_SUCCESS);
476
477
79
  _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
478
79
  source = &source_copy.base;
479
2.42M
    } else {
480
2.42M
  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.42M
  if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
492
1.05k
      dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
493
1.05k
      if (unlikely (dev_glyphs == NULL)) {
494
0
    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
495
0
    goto FINISH;
496
0
      }
497
1.05k
  }
498
499
2.42M
  memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
500
2.42M
    }
501
502
2.42M
    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
503
2.42M
                utf8, utf8_len,
504
2.42M
                dev_glyphs, num_glyphs,
505
2.42M
                clusters, num_clusters,
506
2.42M
                cluster_flags,
507
2.42M
                dev_scaled_font,
508
2.42M
                dev_clip);
509
2.42M
 FINISH:
510
2.42M
    _cairo_clip_destroy (dev_clip);
511
2.42M
    if (dev_glyphs != stack_glyphs)
512
1.05k
  free (dev_glyphs);
513
2.42M
    if (dev_scaled_font != scaled_font)
514
18
  cairo_scaled_font_destroy (dev_scaled_font);
515
2.42M
    return status;
516
2.42M
}
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
26.7k
{
560
26.7k
    return
561
26.7k
  (wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
562
26.7k
  ! _cairo_matrix_is_identity (&wrapper->transform) ||
563
26.7k
  ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
564
26.7k
}
565
566
void
567
_cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper,
568
            const cairo_rectangle_int_t *extents)
569
11.9k
{
570
11.9k
    if (! wrapper->has_extents) {
571
11.9k
  wrapper->extents = *extents;
572
11.9k
  wrapper->has_extents = TRUE;
573
11.9k
    } else
574
0
  _cairo_rectangle_intersect (&wrapper->extents, extents);
575
576
11.9k
    wrapper->needs_transform =
577
11.9k
  _cairo_surface_wrapper_needs_device_transform (wrapper);
578
11.9k
}
579
580
void
581
_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
582
                const cairo_matrix_t *transform)
583
17.3k
{
584
17.3k
    cairo_status_t status;
585
586
17.3k
    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
587
14.7k
  cairo_matrix_init_identity (&wrapper->transform);
588
589
14.7k
  wrapper->needs_transform =
590
14.7k
      _cairo_surface_wrapper_needs_device_transform (wrapper);
591
14.7k
    } else {
592
2.56k
  wrapper->transform = *transform;
593
2.56k
  status = cairo_matrix_invert (&wrapper->transform);
594
  /* should always be invertible unless given pathological input */
595
2.56k
  assert (status == CAIRO_STATUS_SUCCESS);
596
597
2.56k
  wrapper->needs_transform = TRUE;
598
2.56k
    }
599
17.3k
}
600
601
void
602
_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
603
         const cairo_clip_t *clip)
604
17.3k
{
605
17.3k
    wrapper->clip = clip;
606
17.3k
}
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
17.3k
{
634
17.3k
    wrapper->target = cairo_surface_reference (target);
635
17.3k
    cairo_matrix_init_identity (&wrapper->transform);
636
17.3k
    wrapper->has_extents = FALSE;
637
17.3k
    wrapper->extents.x = wrapper->extents.y = 0;
638
17.3k
    wrapper->clip = NULL;
639
17.3k
    wrapper->source_region_id = 0;
640
17.3k
    wrapper->mask_region_id = 0;
641
642
17.3k
    wrapper->needs_transform = FALSE;
643
17.3k
    if (target) {
644
17.3k
  wrapper->needs_transform =
645
17.3k
      ! _cairo_matrix_is_identity (&target->device_transform);
646
17.3k
    }
647
17.3k
}
648
649
void
650
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
651
17.3k
{
652
17.3k
    cairo_surface_destroy (wrapper->target);
653
17.3k
}
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
17.3k
{
660
17.3k
    cairo_rectangle_int_t clip;
661
17.3k
    cairo_bool_t has_clip = FALSE;
662
663
17.3k
    if (!surface_is_unbounded)
664
16.7k
  has_clip = _cairo_surface_get_extents (wrapper->target, &clip);
665
666
17.3k
    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
17.3k
    if (has_clip && wrapper->needs_transform) {
678
5.15k
  cairo_matrix_t m;
679
5.15k
  double x1, y1, x2, y2;
680
681
5.15k
  _cairo_surface_wrapper_get_inverse_transform (wrapper, &m);
682
683
5.15k
  x1 = clip.x;
684
5.15k
  y1 = clip.y;
685
5.15k
  x2 = clip.x + clip.width;
686
5.15k
  y2 = clip.y + clip.height;
687
688
5.15k
  _cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL);
689
690
5.15k
  clip.x = floor (x1);
691
5.15k
  clip.y = floor (y1);
692
5.15k
  clip.width  = ceil (x2) - clip.x;
693
5.15k
  clip.height = ceil (y2) - clip.y;
694
5.15k
    }
695
696
17.3k
    if (has_clip) {
697
14.2k
  if (wrapper->has_extents) {
698
11.0k
      *extents = wrapper->extents;
699
11.0k
      return _cairo_rectangle_intersect (extents, &clip);
700
11.0k
  } else {
701
3.21k
      *extents = clip;
702
3.21k
      return TRUE;
703
3.21k
  }
704
14.2k
    } else if (wrapper->has_extents) {
705
900
  *extents = wrapper->extents;
706
900
  return TRUE;
707
2.21k
    } else {
708
2.21k
  _cairo_unbounded_rectangle_init (extents);
709
2.21k
  return TRUE;
710
2.21k
    }
711
17.3k
}