Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14952 fschmid 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
18122 mrdocs 16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14952 fschmid 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 <cworth@cworth.org>
35
 *      Chris Wilson <chris@chris-wilson.co.uk>
36
 */
37
 
38
/* This surface supports redirecting all its input to multiple surfaces.
39
 */
40
 
41
#include "cairoint.h"
42
 
43
#include "cairo-tee-surface-private.h"
44
#include "cairo-surface-wrapper-private.h"
45
 
46
typedef struct _cairo_tee_surface {
47
    cairo_surface_t base;
48
 
49
    cairo_surface_wrapper_t master;
50
    cairo_array_t slaves;
51
} cairo_tee_surface_t;
52
 
53
slim_hidden_proto (cairo_tee_surface_create);
54
slim_hidden_proto (cairo_tee_surface_add);
55
 
56
static cairo_surface_t *
57
_cairo_tee_surface_create_similar (void                 *abstract_surface,
58
                                   cairo_content_t       content,
59
                                   int                   width,
60
                                   int                   height)
61
{
62
 
63
    cairo_tee_surface_t *other = abstract_surface;
64
    cairo_surface_t *similar;
65
    cairo_surface_t *surface;
66
    cairo_surface_wrapper_t *slaves;
67
    int n, num_slaves;
68
 
69
    similar = _cairo_surface_wrapper_create_similar (&other->master,
70
                                                     content, width, height);
71
    surface = cairo_tee_surface_create (similar);
72
    cairo_surface_destroy (similar);
73
    if (unlikely (surface->status))
74
        return surface;
75
 
76
    num_slaves = _cairo_array_num_elements (&other->slaves);
77
    slaves = _cairo_array_index (&other->slaves, 0);
78
    for (n = 0; n < num_slaves; n++) {
79
 
80
        similar = _cairo_surface_wrapper_create_similar (&slaves[n],
81
                                                         content,
82
                                                         width, height);
83
        cairo_tee_surface_add (surface, similar);
84
        cairo_surface_destroy (similar);
85
    }
86
 
87
    if (unlikely (surface->status)) {
88
        cairo_status_t status = surface->status;
89
        cairo_surface_destroy (surface);
90
        surface = _cairo_surface_create_in_error (status);
91
    }
92
 
93
    return surface;
94
}
95
 
96
static cairo_status_t
97
_cairo_tee_surface_finish (void *abstract_surface)
98
{
99
    cairo_tee_surface_t *surface = abstract_surface;
100
    cairo_surface_wrapper_t *slaves;
101
    int n, num_slaves;
102
 
103
    _cairo_surface_wrapper_fini (&surface->master);
104
 
105
    num_slaves = _cairo_array_num_elements (&surface->slaves);
106
    slaves = _cairo_array_index (&surface->slaves, 0);
107
    for (n = 0; n < num_slaves; n++)
108
        _cairo_surface_wrapper_fini (&slaves[n]);
109
 
110
    _cairo_array_fini (&surface->slaves);
111
 
112
    return CAIRO_STATUS_SUCCESS;
113
}
114
 
115
static cairo_status_t
116
_cairo_tee_surface_acquire_source_image (void        *abstract_surface,
117
                                         cairo_image_surface_t **image_out,
118
                                         void            **image_extra)
119
{
120
    cairo_tee_surface_t *surface = abstract_surface;
121
    cairo_surface_wrapper_t *slaves;
122
    int num_slaves, n;
123
 
124
    /* we prefer to use a real image surface if available */
125
    if (_cairo_surface_is_image (surface->master.target)) {
126
        return _cairo_surface_wrapper_acquire_source_image (&surface->master,
127
                                                            image_out, image_extra);
128
    }
129
 
130
    num_slaves = _cairo_array_num_elements (&surface->slaves);
131
    slaves = _cairo_array_index (&surface->slaves, 0);
132
    for (n = 0; n < num_slaves; n++) {
133
        if (_cairo_surface_is_image (slaves[n].target)) {
134
            return _cairo_surface_wrapper_acquire_source_image (&slaves[n],
135
                                                                image_out,
136
                                                                image_extra);
137
        }
138
    }
139
 
140
    return _cairo_surface_wrapper_acquire_source_image (&surface->master,
141
                                                        image_out, image_extra);
142
}
143
 
144
static void
145
_cairo_tee_surface_release_source_image (void        *abstract_surface,
146
                                         cairo_image_surface_t  *image,
147
                                         void             *image_extra)
148
{
149
    cairo_tee_surface_t *surface = abstract_surface;
150
 
151
    _cairo_surface_wrapper_release_source_image (&surface->master,
152
                                                 image, image_extra);
153
}
154
 
155
static cairo_surface_t *
156
_cairo_tee_surface_snapshot (void *abstract_surface)
157
{
158
    cairo_tee_surface_t *surface = abstract_surface;
159
    cairo_surface_wrapper_t *slaves;
160
    int num_slaves, n;
161
 
162
    /* we prefer to use a meta surface for our snapshots */
163
    if (_cairo_surface_is_meta (surface->master.target))
164
        return _cairo_surface_wrapper_snapshot (&surface->master);
165
 
166
    num_slaves = _cairo_array_num_elements (&surface->slaves);
167
    slaves = _cairo_array_index (&surface->slaves, 0);
168
    for (n = 0; n < num_slaves; n++) {
169
        if (_cairo_surface_is_meta (slaves[n].target))
170
            return _cairo_surface_wrapper_snapshot (&slaves[n]);
171
    }
172
 
173
    return _cairo_surface_wrapper_snapshot (&surface->master);
174
}
175
 
176
static cairo_bool_t
177
_cairo_tee_surface_get_extents (void                    *abstract_surface,
178
                                cairo_rectangle_int_t   *rectangle)
179
{
180
    cairo_tee_surface_t *surface = abstract_surface;
181
 
182
    return _cairo_surface_wrapper_get_extents (&surface->master, rectangle);
183
}
184
 
185
static void
186
_cairo_tee_surface_get_font_options (void                  *abstract_surface,
187
                                     cairo_font_options_t  *options)
188
{
189
    cairo_tee_surface_t *surface = abstract_surface;
190
 
191
    _cairo_surface_wrapper_get_font_options (&surface->master, options);
192
}
193
 
194
static cairo_int_status_t
195
_cairo_tee_surface_paint (void                  *abstract_surface,
196
                          cairo_operator_t       op,
197
                          const cairo_pattern_t *source,
198
                          cairo_clip_t          *clip)
199
{
200
    cairo_tee_surface_t *surface = abstract_surface;
201
    cairo_surface_wrapper_t *slaves;
202
    int n, num_slaves;
203
    cairo_status_t status;
204
 
205
    status = _cairo_surface_wrapper_paint (&surface->master, op, source, clip);
206
    if (unlikely (status))
207
        return status;
208
 
209
    num_slaves = _cairo_array_num_elements (&surface->slaves);
210
    slaves = _cairo_array_index (&surface->slaves, 0);
211
    for (n = 0; n < num_slaves; n++) {
212
        status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip);
213
        if (unlikely (status))
214
            return status;
215
    }
216
 
217
    return CAIRO_STATUS_SUCCESS;
218
}
219
 
220
static cairo_int_status_t
221
_cairo_tee_surface_mask (void                   *abstract_surface,
222
                         cairo_operator_t        op,
223
                         const cairo_pattern_t  *source,
224
                         const cairo_pattern_t  *mask,
225
                         cairo_clip_t           *clip)
226
{
227
    cairo_tee_surface_t *surface = abstract_surface;
228
    cairo_surface_wrapper_t *slaves;
229
    int n, num_slaves;
230
    cairo_status_t status;
231
 
232
    status = _cairo_surface_wrapper_mask (&surface->master,
233
                                          op, source, mask, clip);
234
    if (unlikely (status))
235
        return status;
236
 
237
    num_slaves = _cairo_array_num_elements (&surface->slaves);
238
    slaves = _cairo_array_index (&surface->slaves, 0);
239
    for (n = 0; n < num_slaves; n++) {
240
        status = _cairo_surface_wrapper_mask (&slaves[n],
241
                                              op, source, mask, clip);
242
        if (unlikely (status))
243
            return status;
244
    }
245
 
246
    return CAIRO_STATUS_SUCCESS;
247
}
248
 
249
static cairo_int_status_t
250
_cairo_tee_surface_stroke (void                         *abstract_surface,
251
                           cairo_operator_t              op,
252
                           const cairo_pattern_t        *source,
253
                           cairo_path_fixed_t           *path,
254
                           cairo_stroke_style_t         *style,
255
                           cairo_matrix_t               *ctm,
256
                           cairo_matrix_t               *ctm_inverse,
257
                           double                        tolerance,
258
                           cairo_antialias_t             antialias,
259
                           cairo_clip_t                 *clip)
260
{
261
    cairo_tee_surface_t *surface = abstract_surface;
262
    cairo_surface_wrapper_t *slaves;
263
    int n, num_slaves;
264
    cairo_status_t status;
265
 
266
    status = _cairo_surface_wrapper_stroke (&surface->master,
267
                                            op, source,
268
                                            path, style,
269
                                            ctm, ctm_inverse,
270
                                            tolerance, antialias,
271
                                            clip);
272
    if (unlikely (status))
273
        return status;
274
 
275
    num_slaves = _cairo_array_num_elements (&surface->slaves);
276
    slaves = _cairo_array_index (&surface->slaves, 0);
277
    for (n = 0; n < num_slaves; n++) {
278
        status = _cairo_surface_wrapper_stroke (&slaves[n],
279
                                                op, source,
280
                                                path, style,
281
                                                ctm, ctm_inverse,
282
                                                tolerance, antialias,
283
                                                clip);
284
        if (unlikely (status))
285
            return status;
286
    }
287
 
288
    return CAIRO_STATUS_SUCCESS;
289
}
290
 
291
static cairo_int_status_t
292
_cairo_tee_surface_fill (void                           *abstract_surface,
293
                         cairo_operator_t                op,
294
                         const cairo_pattern_t          *source,
295
                         cairo_path_fixed_t             *path,
296
                         cairo_fill_rule_t               fill_rule,
297
                         double                          tolerance,
298
                         cairo_antialias_t               antialias,
299
                         cairo_clip_t                   *clip)
300
{
301
    cairo_tee_surface_t *surface = abstract_surface;
302
    cairo_surface_wrapper_t *slaves;
303
    int n, num_slaves;
304
    cairo_status_t status;
305
 
306
    status = _cairo_surface_wrapper_fill (&surface->master,
307
                                          op, source,
308
                                          path, fill_rule,
309
                                          tolerance, antialias,
310
                                          clip);
311
    if (unlikely (status))
312
        return status;
313
 
314
    num_slaves = _cairo_array_num_elements (&surface->slaves);
315
    slaves = _cairo_array_index (&surface->slaves, 0);
316
    for (n = 0; n < num_slaves; n++) {
317
        status = _cairo_surface_wrapper_fill (&slaves[n],
318
                                              op, source,
319
                                              path, fill_rule,
320
                                              tolerance, antialias,
321
                                              clip);
322
        if (unlikely (status))
323
            return status;
324
    }
325
 
326
    return CAIRO_STATUS_SUCCESS;
327
}
328
 
329
static cairo_bool_t
330
_cairo_tee_surface_has_show_text_glyphs (void *abstract_surface)
331
{
332
    return TRUE;
333
}
334
 
335
static cairo_int_status_t
336
_cairo_tee_surface_show_text_glyphs (void                   *abstract_surface,
337
                                     cairo_operator_t        op,
338
                                     const cairo_pattern_t  *source,
339
                                     const char             *utf8,
340
                                     int                     utf8_len,
341
                                     cairo_glyph_t          *glyphs,
342
                                     int                     num_glyphs,
343
                                     const cairo_text_cluster_t *clusters,
344
                                     int                     num_clusters,
345
                                     cairo_text_cluster_flags_t cluster_flags,
346
                                     cairo_scaled_font_t    *scaled_font,
347
                                     cairo_clip_t           *clip)
348
{
349
    cairo_tee_surface_t *surface = abstract_surface;
350
    cairo_surface_wrapper_t *slaves;
351
    int n, num_slaves;
352
    cairo_status_t status;
353
    cairo_glyph_t *glyphs_copy;
354
 
355
    /* XXX: This copying is ugly. */
356
    glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
357
    if (unlikely (glyphs_copy == NULL))
358
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
359
 
360
    memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
361
    status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
362
                                                      source,
363
                                                      utf8, utf8_len,
364
                                                      glyphs_copy, num_glyphs,
365
                                                      clusters, num_clusters,
366
                                                      cluster_flags,
367
                                                      scaled_font,
368
                                                      clip);
369
    if (unlikely (status))
370
        goto CLEANUP;
371
 
372
    num_slaves = _cairo_array_num_elements (&surface->slaves);
373
    slaves = _cairo_array_index (&surface->slaves, 0);
374
    for (n = 0; n < num_slaves; n++) {
375
        memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
376
        status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], 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
        if (unlikely (status))
385
            goto CLEANUP;
386
    }
387
 
388
  CLEANUP:
389
    free (glyphs_copy);
390
    return status;
391
}
392
 
393
static const cairo_surface_backend_t cairo_tee_surface_backend = {
394
    CAIRO_SURFACE_TYPE_TEE,
395
    _cairo_tee_surface_create_similar,
396
    _cairo_tee_surface_finish,
397
    _cairo_tee_surface_acquire_source_image,
398
    _cairo_tee_surface_release_source_image,
399
    NULL, NULL, /* dest_image */
400
    NULL, /* clone_similar */
401
    NULL, /* composite */
402
    NULL, /* fill_rectangles */
403
    NULL, /* composite_trapezoids */
404
    NULL, /* create_span_renderer */
405
    NULL, /* check_span_renderer */
406
    NULL, /* copy_page */
407
    NULL, /* show_page */
408
    _cairo_tee_surface_get_extents,
409
    NULL, /* old_show_glyphs */
410
    _cairo_tee_surface_get_font_options,
411
    NULL, /* flush */
412
    NULL, /* mark_dirty_rectangle */
413
    NULL, /* scaled_font_fini */
414
    NULL, /* scaled_glyph_fini */
415
 
416
    _cairo_tee_surface_paint,
417
    _cairo_tee_surface_mask,
418
    _cairo_tee_surface_stroke,
419
    _cairo_tee_surface_fill,
420
    NULL, /* replaced by show_text_glyphs */
421
 
422
    _cairo_tee_surface_snapshot,
423
    NULL, /* is_similar */
424
    NULL, /* fill_stroke */
425
    NULL, /* create_solid_pattern_surface */
426
    NULL, /* can_repaint_solid_pattern_surface */
427
 
428
    _cairo_tee_surface_has_show_text_glyphs,
429
    _cairo_tee_surface_show_text_glyphs
430
};
431
 
432
cairo_surface_t *
433
cairo_tee_surface_create (cairo_surface_t *master)
434
{
435
    cairo_tee_surface_t *surface;
436
 
437
    if (unlikely (master->status))
438
        return _cairo_surface_create_in_error (master->status);
439
 
440
    surface = malloc (sizeof (cairo_tee_surface_t));
441
    if (unlikely (surface == NULL))
442
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
443
 
444
    _cairo_surface_init (&surface->base,
445
                         &cairo_tee_surface_backend,
446
                         master->content);
447
 
448
    _cairo_surface_wrapper_init (&surface->master, master);
449
    /* we trust that these are already set and remain constant */
450
    surface->base.device_transform = master->device_transform;
451
    surface->base.device_transform_inverse = master->device_transform_inverse;
452
 
453
    _cairo_array_init (&surface->slaves, sizeof (cairo_surface_wrapper_t));
454
 
455
    return &surface->base;
456
}
457
slim_hidden_def (cairo_tee_surface_create);
458
 
459
void
460
cairo_tee_surface_add (cairo_surface_t *abstract_surface,
461
                       cairo_surface_t *target)
462
{
463
    cairo_tee_surface_t *surface;
464
    cairo_surface_wrapper_t slave;
465
    cairo_status_t status;
466
 
467
    if (unlikely (abstract_surface->status))
468
        return;
469
 
470
    if (abstract_surface->backend != &cairo_tee_surface_backend) {
471
        status = _cairo_surface_set_error (abstract_surface,
472
                                           _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
473
        return;
474
    }
475
 
476
    if (unlikely (target->status)) {
477
        status = _cairo_surface_set_error (abstract_surface, target->status);
478
        return;
479
    }
480
 
481
    surface = (cairo_tee_surface_t *) abstract_surface;
482
 
483
    _cairo_surface_wrapper_init (&slave, target);
484
    status = _cairo_array_append (&surface->slaves, &slave);
485
    if (unlikely (status)) {
486
        _cairo_surface_wrapper_fini (&slave);
487
        status = _cairo_surface_set_error (&surface->base, status);
488
    }
489
}
490
slim_hidden_def (cairo_tee_surface_add);
491
 
492
void
493
cairo_tee_surface_remove (cairo_surface_t *abstract_surface,
494
                          cairo_surface_t *target)
495
{
496
    cairo_tee_surface_t *surface;
497
    cairo_surface_wrapper_t *slaves;
498
    int n, num_slaves;
499
    cairo_status_t status;
500
 
501
    if (abstract_surface->backend != &cairo_tee_surface_backend) {
502
        status = _cairo_surface_set_error (abstract_surface,
503
                                           _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
504
        return;
505
    }
506
 
507
    surface = (cairo_tee_surface_t *) abstract_surface;
508
    if (target == surface->master.target) {
509
        status = _cairo_surface_set_error (abstract_surface,
510
                                           _cairo_error (CAIRO_STATUS_INVALID_INDEX));
511
        return;
512
    }
513
 
514
    num_slaves = _cairo_array_num_elements (&surface->slaves);
515
    slaves = _cairo_array_index (&surface->slaves, 0);
516
    for (n = 0; n < num_slaves; n++) {
517
        if (slaves[n].target == target)
518
            break;
519
    }
520
 
521
    if (n == num_slaves) {
522
        status = _cairo_surface_set_error (abstract_surface,
523
                                           _cairo_error (CAIRO_STATUS_INVALID_INDEX));
524
        return;
525
    }
526
 
527
    _cairo_surface_wrapper_fini (&slaves[n]);
528
    for (n++; n < num_slaves; n++)
529
        slaves[n-1] = slaves[n];
530
    surface->slaves.num_elements--; /* XXX: cairo_array_remove()? */
531
}
532
 
533
cairo_surface_t *
534
cairo_tee_surface_index (cairo_surface_t *abstract_surface,
535
                         int index)
536
{
537
    cairo_tee_surface_t *surface;
538
 
539
    if (unlikely (abstract_surface->status))
540
        return _cairo_surface_create_in_error (abstract_surface->status);
541
 
542
    if (abstract_surface->backend != &cairo_tee_surface_backend)
543
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
544
 
545
    surface = (cairo_tee_surface_t *) abstract_surface;
546
    if (index == 0) {
547
        return surface->master.target;
548
    } else {
549
        cairo_surface_wrapper_t *slave;
550
 
551
        index--;
552
 
553
        if (index >= _cairo_array_num_elements (&surface->slaves))
554
            return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX));
555
 
556
        slave = _cairo_array_index (&surface->slaves, index);
557
        return slave->target;
558
    }
559
}
560
 
561
cairo_surface_t *
562
_cairo_tee_surface_find_match (void *abstract_surface,
563
                               const cairo_surface_backend_t *backend,
564
                               cairo_content_t content)
565
{
566
    cairo_tee_surface_t *surface = abstract_surface;
567
    cairo_surface_wrapper_t *slaves;
568
    int num_slaves, n;
569
 
570
    /* exact match first */
571
    if (surface->master.target->backend == backend &&
572
        surface->master.target->content == content)
573
    {
574
        return surface->master.target;
575
    }
576
 
577
    num_slaves = _cairo_array_num_elements (&surface->slaves);
578
    slaves = _cairo_array_index (&surface->slaves, 0);
579
    for (n = 0; n < num_slaves; n++) {
580
        if (slaves[n].target->backend == backend &&
581
            slaves[n].target->content == content)
582
        {
583
            return slaves[n].target;
584
        }
585
    }
586
 
587
    /* matching backend? */
588
    if (surface->master.target->backend == backend)
589
        return surface->master.target;
590
 
591
    num_slaves = _cairo_array_num_elements (&surface->slaves);
592
    slaves = _cairo_array_index (&surface->slaves, 0);
593
    for (n = 0; n < num_slaves; n++) {
594
        if (slaves[n].target->backend == backend)
595
            return slaves[n].target;
596
    }
597
 
598
    return NULL;
599
}