~ubuntu-branches/ubuntu/karmic/moon/karmic

« back to all changes in this revision

Viewing changes to cairo/src/cairo-analysis-surface.c

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2006 Keith Packard
 
3
 * Copyright Ā© 2007 Adrian Johnson
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it either under the terms of the GNU Lesser General Public
 
7
 * License version 2.1 as published by the Free Software Foundation
 
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 
10
 * notice, a recipient may use your version of this file under either
 
11
 * the MPL or the LGPL.
 
12
 *
 
13
 * You should have received a copy of the LGPL along with this library
 
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 
15
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 * You should have received a copy of the MPL along with this library
 
17
 * in the file COPYING-MPL-1.1
 
18
 *
 
19
 * The contents of this file are subject to the Mozilla Public License
 
20
 * Version 1.1 (the "License"); you may not use this file except in
 
21
 * compliance with the License. You may obtain a copy of the License at
 
22
 * http://www.mozilla.org/MPL/
 
23
 *
 
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 
26
 * the specific language governing rights and limitations.
 
27
 *
 
28
 * The Original Code is the cairo graphics library.
 
29
 *
 
30
 * The Initial Developer of the Original Code is Keith Packard
 
31
 *
 
32
 * Contributor(s):
 
33
 *      Keith Packard <keithp@keithp.com>
 
34
 *      Adrian Johnson <ajohnson@redneon.com>
 
35
 */
 
36
 
 
37
#include "cairoint.h"
 
38
 
 
39
#include "cairo-analysis-surface-private.h"
 
40
#include "cairo-paginated-private.h"
 
41
#include "cairo-region-private.h"
 
42
#include "cairo-meta-surface-private.h"
 
43
 
 
44
typedef struct {
 
45
    cairo_surface_t base;
 
46
    int width;
 
47
    int height;
 
48
 
 
49
    cairo_surface_t     *target;
 
50
 
 
51
    cairo_bool_t first_op;
 
52
    cairo_bool_t has_supported;
 
53
    cairo_bool_t has_unsupported;
 
54
 
 
55
    cairo_region_t supported_region;
 
56
    cairo_region_t fallback_region;
 
57
    cairo_rectangle_int_t current_clip;
 
58
    cairo_box_t page_bbox;
 
59
 
 
60
    cairo_bool_t has_ctm;
 
61
    cairo_matrix_t ctm;
 
62
 
 
63
} cairo_analysis_surface_t;
 
64
 
 
65
static cairo_int_status_t
 
66
_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
 
67
                               cairo_pattern_t          *pattern)
 
68
{
 
69
    cairo_surface_t *analysis = &surface->base;
 
70
    cairo_surface_pattern_t *surface_pattern;
 
71
    cairo_status_t status;
 
72
    cairo_bool_t old_has_ctm;
 
73
    cairo_matrix_t old_ctm, p2d;
 
74
    cairo_rectangle_int_t old_clip;
 
75
    cairo_rectangle_int_t meta_extents;
 
76
    int old_width;
 
77
    int old_height;
 
78
 
 
79
    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
 
80
    surface_pattern = (cairo_surface_pattern_t *) pattern;
 
81
    assert (_cairo_surface_is_meta (surface_pattern->surface));
 
82
 
 
83
    old_width = surface->width;
 
84
    old_height = surface->height;
 
85
    old_clip = surface->current_clip;
 
86
    status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
 
87
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
88
        return status;
 
89
 
 
90
    surface->width = meta_extents.width;
 
91
    surface->height = meta_extents.height;
 
92
    surface->current_clip.x = 0;
 
93
    surface->current_clip.y = 0;
 
94
    surface->current_clip.width = surface->width;
 
95
    surface->current_clip.height = surface->height;
 
96
    old_ctm = surface->ctm;
 
97
    old_has_ctm = surface->has_ctm;
 
98
    p2d = pattern->matrix;
 
99
    status = cairo_matrix_invert (&p2d);
 
100
    /* _cairo_pattern_set_matrix guarantees invertibility */
 
101
    assert (status == CAIRO_STATUS_SUCCESS);
 
102
 
 
103
    cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
 
104
    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
 
105
 
 
106
    status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
 
107
                                                            analysis);
 
108
    if (status == CAIRO_STATUS_SUCCESS)
 
109
        status = analysis->status;
 
110
 
 
111
    surface->ctm = old_ctm;
 
112
    surface->has_ctm = old_has_ctm;
 
113
    surface->current_clip = old_clip;
 
114
    surface->width = old_width;
 
115
    surface->height = old_height;
 
116
 
 
117
    return status;
 
118
}
 
119
 
 
120
static cairo_int_status_t
 
121
_add_operation  (cairo_analysis_surface_t *surface,
 
122
                 cairo_rectangle_int_t    *rect,
 
123
                 cairo_int_status_t        backend_status)
 
124
{
 
125
    cairo_int_status_t status;
 
126
    cairo_box_t bbox;
 
127
 
 
128
    if (rect->width == 0 || rect->height == 0) {
 
129
        /* Even though the operation is not visible we must be careful
 
130
         * to not allow unsupported operations to be replayed to the
 
131
         * backend during CAIRO_PAGINATED_MODE_RENDER */
 
132
        if (backend_status == CAIRO_STATUS_SUCCESS ||
 
133
            backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
 
134
        {
 
135
            return CAIRO_STATUS_SUCCESS;
 
136
        }
 
137
        else
 
138
        {
 
139
            return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
140
        }
 
141
    }
 
142
 
 
143
    _cairo_box_from_rectangle (&bbox, rect);
 
144
 
 
145
    if (surface->has_ctm) {
 
146
 
 
147
        _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
 
148
 
 
149
        if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
 
150
            /* Even though the operation is not visible we must be
 
151
             * careful to not allow unsupported operations to be
 
152
             * replayed to the backend during
 
153
             * CAIRO_PAGINATED_MODE_RENDER */
 
154
            if (backend_status == CAIRO_STATUS_SUCCESS ||
 
155
                backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
 
156
            {
 
157
                return CAIRO_STATUS_SUCCESS;
 
158
            }
 
159
            else
 
160
            {
 
161
                return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
162
            }
 
163
        }
 
164
 
 
165
        _cairo_box_round_to_rectangle (&bbox, rect);
 
166
    }
 
167
 
 
168
    if (surface->first_op) {
 
169
        surface->first_op = FALSE;
 
170
        surface->page_bbox = bbox;
 
171
    } else {
 
172
        if (bbox.p1.x < surface->page_bbox.p1.x)
 
173
            surface->page_bbox.p1.x = bbox.p1.x;
 
174
        if (bbox.p1.y < surface->page_bbox.p1.y)
 
175
            surface->page_bbox.p1.y = bbox.p1.y;
 
176
        if (bbox.p2.x > surface->page_bbox.p2.x)
 
177
            surface->page_bbox.p2.x = bbox.p2.x;
 
178
        if (bbox.p2.y > surface->page_bbox.p2.y)
 
179
            surface->page_bbox.p2.y = bbox.p2.y;
 
180
    }
 
181
 
 
182
    /* If the operation is completely enclosed within the fallback
 
183
     * region there is no benefit in emitting a native operation as
 
184
     * the fallback image will be painted on top.
 
185
     */
 
186
    if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
 
187
        return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
188
 
 
189
    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
 
190
        /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
 
191
         * that the backend only supports this operation if the
 
192
         * transparency removed. If the extents of this operation does
 
193
         * not intersect any other native operation, the operation is
 
194
         * natively supported and the backend will blend the
 
195
         * transparency into the white background.
 
196
         */
 
197
        if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
 
198
            backend_status = CAIRO_STATUS_SUCCESS;
 
199
    }
 
200
 
 
201
    if (backend_status == CAIRO_STATUS_SUCCESS) {
 
202
        /* Add the operation to the supported region. Operations in
 
203
         * this region will be emitted as native operations.
 
204
         */
 
205
        surface->has_supported = TRUE;
 
206
        status = _cairo_region_union_rect (&surface->supported_region,
 
207
                                           &surface->supported_region,
 
208
                                           rect);
 
209
        return status;
 
210
    }
 
211
 
 
212
    /* Add the operation to the unsupported region. This region will
 
213
     * be painted as an image after all native operations have been
 
214
     * emitted.
 
215
     */
 
216
    surface->has_unsupported = TRUE;
 
217
    status = _cairo_region_union_rect (&surface->fallback_region,
 
218
                                       &surface->fallback_region,
 
219
                                       rect);
 
220
 
 
221
    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
 
222
     * unsupported operations to the meta surface as using
 
223
     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
 
224
     * invoke the cairo-surface-fallback path then return
 
225
     * CAIRO_STATUS_SUCCESS.
 
226
     */
 
227
    if (status == CAIRO_STATUS_SUCCESS)
 
228
        return CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
229
    else
 
230
        return status;
 
231
}
 
232
 
 
233
static cairo_status_t
 
234
_cairo_analysis_surface_finish (void *abstract_surface)
 
235
{
 
236
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
237
 
 
238
    _cairo_region_fini (&surface->supported_region);
 
239
    _cairo_region_fini (&surface->fallback_region);
 
240
 
 
241
    cairo_surface_destroy (surface->target);
 
242
 
 
243
    return CAIRO_STATUS_SUCCESS;
 
244
}
 
245
 
 
246
static cairo_int_status_t
 
247
_cairo_analysis_surface_intersect_clip_path (void               *abstract_surface,
 
248
                                             cairo_path_fixed_t *path,
 
249
                                             cairo_fill_rule_t   fill_rule,
 
250
                                             double              tolerance,
 
251
                                             cairo_antialias_t   antialias)
 
252
{
 
253
    cairo_analysis_surface_t *surface = abstract_surface;
 
254
    double                    x1, y1, x2, y2;
 
255
    cairo_rectangle_int_t   extent;
 
256
 
 
257
    if (path == NULL) {
 
258
        surface->current_clip.x = 0;
 
259
        surface->current_clip.y = 0;
 
260
        surface->current_clip.width  = surface->width;
 
261
        surface->current_clip.height = surface->height;
 
262
    } else {
 
263
        cairo_status_t status;
 
264
 
 
265
        status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
 
266
        if (status)
 
267
            return status;
 
268
 
 
269
        extent.x = floor (x1);
 
270
        extent.y = floor (y1);
 
271
        extent.width  = ceil (x2) - extent.x;
 
272
        extent.height = ceil (y2) - extent.y;
 
273
 
 
274
        _cairo_rectangle_intersect (&surface->current_clip, &extent);
 
275
    }
 
276
 
 
277
    return CAIRO_STATUS_SUCCESS;
 
278
}
 
279
 
 
280
static cairo_int_status_t
 
281
_cairo_analysis_surface_get_extents (void                       *abstract_surface,
 
282
                                     cairo_rectangle_int_t      *rectangle)
 
283
{
 
284
    cairo_analysis_surface_t *surface = abstract_surface;
 
285
 
 
286
    return _cairo_surface_get_extents (surface->target, rectangle);
 
287
}
 
288
 
 
289
static cairo_int_status_t
 
290
_cairo_analysis_surface_paint (void                     *abstract_surface,
 
291
                              cairo_operator_t          op,
 
292
                              cairo_pattern_t           *source)
 
293
{
 
294
    cairo_analysis_surface_t *surface = abstract_surface;
 
295
    cairo_status_t           status, backend_status;
 
296
    cairo_rectangle_int_t  extents;
 
297
 
 
298
    if (!surface->target->backend->paint)
 
299
        backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
300
    else
 
301
        backend_status = (*surface->target->backend->paint) (surface->target, op,
 
302
                                                             source);
 
303
 
 
304
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
 
305
        backend_status = _analyze_meta_surface_pattern (surface, source);
 
306
 
 
307
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
308
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
309
        return status;
 
310
 
 
311
    if (_cairo_operator_bounded_by_source (op)) {
 
312
        cairo_rectangle_int_t source_extents;
 
313
        status = _cairo_pattern_get_extents (source, &source_extents);
 
314
        if (status)
 
315
            return status;
 
316
 
 
317
        _cairo_rectangle_intersect (&extents, &source_extents);
 
318
    }
 
319
 
 
320
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
321
 
 
322
    status = _add_operation (surface, &extents, backend_status);
 
323
 
 
324
    return status;
 
325
}
 
326
 
 
327
static cairo_int_status_t
 
328
_cairo_analysis_surface_mask (void              *abstract_surface,
 
329
                              cairo_operator_t   op,
 
330
                              cairo_pattern_t   *source,
 
331
                              cairo_pattern_t   *mask)
 
332
{
 
333
    cairo_analysis_surface_t *surface = abstract_surface;
 
334
    cairo_int_status_t        status, backend_status;
 
335
    cairo_rectangle_int_t   extents;
 
336
 
 
337
    if (!surface->target->backend->mask)
 
338
        backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
339
    else
 
340
        backend_status = (*surface->target->backend->mask) (surface->target, op,
 
341
                                                            source, mask);
 
342
 
 
343
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
 
344
        cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
 
345
        cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
 
346
 
 
347
        if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 
348
            cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
 
349
            if (_cairo_surface_is_meta (surface_pattern->surface)) {
 
350
                backend_source_status =
 
351
                    _analyze_meta_surface_pattern (surface, source);
 
352
                if (backend_source_status != CAIRO_STATUS_SUCCESS &&
 
353
                    backend_source_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
 
354
                    return backend_source_status;
 
355
            }
 
356
        }
 
357
 
 
358
        if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
 
359
            cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
 
360
            if (_cairo_surface_is_meta (surface_pattern->surface)) {
 
361
                backend_mask_status =
 
362
                    _analyze_meta_surface_pattern (surface, mask);
 
363
                if (backend_mask_status != CAIRO_STATUS_SUCCESS &&
 
364
                    backend_mask_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
 
365
                    return backend_status;
 
366
            }
 
367
        }
 
368
 
 
369
        backend_status = CAIRO_STATUS_SUCCESS;
 
370
 
 
371
        if (backend_source_status == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
 
372
            backend_mask_status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
 
373
        {
 
374
            backend_status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
 
375
        }
 
376
    }
 
377
 
 
378
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
379
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
380
        return status;
 
381
 
 
382
    if (_cairo_operator_bounded_by_source (op)) {
 
383
        cairo_rectangle_int_t source_extents;
 
384
        status = _cairo_pattern_get_extents (source, &source_extents);
 
385
        if (status)
 
386
            return status;
 
387
 
 
388
        _cairo_rectangle_intersect (&extents, &source_extents);
 
389
 
 
390
        status = _cairo_pattern_get_extents (mask, &source_extents);
 
391
        if (status)
 
392
            return status;
 
393
 
 
394
        _cairo_rectangle_intersect (&extents, &source_extents);
 
395
    }
 
396
 
 
397
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
398
 
 
399
    status = _add_operation (surface, &extents, backend_status);
 
400
 
 
401
    return status;
 
402
}
 
403
 
 
404
static cairo_int_status_t
 
405
_cairo_analysis_surface_stroke (void                    *abstract_surface,
 
406
                                cairo_operator_t         op,
 
407
                                cairo_pattern_t         *source,
 
408
                                cairo_path_fixed_t      *path,
 
409
                                cairo_stroke_style_t    *style,
 
410
                                cairo_matrix_t          *ctm,
 
411
                                cairo_matrix_t          *ctm_inverse,
 
412
                                double                   tolerance,
 
413
                                cairo_antialias_t        antialias)
 
414
{
 
415
    cairo_analysis_surface_t *surface = abstract_surface;
 
416
    cairo_status_t           status, backend_status;
 
417
    cairo_traps_t            traps;
 
418
    cairo_rectangle_int_t  extents;
 
419
 
 
420
    if (!surface->target->backend->stroke)
 
421
        backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
422
    else
 
423
        backend_status = (*surface->target->backend->stroke) (surface->target, op,
 
424
                                                              source, path, style,
 
425
                                                              ctm, ctm_inverse,
 
426
                                                              tolerance, antialias);
 
427
 
 
428
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
 
429
        backend_status = _analyze_meta_surface_pattern (surface, source);
 
430
 
 
431
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
432
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
433
        return status;
 
434
 
 
435
    if (_cairo_operator_bounded_by_source (op)) {
 
436
        cairo_rectangle_int_t source_extents;
 
437
        status = _cairo_pattern_get_extents (source, &source_extents);
 
438
        if (status)
 
439
            return status;
 
440
 
 
441
        _cairo_rectangle_intersect (&extents, &source_extents);
 
442
    }
 
443
 
 
444
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
445
 
 
446
    if (_cairo_operator_bounded_by_mask (op)) {
 
447
        cairo_box_t box;
 
448
 
 
449
        _cairo_box_from_rectangle (&box, &extents);
 
450
 
 
451
        _cairo_traps_init (&traps);
 
452
        _cairo_traps_limit (&traps, &box);
 
453
        status = _cairo_path_fixed_stroke_to_traps (path,
 
454
                                                    style,
 
455
                                                    ctm, ctm_inverse,
 
456
                                                    tolerance,
 
457
                                                    &traps);
 
458
        if (status) {
 
459
            _cairo_traps_fini (&traps);
 
460
            return status;
 
461
        }
 
462
 
 
463
        _cairo_traps_extents (&traps, &box);
 
464
        _cairo_traps_fini (&traps);
 
465
 
 
466
        _cairo_box_round_to_rectangle (&box, &extents);
 
467
    }
 
468
 
 
469
    status = _add_operation (surface, &extents, backend_status);
 
470
 
 
471
    return status;
 
472
}
 
473
 
 
474
static cairo_int_status_t
 
475
_cairo_analysis_surface_fill (void                      *abstract_surface,
 
476
                              cairo_operator_t           op,
 
477
                              cairo_pattern_t           *source,
 
478
                              cairo_path_fixed_t        *path,
 
479
                              cairo_fill_rule_t          fill_rule,
 
480
                              double                     tolerance,
 
481
                              cairo_antialias_t          antialias)
 
482
{
 
483
    cairo_analysis_surface_t *surface = abstract_surface;
 
484
    cairo_status_t           status, backend_status;
 
485
    cairo_traps_t            traps;
 
486
    cairo_rectangle_int_t  extents;
 
487
 
 
488
    if (!surface->target->backend->fill)
 
489
        backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
490
    else
 
491
        backend_status = (*surface->target->backend->fill) (surface->target, op,
 
492
                                                    source, path, fill_rule,
 
493
                                                    tolerance, antialias);
 
494
 
 
495
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
 
496
        backend_status = _analyze_meta_surface_pattern (surface, source);
 
497
 
 
498
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
499
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
500
        return status;
 
501
 
 
502
    if (_cairo_operator_bounded_by_source (op)) {
 
503
        cairo_rectangle_int_t source_extents;
 
504
        status = _cairo_pattern_get_extents (source, &source_extents);
 
505
        if (status)
 
506
            return status;
 
507
 
 
508
        _cairo_rectangle_intersect (&extents, &source_extents);
 
509
    }
 
510
 
 
511
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
512
 
 
513
    if (_cairo_operator_bounded_by_mask (op)) {
 
514
        cairo_box_t box;
 
515
 
 
516
        _cairo_box_from_rectangle (&box, &extents);
 
517
 
 
518
        _cairo_traps_init (&traps);
 
519
        _cairo_traps_limit (&traps, &box);
 
520
        status = _cairo_path_fixed_fill_to_traps (path,
 
521
                                                  fill_rule,
 
522
                                                  tolerance,
 
523
                                                  &traps);
 
524
        if (status) {
 
525
            _cairo_traps_fini (&traps);
 
526
            return status;
 
527
        }
 
528
 
 
529
        _cairo_traps_extents (&traps, &box);
 
530
        _cairo_traps_fini (&traps);
 
531
 
 
532
        _cairo_box_round_to_rectangle (&box, &extents);
 
533
    }
 
534
 
 
535
    status = _add_operation (surface, &extents, backend_status);
 
536
 
 
537
    return status;
 
538
}
 
539
 
 
540
static cairo_int_status_t
 
541
_cairo_analysis_surface_show_glyphs (void                 *abstract_surface,
 
542
                                     cairo_operator_t      op,
 
543
                                     cairo_pattern_t      *source,
 
544
                                     cairo_glyph_t        *glyphs,
 
545
                                     int                   num_glyphs,
 
546
                                     cairo_scaled_font_t  *scaled_font,
 
547
                                     int                  *remaining_glyphs)
 
548
{
 
549
    cairo_analysis_surface_t *surface = abstract_surface;
 
550
    cairo_status_t           status, backend_status;
 
551
    cairo_rectangle_int_t    extents, glyph_extents;
 
552
 
 
553
    /* Adapted from _cairo_surface_show_glyphs */
 
554
    if (surface->target->backend->show_glyphs)
 
555
        backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
 
556
                                                                   source,
 
557
                                                                   glyphs, num_glyphs,
 
558
                                                                   scaled_font,
 
559
                                                                   remaining_glyphs);
 
560
    else if (surface->target->backend->show_text_glyphs)
 
561
        backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
 
562
                                                                     source,
 
563
                                                                     NULL, 0,
 
564
                                                                     glyphs, num_glyphs,
 
565
                                                                     NULL, 0,
 
566
                                                                     FALSE,
 
567
                                                                     scaled_font);
 
568
    else
 
569
        backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
570
 
 
571
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
 
572
        backend_status = _analyze_meta_surface_pattern (surface, source);
 
573
 
 
574
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
575
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
576
        return status;
 
577
 
 
578
    if (_cairo_operator_bounded_by_source (op)) {
 
579
        cairo_rectangle_int_t source_extents;
 
580
        status = _cairo_pattern_get_extents (source, &source_extents);
 
581
        if (status)
 
582
            return status;
 
583
 
 
584
        _cairo_rectangle_intersect (&extents, &source_extents);
 
585
    }
 
586
 
 
587
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
588
 
 
589
    if (_cairo_operator_bounded_by_mask (op)) {
 
590
        status = _cairo_scaled_font_glyph_device_extents (scaled_font,
 
591
                                                          glyphs,
 
592
                                                          num_glyphs,
 
593
                                                          &glyph_extents);
 
594
        if (status)
 
595
            return status;
 
596
 
 
597
        _cairo_rectangle_intersect (&extents, &glyph_extents);
 
598
    }
 
599
 
 
600
    status = _add_operation (surface, &extents, backend_status);
 
601
 
 
602
    return status;
 
603
}
 
604
 
 
605
static cairo_bool_t
 
606
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
 
607
{
 
608
    cairo_analysis_surface_t *surface = abstract_surface;
 
609
 
 
610
    return cairo_surface_has_show_text_glyphs (surface->target);
 
611
}
 
612
 
 
613
static cairo_int_status_t
 
614
_cairo_analysis_surface_show_text_glyphs (void                      *abstract_surface,
 
615
                                          cairo_operator_t           op,
 
616
                                          cairo_pattern_t           *source,
 
617
                                          const char                *utf8,
 
618
                                          int                        utf8_len,
 
619
                                          cairo_glyph_t             *glyphs,
 
620
                                          int                        num_glyphs,
 
621
                                          const cairo_text_cluster_t *clusters,
 
622
                                          int                        num_clusters,
 
623
                                          cairo_text_cluster_flags_t cluster_flags,
 
624
                                          cairo_scaled_font_t       *scaled_font)
 
625
{
 
626
    cairo_analysis_surface_t *surface = abstract_surface;
 
627
    cairo_status_t           status, backend_status;
 
628
    cairo_rectangle_int_t    extents, glyph_extents;
 
629
 
 
630
    /* Adapted from _cairo_surface_show_glyphs */
 
631
    backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
 
632
    if (surface->target->backend->show_text_glyphs)
 
633
        backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
 
634
                                                                     source,
 
635
                                                                     utf8, utf8_len,
 
636
                                                                     glyphs, num_glyphs,
 
637
                                                                     clusters, num_clusters, cluster_flags,
 
638
                                                                     scaled_font);
 
639
    if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
 
640
        int remaining_glyphs = num_glyphs;
 
641
        backend_status = surface->target->backend->show_glyphs (surface->target, op,
 
642
                                                                source,
 
643
                                                                glyphs, num_glyphs,
 
644
                                                                scaled_font,
 
645
                                                                &remaining_glyphs);
 
646
        glyphs += num_glyphs - remaining_glyphs;
 
647
        num_glyphs = remaining_glyphs;
 
648
        if (remaining_glyphs == 0)
 
649
            backend_status = CAIRO_STATUS_SUCCESS;
 
650
    }
 
651
 
 
652
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
 
653
        backend_status = _analyze_meta_surface_pattern (surface, source);
 
654
 
 
655
    status = _cairo_surface_get_extents (&surface->base, &extents);
 
656
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
 
657
        return status;
 
658
 
 
659
    if (_cairo_operator_bounded_by_source (op)) {
 
660
        cairo_rectangle_int_t source_extents;
 
661
        status = _cairo_pattern_get_extents (source, &source_extents);
 
662
        if (status)
 
663
            return status;
 
664
 
 
665
        _cairo_rectangle_intersect (&extents, &source_extents);
 
666
    }
 
667
 
 
668
    _cairo_rectangle_intersect (&extents, &surface->current_clip);
 
669
 
 
670
    if (_cairo_operator_bounded_by_mask (op)) {
 
671
        status = _cairo_scaled_font_glyph_device_extents (scaled_font,
 
672
                                                          glyphs,
 
673
                                                          num_glyphs,
 
674
                                                          &glyph_extents);
 
675
        if (status)
 
676
            return status;
 
677
 
 
678
        _cairo_rectangle_intersect (&extents, &glyph_extents);
 
679
    }
 
680
 
 
681
    status = _add_operation (surface, &extents, backend_status);
 
682
 
 
683
    return status;
 
684
}
 
685
 
 
686
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
 
687
    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
 
688
    NULL, /* create_similar */
 
689
    _cairo_analysis_surface_finish,
 
690
    NULL, /* acquire_source_image */
 
691
    NULL, /* release_source_image */
 
692
    NULL, /* acquire_dest_image */
 
693
    NULL, /* release_dest_image */
 
694
    NULL, /* clone_similar */
 
695
    NULL, /* composite */
 
696
    NULL, /* fill_rectangles */
 
697
    NULL, /* composite_trapezoids */
 
698
    NULL, /* copy_page */
 
699
    NULL, /* show_page */
 
700
    NULL, /* set_clip_region */
 
701
    _cairo_analysis_surface_intersect_clip_path,
 
702
    _cairo_analysis_surface_get_extents,
 
703
    NULL, /* old_show_glyphs */
 
704
    NULL, /* get_font_options */
 
705
    NULL, /* flush */
 
706
    NULL, /* mark_dirty_rectangle */
 
707
    NULL, /* scaled_font_fini */
 
708
    NULL, /* scaled_glyph_fini */
 
709
    _cairo_analysis_surface_paint,
 
710
    _cairo_analysis_surface_mask,
 
711
    _cairo_analysis_surface_stroke,
 
712
    _cairo_analysis_surface_fill,
 
713
    _cairo_analysis_surface_show_glyphs,
 
714
    NULL, /* snapshot */
 
715
    NULL, /* is_similar */
 
716
    NULL, /* reset */
 
717
    NULL, /* fill_stroke */
 
718
    NULL, /* create_solid_pattern_surface */
 
719
    _cairo_analysis_surface_has_show_text_glyphs,
 
720
    _cairo_analysis_surface_show_text_glyphs
 
721
};
 
722
 
 
723
cairo_surface_t *
 
724
_cairo_analysis_surface_create (cairo_surface_t         *target,
 
725
                                int                      width,
 
726
                                int                      height)
 
727
{
 
728
    cairo_analysis_surface_t *surface;
 
729
 
 
730
    surface = malloc (sizeof (cairo_analysis_surface_t));
 
731
    if (surface == NULL)
 
732
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
733
 
 
734
    /* I believe the content type here is truly arbitrary. I'm quite
 
735
     * sure nothing will ever use this value. */
 
736
    _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
 
737
                         CAIRO_CONTENT_COLOR_ALPHA);
 
738
 
 
739
    surface->width = width;
 
740
    surface->height = height;
 
741
    cairo_matrix_init_identity (&surface->ctm);
 
742
    surface->has_ctm = FALSE;
 
743
 
 
744
    surface->target = cairo_surface_reference (target);
 
745
    surface->first_op  = TRUE;
 
746
    surface->has_supported = FALSE;
 
747
    surface->has_unsupported = FALSE;
 
748
 
 
749
    surface->page_bbox.p1.x = 0;
 
750
    surface->page_bbox.p1.y = 0;
 
751
    surface->page_bbox.p2.x = 0;
 
752
    surface->page_bbox.p2.y = 0;
 
753
 
 
754
    _cairo_region_init (&surface->supported_region);
 
755
    _cairo_region_init (&surface->fallback_region);
 
756
 
 
757
    if (width == -1 && height == -1) {
 
758
        surface->current_clip.x      = CAIRO_RECT_INT_MIN;
 
759
        surface->current_clip.y      = CAIRO_RECT_INT_MIN;
 
760
        surface->current_clip.width  = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
 
761
        surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
 
762
    } else {
 
763
        surface->current_clip.x = 0;
 
764
        surface->current_clip.y = 0;
 
765
        surface->current_clip.width = width;
 
766
        surface->current_clip.height = height;
 
767
    }
 
768
 
 
769
    return &surface->base;
 
770
}
 
771
 
 
772
cairo_private void
 
773
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
 
774
                                 cairo_matrix_t  *ctm)
 
775
{
 
776
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
777
 
 
778
    surface->ctm = *ctm;
 
779
    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
 
780
}
 
781
 
 
782
cairo_private void
 
783
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
 
784
                                 cairo_matrix_t  *ctm)
 
785
{
 
786
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
787
 
 
788
    *ctm = surface->ctm;
 
789
}
 
790
 
 
791
 
 
792
cairo_region_t *
 
793
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
 
794
{
 
795
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
796
 
 
797
    return &surface->supported_region;
 
798
}
 
799
 
 
800
cairo_region_t *
 
801
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
 
802
{
 
803
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
804
 
 
805
    return &surface->fallback_region;
 
806
}
 
807
 
 
808
cairo_bool_t
 
809
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
 
810
{
 
811
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
812
 
 
813
    return surface->has_supported;
 
814
}
 
815
 
 
816
cairo_bool_t
 
817
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
 
818
{
 
819
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
820
 
 
821
    return surface->has_unsupported;
 
822
}
 
823
 
 
824
void
 
825
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
 
826
                                          cairo_box_t     *bbox)
 
827
{
 
828
    cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
 
829
 
 
830
    *bbox = surface->page_bbox;
 
831
}
 
832
 
 
833
/* null surface type: a surface that does nothing (has no side effects, yay!) */
 
834
 
 
835
static cairo_int_status_t
 
836
_return_success (void)
 
837
{
 
838
    return CAIRO_STATUS_SUCCESS;
 
839
}
 
840
 
 
841
/* These typedefs are just to silence the compiler... */
 
842
typedef cairo_int_status_t
 
843
(*_set_clip_region_func)        (void                   *surface,
 
844
                                 cairo_region_t         *region);
 
845
typedef cairo_int_status_t
 
846
(*_paint_func)                  (void                   *surface,
 
847
                                 cairo_operator_t        op,
 
848
                                 cairo_pattern_t        *source);
 
849
 
 
850
typedef cairo_int_status_t
 
851
(*_mask_func)                   (void                   *surface,
 
852
                                 cairo_operator_t        op,
 
853
                                 cairo_pattern_t        *source,
 
854
                                 cairo_pattern_t        *mask);
 
855
 
 
856
typedef cairo_int_status_t
 
857
(*_stroke_func)                 (void                   *surface,
 
858
                                 cairo_operator_t        op,
 
859
                                 cairo_pattern_t        *source,
 
860
                                 cairo_path_fixed_t     *path,
 
861
                                 cairo_stroke_style_t   *style,
 
862
                                 cairo_matrix_t         *ctm,
 
863
                                 cairo_matrix_t         *ctm_inverse,
 
864
                                 double                  tolerance,
 
865
                                 cairo_antialias_t       antialias);
 
866
 
 
867
typedef cairo_int_status_t
 
868
(*_fill_func)                   (void                   *surface,
 
869
                                 cairo_operator_t        op,
 
870
                                 cairo_pattern_t        *source,
 
871
                                 cairo_path_fixed_t     *path,
 
872
                                 cairo_fill_rule_t       fill_rule,
 
873
                                 double                  tolerance,
 
874
                                 cairo_antialias_t       antialias);
 
875
 
 
876
typedef cairo_int_status_t
 
877
(*_show_glyphs_func)            (void                   *surface,
 
878
                                 cairo_operator_t        op,
 
879
                                 cairo_pattern_t        *source,
 
880
                                 cairo_glyph_t          *glyphs,
 
881
                                 int                     num_glyphs,
 
882
                                 cairo_scaled_font_t    *scaled_font,
 
883
                                 int                    *remaining_glyphs);
 
884
 
 
885
static const cairo_surface_backend_t cairo_null_surface_backend = {
 
886
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
 
887
 
 
888
    NULL, /* create_similar */
 
889
    NULL, /* finish */
 
890
    NULL, /* acquire_source_image */
 
891
    NULL, /* release_source_image */
 
892
    NULL, /* acquire_dest_image */
 
893
    NULL, /* release_dest_image */
 
894
    NULL, /* clone_similar */
 
895
    NULL, /* composite */
 
896
    NULL, /* fill_rectangles */
 
897
    NULL, /* composite_trapezoids */
 
898
    NULL, /* copy_page */
 
899
    NULL, /* show_page */
 
900
    (_set_clip_region_func) _return_success, /* set_clip_region */
 
901
    NULL, /* intersect_clip_path */
 
902
    NULL, /* get_extents */
 
903
    NULL, /* old_show_glyphs */
 
904
    NULL, /* get_font_options */
 
905
    NULL, /* flush */
 
906
    NULL, /* mark_dirty_rectangle */
 
907
    NULL, /* scaled_font_fini */
 
908
    NULL, /* scaled_glyph_fini */
 
909
    (_paint_func) _return_success,          /* paint */
 
910
    (_mask_func) _return_success,           /* mask */
 
911
    (_stroke_func) _return_success,         /* stroke */
 
912
    (_fill_func) _return_success,           /* fill */
 
913
    (_show_glyphs_func) _return_success,    /* show_glyphs */
 
914
    NULL, /* snapshot */
 
915
    NULL, /* is_similar */
 
916
    NULL, /* reset */
 
917
    NULL, /* fill_stroke */
 
918
    NULL, /* create_solid_pattern_surface */
 
919
    NULL, /* has_show_text_glyphs */
 
920
    NULL  /* show_text_glyphs */
 
921
};
 
922
 
 
923
cairo_surface_t *
 
924
_cairo_null_surface_create (cairo_content_t content)
 
925
{
 
926
    cairo_surface_t *surface;
 
927
 
 
928
    surface = malloc (sizeof (cairo_surface_t));
 
929
    if (surface == NULL) {
 
930
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
931
    }
 
932
 
 
933
    _cairo_surface_init (surface, &cairo_null_surface_backend, content);
 
934
 
 
935
    return surface;
 
936
}