Subversion Repositories Kolibri OS

Rev

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