Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 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 
36
 */
37
 
38
#include "cairoint.h"
39
 
40
#include "cairo-error-private.h"
41
#include "cairo-surface-wrapper-private.h"
42
 
43
/* A collection of routines to facilitate surface wrapping */
44
 
45
static void
46
_copy_transformed_pattern (cairo_pattern_t *pattern,
47
			   const cairo_pattern_t *original,
48
			   const cairo_matrix_t  *ctm_inverse)
49
{
50
    _cairo_pattern_init_static_copy (pattern, original);
51
 
52
    /* apply device_transform first so that it is transformed by ctm_inverse */
53
    if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
54
	cairo_surface_pattern_t *surface_pattern;
55
	cairo_surface_t *surface;
56
 
57
        surface_pattern = (cairo_surface_pattern_t *) original;
58
        surface = surface_pattern->surface;
59
 
60
	if (_cairo_surface_has_device_transform (surface))
61
	    _cairo_pattern_transform (pattern, &surface->device_transform);
62
    }
63
 
64
    if (! _cairo_matrix_is_identity (ctm_inverse))
65
	_cairo_pattern_transform (pattern, ctm_inverse);
66
}
67
 
68
static inline cairo_bool_t
69
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
70
{
71
    return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
72
}
73
 
74
static cairo_bool_t
75
_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
76
{
77
    return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
78
}
79
 
80
cairo_status_t
81
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
82
					     cairo_image_surface_t  **image_out,
83
					     void                   **image_extra)
84
{
85
    if (unlikely (wrapper->target->status))
86
	return wrapper->target->status;
87
 
88
    return _cairo_surface_acquire_source_image (wrapper->target,
89
						image_out, image_extra);
90
}
91
 
92
void
93
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
94
					     cairo_image_surface_t  *image,
95
					     void                   *image_extra)
96
{
97
    _cairo_surface_release_source_image (wrapper->target, image, image_extra);
98
}
99
 
100
cairo_status_t
101
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
102
			      cairo_operator_t	 op,
103
			      const cairo_pattern_t *source,
104
			      cairo_clip_t	    *clip)
105
{
106
    cairo_status_t status;
107
    cairo_clip_t clip_copy, *dev_clip = clip;
108
    cairo_pattern_union_t source_copy;
109
    cairo_clip_t target_clip;
110
 
111
    if (unlikely (wrapper->target->status))
112
	return wrapper->target->status;
113
 
114
    if (wrapper->has_extents) {
115
	_cairo_clip_init_copy (&target_clip, clip);
116
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
117
	if (unlikely (status))
118
	    goto FINISH;
119
 
120
	dev_clip = clip = &target_clip;
121
    }
122
 
123
    if (clip && clip->all_clipped) {
124
	status = CAIRO_STATUS_SUCCESS;
125
	goto FINISH;
126
    }
127
 
128
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
129
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
130
    {
131
	cairo_matrix_t m;
132
 
133
	cairo_matrix_init_identity (&m);
134
 
135
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
136
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
137
 
138
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
139
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
140
 
141
	if (clip != NULL) {
142
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
143
	    if (unlikely (status))
144
		goto FINISH;
145
 
146
	    dev_clip = &clip_copy;
147
	}
148
 
149
	status = cairo_matrix_invert (&m);
150
	assert (status == CAIRO_STATUS_SUCCESS);
151
 
152
	_copy_transformed_pattern (&source_copy.base, source, &m);
153
	source = &source_copy.base;
154
    }
155
 
156
    status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
157
 
158
  FINISH:
159
    if (wrapper->has_extents)
160
	_cairo_clip_reset (&target_clip);
161
    if (dev_clip != clip)
162
	_cairo_clip_reset (dev_clip);
163
    return status;
164
}
165
 
166
cairo_status_t
167
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
168
			     cairo_operator_t	 op,
169
			     const cairo_pattern_t *source,
170
			     const cairo_pattern_t *mask,
171
			     cairo_clip_t	    *clip)
172
{
173
    cairo_status_t status;
174
    cairo_clip_t clip_copy, *dev_clip = clip;
175
    cairo_pattern_union_t source_copy;
176
    cairo_pattern_union_t mask_copy;
177
    cairo_clip_t target_clip;
178
 
179
    if (unlikely (wrapper->target->status))
180
	return wrapper->target->status;
181
 
182
    if (wrapper->has_extents) {
183
	_cairo_clip_init_copy (&target_clip, clip);
184
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
185
	if (unlikely (status))
186
	    goto FINISH;
187
 
188
	dev_clip = clip = &target_clip;
189
    }
190
 
191
    if (clip && clip->all_clipped) {
192
	status = CAIRO_STATUS_SUCCESS;
193
	goto FINISH;
194
    }
195
 
196
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
197
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
198
    {
199
	cairo_matrix_t m;
200
 
201
	cairo_matrix_init_identity (&m);
202
 
203
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
204
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
205
 
206
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
207
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
208
 
209
	if (clip != NULL) {
210
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
211
	    if (unlikely (status))
212
		goto FINISH;
213
 
214
	    dev_clip = &clip_copy;
215
	}
216
 
217
	status = cairo_matrix_invert (&m);
218
	assert (status == CAIRO_STATUS_SUCCESS);
219
 
220
	_copy_transformed_pattern (&source_copy.base, source, &m);
221
	source = &source_copy.base;
222
 
223
	_copy_transformed_pattern (&mask_copy.base, mask, &m);
224
	mask = &mask_copy.base;
225
    }
226
 
227
    status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
228
 
229
  FINISH:
230
    if (wrapper->has_extents)
231
	_cairo_clip_reset (&target_clip);
232
    if (dev_clip != clip)
233
	_cairo_clip_reset (dev_clip);
234
    return status;
235
}
236
 
237
cairo_status_t
238
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
239
			       cairo_operator_t		 op,
240
			       const cairo_pattern_t	*source,
241
			       cairo_path_fixed_t	*path,
242
			       const cairo_stroke_style_t	*stroke_style,
243
			       const cairo_matrix_t		*ctm,
244
			       const cairo_matrix_t		*ctm_inverse,
245
			       double			 tolerance,
246
			       cairo_antialias_t	 antialias,
247
			       cairo_clip_t		*clip)
248
{
249
    cairo_status_t status;
250
    cairo_path_fixed_t path_copy, *dev_path = path;
251
    cairo_clip_t clip_copy, *dev_clip = clip;
252
    cairo_matrix_t dev_ctm = *ctm;
253
    cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
254
    cairo_pattern_union_t source_copy;
255
    cairo_clip_t target_clip;
256
 
257
    if (unlikely (wrapper->target->status))
258
	return wrapper->target->status;
259
 
260
    if (wrapper->has_extents) {
261
	_cairo_clip_init_copy (&target_clip, clip);
262
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
263
	if (unlikely (status))
264
	    goto FINISH;
265
 
266
	dev_clip = clip = &target_clip;
267
    }
268
 
269
    if (clip && clip->all_clipped) {
270
	status = CAIRO_STATUS_SUCCESS;
271
	goto FINISH;
272
    }
273
 
274
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
275
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
276
    {
277
	cairo_matrix_t m;
278
 
279
	cairo_matrix_init_identity (&m);
280
 
281
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
282
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
283
 
284
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
285
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
286
 
287
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
288
	if (unlikely (status))
289
	    goto FINISH;
290
 
291
	_cairo_path_fixed_transform (&path_copy, &m);
292
	dev_path = &path_copy;
293
 
294
	if (clip != NULL) {
295
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
296
	    if (unlikely (status))
297
		goto FINISH;
298
 
299
	    dev_clip = &clip_copy;
300
	}
301
 
302
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
303
 
304
	status = cairo_matrix_invert (&m);
305
	assert (status == CAIRO_STATUS_SUCCESS);
306
 
307
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
308
 
309
	_copy_transformed_pattern (&source_copy.base, source, &m);
310
	source = &source_copy.base;
311
    }
312
    else
313
    {
314
	if (clip != NULL) {
315
	    dev_clip = &clip_copy;
316
	    _cairo_clip_init_copy (&clip_copy, clip);
317
	}
318
    }
319
 
320
    status = _cairo_surface_stroke (wrapper->target, op, source,
321
				    dev_path, stroke_style,
322
				    &dev_ctm, &dev_ctm_inverse,
323
				    tolerance, antialias,
324
				    dev_clip);
325
 
326
 FINISH:
327
    if (dev_path != path)
328
	_cairo_path_fixed_fini (dev_path);
329
    if (wrapper->has_extents)
330
	_cairo_clip_reset (&target_clip);
331
    if (dev_clip != clip)
332
	_cairo_clip_reset (dev_clip);
333
    return status;
334
}
335
 
336
cairo_status_t
337
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
338
				    cairo_operator_t	     fill_op,
339
				    const cairo_pattern_t   *fill_source,
340
				    cairo_fill_rule_t	     fill_rule,
341
				    double		     fill_tolerance,
342
				    cairo_antialias_t	     fill_antialias,
343
				    cairo_path_fixed_t	    *path,
344
				    cairo_operator_t	     stroke_op,
345
				    const cairo_pattern_t   *stroke_source,
346
				    const cairo_stroke_style_t    *stroke_style,
347
				    const cairo_matrix_t	    *stroke_ctm,
348
				    const cairo_matrix_t	    *stroke_ctm_inverse,
349
				    double		     stroke_tolerance,
350
				    cairo_antialias_t	     stroke_antialias,
351
				    cairo_clip_t	    *clip)
352
{
353
    cairo_status_t status;
354
    cairo_path_fixed_t path_copy, *dev_path = path;
355
    cairo_clip_t clip_copy, *dev_clip = clip;
356
    cairo_matrix_t dev_ctm = *stroke_ctm;
357
    cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
358
    cairo_pattern_union_t stroke_source_copy;
359
    cairo_pattern_union_t fill_source_copy;
360
    cairo_clip_t target_clip;
361
 
362
    if (unlikely (wrapper->target->status))
363
	return wrapper->target->status;
364
 
365
    if (wrapper->has_extents) {
366
	_cairo_clip_init_copy (&target_clip, clip);
367
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
368
	if (unlikely (status))
369
	    goto FINISH;
370
 
371
	dev_clip = clip = &target_clip;
372
    }
373
 
374
    if (clip && clip->all_clipped) {
375
	status = CAIRO_STATUS_SUCCESS;
376
	goto FINISH;
377
    }
378
 
379
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
380
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
381
    {
382
	cairo_matrix_t m;
383
 
384
	cairo_matrix_init_identity (&m);
385
 
386
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
387
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
388
 
389
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
390
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
391
 
392
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
393
	if (unlikely (status))
394
	    goto FINISH;
395
 
396
	_cairo_path_fixed_transform (&path_copy, &m);
397
	dev_path = &path_copy;
398
 
399
	if (clip != NULL) {
400
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
401
	    if (unlikely (status))
402
		goto FINISH;
403
 
404
	    dev_clip = &clip_copy;
405
	}
406
 
407
	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
408
 
409
	status = cairo_matrix_invert (&m);
410
	assert (status == CAIRO_STATUS_SUCCESS);
411
 
412
	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
413
 
414
	_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
415
	stroke_source = &stroke_source_copy.base;
416
 
417
	_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
418
	fill_source = &fill_source_copy.base;
419
    }
420
    else
421
    {
422
	if (clip != NULL) {
423
	    dev_clip = &clip_copy;
424
	    _cairo_clip_init_copy (&clip_copy, clip);
425
	}
426
    }
427
 
428
    status = _cairo_surface_fill_stroke (wrapper->target,
429
					 fill_op, fill_source, fill_rule,
430
					 fill_tolerance, fill_antialias,
431
					 dev_path,
432
					 stroke_op, stroke_source,
433
					 stroke_style,
434
					 &dev_ctm, &dev_ctm_inverse,
435
					 stroke_tolerance, stroke_antialias,
436
					 dev_clip);
437
 
438
  FINISH:
439
    if (dev_path != path)
440
	_cairo_path_fixed_fini (dev_path);
441
    if (wrapper->has_extents)
442
	_cairo_clip_reset (&target_clip);
443
    if (dev_clip != clip)
444
	_cairo_clip_reset (dev_clip);
445
    return status;
446
}
447
 
448
cairo_status_t
449
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
450
			     cairo_operator_t	 op,
451
			     const cairo_pattern_t *source,
452
			     cairo_path_fixed_t	*path,
453
			     cairo_fill_rule_t	 fill_rule,
454
			     double		 tolerance,
455
			     cairo_antialias_t	 antialias,
456
			     cairo_clip_t	*clip)
457
{
458
    cairo_status_t status;
459
    cairo_path_fixed_t path_copy, *dev_path = path;
460
    cairo_clip_t clip_copy, *dev_clip = clip;
461
    cairo_pattern_union_t source_copy;
462
    cairo_clip_t target_clip;
463
 
464
    if (unlikely (wrapper->target->status))
465
	return wrapper->target->status;
466
 
467
    if (wrapper->has_extents) {
468
	_cairo_clip_init_copy (&target_clip, clip);
469
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
470
	if (unlikely (status))
471
	    goto FINISH;
472
 
473
	dev_clip = clip = &target_clip;
474
    }
475
 
476
    if (clip && clip->all_clipped) {
477
	status = CAIRO_STATUS_SUCCESS;
478
	goto FINISH;
479
    }
480
 
481
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
482
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
483
    {
484
	cairo_matrix_t m;
485
 
486
	cairo_matrix_init_identity (&m);
487
 
488
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
489
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
490
 
491
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
492
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
493
 
494
	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
495
	if (unlikely (status))
496
	    goto FINISH;
497
 
498
	_cairo_path_fixed_transform (&path_copy, &m);
499
	dev_path = &path_copy;
500
 
501
	if (clip != NULL) {
502
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
503
	    if (unlikely (status))
504
		goto FINISH;
505
 
506
	    dev_clip = &clip_copy;
507
	}
508
 
509
	status = cairo_matrix_invert (&m);
510
	assert (status == CAIRO_STATUS_SUCCESS);
511
 
512
	_copy_transformed_pattern (&source_copy.base, source, &m);
513
	source = &source_copy.base;
514
    }
515
    else
516
    {
517
	if (clip != NULL) {
518
	    dev_clip = &clip_copy;
519
	    _cairo_clip_init_copy (&clip_copy, clip);
520
	}
521
    }
522
 
523
    status = _cairo_surface_fill (wrapper->target, op, source,
524
				  dev_path, fill_rule,
525
				  tolerance, antialias,
526
				  dev_clip);
527
 
528
 FINISH:
529
    if (dev_path != path)
530
	_cairo_path_fixed_fini (dev_path);
531
    if (wrapper->has_extents)
532
	_cairo_clip_reset (&target_clip);
533
    if (dev_clip != clip)
534
	_cairo_clip_reset (dev_clip);
535
    return status;
536
}
537
 
538
cairo_status_t
539
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
540
					 cairo_operator_t	     op,
541
					 const cairo_pattern_t	    *source,
542
					 const char		    *utf8,
543
					 int			     utf8_len,
544
					 cairo_glyph_t		    *glyphs,
545
					 int			     num_glyphs,
546
					 const cairo_text_cluster_t *clusters,
547
					 int			     num_clusters,
548
					 cairo_text_cluster_flags_t  cluster_flags,
549
					 cairo_scaled_font_t	    *scaled_font,
550
					 cairo_clip_t		    *clip)
551
{
552
    cairo_status_t status;
553
    cairo_clip_t clip_copy, *dev_clip = clip;
554
    cairo_glyph_t *dev_glyphs = glyphs;
555
    cairo_pattern_union_t source_copy;
556
    cairo_clip_t target_clip;
557
 
558
    if (unlikely (wrapper->target->status))
559
	return wrapper->target->status;
560
 
561
    if (glyphs == NULL || num_glyphs == 0)
562
	return CAIRO_STATUS_SUCCESS;
563
 
564
    if (wrapper->has_extents) {
565
	_cairo_clip_init_copy (&target_clip, clip);
566
	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
567
	if (unlikely (status))
568
	    goto FINISH;
569
 
570
	dev_clip = clip = &target_clip;
571
    }
572
 
573
    if (clip && clip->all_clipped) {
574
	status = CAIRO_STATUS_SUCCESS;
575
	goto FINISH;
576
    }
577
 
578
    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
579
	_cairo_surface_wrapper_needs_extents_transform (wrapper))
580
    {
581
	cairo_matrix_t m;
582
	int i;
583
 
584
	cairo_matrix_init_identity (&m);
585
 
586
	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
587
	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
588
 
589
	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
590
	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
591
 
592
	if (clip != NULL) {
593
	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
594
	    if (unlikely (status))
595
		goto FINISH;
596
 
597
	    dev_clip = &clip_copy;
598
	}
599
 
600
	dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
601
	if (dev_glyphs == NULL) {
602
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
603
	    goto FINISH;
604
	}
605
 
606
	for (i = 0; i < num_glyphs; i++) {
607
	    dev_glyphs[i] = glyphs[i];
608
	    cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
609
	}
610
 
611
	status = cairo_matrix_invert (&m);
612
	assert (status == CAIRO_STATUS_SUCCESS);
613
 
614
	_copy_transformed_pattern (&source_copy.base, source, &m);
615
	source = &source_copy.base;
616
    }
617
    else
618
    {
619
	if (clip != NULL) {
620
	    dev_clip = &clip_copy;
621
	    _cairo_clip_init_copy (&clip_copy, clip);
622
	}
623
    }
624
 
625
    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
626
					      utf8, utf8_len,
627
					      dev_glyphs, num_glyphs,
628
					      clusters, num_clusters,
629
					      cluster_flags,
630
					      scaled_font,
631
					      dev_clip);
632
 
633
 FINISH:
634
    if (dev_clip != clip)
635
	_cairo_clip_reset (dev_clip);
636
    if (wrapper->has_extents)
637
	_cairo_clip_reset (&target_clip);
638
    if (dev_glyphs != glyphs)
639
	free (dev_glyphs);
640
    return status;
641
}
642
 
643
cairo_surface_t *
644
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
645
				       cairo_content_t	content,
646
				       int		width,
647
				       int		height)
648
{
649
    return _cairo_surface_create_similar_scratch (wrapper->target,
650
						  content, width, height);
651
}
652
 
653
cairo_bool_t
654
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
655
				    cairo_rectangle_int_t   *extents)
656
{
657
    if (wrapper->has_extents) {
658
	if (_cairo_surface_get_extents (wrapper->target, extents))
659
	    _cairo_rectangle_intersect (extents, &wrapper->extents);
660
	else
661
	    *extents = wrapper->extents;
662
 
663
	return TRUE;
664
    } else {
665
	return _cairo_surface_get_extents (wrapper->target, extents);
666
    }
667
}
668
 
669
void
670
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
671
				    const cairo_rectangle_int_t *extents)
672
{
673
    if (extents != NULL) {
674
	wrapper->extents = *extents;
675
	wrapper->has_extents = TRUE;
676
    } else {
677
	wrapper->has_extents = FALSE;
678
    }
679
}
680
 
681
void
682
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t    *wrapper,
683
					 cairo_font_options_t	    *options)
684
{
685
    cairo_surface_get_font_options (wrapper->target, options);
686
}
687
 
688
cairo_surface_t *
689
_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
690
{
691
    return _cairo_surface_snapshot (wrapper->target);
692
}
693
 
694
cairo_bool_t
695
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
696
{
697
    return cairo_surface_has_show_text_glyphs (wrapper->target);
698
}
699
 
700
void
701
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
702
			     cairo_surface_t *target)
703
{
704
    wrapper->target = cairo_surface_reference (target);
705
    wrapper->has_extents = FALSE;
706
}
707
 
708
void
709
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
710
{
711
    cairo_surface_destroy (wrapper->target);
712
}