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