Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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