Subversion Repositories Scribus

Rev

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

Rev Author Line No. Line
14952 fschmid 1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2005 Red Hat, Inc
5
 * Copyright © 2007 Adrian Johnson
6
 *
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
18122 mrdocs 17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14952 fschmid 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
 *      Kristian Høgsberg <krh@redhat.com>
36
 *      Carl Worth <cworth@cworth.org>
37
 *      Adrian Johnson <ajohnson@redneon.com>
38
 */
39
 
40
/* A meta surface is a surface that records all drawing operations at
41
 * the highest level of the surface backend interface, (that is, the
42
 * level of paint, mask, stroke, fill, and show_text_glyphs). The meta
43
 * surface can then be "replayed" against any target surface with:
44
 *
45
 * <informalexample><programlisting>
46
 *      cairo_meta_surface_replay (meta, target);
47
 * </programlisting></informalexample>
48
 *
49
 * after which the results in target will be identical to the results
50
 * that would have been obtained if the original operations applied to
51
 * the meta surface had instead been applied to the target surface.
52
 *
53
 * A meta surface is logically unbounded, i.e. it has no implicit constraint
54
 * on the size of the drawing surface. However, in practice this is rarely
55
 * useful as you wish to replay against a particular target surface with
56
 * known bounds. For this case, it is more efficient to specify the target
57
 * extents to the meta surface upon creation.
58
 *
59
 * The recording phase of the meta surface is careful to snapshot all
60
 * necessary objects (paths, patterns, etc.), in order to achieve
61
 * accurate replay. The efficiency of the meta surface could be
62
 * improved by improving the implementation of snapshot for the
63
 * various objects. For example, it would be nice to have a
64
 * copy-on-write implementation for _cairo_surface_snapshot.
65
 */
66
 
67
/* XXX Rename to recording surface */
68
 
69
#include "cairoint.h"
70
#include "cairo-analysis-surface-private.h"
71
#include "cairo-meta-surface-private.h"
72
#include "cairo-clip-private.h"
73
#include "cairo-surface-wrapper-private.h"
74
 
75
typedef enum {
76
    CAIRO_META_REPLAY,
77
    CAIRO_META_CREATE_REGIONS
78
} cairo_meta_replay_type_t;
79
 
80
static const cairo_surface_backend_t cairo_meta_surface_backend;
81
 
82
/* Currently all meta surfaces do have a size which should be passed
83
 * in as the maximum size of any target surface against which the
84
 * meta-surface will ever be replayed.
85
 *
86
 * XXX: The naming of "pixels" in the size here is a misnomer. It's
87
 * actually a size in whatever device-space units are desired (again,
88
 * according to the intended replay target).
89
 */
90
 
91
/**
92
 * cairo_meta_surface_create:
93
 * @content: the content of the meta surface
94
 * @extents_pixels: the extents to record in pixels, can be %NULL to record
95
 *                  unbounded operations.
96
 *
97
 * Creates a meta-surface which can be used to record all drawing operations
98
 * at the highest level (that is, the level of paint, mask, stroke, fill
99
 * and show_text_glyphs). The meta surface can then be "replayed" against
100
 * any target surface with:
101
 *
102
 * <informalexample><programlisting>
103
 *      cairo_meta_surface_replay (meta, target);
104
 * </programlisting></informalexample>
105
 *
106
 * after which the results in target will be identical to the results
107
 * that would have been obtained if the original operations applied to
108
 * the meta surface had instead been applied to the target surface.
109
 *
110
 * The recording phase of the meta surface is careful to snapshot all
111
 * necessary objects (paths, patterns, etc.), in order to achieve
112
 * accurate replay.
113
 *
114
 * Since 1.10
115
 **/
116
cairo_surface_t *
117
cairo_meta_surface_create (cairo_content_t               content,
118
                           const cairo_rectangle_t      *extents)
119
{
120
    cairo_meta_surface_t *meta;
121
    cairo_status_t status;
122
 
123
    meta = malloc (sizeof (cairo_meta_surface_t));
124
    if (unlikely (meta == NULL))
125
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
126
 
127
    _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, content);
128
 
129
    meta->content = content;
130
 
131
    /* unbounded -> 'infinite' extents */
132
    if (extents != NULL) {
133
        meta->extents_pixels = *extents;
134
 
135
        /* XXX check for overflow */
136
        meta->extents.x = floor (extents->x);
137
        meta->extents.y = floor (extents->y);
138
        meta->extents.width = ceil (extents->x + extents->width) - meta->extents.x;
139
        meta->extents.height = ceil (extents->y + extents->height) - meta->extents.y;
140
 
141
        status = _cairo_clip_init_rectangle (&meta->clip, &meta->extents);
142
        if (unlikely (status)) {
143
            free (meta);
144
            return _cairo_surface_create_in_error (status);
145
        }
146
 
147
        meta->unbounded = FALSE;
148
    } else {
149
        meta->unbounded = TRUE;
150
        _cairo_clip_init (&meta->clip);
151
    }
152
 
153
    _cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
154
    meta->commands_owner = NULL;
155
 
156
    meta->replay_start_idx = 0;
157
 
158
    return &meta->base;
159
}
160
slim_hidden_def (cairo_meta_surface_create);
161
 
162
static cairo_surface_t *
163
_cairo_meta_surface_create_similar (void               *abstract_surface,
164
                                    cairo_content_t     content,
165
                                    int                 width,
166
                                    int                 height)
167
{
168
    cairo_rectangle_t extents;
169
    extents.x = extents.y = 0;
170
    extents.width = width;
171
    extents.height = height;
172
    return cairo_meta_surface_create (content, &extents);
173
}
174
 
175
static cairo_status_t
176
_cairo_meta_surface_finish (void *abstract_surface)
177
{
178
    cairo_meta_surface_t *meta = abstract_surface;
179
    cairo_command_t **elements;
180
    int i, num_elements;
181
 
182
    if (meta->commands_owner) {
183
        cairo_surface_destroy (meta->commands_owner);
184
        return CAIRO_STATUS_SUCCESS;
185
    }
186
 
187
    num_elements = meta->commands.num_elements;
188
    elements = _cairo_array_index (&meta->commands, 0);
189
    for (i = 0; i < num_elements; i++) {
190
        cairo_command_t *command = elements[i];
191
 
192
        _cairo_clip_reset (&command->header.clip);
193
 
194
        switch (command->header.type) {
195
        case CAIRO_COMMAND_PAINT:
196
            _cairo_pattern_fini_snapshot (&command->paint.source.base);
197
            free (command);
198
            break;
199
 
200
        case CAIRO_COMMAND_MASK:
201
            _cairo_pattern_fini_snapshot (&command->mask.source.base);
202
            _cairo_pattern_fini_snapshot (&command->mask.mask.base);
203
            free (command);
204
            break;
205
 
206
        case CAIRO_COMMAND_STROKE:
207
            _cairo_pattern_fini_snapshot (&command->stroke.source.base);
208
            _cairo_path_fixed_fini (&command->stroke.path);
209
            _cairo_stroke_style_fini (&command->stroke.style);
210
            free (command);
211
            break;
212
 
213
        case CAIRO_COMMAND_FILL:
214
            _cairo_pattern_fini_snapshot (&command->fill.source.base);
215
            _cairo_path_fixed_fini (&command->fill.path);
216
            free (command);
217
            break;
218
 
219
        case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
220
            _cairo_pattern_fini_snapshot (&command->show_text_glyphs.source.base);
221
            free (command->show_text_glyphs.utf8);
222
            free (command->show_text_glyphs.glyphs);
223
            free (command->show_text_glyphs.clusters);
224
            cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
225
            free (command);
226
            break;
227
 
228
        default:
229
            ASSERT_NOT_REACHED;
230
        }
231
    }
232
 
233
    _cairo_array_fini (&meta->commands);
234
    _cairo_clip_reset (&meta->clip);
235
 
236
    return CAIRO_STATUS_SUCCESS;
237
}
238
 
239
static cairo_status_t
240
_cairo_meta_surface_acquire_source_image (void                   *abstract_surface,
241
                                          cairo_image_surface_t **image_out,
242
                                          void                  **image_extra)
243
{
244
    cairo_status_t status;
245
    cairo_meta_surface_t *surface = abstract_surface;
246
    cairo_surface_t *image;
247
 
248
    image = _cairo_surface_has_snapshot (&surface->base,
249
                                         &_cairo_image_surface_backend,
250
                                         surface->content);
251
    if (image != NULL) {
252
        *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
253
        *image_extra = NULL;
254
        return CAIRO_STATUS_SUCCESS;
255
    }
256
 
257
    image = _cairo_image_surface_create_with_content (surface->content,
258
                                                      surface->extents.width,
259
                                                      surface->extents.height);
260
    if (unlikely (image->status))
261
        return image->status;
262
 
263
    cairo_surface_set_device_offset (image,
264
                                     -surface->extents.x,
265
                                     -surface->extents.y);
266
 
267
    status = cairo_meta_surface_replay (&surface->base, image);
268
    if (unlikely (status)) {
269
        cairo_surface_destroy (image);
270
        return status;
271
    }
272
 
273
    status = _cairo_surface_attach_snapshot (&surface->base, image, NULL);
274
    if (unlikely (status)) {
275
        cairo_surface_destroy (image);
276
        return status;
277
    }
278
 
279
    *image_out = (cairo_image_surface_t *) image;
280
    *image_extra = NULL;
281
    return CAIRO_STATUS_SUCCESS;
282
}
283
 
284
static void
285
_cairo_meta_surface_release_source_image (void                  *abstract_surface,
286
                                          cairo_image_surface_t *image,
287
                                          void                  *image_extra)
288
{
289
    cairo_surface_destroy (&image->base);
290
}
291
 
292
static cairo_status_t
293
_command_init (cairo_meta_surface_t *meta,
294
               cairo_command_header_t *command,
295
               cairo_command_type_t type,
296
               cairo_operator_t op,
297
               cairo_clip_t *clip)
298
{
299
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
300
 
301
    command->type = type;
302
    command->op = op;
303
    command->region = CAIRO_META_REGION_ALL;
304
    _cairo_clip_init_copy (&command->clip, clip);
305
    if (meta->clip.path != NULL)
306
        status = _cairo_clip_apply_clip (&command->clip, &meta->clip);
307
 
308
    return status;
309
}
310
 
311
static cairo_int_status_t
312
_cairo_meta_surface_paint (void                   *abstract_surface,
313
                           cairo_operator_t        op,
314
                           const cairo_pattern_t  *source,
315
                           cairo_clip_t           *clip)
316
{
317
    cairo_status_t status;
318
    cairo_meta_surface_t *meta = abstract_surface;
319
    cairo_command_paint_t *command;
320
 
321
    command = malloc (sizeof (cairo_command_paint_t));
322
    if (unlikely (command == NULL))
323
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
324
 
325
    status = _command_init (meta,
326
                            &command->header, CAIRO_COMMAND_PAINT, op, clip);
327
    if (unlikely (status))
328
        goto CLEANUP_COMMAND;
329
 
330
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
331
    if (unlikely (status))
332
        goto CLEANUP_COMMAND;
333
 
334
    status = _cairo_array_append (&meta->commands, &command);
335
    if (unlikely (status))
336
        goto CLEANUP_SOURCE;
337
 
338
    /* An optimisation that takes care to not replay what was done
339
     * before surface is cleared. We don't erase recorded commands
340
     * since we may have earlier snapshots of this surface. */
341
    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
342
        meta->replay_start_idx = meta->commands.num_elements;
343
 
344
    return CAIRO_STATUS_SUCCESS;
345
 
346
  CLEANUP_SOURCE:
347
    _cairo_pattern_fini_snapshot (&command->source.base);
348
  CLEANUP_COMMAND:
349
    free (command);
350
    return status;
351
}
352
 
353
static cairo_int_status_t
354
_cairo_meta_surface_mask (void                  *abstract_surface,
355
                          cairo_operator_t       op,
356
                          const cairo_pattern_t *source,
357
                          const cairo_pattern_t *mask,
358
                          cairo_clip_t          *clip)
359
{
360
    cairo_status_t status;
361
    cairo_meta_surface_t *meta = abstract_surface;
362
    cairo_command_mask_t *command;
363
 
364
    command = malloc (sizeof (cairo_command_mask_t));
365
    if (unlikely (command == NULL))
366
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
367
 
368
    status = _command_init (meta,
369
                            &command->header, CAIRO_COMMAND_MASK, op, clip);
370
    if (unlikely (status))
371
        goto CLEANUP_COMMAND;
372
 
373
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
374
    if (unlikely (status))
375
        goto CLEANUP_COMMAND;
376
 
377
    status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
378
    if (unlikely (status))
379
        goto CLEANUP_SOURCE;
380
 
381
    status = _cairo_array_append (&meta->commands, &command);
382
    if (unlikely (status))
383
        goto CLEANUP_MASK;
384
 
385
    return CAIRO_STATUS_SUCCESS;
386
 
387
  CLEANUP_MASK:
388
    _cairo_pattern_fini_snapshot (&command->mask.base);
389
  CLEANUP_SOURCE:
390
    _cairo_pattern_fini_snapshot (&command->source.base);
391
  CLEANUP_COMMAND:
392
    free (command);
393
    return status;
394
}
395
 
396
static cairo_int_status_t
397
_cairo_meta_surface_stroke (void                        *abstract_surface,
398
                            cairo_operator_t             op,
399
                            const cairo_pattern_t       *source,
400
                            cairo_path_fixed_t          *path,
401
                            cairo_stroke_style_t        *style,
402
                            cairo_matrix_t              *ctm,
403
                            cairo_matrix_t              *ctm_inverse,
404
                            double                       tolerance,
405
                            cairo_antialias_t            antialias,
406
                            cairo_clip_t                *clip)
407
{
408
    cairo_status_t status;
409
    cairo_meta_surface_t *meta = abstract_surface;
410
    cairo_command_stroke_t *command;
411
 
412
    command = malloc (sizeof (cairo_command_stroke_t));
413
    if (unlikely (command == NULL))
414
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
415
 
416
    status = _command_init (meta,
417
                            &command->header, CAIRO_COMMAND_STROKE, op, clip);
418
    if (unlikely (status))
419
        goto CLEANUP_COMMAND;
420
 
421
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
422
    if (unlikely (status))
423
        goto CLEANUP_COMMAND;
424
 
425
    status = _cairo_path_fixed_init_copy (&command->path, path);
426
    if (unlikely (status))
427
        goto CLEANUP_SOURCE;
428
 
429
    status = _cairo_stroke_style_init_copy (&command->style, style);
430
    if (unlikely (status))
431
        goto CLEANUP_PATH;
432
 
433
    command->ctm = *ctm;
434
    command->ctm_inverse = *ctm_inverse;
435
    command->tolerance = tolerance;
436
    command->antialias = antialias;
437
 
438
    status = _cairo_array_append (&meta->commands, &command);
439
    if (unlikely (status))
440
        goto CLEANUP_STYLE;
441
 
442
    return CAIRO_STATUS_SUCCESS;
443
 
444
  CLEANUP_STYLE:
445
    _cairo_stroke_style_fini (&command->style);
446
  CLEANUP_PATH:
447
    _cairo_path_fixed_fini (&command->path);
448
  CLEANUP_SOURCE:
449
    _cairo_pattern_fini_snapshot (&command->source.base);
450
  CLEANUP_COMMAND:
451
    free (command);
452
    return status;
453
}
454
 
455
static cairo_int_status_t
456
_cairo_meta_surface_fill (void                  *abstract_surface,
457
                          cairo_operator_t       op,
458
                          const cairo_pattern_t *source,
459
                          cairo_path_fixed_t    *path,
460
                          cairo_fill_rule_t      fill_rule,
461
                          double                 tolerance,
462
                          cairo_antialias_t      antialias,
463
                          cairo_clip_t          *clip)
464
{
465
    cairo_status_t status;
466
    cairo_meta_surface_t *meta = abstract_surface;
467
    cairo_command_fill_t *command;
468
 
469
    command = malloc (sizeof (cairo_command_fill_t));
470
    if (unlikely (command == NULL))
471
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
472
 
473
    status =_command_init (meta,
474
                           &command->header, CAIRO_COMMAND_FILL, op, clip);
475
    if (unlikely (status))
476
        goto CLEANUP_COMMAND;
477
 
478
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
479
    if (unlikely (status))
480
        goto CLEANUP_COMMAND;
481
 
482
    status = _cairo_path_fixed_init_copy (&command->path, path);
483
    if (unlikely (status))
484
        goto CLEANUP_SOURCE;
485
 
486
    command->fill_rule = fill_rule;
487
    command->tolerance = tolerance;
488
    command->antialias = antialias;
489
 
490
    status = _cairo_array_append (&meta->commands, &command);
491
    if (unlikely (status))
492
        goto CLEANUP_PATH;
493
 
494
    return CAIRO_STATUS_SUCCESS;
495
 
496
  CLEANUP_PATH:
497
    _cairo_path_fixed_fini (&command->path);
498
  CLEANUP_SOURCE:
499
    _cairo_pattern_fini_snapshot (&command->source.base);
500
  CLEANUP_COMMAND:
501
    free (command);
502
    return status;
503
}
504
 
505
static cairo_bool_t
506
_cairo_meta_surface_has_show_text_glyphs (void *abstract_surface)
507
{
508
    return TRUE;
509
}
510
 
511
static cairo_int_status_t
512
_cairo_meta_surface_show_text_glyphs (void                          *abstract_surface,
513
                                      cairo_operator_t               op,
514
                                      const cairo_pattern_t         *source,
515
                                      const char                    *utf8,
516
                                      int                            utf8_len,
517
                                      cairo_glyph_t                 *glyphs,
518
                                      int                            num_glyphs,
519
                                      const cairo_text_cluster_t    *clusters,
520
                                      int                            num_clusters,
521
                                      cairo_text_cluster_flags_t     cluster_flags,
522
                                      cairo_scaled_font_t           *scaled_font,
523
                                      cairo_clip_t                  *clip)
524
{
525
    cairo_status_t status;
526
    cairo_meta_surface_t *meta = abstract_surface;
527
    cairo_command_show_text_glyphs_t *command;
528
 
529
    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
530
    if (unlikely (command == NULL))
531
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
532
 
533
    status = _command_init (meta,
534
                            &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
535
                            op, clip);
536
    if (unlikely (status))
537
        goto CLEANUP_COMMAND;
538
 
539
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
540
    if (unlikely (status))
541
        goto CLEANUP_COMMAND;
542
 
543
    command->utf8 = NULL;
544
    command->utf8_len = utf8_len;
545
    command->glyphs = NULL;
546
    command->num_glyphs = num_glyphs;
547
    command->clusters = NULL;
548
    command->num_clusters = num_clusters;
549
 
550
    if (utf8_len) {
551
        command->utf8 = malloc (utf8_len);
552
        if (unlikely (command->utf8 == NULL)) {
553
            status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
554
            goto CLEANUP_ARRAYS;
555
        }
556
        memcpy (command->utf8, utf8, utf8_len);
557
    }
558
    if (num_glyphs) {
559
        command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
560
        if (unlikely (command->glyphs == NULL)) {
561
            status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
562
            goto CLEANUP_ARRAYS;
563
        }
564
        memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
565
    }
566
    if (num_clusters) {
567
        command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
568
        if (unlikely (command->clusters == NULL)) {
569
            status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
570
            goto CLEANUP_ARRAYS;
571
        }
572
        memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
573
    }
574
 
575
    command->cluster_flags = cluster_flags;
576
 
577
    command->scaled_font = cairo_scaled_font_reference (scaled_font);
578
 
579
    status = _cairo_array_append (&meta->commands, &command);
580
    if (unlikely (status))
581
        goto CLEANUP_SCALED_FONT;
582
 
583
    return CAIRO_STATUS_SUCCESS;
584
 
585
  CLEANUP_SCALED_FONT:
586
    cairo_scaled_font_destroy (command->scaled_font);
587
  CLEANUP_ARRAYS:
588
    free (command->utf8);
589
    free (command->glyphs);
590
    free (command->clusters);
591
 
592
    _cairo_pattern_fini_snapshot (&command->source.base);
593
  CLEANUP_COMMAND:
594
    free (command);
595
    return status;
596
}
597
 
598
/**
599
 * _cairo_meta_surface_snapshot
600
 * @surface: a #cairo_surface_t which must be a meta surface
601
 *
602
 * Make an immutable copy of @surface. It is an error to call a
603
 * surface-modifying function on the result of this function.
604
 *
605
 * The caller owns the return value and should call
606
 * cairo_surface_destroy() when finished with it. This function will not
607
 * return %NULL, but will return a nil surface instead.
608
 *
609
 * Return value: The snapshot surface.
610
 **/
611
static cairo_surface_t *
612
_cairo_meta_surface_snapshot (void *abstract_other)
613
{
614
    cairo_meta_surface_t *other = abstract_other;
615
    cairo_meta_surface_t *meta;
616
 
617
    meta = malloc (sizeof (cairo_meta_surface_t));
618
    if (unlikely (meta == NULL))
619
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
620
 
621
    _cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
622
                         other->base.content);
623
 
624
    meta->extents_pixels = other->extents_pixels;
625
    meta->extents = other->extents;
626
    meta->unbounded = other->unbounded;
627
    meta->replay_start_idx = other->replay_start_idx;
628
    meta->content = other->content;
629
 
630
    _cairo_array_init_snapshot (&meta->commands, &other->commands);
631
    meta->commands_owner = cairo_surface_reference (&other->base);
632
 
633
    _cairo_clip_init_copy (&meta->clip, &other->clip);
634
 
635
    return &meta->base;
636
}
637
 
638
static cairo_bool_t
639
_cairo_meta_surface_get_extents (void                    *abstract_surface,
640
                                 cairo_rectangle_int_t   *rectangle)
641
{
642
    cairo_meta_surface_t *surface = abstract_surface;
643
 
644
    if (surface->unbounded)
645
        return FALSE;
646
 
647
    *rectangle = surface->extents;
648
    return TRUE;
649
}
650
 
651
/**
652
 * _cairo_surface_is_meta:
653
 * @surface: a #cairo_surface_t
654
 *
655
 * Checks if a surface is a #cairo_meta_surface_t
656
 *
657
 * Return value: %TRUE if the surface is a meta surface
658
 **/
659
cairo_bool_t
660
_cairo_surface_is_meta (const cairo_surface_t *surface)
661
{
662
    return surface->backend == &cairo_meta_surface_backend;
663
}
664
 
665
static const cairo_surface_backend_t cairo_meta_surface_backend = {
666
    CAIRO_SURFACE_TYPE_META,
667
    _cairo_meta_surface_create_similar,
668
    _cairo_meta_surface_finish,
669
    _cairo_meta_surface_acquire_source_image,
670
    _cairo_meta_surface_release_source_image,
671
    NULL, /* acquire_dest_image */
672
    NULL, /* release_dest_image */
673
    NULL, /* clone_similar */
674
    NULL, /* composite */
675
    NULL, /* fill_rectangles */
676
    NULL, /* composite_trapezoids */
677
    NULL, /* create_span_renderer */
678
    NULL, /* check_span_renderer */
679
    NULL, /* copy_page */
680
    NULL, /* show_page */
681
    _cairo_meta_surface_get_extents,
682
    NULL, /* old_show_glyphs */
683
    NULL, /* get_font_options */
684
    NULL, /* flush */
685
    NULL, /* mark_dirty_rectangle */
686
    NULL, /* scaled_font_fini */
687
    NULL, /* scaled_glyph_fini */
688
 
689
    /* Here are the 5 basic drawing operations, (which are in some
690
     * sense the only things that cairo_meta_surface should need to
691
     * implement).  However, we implement the more generic show_text_glyphs
692
     * instead of show_glyphs.  One or the other is eough. */
693
 
694
    _cairo_meta_surface_paint,
695
    _cairo_meta_surface_mask,
696
    _cairo_meta_surface_stroke,
697
    _cairo_meta_surface_fill,
698
    NULL,
699
 
700
    _cairo_meta_surface_snapshot,
701
 
702
    NULL, /* is_similar */
703
    NULL, /* fill_stroke */
704
    NULL, /* create_solid_pattern_surface */
705
    NULL, /* can_repaint_solid_pattern_surface */
706
 
707
    _cairo_meta_surface_has_show_text_glyphs,
708
    _cairo_meta_surface_show_text_glyphs
709
};
710
 
711
cairo_int_status_t
712
_cairo_meta_surface_get_path (cairo_surface_t    *surface,
713
                              cairo_path_fixed_t *path)
714
{
715
    cairo_meta_surface_t *meta;
716
    cairo_command_t **elements;
717
    int i, num_elements;
718
    cairo_int_status_t status;
719
 
720
    if (surface->status)
721
        return surface->status;
722
 
723
    meta = (cairo_meta_surface_t *) surface;
724
    status = CAIRO_STATUS_SUCCESS;
725
 
726
    num_elements = meta->commands.num_elements;
727
    elements = _cairo_array_index (&meta->commands, 0);
728
    for (i = meta->replay_start_idx; i < num_elements; i++) {
729
        cairo_command_t *command = elements[i];
730
 
731
        switch (command->header.type) {
732
        case CAIRO_COMMAND_PAINT:
733
        case CAIRO_COMMAND_MASK:
734
            status = CAIRO_INT_STATUS_UNSUPPORTED;
735
            break;
736
 
737
        case CAIRO_COMMAND_STROKE:
738
        {
739
            cairo_traps_t traps;
740
 
741
            _cairo_traps_init (&traps);
742
 
743
            /* XXX call cairo_stroke_to_path() when that is implemented */
744
            status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
745
                                                        &command->stroke.style,
746
                                                        &command->stroke.ctm,
747
                                                        &command->stroke.ctm_inverse,
748
                                                        command->stroke.tolerance,
749
                                                        &traps);
750
 
751
            if (status == CAIRO_STATUS_SUCCESS)
752
                status = _cairo_traps_path (&traps, path);
753
 
754
            _cairo_traps_fini (&traps);
755
            break;
756
        }
757
        case CAIRO_COMMAND_FILL:
758
        {
759
            status = _cairo_path_fixed_append (path,
760
                                               &command->fill.path, CAIRO_DIRECTION_FORWARD,
761
                                               0, 0);
762
            break;
763
        }
764
        case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
765
        {
766
            status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
767
                                                    command->show_text_glyphs.glyphs,
768
                                                    command->show_text_glyphs.num_glyphs,
769
                                                    path);
770
            break;
771
        }
772
 
773
        default:
774
            ASSERT_NOT_REACHED;
775
        }
776
 
777
        if (unlikely (status))
778
            break;
779
    }
780
 
781
    return _cairo_surface_set_error (surface, status);
782
}
783
 
784
#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
785
static cairo_status_t
786
_cairo_meta_surface_replay_internal (cairo_surface_t         *surface,
787
                                     cairo_surface_t         *target,
788
                                     cairo_meta_replay_type_t type,
789
                                     cairo_meta_region_type_t region)
790
{
791
    cairo_meta_surface_t *meta;
792
    cairo_command_t **elements;
793
    int i, num_elements;
794
    cairo_int_status_t status;
795
    cairo_surface_wrapper_t wrapper;
796
 
797
    if (unlikely (surface->status))
798
        return surface->status;
799
 
800
    if (unlikely (target->status))
801
        return _cairo_surface_set_error (surface, target->status);
802
 
803
    _cairo_surface_wrapper_init (&wrapper, target);
804
 
805
    meta = (cairo_meta_surface_t *) surface;
806
    status = CAIRO_STATUS_SUCCESS;
807
 
808
    num_elements = meta->commands.num_elements;
809
    elements = _cairo_array_index (&meta->commands, 0);
810
    for (i = meta->replay_start_idx; i < num_elements; i++) {
811
        cairo_command_t *command = elements[i];
812
 
813
        if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) {
814
            if (command->header.region != region)
815
                continue;
816
        }
817
 
818
        switch (command->header.type) {
819
        case CAIRO_COMMAND_PAINT:
820
            status = _cairo_surface_wrapper_paint (&wrapper,
821
                                                   command->header.op,
822
                                                   &command->paint.source.base,
823
                                                   _clip (command));
824
            break;
825
 
826
        case CAIRO_COMMAND_MASK:
827
            status = _cairo_surface_wrapper_mask (&wrapper,
828
                                                  command->header.op,
829
                                                  &command->mask.source.base,
830
                                                  &command->mask.mask.base,
831
                                                  _clip (command));
832
            break;
833
 
834
        case CAIRO_COMMAND_STROKE:
835
        {
836
            status = _cairo_surface_wrapper_stroke (&wrapper,
837
                                                    command->header.op,
838
                                                    &command->stroke.source.base,
839
                                                    &command->stroke.path,
840
                                                    &command->stroke.style,
841
                                                    &command->stroke.ctm,
842
                                                    &command->stroke.ctm_inverse,
843
                                                    command->stroke.tolerance,
844
                                                    command->stroke.antialias,
845
                                                    _clip (command));
846
            break;
847
        }
848
        case CAIRO_COMMAND_FILL:
849
        {
850
            cairo_command_t *stroke_command;
851
 
852
            stroke_command = NULL;
853
            if (type != CAIRO_META_CREATE_REGIONS && i < num_elements - 1)
854
                stroke_command = elements[i + 1];
855
 
856
            if (stroke_command != NULL &&
857
                type == CAIRO_META_REPLAY &&
858
                region != CAIRO_META_REGION_ALL)
859
            {
860
                if (stroke_command->header.region != region)
861
                    stroke_command = NULL;
862
            }
863
 
864
            if (stroke_command != NULL &&
865
                stroke_command->header.type == CAIRO_COMMAND_STROKE &&
866
                _cairo_path_fixed_is_equal (&command->fill.path,
867
                                            &stroke_command->stroke.path))
868
            {
869
                status = _cairo_surface_wrapper_fill_stroke (&wrapper,
870
                                                             command->header.op,
871
                                                             &command->fill.source.base,
872
                                                             command->fill.fill_rule,
873
                                                             command->fill.tolerance,
874
                                                             command->fill.antialias,
875
                                                             &command->fill.path,
876
                                                             stroke_command->header.op,
877
                                                             &stroke_command->stroke.source.base,
878
                                                             &stroke_command->stroke.style,
879
                                                             &stroke_command->stroke.ctm,
880
                                                             &stroke_command->stroke.ctm_inverse,
881
                                                             stroke_command->stroke.tolerance,
882
                                                             stroke_command->stroke.antialias,
883
                                                             _clip (command));
884
                i++;
885
            }
886
            else
887
            {
888
                status = _cairo_surface_wrapper_fill (&wrapper,
889
                                                      command->header.op,
890
                                                      &command->fill.source.base,
891
                                                      &command->fill.path,
892
                                                      command->fill.fill_rule,
893
                                                      command->fill.tolerance,
894
                                                      command->fill.antialias,
895
                                                      _clip (command));
896
            }
897
            break;
898
        }
899
        case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
900
        {
901
            cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
902
            cairo_glyph_t *glyphs_copy;
903
            int num_glyphs = command->show_text_glyphs.num_glyphs;
904
 
905
            /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
906
             * to modify the glyph array that's passed in.  We must always
907
             * copy the array before handing it to the backend.
908
             */
909
            glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
910
            if (unlikely (glyphs_copy == NULL)) {
911
                status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
912
                break;
913
            }
914
 
915
            memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
916
 
917
            status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
918
                                                              command->header.op,
919
                                                              &command->show_text_glyphs.source.base,
920
                                                              command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
921
                                                              glyphs_copy, num_glyphs,
922
                                                              command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
923
                                                              command->show_text_glyphs.cluster_flags,
924
                                                              command->show_text_glyphs.scaled_font,
925
                                                              _clip (command));
926
            free (glyphs_copy);
927
            break;
928
        }
929
        default:
930
            ASSERT_NOT_REACHED;
931
        }
932
 
933
        if (type == CAIRO_META_CREATE_REGIONS) {
934
            if (status == CAIRO_STATUS_SUCCESS) {
935
                command->header.region = CAIRO_META_REGION_NATIVE;
936
            } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
937
                command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
938
                status = CAIRO_STATUS_SUCCESS;
939
            } else {
940
                assert (_cairo_status_is_error (status));
941
            }
942
        }
943
 
944
        if (unlikely (status))
945
            break;
946
    }
947
 
948
    /* free up any caches */
949
    for (i = meta->replay_start_idx; i < num_elements; i++) {
950
        cairo_command_t *command = elements[i];
951
 
952
        _cairo_clip_drop_cache (&command->header.clip);
953
    }
954
 
955
    _cairo_surface_wrapper_fini (&wrapper);
956
 
957
    return _cairo_surface_set_error (surface, status);
958
}
959
 
960
/**
961
 * cairo_meta_surface_replay:
962
 * @surface: the #cairo_meta_surface_t
963
 * @target: a target #cairo_surface_t onto which to replay the operations
964
 * @width_pixels: width of the surface, in pixels
965
 * @height_pixels: height of the surface, in pixels
966
 *
967
 * A meta surface can be "replayed" against any target surface,
968
 * after which the results in target will be identical to the results
969
 * that would have been obtained if the original operations applied to
970
 * the meta surface had instead been applied to the target surface.
971
 *
972
 * Since 1.10
973
 **/
974
cairo_status_t
975
cairo_meta_surface_replay (cairo_surface_t *surface,
976
                           cairo_surface_t *target)
977
{
978
    return _cairo_meta_surface_replay_internal (surface,
979
                                                target,
980
                                                CAIRO_META_REPLAY,
981
                                                CAIRO_META_REGION_ALL);
982
}
983
slim_hidden_def (cairo_meta_surface_replay);
984
 
985
/* Replay meta to surface. When the return status of each operation is
986
 * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
987
 * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
988
 * will be stored in the meta surface. Any other status will abort the
989
 * replay and return the status.
990
 */
991
cairo_status_t
992
_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
993
                                               cairo_surface_t *target)
994
{
995
    return _cairo_meta_surface_replay_internal (surface,
996
                                                target,
997
                                                CAIRO_META_CREATE_REGIONS,
998
                                                CAIRO_META_REGION_ALL);
999
}
1000
 
1001
cairo_status_t
1002
_cairo_meta_surface_replay_region (cairo_surface_t          *surface,
1003
                                   cairo_surface_t          *target,
1004
                                   cairo_meta_region_type_t  region)
1005
{
1006
    return _cairo_meta_surface_replay_internal (surface,
1007
                                                target,
1008
                                                CAIRO_META_REPLAY,
1009
                                                region);
1010
}
1011
 
1012
static cairo_status_t
1013
_meta_surface_get_ink_bbox (cairo_meta_surface_t *surface,
1014
                            cairo_box_t *bbox,
1015
                            const cairo_matrix_t *transform)
1016
{
1017
    cairo_surface_t *null_surface;
1018
    cairo_surface_t *analysis_surface;
1019
    cairo_status_t status;
1020
 
1021
    null_surface = _cairo_null_surface_create (surface->content);
1022
    analysis_surface = _cairo_analysis_surface_create (null_surface);
1023
    cairo_surface_destroy (null_surface);
1024
 
1025
    status = analysis_surface->status;
1026
    if (unlikely (status))
1027
        return status;
1028
 
1029
    if (transform != NULL)
1030
        _cairo_analysis_surface_set_ctm (analysis_surface, transform);
1031
 
1032
    status = cairo_meta_surface_replay (&surface->base, analysis_surface);
1033
    _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
1034
    cairo_surface_destroy (analysis_surface);
1035
 
1036
    return status;
1037
}
1038
 
1039
/**
1040
 * cairo_meta_surface_ink_extents:
1041
 * @surface: a #cairo_meta_surface_t
1042
 * @x0: the x-coordinate of the top-left of the ink bounding box
1043
 * @y0: the y-coordinate of the top-left of the ink bounding box
1044
 * @width: the width of the ink bounding box
1045
 * @height: the height of the ink bounding box
1046
 *
1047
 * Measures the extents of the operations stored within the meta-surface.
1048
 * This is useful to compute the required size of an image surface (or
1049
 * equivalent) into which to replay the full sequence of drawing operations.
1050
 *
1051
 * Since: 1.10
1052
 **/
1053
void
1054
cairo_meta_surface_ink_extents (cairo_surface_t *surface,
1055
                                double *x0,
1056
                                double *y0,
1057
                                double *width,
1058
                                double *height)
1059
{
1060
    cairo_status_t status;
1061
    cairo_box_t bbox;
1062
 
1063
    memset (&bbox, 0, sizeof (bbox));
1064
 
1065
    if (! _cairo_surface_is_meta (surface)) {
1066
        _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1067
        goto DONE;
1068
    }
1069
 
1070
    status = _meta_surface_get_ink_bbox ((cairo_meta_surface_t *) surface,
1071
                                         &bbox,
1072
                                         NULL);
1073
    if (unlikely (status))
1074
        status = _cairo_surface_set_error (surface, status);
1075
 
1076
DONE:
1077
    if (x0)
1078
        *x0 = _cairo_fixed_to_double (bbox.p1.x);
1079
    if (y0)
1080
        *y0 = _cairo_fixed_to_double (bbox.p1.y);
1081
    if (width)
1082
        *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
1083
    if (height)
1084
        *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
1085
}
1086
 
1087
cairo_status_t
1088
_cairo_meta_surface_get_bbox (cairo_meta_surface_t *surface,
1089
                              cairo_box_t *bbox,
1090
                              const cairo_matrix_t *transform)
1091
{
1092
    if (! surface->unbounded) {
1093
        _cairo_box_from_rectangle (bbox, &surface->extents);
1094
        if (transform != NULL)
1095
            _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
1096
 
1097
        return CAIRO_STATUS_SUCCESS;
1098
    }
1099
 
1100
    return _meta_surface_get_ink_bbox (surface, bbox, transform);
1101
}