1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/*
3
 * Copyright © 2006 Keith Packard
4
 * Copyright © 2007 Adrian Johnson
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Keith Packard
32
 *
33
 * Contributor(s):
34
 *      Keith Packard <keithp@keithp.com>
35
 *      Adrian Johnson <ajohnson@redneon.com>
36
 */
37

            
38
#include "cairoint.h"
39

            
40
#include "cairo-analysis-surface-private.h"
41
#include "cairo-box-inline.h"
42
#include "cairo-default-context-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-paginated-private.h"
45
#include "cairo-recording-surface-inline.h"
46
#include "cairo-surface-snapshot-inline.h"
47
#include "cairo-surface-subsurface-inline.h"
48
#include "cairo-region-private.h"
49

            
50
typedef struct {
51
    cairo_surface_t base;
52

            
53
    cairo_surface_t *target;
54

            
55
    cairo_bool_t first_op;
56
    cairo_bool_t has_supported;
57
    cairo_bool_t has_unsupported;
58

            
59
    cairo_region_t supported_region;
60
    cairo_region_t fallback_region;
61
    cairo_box_t page_bbox;
62

            
63
    cairo_bool_t create_region_ids;
64
    unsigned source_region_id;
65
    unsigned mask_region_id;
66

            
67
    cairo_bool_t has_ctm;
68
    cairo_matrix_t ctm;
69

            
70
} cairo_analysis_surface_t;
71

            
72
cairo_int_status_t
73
6
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
74
				      cairo_int_status_t status_b)
75
{
76
    /* fatal errors should be checked and propagated at source */
77
6
    assert (! _cairo_int_status_is_error (status_a));
78
6
    assert (! _cairo_int_status_is_error (status_b));
79

            
80
    /* return the most important status */
81
6
    if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
82
	status_b == CAIRO_INT_STATUS_UNSUPPORTED)
83
	return CAIRO_INT_STATUS_UNSUPPORTED;
84

            
85
6
    if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
86
	status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
87
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
88

            
89
6
    if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
90
	status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
91
	return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
92

            
93
6
    if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
94
	status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
95
	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
96

            
97
    /* at this point we have checked all the valid internal codes, so... */
98
6
    assert (status_a == CAIRO_INT_STATUS_SUCCESS &&
99
	    status_b == CAIRO_INT_STATUS_SUCCESS);
100

            
101
6
    return CAIRO_INT_STATUS_SUCCESS;
102
}
103

            
104
struct proxy {
105
    cairo_surface_t base;
106
    cairo_surface_t *target;
107
};
108

            
109
static cairo_status_t
110
158
proxy_finish (void *abstract_surface)
111
{
112
158
    return CAIRO_STATUS_SUCCESS;
113
}
114

            
115
static const cairo_surface_backend_t proxy_backend  = {
116
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
117
    proxy_finish,
118
};
119

            
120
static cairo_surface_t *
121
158
attach_proxy (cairo_surface_t *source,
122
	      cairo_surface_t *target)
123
{
124
    struct proxy *proxy;
125

            
126
158
    proxy = _cairo_calloc (sizeof (*proxy));
127
158
    if (unlikely (proxy == NULL))
128
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
129

            
130
158
    _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content, target->is_vector);
131

            
132
158
    proxy->target = target;
133
158
    _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
134

            
135
158
    return &proxy->base;
136
}
137

            
138
static void
139
158
detach_proxy (cairo_surface_t *proxy)
140
{
141
158
    cairo_surface_finish (proxy);
142
158
    cairo_surface_destroy (proxy);
143
158
}
144

            
145
static cairo_int_status_t
146
1604
_add_operation (cairo_analysis_surface_t *surface,
147
		cairo_rectangle_int_t    *rect,
148
		cairo_int_status_t        backend_status)
149
{
150
    cairo_int_status_t status;
151
    cairo_box_t bbox;
152

            
153
1604
    if (rect->width == 0 || rect->height == 0) {
154
	/* Even though the operation is not visible we must be careful
155
	 * to not allow unsupported operations to be replayed to the
156
	 * backend during CAIRO_PAGINATED_MODE_RENDER */
157
	if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
158
	    backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
159
	    backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
160
	{
161
	    return CAIRO_INT_STATUS_SUCCESS;
162
	}
163
	else
164
	{
165
	    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
166
	}
167
    }
168

            
169
1604
    _cairo_box_from_rectangle (&bbox, rect);
170

            
171
1604
    if (surface->has_ctm) {
172
	int tx, ty;
173

            
174
1254
	if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
175
30
	    rect->x += tx;
176
30
	    rect->y += ty;
177

            
178
30
	    tx = _cairo_fixed_from_int (tx);
179
30
	    bbox.p1.x += tx;
180
30
	    bbox.p2.x += tx;
181

            
182
30
	    ty = _cairo_fixed_from_int (ty);
183
30
	    bbox.p1.y += ty;
184
30
	    bbox.p2.y += ty;
185
	} else {
186
1224
	    _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
187
							&bbox, NULL);
188

            
189
1224
	    if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
190
		/* Even though the operation is not visible we must be
191
		 * careful to not allow unsupported operations to be
192
		 * replayed to the backend during
193
		 * CAIRO_PAGINATED_MODE_RENDER */
194
		if (backend_status == CAIRO_INT_STATUS_SUCCESS ||
195
		    backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
196
		    backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO)
197
		{
198
		    return CAIRO_INT_STATUS_SUCCESS;
199
		}
200
		else
201
		{
202
		    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
203
		}
204
	    }
205

            
206
1224
	    _cairo_box_round_to_rectangle (&bbox, rect);
207
	}
208
    }
209

            
210
1604
    if (surface->first_op) {
211
1195
	surface->first_op = FALSE;
212
1195
	surface->page_bbox = bbox;
213
    } else
214
409
	_cairo_box_add_box(&surface->page_bbox, &bbox);
215

            
216
    /* If the operation is completely enclosed within the fallback
217
     * region there is no benefit in emitting a native operation as
218
     * the fallback image will be painted on top.
219
     */
220
1604
    if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
221
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
222

            
223
1604
    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
224
	/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
225
	 * that the backend only supports this operation if the
226
	 * transparency removed. If the extents of this operation does
227
	 * not intersect any other native operation, the operation is
228
	 * natively supported and the backend will blend the
229
	 * transparency into the white background.
230
	 */
231
12
	if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
232
	    backend_status = CAIRO_INT_STATUS_SUCCESS;
233
    }
234

            
235
1604
    if (backend_status == CAIRO_INT_STATUS_SUCCESS) {
236
	/* Add the operation to the supported region. Operations in
237
	 * this region will be emitted as native operations.
238
	 */
239
1575
	surface->has_supported = TRUE;
240
1575
	return cairo_region_union_rectangle (&surface->supported_region, rect);
241
    }
242

            
243
    /* Add the operation to the unsupported region. This region will
244
     * be painted as an image after all native operations have been
245
     * emitted.
246
     */
247
29
    surface->has_unsupported = TRUE;
248
29
    status = cairo_region_union_rectangle (&surface->fallback_region, rect);
249

            
250
    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
251
     * unsupported operations to the recording surface as using
252
     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
253
     * invoke the cairo-surface-fallback path then return
254
     * CAIRO_STATUS_SUCCESS.
255
     */
256
29
    if (status == CAIRO_INT_STATUS_SUCCESS)
257
29
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
258
    else
259
	return status;
260
}
261

            
262
static cairo_int_status_t
263
158
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
264
				    const cairo_pattern_t    *pattern,
265
				    cairo_rectangle_int_t    *extents,
266
				    unsigned int             *regions_id,
267
				    cairo_analysis_source_t   source_type)
268
{
269
    const cairo_surface_pattern_t *surface_pattern;
270
    cairo_analysis_surface_t *tmp;
271
    cairo_surface_t *source, *proxy;
272
    cairo_matrix_t p2d;
273
    cairo_int_status_t status;
274
158
    cairo_int_status_t analysis_status = CAIRO_INT_STATUS_SUCCESS;
275
    cairo_bool_t surface_is_unbounded;
276
    cairo_bool_t unused;
277
    cairo_bool_t replay_all;
278

            
279
158
    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
280
158
    surface_pattern = (const cairo_surface_pattern_t *) pattern;
281
158
    assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
282
158
    source = surface_pattern->surface;
283

            
284
158
    proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
285
158
    if (proxy != NULL) {
286
	/* nothing untoward found so far */
287
	return CAIRO_STATUS_SUCCESS;
288
    }
289

            
290
    tmp = (cairo_analysis_surface_t *)
291
158
	_cairo_analysis_surface_create (surface->target, surface->create_region_ids);
292
158
    if (unlikely (tmp->base.status)) {
293
	status = tmp->base.status;
294
	goto cleanup1;
295
    }
296
158
    proxy = attach_proxy (source, &tmp->base);
297

            
298
158
    p2d = pattern->matrix;
299
158
    status = cairo_matrix_invert (&p2d);
300
158
    assert (status == CAIRO_INT_STATUS_SUCCESS);
301
158
    _cairo_analysis_surface_set_ctm (&tmp->base, &p2d);
302

            
303
158
    source = _cairo_surface_get_source (source, NULL);
304
316
    surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT
305
158
			    || pattern->extend == CAIRO_EXTEND_REFLECT);
306

            
307
158
    if (surface->create_region_ids) {
308
18
	status = _cairo_recording_surface_region_array_attach (source, regions_id);
309
18
	if (unlikely (status))
310
	    goto cleanup2;
311
    }
312

            
313
158
    replay_all = FALSE;
314
158
    if (surface->target->backend->analyze_recording_surface) {
315
9
	status = surface->target->backend->analyze_recording_surface (
316
9
	    surface->target,
317
	    surface_pattern,
318
9
	    surface->create_region_ids ? *regions_id : 0,
319
	    source_type,
320
	    TRUE);
321
9
        if (status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
322
	    /* Ensure all commands are replayed even if previously
323
	     * replayed and assigned to a region.*/
324
            replay_all = TRUE;
325
            status = CAIRO_INT_STATUS_SUCCESS;
326
        }
327
9
        if (unlikely (status))
328
            goto cleanup3;
329
    }
330

            
331
158
    if (surface->create_region_ids) {
332
18
	status = _cairo_recording_surface_replay_and_create_regions (source,
333
								     *regions_id,
334
								     &pattern->matrix,
335
								     &tmp->base,
336
								     surface_is_unbounded,
337
								     replay_all);
338
18
	if (unlikely (status))
339
	    goto cleanup3;
340
    } else {
341
140
	status = _cairo_recording_surface_replay_with_transform (source,
342
								 &pattern->matrix,
343
								 &tmp->base,
344
								 surface_is_unbounded,
345
								 replay_all);
346
140
	if (unlikely (status))
347
	    goto cleanup3;
348
    }
349

            
350
158
    if (surface->target->backend->analyze_recording_surface) {
351
9
	status = surface->target->backend->analyze_recording_surface (
352
9
	    surface->target,
353
	    surface_pattern,
354
9
	    surface->create_region_ids ? *regions_id : 0,
355
	    source_type,
356
	    FALSE);
357
9
        if (unlikely (status))
358
            goto cleanup3;
359
    }
360

            
361
    /* black background or mime data fills entire extents */
362
158
    if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) {
363
	cairo_rectangle_int_t rect;
364

            
365
	if (_cairo_surface_get_extents (source, &rect)) {
366
	    cairo_box_t bbox;
367

            
368
	    _cairo_box_from_rectangle (&bbox, &rect);
369
	    _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL);
370
	    _cairo_box_round_to_rectangle (&bbox, &rect);
371
	    status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS);
372
	    if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
373
		status = CAIRO_INT_STATUS_SUCCESS;
374
	    if (unlikely (status))
375
		goto cleanup3;
376
	}
377
    }
378

            
379
158
    if (tmp->has_supported) {
380
158
	surface->has_supported = TRUE;
381
158
	unused = cairo_region_union (&surface->supported_region, &tmp->supported_region);
382
    }
383

            
384
158
    if (tmp->has_unsupported) {
385
9
	surface->has_unsupported = TRUE;
386
9
	unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region);
387
    }
388

            
389
158
    analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
390
158
    if (pattern->extend != CAIRO_EXTEND_NONE) {
391
	_cairo_unbounded_rectangle_init (extents);
392
    } else {
393
158
	status = cairo_matrix_invert (&tmp->ctm);
394
158
	_cairo_matrix_transform_bounding_box_fixed (&tmp->ctm,
395
						    &tmp->page_bbox, NULL);
396
158
	_cairo_box_round_to_rectangle (&tmp->page_bbox, extents);
397
    }
398

            
399
158
  cleanup3:
400
158
    if (surface->create_region_ids && unlikely (status)) {
401
	_cairo_recording_surface_region_array_remove (source, *regions_id);
402
    }
403
158
  cleanup2:
404
158
    detach_proxy (proxy);
405
158
  cleanup1:
406
158
    cairo_surface_destroy (&tmp->base);
407

            
408
158
    if (unlikely (status))
409
	return status;
410
    else
411
158
	return analysis_status;
412
}
413

            
414
static cairo_status_t
415
1258
_cairo_analysis_surface_finish (void *abstract_surface)
416
{
417
1258
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
418

            
419
1258
    _cairo_region_fini (&surface->supported_region);
420
1258
    _cairo_region_fini (&surface->fallback_region);
421

            
422
1258
    cairo_surface_destroy (surface->target);
423

            
424
1258
    return CAIRO_STATUS_SUCCESS;
425
}
426

            
427
static cairo_bool_t
428
2799
_cairo_analysis_surface_get_extents (void			*abstract_surface,
429
				     cairo_rectangle_int_t	*rectangle)
430
{
431
2799
    cairo_analysis_surface_t *surface = abstract_surface;
432

            
433
2799
    return _cairo_surface_get_extents (surface->target, rectangle);
434
}
435

            
436
static void
437
1604
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip)
438
{
439
1604
    if (clip != NULL)
440
134
	_cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip));
441
1604
}
442

            
443
static void
444
1604
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
445
					   cairo_operator_t op,
446
					   const cairo_pattern_t *source,
447
					   const cairo_clip_t *clip,
448
					   cairo_rectangle_int_t *extents)
449
{
450
    cairo_bool_t is_empty;
451

            
452
1604
    is_empty = _cairo_surface_get_extents (&surface->base, extents);
453

            
454
1604
    if (_cairo_operator_bounded_by_source (op)) {
455
	cairo_rectangle_int_t source_extents;
456

            
457
1532
	_cairo_pattern_get_extents (source, &source_extents, surface->target->is_vector);
458
1532
	_cairo_rectangle_intersect (extents, &source_extents);
459
    }
460

            
461
1604
    _rectangle_intersect_clip (extents, clip);
462
1604
}
463

            
464
static cairo_int_status_t
465
170
_cairo_analysis_surface_paint (void			*abstract_surface,
466
			       cairo_operator_t		op,
467
			       const cairo_pattern_t	*source,
468
			       const cairo_clip_t	*clip)
469
{
470
170
    cairo_analysis_surface_t *surface = abstract_surface;
471
    cairo_int_status_t	     backend_status;
472
    cairo_rectangle_int_t  extents;
473

            
474
170
    surface->source_region_id = 0;
475
170
    surface->mask_region_id = 0;
476
170
    if (surface->target->backend->paint == NULL) {
477
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
478
    } else {
479
	backend_status =
480
170
	    surface->target->backend->paint (surface->target,
481
					     op, source, clip);
482
170
	if (_cairo_int_status_is_error (backend_status))
483
	    return backend_status;
484
    }
485

            
486
170
    _cairo_analysis_surface_operation_extents (surface,
487
					       op, source, clip,
488
					       &extents);
489
170
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
490
	cairo_rectangle_int_t rec_extents;
491
152
	backend_status = _analyze_recording_surface_pattern (surface,
492
							     source,
493
							     &rec_extents,
494
							     &surface->source_region_id,
495
							     CAIRO_ANALYSIS_SOURCE_PAINT);
496
152
	_cairo_rectangle_intersect (&extents, &rec_extents);
497
    }
498

            
499
170
    return _add_operation (surface, &extents, backend_status);
500
}
501

            
502
static cairo_int_status_t
503
21
_cairo_analysis_surface_mask (void			*abstract_surface,
504
			      cairo_operator_t		 op,
505
			      const cairo_pattern_t	*source,
506
			      const cairo_pattern_t	*mask,
507
			      const cairo_clip_t	*clip)
508
{
509
21
    cairo_analysis_surface_t *surface = abstract_surface;
510
    cairo_int_status_t	      backend_status;
511
    cairo_rectangle_int_t   extents;
512

            
513
21
    surface->source_region_id = 0;
514
21
    surface->mask_region_id = 0;
515
21
    if (surface->target->backend->mask == NULL) {
516
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
517
    } else {
518
	backend_status =
519
21
	    surface->target->backend->mask (surface->target,
520
					    op, source, mask, clip);
521
21
	if (_cairo_int_status_is_error (backend_status))
522
	    return backend_status;
523
    }
524

            
525
21
    _cairo_analysis_surface_operation_extents (surface,
526
					       op, source, clip,
527
					       &extents);
528
21
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
529
6
	cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
530
6
	cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
531
	cairo_rectangle_int_t rec_extents;
532

            
533
6
	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
534
6
	    cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface;
535
6
	    src_surface = _cairo_surface_get_source (src_surface, NULL);
536
6
	    if (_cairo_surface_is_recording (src_surface)) {
537
		backend_source_status =
538
6
		    _analyze_recording_surface_pattern (surface,
539
							source,
540
							&rec_extents,
541
							&surface->source_region_id,
542
							CAIRO_ANALYSIS_SOURCE_MASK);
543
6
		if (_cairo_int_status_is_error (backend_source_status))
544
		    return backend_source_status;
545

            
546
6
		_cairo_rectangle_intersect (&extents, &rec_extents);
547
	    }
548
	}
549

            
550
6
	if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
551
	    cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface;
552
	    mask_surface = _cairo_surface_get_source (mask_surface, NULL);
553
	    if (_cairo_surface_is_recording (mask_surface)) {
554
		backend_mask_status =
555
		    _analyze_recording_surface_pattern (surface,
556
							mask,
557
							&rec_extents,
558
							&surface->mask_region_id,
559
							CAIRO_ANALYSIS_MASK_MASK);
560
		if (_cairo_int_status_is_error (backend_mask_status))
561
		    return backend_mask_status;
562

            
563
		_cairo_rectangle_intersect (&extents, &rec_extents);
564
	    }
565
	}
566

            
567
	backend_status =
568
6
	    _cairo_analysis_surface_merge_status (backend_source_status,
569
						  backend_mask_status);
570
    }
571

            
572
21
    if (_cairo_operator_bounded_by_mask (op)) {
573
	cairo_rectangle_int_t mask_extents;
574

            
575
21
	_cairo_pattern_get_extents (mask, &mask_extents, surface->target->is_vector);
576
21
	_cairo_rectangle_intersect (&extents, &mask_extents);
577
    }
578

            
579
21
    return _add_operation (surface, &extents, backend_status);
580
}
581

            
582
static cairo_int_status_t
583
672
_cairo_analysis_surface_stroke (void			   *abstract_surface,
584
				cairo_operator_t	    op,
585
				const cairo_pattern_t	   *source,
586
				const cairo_path_fixed_t   *path,
587
				const cairo_stroke_style_t *style,
588
				const cairo_matrix_t	   *ctm,
589
				const cairo_matrix_t	   *ctm_inverse,
590
				double			    tolerance,
591
				cairo_antialias_t	    antialias,
592
				const cairo_clip_t	   *clip)
593
{
594
672
    cairo_analysis_surface_t *surface = abstract_surface;
595
    cairo_int_status_t	     backend_status;
596
    cairo_rectangle_int_t    extents;
597

            
598
672
    surface->source_region_id = 0;
599
672
    surface->mask_region_id = 0;
600
672
    if (surface->target->backend->stroke == NULL) {
601
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
602
    } else {
603
	backend_status =
604
672
	    surface->target->backend->stroke (surface->target, op,
605
					      source, path, style,
606
					      ctm, ctm_inverse,
607
					      tolerance, antialias,
608
					      clip);
609
672
	if (_cairo_int_status_is_error (backend_status))
610
	    return backend_status;
611
    }
612

            
613
672
    _cairo_analysis_surface_operation_extents (surface,
614
					       op, source, clip,
615
					       &extents);
616
672
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
617
	cairo_rectangle_int_t rec_extents;
618
	backend_status = _analyze_recording_surface_pattern (surface,
619
							     source,
620
							     &rec_extents,
621
							     &surface->source_region_id,
622
							     CAIRO_ANALYSIS_SOURCE_STROKE);
623
	_cairo_rectangle_intersect (&extents, &rec_extents);
624
    }
625

            
626
672
    if (_cairo_operator_bounded_by_mask (op)) {
627
	cairo_rectangle_int_t mask_extents;
628
	cairo_int_status_t status;
629

            
630
672
	status = _cairo_path_fixed_stroke_extents (path, style,
631
						   ctm, ctm_inverse,
632
						   tolerance,
633
						   &mask_extents);
634
672
	if (unlikely (status))
635
	    return status;
636

            
637
672
	_cairo_rectangle_intersect (&extents, &mask_extents);
638
    }
639

            
640
672
    return _add_operation (surface, &extents, backend_status);
641
}
642

            
643
static cairo_int_status_t
644
693
_cairo_analysis_surface_fill (void			*abstract_surface,
645
			      cairo_operator_t		 op,
646
			      const cairo_pattern_t	*source,
647
			      const cairo_path_fixed_t	*path,
648
			      cairo_fill_rule_t		 fill_rule,
649
			      double			 tolerance,
650
			      cairo_antialias_t		 antialias,
651
			      const cairo_clip_t	*clip)
652
{
653
693
    cairo_analysis_surface_t *surface = abstract_surface;
654
    cairo_int_status_t	     backend_status;
655
    cairo_rectangle_int_t    extents;
656

            
657
693
    if (surface->target->backend->fill == NULL) {
658
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
659
    } else {
660
	backend_status =
661
693
	    surface->target->backend->fill (surface->target, op,
662
					    source, path, fill_rule,
663
					    tolerance, antialias,
664
					    clip);
665
693
	if (_cairo_int_status_is_error (backend_status))
666
	    return backend_status;
667
    }
668

            
669
693
    _cairo_analysis_surface_operation_extents (surface,
670
					       op, source, clip,
671
					       &extents);
672
693
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
673
	cairo_rectangle_int_t rec_extents;
674
	backend_status = _analyze_recording_surface_pattern (surface,
675
							     source,
676
							     &rec_extents,
677
							     &surface->source_region_id,
678
							     CAIRO_ANALYSIS_SOURCE_FILL);
679
	_cairo_rectangle_intersect (&extents, &rec_extents);
680
    }
681

            
682
693
    if (_cairo_operator_bounded_by_mask (op)) {
683
	cairo_rectangle_int_t mask_extents;
684

            
685
693
	_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
686
					&mask_extents);
687

            
688
693
	_cairo_rectangle_intersect (&extents, &mask_extents);
689
    }
690

            
691
693
    return _add_operation (surface, &extents, backend_status);
692
}
693

            
694
static cairo_int_status_t
695
_cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
696
				     cairo_operator_t	   op,
697
				     const cairo_pattern_t *source,
698
				     cairo_glyph_t	  *glyphs,
699
				     int		   num_glyphs,
700
				     cairo_scaled_font_t  *scaled_font,
701
				     const cairo_clip_t         *clip)
702
{
703
    cairo_analysis_surface_t *surface = abstract_surface;
704
    cairo_int_status_t	     status, backend_status;
705
    cairo_rectangle_int_t    extents, glyph_extents;
706

            
707
    surface->source_region_id = 0;
708
    surface->mask_region_id = 0;
709

            
710
    /* Adapted from _cairo_surface_show_glyphs */
711
    if (surface->target->backend->show_glyphs != NULL) {
712
	backend_status =
713
	    surface->target->backend->show_glyphs (surface->target, op,
714
						   source,
715
						   glyphs, num_glyphs,
716
						   scaled_font,
717
						   clip);
718
	if (_cairo_int_status_is_error (backend_status))
719
	    return backend_status;
720
    }
721
    else if (surface->target->backend->show_text_glyphs != NULL)
722
    {
723
	backend_status =
724
	    surface->target->backend->show_text_glyphs (surface->target, op,
725
							source,
726
							NULL, 0,
727
							glyphs, num_glyphs,
728
							NULL, 0,
729
							FALSE,
730
							scaled_font,
731
							clip);
732
	if (_cairo_int_status_is_error (backend_status))
733
	    return backend_status;
734
    }
735
    else
736
    {
737
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
738
    }
739

            
740
    _cairo_analysis_surface_operation_extents (surface,
741
					       op, source, clip,
742
					       &extents);
743
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
744
	cairo_rectangle_int_t rec_extents;
745
	backend_status = _analyze_recording_surface_pattern (surface,
746
							     source,
747
							     &rec_extents,
748
							     &surface->source_region_id,
749
							     CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
750
	_cairo_rectangle_intersect (&extents, &rec_extents);
751
    }
752

            
753
    if (_cairo_operator_bounded_by_mask (op)) {
754
	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
755
							  glyphs,
756
							  num_glyphs,
757
							  &glyph_extents,
758
							  NULL);
759
	if (unlikely (status))
760
	    return status;
761

            
762
	_cairo_rectangle_intersect (&extents, &glyph_extents);
763
    }
764

            
765
    return _add_operation (surface, &extents, backend_status);
766
}
767

            
768
static cairo_bool_t
769
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
770
{
771
    cairo_analysis_surface_t *surface = abstract_surface;
772

            
773
    return cairo_surface_has_show_text_glyphs (surface->target);
774
}
775

            
776
static cairo_int_status_t
777
48
_cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
778
					  cairo_operator_t	     op,
779
					  const cairo_pattern_t	    *source,
780
					  const char		    *utf8,
781
					  int			     utf8_len,
782
					  cairo_glyph_t		    *glyphs,
783
					  int			     num_glyphs,
784
					  const cairo_text_cluster_t *clusters,
785
					  int			     num_clusters,
786
					  cairo_text_cluster_flags_t cluster_flags,
787
					  cairo_scaled_font_t	    *scaled_font,
788
					  const cairo_clip_t		    *clip)
789
{
790
48
    cairo_analysis_surface_t *surface = abstract_surface;
791
    cairo_int_status_t	     status, backend_status;
792
    cairo_rectangle_int_t    extents, glyph_extents;
793

            
794
48
    surface->source_region_id = 0;
795
48
    surface->mask_region_id = 0;
796

            
797
    /* Adapted from _cairo_surface_show_glyphs */
798
48
    backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
799
48
    if (surface->target->backend->show_text_glyphs != NULL) {
800
	backend_status =
801
	    surface->target->backend->show_text_glyphs (surface->target, op,
802
							source,
803
							utf8, utf8_len,
804
							glyphs, num_glyphs,
805
							clusters, num_clusters,
806
							cluster_flags,
807
							scaled_font,
808
							clip);
809
	if (_cairo_int_status_is_error (backend_status))
810
	    return backend_status;
811
    }
812
48
    if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
813
48
	surface->target->backend->show_glyphs != NULL)
814
    {
815
	backend_status =
816
48
	    surface->target->backend->show_glyphs (surface->target, op,
817
						   source,
818
						   glyphs, num_glyphs,
819
						   scaled_font,
820
						   clip);
821
48
	if (_cairo_int_status_is_error (backend_status))
822
	    return backend_status;
823
    }
824

            
825
48
    _cairo_analysis_surface_operation_extents (surface,
826
					       op, source, clip,
827
					       &extents);
828
48
    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
829
	cairo_rectangle_int_t rec_extents;
830
	_analyze_recording_surface_pattern (surface,
831
					    source,
832
					    &rec_extents,
833
					    &surface->source_region_id,
834
					    CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS);
835
	_cairo_rectangle_intersect (&extents, &rec_extents);
836
    }
837

            
838
48
    if (_cairo_operator_bounded_by_mask (op)) {
839
48
	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
840
							  glyphs,
841
							  num_glyphs,
842
							  &glyph_extents,
843
							  NULL);
844
48
	if (unlikely (status))
845
	    return status;
846

            
847
48
	_cairo_rectangle_intersect (&extents, &glyph_extents);
848
    }
849

            
850
48
    return _add_operation (surface, &extents, backend_status);
851
}
852

            
853
static cairo_int_status_t
854
_cairo_analysis_surface_tag (void	                *abstract_surface,
855
			     cairo_bool_t                begin,
856
			     const char                 *tag_name,
857
			     const char                 *attributes)
858
{
859
    cairo_analysis_surface_t *surface = abstract_surface;
860
    cairo_int_status_t	     backend_status;
861

            
862
    surface->source_region_id = 0;
863
    surface->mask_region_id = 0;
864
    backend_status = CAIRO_INT_STATUS_SUCCESS;
865
    if (surface->target->backend->tag != NULL) {
866
	backend_status =
867
	    surface->target->backend->tag (surface->target,
868
					   begin,
869
					   tag_name,
870
					   attributes);
871
        if (backend_status == CAIRO_INT_STATUS_SUCCESS)
872
            surface->has_supported = TRUE;
873
    }
874

            
875
    return backend_status;
876
}
877

            
878
static cairo_bool_t
879
_cairo_analysis_surface_supports_color_glyph (void                 *abstract_surface,
880
                                              cairo_scaled_font_t  *scaled_font,
881
                                              unsigned long         glyph_index)
882
{
883
    return TRUE;
884
}
885

            
886
static cairo_int_status_t
887
1604
_cairo_analysis_surface_command_id (void                 *abstract_surface,
888
				    unsigned int          recording_id,
889
				    unsigned int          command_id)
890
{
891
1604
    cairo_analysis_surface_t *surface = abstract_surface;
892
    cairo_int_status_t backend_status;
893

            
894
1604
    backend_status = CAIRO_INT_STATUS_SUCCESS;
895
1604
    if (surface->target->backend->command_id != NULL) {
896
	backend_status =
897
45
	    surface->target->backend->command_id (surface->target,
898
						  recording_id,
899
						  command_id);
900
    }
901

            
902
1604
    return backend_status;
903
}
904

            
905
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
906
    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
907

            
908
    _cairo_analysis_surface_finish,
909
    NULL,
910

            
911
    NULL, /* create_similar */
912
    NULL, /* create_similar_image */
913
    NULL, /* map_to_image */
914
    NULL, /* unmap */
915

            
916
    NULL, /* source */
917
    NULL, /* acquire_source_image */
918
    NULL, /* release_source_image */
919
    NULL, /* snapshot */
920

            
921
    NULL, /* copy_page */
922
    NULL, /* show_page */
923

            
924
    _cairo_analysis_surface_get_extents,
925
    NULL, /* get_font_options */
926

            
927
    NULL, /* flush */
928
    NULL, /* mark_dirty_rectangle */
929

            
930
    _cairo_analysis_surface_paint,
931
    _cairo_analysis_surface_mask,
932
    _cairo_analysis_surface_stroke,
933
    _cairo_analysis_surface_fill,
934
    NULL, /* fill_stroke */
935
    _cairo_analysis_surface_show_glyphs,
936
    _cairo_analysis_surface_has_show_text_glyphs,
937
    _cairo_analysis_surface_show_text_glyphs,
938
    NULL, /* get_supported_mime_types */
939
    _cairo_analysis_surface_tag,
940
    _cairo_analysis_surface_supports_color_glyph,
941
    NULL, /* analyze_recording_surface */
942
    _cairo_analysis_surface_command_id,
943
};
944

            
945
cairo_surface_t *
946
1258
_cairo_analysis_surface_create (cairo_surface_t		*target,
947
				cairo_bool_t             create_region_ids)
948
{
949
    cairo_analysis_surface_t *surface;
950
    cairo_status_t status;
951

            
952
1258
    status = target->status;
953
1258
    if (unlikely (status))
954
	return _cairo_surface_create_in_error (status);
955

            
956
1258
    surface = _cairo_calloc (sizeof (cairo_analysis_surface_t));
957
1258
    if (unlikely (surface == NULL))
958
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
959

            
960
    /* I believe the content type here is truly arbitrary. I'm quite
961
     * sure nothing will ever use this value. */
962
1258
    _cairo_surface_init (&surface->base,
963
			 &cairo_analysis_surface_backend,
964
			 NULL, /* device */
965
			 CAIRO_CONTENT_COLOR_ALPHA,
966
1258
			 target->is_vector);
967

            
968
1258
    cairo_matrix_init_identity (&surface->ctm);
969
1258
    surface->has_ctm = FALSE;
970

            
971
1258
    surface->target = cairo_surface_reference (target);
972
1258
    surface->first_op  = TRUE;
973
1258
    surface->has_supported = FALSE;
974
1258
    surface->has_unsupported = FALSE;
975

            
976
1258
    surface->create_region_ids = create_region_ids;
977
1258
    surface->source_region_id = 0;
978
1258
    surface->mask_region_id = 0;
979

            
980
1258
    _cairo_region_init (&surface->supported_region);
981
1258
    _cairo_region_init (&surface->fallback_region);
982

            
983
1258
    surface->page_bbox.p1.x = 0;
984
1258
    surface->page_bbox.p1.y = 0;
985
1258
    surface->page_bbox.p2.x = 0;
986
1258
    surface->page_bbox.p2.y = 0;
987

            
988
1258
    return &surface->base;
989
}
990

            
991
void
992
1166
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
993
				 const cairo_matrix_t  *ctm)
994
{
995
    cairo_analysis_surface_t	*surface;
996

            
997
1166
    if (abstract_surface->status)
998
	return;
999

            
1166
    surface = (cairo_analysis_surface_t *) abstract_surface;
1166
    surface->ctm = *ctm;
1166
    surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
				 cairo_matrix_t  *ctm)
{
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
    *ctm = surface->ctm;
}
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
    return &surface->supported_region;
}
cairo_region_t *
7
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
{
7
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
7
    return &surface->fallback_region;
}
cairo_bool_t
24
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
{
24
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
24
    return surface->has_supported;
}
cairo_bool_t
29
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
{
29
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
29
    return surface->has_unsupported;
}
void
1081
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
					  cairo_box_t     *bbox)
{
1081
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
1081
    *bbox = surface->page_bbox;
1081
}
unsigned int
135
_cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface)
{
135
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
135
    return surface->source_region_id;
}
unsigned int
_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface)
{
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;
    return surface->mask_region_id;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
143
_paint_return_success (void			*surface,
		       cairo_operator_t		 op,
		       const cairo_pattern_t	*source,
		       const cairo_clip_t	*clip)
{
143
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
140
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
140
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
134
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
9
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
21
_mask_return_success (void			*surface,
		      cairo_operator_t		 op,
		      const cairo_pattern_t	*source,
		      const cairo_pattern_t	*mask,
		      const cairo_clip_t	*clip)
{
21
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
21
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
21
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
6
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
15
    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
15
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
15
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
15
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
672
_stroke_return_success (void				*surface,
			cairo_operator_t		 op,
			const cairo_pattern_t		*source,
			const cairo_path_fixed_t	*path,
			const cairo_stroke_style_t	*style,
			const cairo_matrix_t		*ctm,
			const cairo_matrix_t		*ctm_inverse,
			double				 tolerance,
			cairo_antialias_t		 antialias,
			const cairo_clip_t		*clip)
{
672
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
672
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
585
_fill_return_success (void			*surface,
		      cairo_operator_t		 op,
		      const cairo_pattern_t	*source,
		      const cairo_path_fixed_t	*path,
		      cairo_fill_rule_t		 fill_rule,
		      double			 tolerance,
		      cairo_antialias_t		 antialias,
		      const cairo_clip_t	*clip)
{
585
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
585
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
48
_show_glyphs_return_success (void			*surface,
			     cairo_operator_t		 op,
			     const cairo_pattern_t	*source,
			     cairo_glyph_t		*glyphs,
			     int			 num_glyphs,
			     cairo_scaled_font_t	*scaled_font,
			     const cairo_clip_t		*clip)
{
48
    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
        if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
            return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
    }
48
    return CAIRO_INT_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_null_surface_backend = {
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
    NULL, /* finish */
    NULL, /* only accessed through the surface functions */
    NULL, /* create_similar */
    NULL, /* create similar image */
    NULL, /* map to image */
    NULL, /* unmap image*/
    NULL, /* source */
    NULL, /* acquire_source_image */
    NULL, /* release_source_image */
    NULL, /* snapshot */
    NULL, /* copy_page */
    NULL, /* show_page */
    NULL, /* get_extents */
    NULL, /* get_font_options */
    NULL, /* flush */
    NULL, /* mark_dirty_rectangle */
    _paint_return_success,	    /* paint */
    _mask_return_success,	    /* mask */
    _stroke_return_success,	    /* stroke */
    _fill_return_success,	    /* fill */
    NULL, /* fill_stroke */
    _show_glyphs_return_success,    /* show_glyphs */
    NULL, /* has_show_text_glyphs */
    NULL, /* show_text_glyphs */
    NULL, /* get_supported_mime_types */
    NULL, /* tag */
    NULL, /* supports_color_glyph */
    NULL, /* analyze_recording_surface */
    NULL, /* command_id*/
};
cairo_surface_t *
1076
_cairo_null_surface_create (cairo_content_t content)
{
    cairo_surface_t *surface;
1076
    surface = _cairo_calloc (sizeof (cairo_surface_t));
1076
    if (unlikely (surface == NULL)) {
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    }
1076
    _cairo_surface_init (surface,
			 &cairo_null_surface_backend,
			 NULL, /* device */
			 content,
			 TRUE); /* is_vector */
1076
    return surface;
}