Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3959 Serge 1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2005 Red Hat, Inc
4
 * Copyright © 2009 Chris Wilson
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Red Hat, Inc.
32
 *
33
 * Contributor(s):
34
 *	Carl Worth 
35
 *	Chris Wilson 
36
 */
37
 
38
/* This surface supports redirecting all its input to multiple surfaces.
39
 */
40
 
41
#include "cairoint.h"
42
 
43
#include "cairo-tee.h"
44
 
45
#include "cairo-default-context-private.h"
46
#include "cairo-error-private.h"
47
#include "cairo-tee-surface-private.h"
48
#include "cairo-recording-surface-inline.h"
49
#include "cairo-surface-wrapper-private.h"
50
#include "cairo-array-private.h"
51
#include "cairo-image-surface-inline.h"
52
 
53
typedef struct _cairo_tee_surface {
54
    cairo_surface_t base;
55
 
56
    cairo_surface_wrapper_t master;
57
    cairo_array_t slaves;
58
} cairo_tee_surface_t;
59
 
60
slim_hidden_proto (cairo_tee_surface_create);
61
slim_hidden_proto (cairo_tee_surface_add);
62
 
63
static cairo_surface_t *
64
_cairo_tee_surface_create_similar (void			*abstract_surface,
65
				   cairo_content_t	 content,
66
				   int			 width,
67
				   int			 height)
68
{
69
 
70
    cairo_tee_surface_t *other = abstract_surface;
71
    cairo_surface_t *similar;
72
    cairo_surface_t *surface;
73
    cairo_surface_wrapper_t *slaves;
74
    int n, num_slaves;
75
 
76
    similar = _cairo_surface_wrapper_create_similar (&other->master,
77
						     content, width, height);
78
    surface = cairo_tee_surface_create (similar);
79
    cairo_surface_destroy (similar);
80
    if (unlikely (surface->status))
81
	return surface;
82
 
83
    num_slaves = _cairo_array_num_elements (&other->slaves);
84
    slaves = _cairo_array_index (&other->slaves, 0);
85
    for (n = 0; n < num_slaves; n++) {
86
 
87
	similar = _cairo_surface_wrapper_create_similar (&slaves[n],
88
							 content,
89
							 width, height);
90
	cairo_tee_surface_add (surface, similar);
91
	cairo_surface_destroy (similar);
92
    }
93
 
94
    if (unlikely (surface->status)) {
95
	cairo_status_t status = surface->status;
96
	cairo_surface_destroy (surface);
97
	surface = _cairo_surface_create_in_error (status);
98
    }
99
 
100
    return surface;
101
}
102
 
103
static cairo_status_t
104
_cairo_tee_surface_finish (void *abstract_surface)
105
{
106
    cairo_tee_surface_t *surface = abstract_surface;
107
    cairo_surface_wrapper_t *slaves;
108
    int n, num_slaves;
109
 
110
    _cairo_surface_wrapper_fini (&surface->master);
111
 
112
    num_slaves = _cairo_array_num_elements (&surface->slaves);
113
    slaves = _cairo_array_index (&surface->slaves, 0);
114
    for (n = 0; n < num_slaves; n++)
115
	_cairo_surface_wrapper_fini (&slaves[n]);
116
 
117
    _cairo_array_fini (&surface->slaves);
118
 
119
    return CAIRO_STATUS_SUCCESS;
120
}
121
 
122
static cairo_surface_t *
123
_cairo_tee_surface_source (void	     *abstract_surface,
124
			   cairo_rectangle_int_t *extents)
125
{
126
    cairo_tee_surface_t *surface = abstract_surface;
127
    return _cairo_surface_get_source (surface->master.target, extents);
128
}
129
 
130
static cairo_status_t
131
_cairo_tee_surface_acquire_source_image (void	     *abstract_surface,
132
					 cairo_image_surface_t **image_out,
133
					 void		 **image_extra)
134
{
135
    cairo_tee_surface_t *surface = abstract_surface;
136
    cairo_surface_wrapper_t *slaves;
137
    int num_slaves, n;
138
 
139
    /* we prefer to use a real image surface if available */
140
    if (_cairo_surface_is_image (surface->master.target)) {
141
	return _cairo_surface_wrapper_acquire_source_image (&surface->master,
142
							    image_out, image_extra);
143
    }
144
 
145
    num_slaves = _cairo_array_num_elements (&surface->slaves);
146
    slaves = _cairo_array_index (&surface->slaves, 0);
147
    for (n = 0; n < num_slaves; n++) {
148
	if (_cairo_surface_is_image (slaves[n].target)) {
149
	    return _cairo_surface_wrapper_acquire_source_image (&slaves[n],
150
								image_out,
151
								image_extra);
152
	}
153
    }
154
 
155
    return _cairo_surface_wrapper_acquire_source_image (&surface->master,
156
							image_out, image_extra);
157
}
158
 
159
static void
160
_cairo_tee_surface_release_source_image (void	     *abstract_surface,
161
					 cairo_image_surface_t	*image,
162
					 void		  *image_extra)
163
{
164
    cairo_tee_surface_t *surface = abstract_surface;
165
 
166
    _cairo_surface_wrapper_release_source_image (&surface->master,
167
						 image, image_extra);
168
}
169
 
170
static cairo_surface_t *
171
_cairo_tee_surface_snapshot (void *abstract_surface)
172
{
173
    cairo_tee_surface_t *surface = abstract_surface;
174
    cairo_surface_wrapper_t *slaves;
175
    int num_slaves, n;
176
 
177
    /* we prefer to use a recording surface for our snapshots */
178
    if (_cairo_surface_is_recording (surface->master.target))
179
	return _cairo_surface_wrapper_snapshot (&surface->master);
180
 
181
    num_slaves = _cairo_array_num_elements (&surface->slaves);
182
    slaves = _cairo_array_index (&surface->slaves, 0);
183
    for (n = 0; n < num_slaves; n++) {
184
	if (_cairo_surface_is_recording (slaves[n].target))
185
	    return _cairo_surface_wrapper_snapshot (&slaves[n]);
186
    }
187
 
188
    return _cairo_surface_wrapper_snapshot (&surface->master);
189
}
190
 
191
static cairo_bool_t
192
_cairo_tee_surface_get_extents (void			*abstract_surface,
193
				cairo_rectangle_int_t	*rectangle)
194
{
195
    cairo_tee_surface_t *surface = abstract_surface;
196
 
197
    return _cairo_surface_wrapper_get_extents (&surface->master, rectangle);
198
}
199
 
200
static void
201
_cairo_tee_surface_get_font_options (void                  *abstract_surface,
202
				     cairo_font_options_t  *options)
203
{
204
    cairo_tee_surface_t *surface = abstract_surface;
205
 
206
    _cairo_surface_wrapper_get_font_options (&surface->master, options);
207
}
208
 
209
static cairo_int_status_t
210
_cairo_tee_surface_paint (void			*abstract_surface,
211
			  cairo_operator_t	 op,
212
			  const cairo_pattern_t	*source,
213
			  const cairo_clip_t	*clip)
214
{
215
    cairo_tee_surface_t *surface = abstract_surface;
216
    cairo_surface_wrapper_t *slaves;
217
    int n, num_slaves;
218
    cairo_int_status_t status;
219
 
220
    num_slaves = _cairo_array_num_elements (&surface->slaves);
221
    slaves = _cairo_array_index (&surface->slaves, 0);
222
    for (n = 0; n < num_slaves; n++) {
223
	status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip);
224
	if (unlikely (status))
225
	    return status;
226
    }
227
 
228
    return _cairo_surface_wrapper_paint (&surface->master, op, source, clip);
229
}
230
 
231
static cairo_int_status_t
232
_cairo_tee_surface_mask (void			*abstract_surface,
233
			 cairo_operator_t	 op,
234
			 const cairo_pattern_t	*source,
235
			 const cairo_pattern_t	*mask,
236
			 const cairo_clip_t	*clip)
237
{
238
    cairo_tee_surface_t *surface = abstract_surface;
239
    cairo_surface_wrapper_t *slaves;
240
    cairo_int_status_t status;
241
    int n, num_slaves;
242
 
243
    num_slaves = _cairo_array_num_elements (&surface->slaves);
244
    slaves = _cairo_array_index (&surface->slaves, 0);
245
    for (n = 0; n < num_slaves; n++) {
246
	status = _cairo_surface_wrapper_mask (&slaves[n],
247
					      op, source, mask, clip);
248
	if (unlikely (status))
249
	    return status;
250
    }
251
 
252
    return _cairo_surface_wrapper_mask (&surface->master,
253
					op, source, mask, clip);
254
}
255
 
256
static cairo_int_status_t
257
_cairo_tee_surface_stroke (void				*abstract_surface,
258
			   cairo_operator_t		 op,
259
			   const cairo_pattern_t	*source,
260
			   const cairo_path_fixed_t	*path,
261
			   const cairo_stroke_style_t	*style,
262
			   const cairo_matrix_t		*ctm,
263
			   const cairo_matrix_t		*ctm_inverse,
264
			   double			 tolerance,
265
			   cairo_antialias_t		 antialias,
266
			   const cairo_clip_t		*clip)
267
{
268
    cairo_tee_surface_t *surface = abstract_surface;
269
    cairo_surface_wrapper_t *slaves;
270
    cairo_int_status_t status;
271
    int n, num_slaves;
272
 
273
    num_slaves = _cairo_array_num_elements (&surface->slaves);
274
    slaves = _cairo_array_index (&surface->slaves, 0);
275
    for (n = 0; n < num_slaves; n++) {
276
	status = _cairo_surface_wrapper_stroke (&slaves[n],
277
						op, source,
278
						path, style,
279
						ctm, ctm_inverse,
280
						tolerance, antialias,
281
						clip);
282
	if (unlikely (status))
283
	    return status;
284
    }
285
 
286
    return _cairo_surface_wrapper_stroke (&surface->master,
287
					  op, source,
288
					  path, style,
289
					  ctm, ctm_inverse,
290
					  tolerance, antialias,
291
					  clip);
292
}
293
 
294
static cairo_int_status_t
295
_cairo_tee_surface_fill (void				*abstract_surface,
296
			 cairo_operator_t		 op,
297
			 const cairo_pattern_t		*source,
298
			 const cairo_path_fixed_t	*path,
299
			 cairo_fill_rule_t		 fill_rule,
300
			 double				 tolerance,
301
			 cairo_antialias_t		 antialias,
302
			 const cairo_clip_t		*clip)
303
{
304
    cairo_tee_surface_t *surface = abstract_surface;
305
    cairo_surface_wrapper_t *slaves;
306
    cairo_int_status_t status;
307
    int n, num_slaves;
308
 
309
    num_slaves = _cairo_array_num_elements (&surface->slaves);
310
    slaves = _cairo_array_index (&surface->slaves, 0);
311
    for (n = 0; n < num_slaves; n++) {
312
	status = _cairo_surface_wrapper_fill (&slaves[n],
313
					      op, source,
314
					      path, fill_rule,
315
					      tolerance, antialias,
316
					      clip);
317
	if (unlikely (status))
318
	    return status;
319
    }
320
 
321
    return _cairo_surface_wrapper_fill (&surface->master,
322
					op, source,
323
					path, fill_rule,
324
					tolerance, antialias,
325
					clip);
326
}
327
 
328
static cairo_bool_t
329
_cairo_tee_surface_has_show_text_glyphs (void *abstract_surface)
330
{
331
    return TRUE;
332
}
333
 
334
static cairo_int_status_t
335
_cairo_tee_surface_show_text_glyphs (void		    *abstract_surface,
336
				     cairo_operator_t	     op,
337
				     const cairo_pattern_t  *source,
338
				     const char		    *utf8,
339
				     int		     utf8_len,
340
				     cairo_glyph_t	    *glyphs,
341
				     int		     num_glyphs,
342
				     const cairo_text_cluster_t *clusters,
343
				     int		     num_clusters,
344
				     cairo_text_cluster_flags_t cluster_flags,
345
				     cairo_scaled_font_t    *scaled_font,
346
				     const cairo_clip_t	    *clip)
347
{
348
    cairo_tee_surface_t *surface = abstract_surface;
349
    cairo_surface_wrapper_t *slaves;
350
    cairo_int_status_t status;
351
    int n, num_slaves;
352
    cairo_glyph_t *glyphs_copy;
353
 
354
    /* XXX: This copying is ugly. */
355
    glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
356
    if (unlikely (glyphs_copy == NULL))
357
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
358
 
359
    num_slaves = _cairo_array_num_elements (&surface->slaves);
360
    slaves = _cairo_array_index (&surface->slaves, 0);
361
    for (n = 0; n < num_slaves; n++) {
362
	memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
363
	status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op,
364
							  source,
365
							  utf8, utf8_len,
366
							  glyphs_copy, num_glyphs,
367
							  clusters, num_clusters,
368
							  cluster_flags,
369
							  scaled_font,
370
							  clip);
371
	if (unlikely (status))
372
	    goto CLEANUP;
373
    }
374
 
375
    memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
376
    status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
377
						      source,
378
						      utf8, utf8_len,
379
						      glyphs_copy, num_glyphs,
380
						      clusters, num_clusters,
381
						      cluster_flags,
382
						      scaled_font,
383
						      clip);
384
CLEANUP:
385
    free (glyphs_copy);
386
    return status;
387
}
388
 
389
static const cairo_surface_backend_t cairo_tee_surface_backend = {
390
    CAIRO_SURFACE_TYPE_TEE,
391
    _cairo_tee_surface_finish,
392
 
393
    _cairo_default_context_create, /* XXX */
394
 
395
    _cairo_tee_surface_create_similar,
396
    NULL, /* create similar image */
397
    NULL, /* map to image */
398
    NULL, /* unmap image */
399
 
400
    _cairo_tee_surface_source,
401
    _cairo_tee_surface_acquire_source_image,
402
    _cairo_tee_surface_release_source_image,
403
    _cairo_tee_surface_snapshot,
404
    NULL, /* copy_page */
405
    NULL, /* show_page */
406
    _cairo_tee_surface_get_extents,
407
    _cairo_tee_surface_get_font_options,
408
    NULL, /* flush */
409
    NULL, /* mark_dirty_rectangle */
410
 
411
    _cairo_tee_surface_paint,
412
    _cairo_tee_surface_mask,
413
    _cairo_tee_surface_stroke,
414
    _cairo_tee_surface_fill,
415
    NULL, /* fill_stroke */
416
 
417
    NULL, /* show_glyphs */
418
 
419
    _cairo_tee_surface_has_show_text_glyphs,
420
    _cairo_tee_surface_show_text_glyphs
421
};
422
 
423
cairo_surface_t *
424
cairo_tee_surface_create (cairo_surface_t *master)
425
{
426
    cairo_tee_surface_t *surface;
427
 
428
    if (unlikely (master->status))
429
	return _cairo_surface_create_in_error (master->status);
430
 
431
    surface = malloc (sizeof (cairo_tee_surface_t));
432
    if (unlikely (surface == NULL))
433
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
434
 
435
    _cairo_surface_init (&surface->base,
436
			 &cairo_tee_surface_backend,
437
			 master->device,
438
			 master->content);
439
 
440
    _cairo_surface_wrapper_init (&surface->master, master);
441
 
442
    _cairo_array_init (&surface->slaves, sizeof (cairo_surface_wrapper_t));
443
 
444
    return &surface->base;
445
}
446
slim_hidden_def (cairo_tee_surface_create);
447
 
448
void
449
cairo_tee_surface_add (cairo_surface_t *abstract_surface,
450
		       cairo_surface_t *target)
451
{
452
    cairo_tee_surface_t *surface;
453
    cairo_surface_wrapper_t slave;
454
    cairo_status_t status;
455
 
456
    if (unlikely (abstract_surface->status))
457
	return;
458
    if (unlikely (abstract_surface->finished)) {
459
	status = _cairo_surface_set_error (abstract_surface,
460
					   _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
461
	return;
462
    }
463
 
464
    if (abstract_surface->backend != &cairo_tee_surface_backend) {
465
	status = _cairo_surface_set_error (abstract_surface,
466
					   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
467
	return;
468
    }
469
 
470
    if (unlikely (target->status)) {
471
	status = _cairo_surface_set_error (abstract_surface, target->status);
472
	return;
473
    }
474
 
475
    surface = (cairo_tee_surface_t *) abstract_surface;
476
 
477
    _cairo_surface_wrapper_init (&slave, target);
478
    status = _cairo_array_append (&surface->slaves, &slave);
479
    if (unlikely (status)) {
480
	_cairo_surface_wrapper_fini (&slave);
481
	status = _cairo_surface_set_error (&surface->base, status);
482
    }
483
}
484
slim_hidden_def (cairo_tee_surface_add);
485
 
486
void
487
cairo_tee_surface_remove (cairo_surface_t *abstract_surface,
488
			  cairo_surface_t *target)
489
{
490
    cairo_tee_surface_t *surface;
491
    cairo_surface_wrapper_t *slaves;
492
    int n, num_slaves;
493
 
494
    if (unlikely (abstract_surface->status))
495
	return;
496
    if (unlikely (abstract_surface->finished)) {
497
	_cairo_surface_set_error (abstract_surface,
498
				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
499
	return;
500
    }
501
 
502
    if (abstract_surface->backend != &cairo_tee_surface_backend) {
503
	_cairo_surface_set_error (abstract_surface,
504
				  _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
505
	return;
506
    }
507
 
508
    surface = (cairo_tee_surface_t *) abstract_surface;
509
    if (target == surface->master.target) {
510
	_cairo_surface_set_error (abstract_surface,
511
				  _cairo_error (CAIRO_STATUS_INVALID_INDEX));
512
	return;
513
    }
514
 
515
    num_slaves = _cairo_array_num_elements (&surface->slaves);
516
    slaves = _cairo_array_index (&surface->slaves, 0);
517
    for (n = 0; n < num_slaves; n++) {
518
	if (slaves[n].target == target)
519
	    break;
520
    }
521
 
522
    if (n == num_slaves) {
523
	_cairo_surface_set_error (abstract_surface,
524
				  _cairo_error (CAIRO_STATUS_INVALID_INDEX));
525
	return;
526
    }
527
 
528
    _cairo_surface_wrapper_fini (&slaves[n]);
529
    for (n++; n < num_slaves; n++)
530
	slaves[n-1] = slaves[n];
531
    surface->slaves.num_elements--; /* XXX: cairo_array_remove()? */
532
}
533
 
534
cairo_surface_t *
535
cairo_tee_surface_index (cairo_surface_t *abstract_surface,
536
			 unsigned int index)
537
{
538
    cairo_tee_surface_t *surface;
539
 
540
    if (unlikely (abstract_surface->status))
541
	return _cairo_surface_create_in_error (abstract_surface->status);
542
    if (unlikely (abstract_surface->finished))
543
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
544
 
545
    if (abstract_surface->backend != &cairo_tee_surface_backend)
546
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
547
 
548
    surface = (cairo_tee_surface_t *) abstract_surface;
549
    if (index == 0) {
550
	return surface->master.target;
551
    } else {
552
	cairo_surface_wrapper_t *slave;
553
 
554
	index--;
555
 
556
	if (index >= _cairo_array_num_elements (&surface->slaves))
557
	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX));
558
 
559
	slave = _cairo_array_index (&surface->slaves, index);
560
	return slave->target;
561
    }
562
}
563
 
564
cairo_surface_t *
565
_cairo_tee_surface_find_match (void *abstract_surface,
566
			       const cairo_surface_backend_t *backend,
567
			       cairo_content_t content)
568
{
569
    cairo_tee_surface_t *surface = abstract_surface;
570
    cairo_surface_wrapper_t *slaves;
571
    int num_slaves, n;
572
 
573
    /* exact match first */
574
    if (surface->master.target->backend == backend &&
575
	surface->master.target->content == content)
576
    {
577
	return surface->master.target;
578
    }
579
 
580
    num_slaves = _cairo_array_num_elements (&surface->slaves);
581
    slaves = _cairo_array_index (&surface->slaves, 0);
582
    for (n = 0; n < num_slaves; n++) {
583
	if (slaves[n].target->backend == backend &&
584
	    slaves[n].target->content == content)
585
	{
586
	    return slaves[n].target;
587
	}
588
    }
589
 
590
    /* matching backend? */
591
    if (surface->master.target->backend == backend)
592
	return surface->master.target;
593
 
594
    num_slaves = _cairo_array_num_elements (&surface->slaves);
595
    slaves = _cairo_array_index (&surface->slaves, 0);
596
    for (n = 0; n < num_slaves; n++) {
597
	if (slaves[n].target->backend == backend)
598
	    return slaves[n].target;
599
    }
600
 
601
    return NULL;
602
}