Coverage Report

Created: 2025-07-07 10:01

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