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
221268
_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
{
54
221268
    _cairo_pattern_init_static_copy (pattern, original);
55

            
56
221268
    if (! _cairo_matrix_is_identity (ctm_inverse))
57
221256
	_cairo_pattern_transform (pattern, ctm_inverse);
58

            
59
221268
    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
60
28639
	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
61
28639
	surface_pattern->region_array_id = region_id;
62
    }
63
221268
}
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
{
70
    if (unlikely (wrapper->target->status))
71
	return wrapper->target->status;
72

            
73
    return _cairo_surface_acquire_source_image (wrapper->target,
74
						image_out, image_extra);
75
}
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
{
82
    _cairo_surface_release_source_image (wrapper->target, image, image_extra);
83
}
84

            
85
static void
86
636771
_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
87
				      cairo_matrix_t *m)
88
{
89
636771
    cairo_matrix_init_identity (m);
90

            
91
636771
    if (! _cairo_matrix_is_identity (&wrapper->transform))
92
435418
	cairo_matrix_multiply (m, &wrapper->transform, m);
93

            
94
636771
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
95
2462
	cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
96
636771
}
97

            
98
static void
99
127986
_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
100
					      cairo_matrix_t *m)
101
{
102
127986
    cairo_matrix_init_identity (m);
103

            
104
127986
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse))
105
1020
	cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m);
106

            
107
127986
    if (! _cairo_matrix_is_identity (&wrapper->transform)) {
108
	cairo_matrix_t inv;
109
	cairo_status_t status;
110

            
111
126966
	inv = wrapper->transform;
112
126966
	status = cairo_matrix_invert (&inv);
113
126966
	assert (status == CAIRO_STATUS_SUCCESS);
114
126966
	cairo_matrix_multiply (m, &inv, m);
115
    }
116
127986
}
117

            
118
static cairo_clip_t *
119
417924
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
120
				 const cairo_clip_t *clip)
121
{
122
    cairo_clip_t *copy;
123
    cairo_matrix_t m;
124

            
125
417924
    copy = _cairo_clip_copy (clip);
126
417924
    if (wrapper->has_extents) {
127
44723
	copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
128
    }
129
417924
    _cairo_surface_wrapper_get_transform (wrapper, &m);
130
417924
    copy = _cairo_clip_transform (copy, &m);
131
417924
    if (wrapper->clip)
132
370131
	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
133

            
134
417924
    return copy;
135
}
136

            
137
cairo_status_t
138
266412
_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
{
144
    cairo_status_t status;
145
    cairo_clip_t *dev_clip;
146
    cairo_pattern_union_t source_copy;
147

            
148
266412
    if (unlikely (wrapper->target->status))
149
	return wrapper->target->status;
150

            
151
266412
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
152
266412
    if (_cairo_clip_is_all_clipped (dev_clip))
153
168
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
154

            
155
266244
    if (wrapper->needs_transform || source_region_id != 0) {
156
	cairo_matrix_t m;
157

            
158
129918
	_cairo_surface_wrapper_get_transform (wrapper, &m);
159

            
160
129918
	status = cairo_matrix_invert (&m);
161
129918
	assert (status == CAIRO_STATUS_SUCCESS);
162

            
163
129918
	_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
164
129918
	source = &source_copy.base;
165
    }
166

            
167
266244
    status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
168

            
169
266244
    _cairo_clip_destroy (dev_clip);
170
266244
    return status;
171
}
172

            
173
cairo_status_t
174
2976
_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
{
182
    cairo_status_t status;
183
    cairo_clip_t *dev_clip;
184
    cairo_pattern_union_t source_copy;
185
    cairo_pattern_union_t mask_copy;
186

            
187
2976
    if (unlikely (wrapper->target->status))
188
	return wrapper->target->status;
189

            
190
2976
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
191
2976
    if (_cairo_clip_is_all_clipped (dev_clip))
192
42
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
193

            
194
2934
    if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) {
195
	cairo_matrix_t m;
196

            
197
2421
	_cairo_surface_wrapper_get_transform (wrapper, &m);
198

            
199
2421
	status = cairo_matrix_invert (&m);
200
2421
	assert (status == CAIRO_STATUS_SUCCESS);
201

            
202
2421
	_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
203
2421
	source = &source_copy.base;
204

            
205
2421
	_copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id);
206
2421
	mask = &mask_copy.base;
207
    }
208

            
209
2934
    status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
210

            
211
2934
    _cairo_clip_destroy (dev_clip);
212
2934
    return status;
213
}
214

            
215
cairo_status_t
216
1771
_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
{
228
    cairo_status_t status;
229
1771
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
230
    cairo_clip_t *dev_clip;
231
1771
    cairo_matrix_t dev_ctm = *ctm;
232
1771
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
233
    cairo_pattern_union_t source_copy;
234

            
235
1771
    if (unlikely (wrapper->target->status))
236
	return wrapper->target->status;
237

            
238
1771
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
239
1771
    if (_cairo_clip_is_all_clipped (dev_clip))
240
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
241

            
242
1771
    if (wrapper->needs_transform || source_region_id != 0) {
243
	cairo_matrix_t m;
244

            
245
1020
	_cairo_surface_wrapper_get_transform (wrapper, &m);
246

            
247
1020
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
248
1020
	if (unlikely (status))
249
	    goto FINISH;
250

            
251
1020
	_cairo_path_fixed_transform (&path_copy, &m);
252
1020
	dev_path = &path_copy;
253

            
254
1020
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
255

            
256
1020
	status = cairo_matrix_invert (&m);
257
1020
	assert (status == CAIRO_STATUS_SUCCESS);
258

            
259
1020
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
260

            
261
1020
	_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
262
1020
	source = &source_copy.base;
263
    }
264

            
265
1771
    status = _cairo_surface_stroke (wrapper->target, op, source,
266
				    dev_path, stroke_style,
267
				    &dev_ctm, &dev_ctm_inverse,
268
				    tolerance, antialias,
269
				    dev_clip);
270

            
271
1771
 FINISH:
272
1771
    if (dev_path != path)
273
1020
	_cairo_path_fixed_fini (dev_path);
274
1771
    _cairo_clip_destroy (dev_clip);
275
1771
    return status;
276
}
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
{
297
    cairo_status_t status;
298
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
299
    cairo_matrix_t dev_ctm = *stroke_ctm;
300
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
301
    cairo_clip_t *dev_clip;
302
    cairo_pattern_union_t stroke_source_copy;
303
    cairo_pattern_union_t fill_source_copy;
304

            
305
    if (unlikely (wrapper->target->status))
306
	return wrapper->target->status;
307

            
308
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
309
    if (_cairo_clip_is_all_clipped (dev_clip))
310
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
311

            
312
    if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) {
313
	cairo_matrix_t m;
314

            
315
	_cairo_surface_wrapper_get_transform (wrapper, &m);
316

            
317
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
318
	if (unlikely (status))
319
	    goto FINISH;
320

            
321
	_cairo_path_fixed_transform (&path_copy, &m);
322
	dev_path = &path_copy;
323

            
324
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
325

            
326
	status = cairo_matrix_invert (&m);
327
	assert (status == CAIRO_STATUS_SUCCESS);
328

            
329
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
330

            
331
	_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id);
332
	stroke_source = &stroke_source_copy.base;
333

            
334
	_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id);
335
	fill_source = &fill_source_copy.base;
336
    }
337

            
338
    status = _cairo_surface_fill_stroke (wrapper->target,
339
					 fill_op, fill_source, fill_rule,
340
					 fill_tolerance, fill_antialias,
341
					 dev_path,
342
					 stroke_op, stroke_source,
343
					 stroke_style,
344
					 &dev_ctm, &dev_ctm_inverse,
345
					 stroke_tolerance, stroke_antialias,
346
					 dev_clip);
347

            
348
  FINISH:
349
    if (dev_path != path)
350
	_cairo_path_fixed_fini (dev_path);
351
    _cairo_clip_destroy (dev_clip);
352
    return status;
353
}
354

            
355
cairo_status_t
356
111101
_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
{
366
    cairo_status_t status;
367
111101
    cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
368
    cairo_pattern_union_t source_copy;
369
    cairo_clip_t *dev_clip;
370

            
371
111101
    if (unlikely (wrapper->target->status))
372
	return wrapper->target->status;
373

            
374
111101
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
375
111101
    if (_cairo_clip_is_all_clipped (dev_clip))
376
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
377

            
378
111101
    if (wrapper->needs_transform || source_region_id != 0) {
379
	cairo_matrix_t m;
380

            
381
55560
	_cairo_surface_wrapper_get_transform (wrapper, &m);
382

            
383
55560
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
384
55560
	if (unlikely (status))
385
	    goto FINISH;
386

            
387
55560
	_cairo_path_fixed_transform (&path_copy, &m);
388
55560
	dev_path = &path_copy;
389

            
390
55560
	status = cairo_matrix_invert (&m);
391
55560
	assert (status == CAIRO_STATUS_SUCCESS);
392

            
393
55560
	_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
394
55560
	source = &source_copy.base;
395
    }
396

            
397
111101
    status = _cairo_surface_fill (wrapper->target, op, source,
398
				  dev_path, fill_rule,
399
				  tolerance, antialias,
400
				  dev_clip);
401

            
402
111101
 FINISH:
403
111101
    if (dev_path != path)
404
55560
	_cairo_path_fixed_fini (dev_path);
405
111101
    _cairo_clip_destroy (dev_clip);
406
111101
    return status;
407
}
408

            
409
cairo_status_t
410
35664
_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
{
424
    cairo_status_t status;
425
    cairo_clip_t *dev_clip;
426
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
427
35664
    cairo_glyph_t *dev_glyphs = stack_glyphs;
428
35664
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
429
    cairo_pattern_union_t source_copy;
430
    cairo_font_options_t options;
431

            
432
35664
    if (unlikely (wrapper->target->status))
433
	return wrapper->target->status;
434

            
435
35664
    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
436
35664
    if (_cairo_clip_is_all_clipped (dev_clip))
437
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
438

            
439
35664
    cairo_surface_get_font_options (wrapper->target, &options);
440
35664
    cairo_font_options_merge (&options, &scaled_font->options);
441

            
442
65592
    if (wrapper->needs_transform || source_region_id != 0) {
443
	cairo_matrix_t m;
444
	int i;
445

            
446
29928
	_cairo_surface_wrapper_get_transform (wrapper, &m);
447

            
448
29928
	if (! _cairo_matrix_is_translation (&m)) {
449
	    cairo_matrix_t ctm;
450

            
451
29799
	    _cairo_matrix_multiply (&ctm,
452
				    &m,
453
29799
				    &scaled_font->ctm);
454
29799
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
455
29799
							&scaled_font->font_matrix,
456
							&ctm, &options);
457
	}
458

            
459
29928
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
460
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
461
	    if (unlikely (dev_glyphs == NULL)) {
462
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
463
		goto FINISH;
464
	    }
465
	}
466

            
467
130596
	for (i = 0; i < num_glyphs; i++) {
468
100668
	    dev_glyphs[i] = glyphs[i];
469
100668
	    cairo_matrix_transform_point (&m,
470
100668
					  &dev_glyphs[i].x,
471
100668
					  &dev_glyphs[i].y);
472
	}
473

            
474
29928
	status = cairo_matrix_invert (&m);
475
29928
	assert (status == CAIRO_STATUS_SUCCESS);
476

            
477
29928
	_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
478
29928
	source = &source_copy.base;
479
    } else {
480
5736
	if (! cairo_font_options_equal (&options, &scaled_font->options)) {
481
5688
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
482
5688
							&scaled_font->font_matrix,
483
5688
							&scaled_font->ctm,
484
							&options);
485
	}
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
5736
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
492
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
493
	    if (unlikely (dev_glyphs == NULL)) {
494
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
495
		goto FINISH;
496
	    }
497
	}
498

            
499
5736
	memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
500
    }
501

            
502
35664
    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
503
					      utf8, utf8_len,
504
					      dev_glyphs, num_glyphs,
505
					      clusters, num_clusters,
506
					      cluster_flags,
507
					      dev_scaled_font,
508
					      dev_clip);
509
35664
 FINISH:
510
35664
    _cairo_clip_destroy (dev_clip);
511
35664
    if (dev_glyphs != stack_glyphs)
512
	free (dev_glyphs);
513
35664
    if (dev_scaled_font != scaled_font)
514
35487
	cairo_scaled_font_destroy (dev_scaled_font);
515
35664
    return status;
516
}
517

            
518
cairo_status_t
519
6
_cairo_surface_wrapper_tag (cairo_surface_wrapper_t     *wrapper,
520
			    cairo_bool_t                 begin,
521
			    const char                  *tag_name,
522
			    const char                  *attributes)
523
{
524
6
    if (unlikely (wrapper->target->status))
525
	return wrapper->target->status;
526

            
527

            
528
6
    return _cairo_surface_tag (wrapper->target, begin, tag_name, attributes);
529
}
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
{
537
    return _cairo_surface_create_scratch (wrapper->target,
538
					  content, width, height, NULL);
539
}
540

            
541
cairo_bool_t
542
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
543
				    cairo_rectangle_int_t   *extents)
544
{
545
    if (wrapper->has_extents) {
546
	if (_cairo_surface_get_extents (wrapper->target, extents))
547
	    _cairo_rectangle_intersect (extents, &wrapper->extents);
548
	else
549
	    *extents = wrapper->extents;
550

            
551
	return TRUE;
552
    } else {
553
	return _cairo_surface_get_extents (wrapper->target, extents);
554
    }
555
}
556

            
557
static cairo_bool_t
558
121073
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
559
{
560
    return
561
143260
	(wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
562
264333
	! _cairo_matrix_is_identity (&wrapper->transform) ||
563
121003
	! _cairo_matrix_is_identity (&wrapper->target->device_transform);
564
}
565

            
566
void
567
11163
_cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper,
568
					  const cairo_rectangle_int_t *extents)
569
{
570
11163
    if (! wrapper->has_extents) {
571
11163
	wrapper->extents = *extents;
572
11163
	wrapper->has_extents = TRUE;
573
    } else
574
	_cairo_rectangle_intersect (&wrapper->extents, extents);
575

            
576
11163
    wrapper->needs_transform =
577
11163
	_cairo_surface_wrapper_needs_device_transform (wrapper);
578
11163
}
579

            
580
void
581
236915
_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
582
					      const cairo_matrix_t *transform)
583
{
584
    cairo_status_t status;
585

            
586
236915
    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
587
109910
	cairo_matrix_init_identity (&wrapper->transform);
588

            
589
109910
	wrapper->needs_transform =
590
109910
	    _cairo_surface_wrapper_needs_device_transform (wrapper);
591
    } else {
592
127005
	wrapper->transform = *transform;
593
127005
	status = cairo_matrix_invert (&wrapper->transform);
594
	/* should always be invertible unless given pathological input */
595
127005
	assert (status == CAIRO_STATUS_SUCCESS);
596

            
597
127005
	wrapper->needs_transform = TRUE;
598
    }
599
236915
}
600

            
601
void
602
236915
_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
603
				 const cairo_clip_t *clip)
604
{
605
236915
    wrapper->clip = clip;
606
236915
}
607

            
608
void
609
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t    *wrapper,
610
					 cairo_font_options_t	    *options)
611
{
612
    cairo_surface_get_font_options (wrapper->target, options);
613
}
614

            
615
cairo_surface_t *
616
_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
617
{
618
    if (wrapper->target->backend->snapshot)
619
	return wrapper->target->backend->snapshot (wrapper->target);
620

            
621
    return NULL;
622
}
623

            
624
cairo_bool_t
625
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
626
{
627
    return cairo_surface_has_show_text_glyphs (wrapper->target);
628
}
629

            
630
void
631
236917
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
632
			     cairo_surface_t *target)
633
{
634
236917
    wrapper->target = cairo_surface_reference (target);
635
236917
    cairo_matrix_init_identity (&wrapper->transform);
636
236917
    wrapper->has_extents = FALSE;
637
236917
    wrapper->extents.x = wrapper->extents.y = 0;
638
236917
    wrapper->clip = NULL;
639
236917
    wrapper->source_region_id = 0;
640
236917
    wrapper->mask_region_id = 0;
641

            
642
236917
    wrapper->needs_transform = FALSE;
643
236917
    if (target) {
644
236915
	wrapper->needs_transform =
645
236915
	    ! _cairo_matrix_is_identity (&target->device_transform);
646
    }
647
236917
}
648

            
649
void
650
236917
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
651
{
652
236917
    cairo_surface_destroy (wrapper->target);
653
236917
}
654

            
655
cairo_bool_t
656
236915
_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
{
660
    cairo_rectangle_int_t clip;
661
236915
    cairo_bool_t has_clip = FALSE;
662

            
663
236915
    if (!surface_is_unbounded)
664
236915
	has_clip = _cairo_surface_get_extents (wrapper->target, &clip);
665

            
666
236915
    if (wrapper->clip) {
667
223290
	if (has_clip) {
668
223290
	    if (! _cairo_rectangle_intersect (&clip,
669
					      _cairo_clip_get_extents (wrapper->clip)))
670
		return FALSE;
671
	} else {
672
	    has_clip = TRUE;
673
	    clip = *_cairo_clip_get_extents (wrapper->clip);
674
	}
675
    }
676

            
677
236915
    if (has_clip && wrapper->needs_transform) {
678
	cairo_matrix_t m;
679
	double x1, y1, x2, y2;
680

            
681
127986
	_cairo_surface_wrapper_get_inverse_transform (wrapper, &m);
682

            
683
127986
	x1 = clip.x;
684
127986
	y1 = clip.y;
685
127986
	x2 = clip.x + clip.width;
686
127986
	y2 = clip.y + clip.height;
687

            
688
127986
	_cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL);
689

            
690
127986
	clip.x = floor (x1);
691
127986
	clip.y = floor (y1);
692
127986
	clip.width  = ceil (x2) - clip.x;
693
127986
	clip.height = ceil (y2) - clip.y;
694
    }
695

            
696
236915
    if (has_clip) {
697
235731
	if (wrapper->has_extents) {
698
11161
	    *extents = wrapper->extents;
699
11161
	    return _cairo_rectangle_intersect (extents, &clip);
700
	} else {
701
224570
	    *extents = clip;
702
224570
	    return TRUE;
703
	}
704
1184
    } else if (wrapper->has_extents) {
705
2
	*extents = wrapper->extents;
706
2
	return TRUE;
707
    } else {
708
1182
	_cairo_unbounded_rectangle_init (extents);
709
1182
	return TRUE;
710
    }
711
}