Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is University of Southern
33
 * California.
34
 *
35
 * Contributor(s):
36
 *	Carl D. Worth 
37
 *      Joonas Pihlaja 
38
 *	Chris Wilson 
39
 */
40
 
41
#include "cairoint.h"
42
 
43
#include "cairo-boxes-private.h"
44
#include "cairo-clip-private.h"
45
#include "cairo-composite-rectangles-private.h"
46
#include "cairo-error-private.h"
47
#include "cairo-region-private.h"
48
#include "cairo-spans-private.h"
49
#include "cairo-surface-fallback-private.h"
50
 
51
typedef struct {
52
    cairo_surface_t *dst;
53
    cairo_rectangle_int_t extents;
54
    cairo_image_surface_t *image;
55
    cairo_rectangle_int_t image_rect;
56
    void *image_extra;
57
} fallback_state_t;
58
 
59
/**
60
 * _fallback_init:
61
 *
62
 * Acquire destination image surface needed for an image-based
63
 * fallback.
64
 *
65
 * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
66
 * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
67
 * went well, or some error status otherwise.
68
 **/
69
static cairo_int_status_t
70
_fallback_init (fallback_state_t *state,
71
		cairo_surface_t  *dst,
72
		int               x,
73
		int               y,
74
		int               width,
75
		int               height)
76
{
77
    cairo_status_t status;
78
 
79
    state->extents.x = x;
80
    state->extents.y = y;
81
    state->extents.width = width;
82
    state->extents.height = height;
83
 
84
    state->dst = dst;
85
 
86
    status = _cairo_surface_acquire_dest_image (dst, &state->extents,
87
						&state->image, &state->image_rect,
88
						&state->image_extra);
89
    if (unlikely (status))
90
	return status;
91
 
92
 
93
    /* XXX: This NULL value tucked away in state->image is a rather
94
     * ugly interface. Cleaner would be to push the
95
     * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
96
     * _cairo_surface_acquire_dest_image and its backend
97
     * counterparts. */
98
    assert (state->image != NULL);
99
 
100
    return CAIRO_STATUS_SUCCESS;
101
}
102
 
103
static void
104
_fallback_fini (fallback_state_t *state)
105
{
106
    _cairo_surface_release_dest_image (state->dst, &state->extents,
107
				       state->image, &state->image_rect,
108
				       state->image_extra);
109
}
110
 
111
typedef cairo_status_t
112
(*cairo_draw_func_t) (void                          *closure,
113
		      cairo_operator_t               op,
114
		      const cairo_pattern_t         *src,
115
		      cairo_surface_t               *dst,
116
		      int                            dst_x,
117
		      int                            dst_y,
118
		      const cairo_rectangle_int_t   *extents,
119
		      cairo_region_t		    *clip_region);
120
 
121
static cairo_status_t
122
_create_composite_mask_pattern (cairo_surface_pattern_t       *mask_pattern,
123
				cairo_clip_t                  *clip,
124
				cairo_draw_func_t              draw_func,
125
				void                          *draw_closure,
126
				cairo_surface_t               *dst,
127
				const cairo_rectangle_int_t   *extents)
128
{
129
    cairo_surface_t *mask;
130
    cairo_region_t *clip_region = NULL, *fallback_region = NULL;
131
    cairo_status_t status;
132
    cairo_bool_t clip_surface = FALSE;
133
 
134
    if (clip != NULL) {
135
	status = _cairo_clip_get_region (clip, &clip_region);
136
	if (unlikely (_cairo_status_is_error (status) ||
137
		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
138
	{
139
	    return status;
140
	}
141
 
142
	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
143
    }
144
 
145
    /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
146
     * a mask (as called via _cairo_surface_mask) triggers assertion failures.
147
     */
148
    mask = _cairo_surface_create_similar_solid (dst,
149
						CAIRO_CONTENT_ALPHA,
150
						extents->width,
151
						extents->height,
152
						CAIRO_COLOR_TRANSPARENT,
153
						TRUE);
154
    if (unlikely (mask->status))
155
	return mask->status;
156
 
157
    if (clip_region && (extents->x || extents->y)) {
158
	fallback_region = cairo_region_copy (clip_region);
159
	status = fallback_region->status;
160
	if (unlikely (status))
161
	    goto CLEANUP_SURFACE;
162
 
163
	cairo_region_translate (fallback_region,
164
				-extents->x,
165
				-extents->y);
166
	clip_region = fallback_region;
167
    }
168
 
169
    status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
170
			&_cairo_pattern_white.base, mask,
171
			extents->x, extents->y,
172
			extents,
173
			clip_region);
174
    if (unlikely (status))
175
	goto CLEANUP_SURFACE;
176
 
177
    if (clip_surface)
178
	status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
179
 
180
    _cairo_pattern_init_for_surface (mask_pattern, mask);
181
 
182
 CLEANUP_SURFACE:
183
    if (fallback_region)
184
        cairo_region_destroy (fallback_region);
185
    cairo_surface_destroy (mask);
186
 
187
    return status;
188
}
189
 
190
/* Handles compositing with a clip surface when the operator allows
191
 * us to combine the clip with the mask
192
 */
193
static cairo_status_t
194
_clip_and_composite_with_mask (cairo_clip_t                  *clip,
195
			       cairo_operator_t               op,
196
			       const cairo_pattern_t         *src,
197
			       cairo_draw_func_t              draw_func,
198
			       void                          *draw_closure,
199
			       cairo_surface_t               *dst,
200
			       const cairo_rectangle_int_t   *extents)
201
{
202
    cairo_surface_pattern_t mask_pattern;
203
    cairo_status_t status;
204
 
205
    status = _create_composite_mask_pattern (&mask_pattern,
206
					     clip,
207
					     draw_func, draw_closure,
208
					     dst, extents);
209
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
210
	status = _cairo_surface_composite (op,
211
					   src, &mask_pattern.base, dst,
212
					   extents->x,     extents->y,
213
					   0,              0,
214
					   extents->x,     extents->y,
215
					   extents->width, extents->height,
216
					   NULL);
217
 
218
	_cairo_pattern_fini (&mask_pattern.base);
219
    }
220
 
221
    return status;
222
}
223
 
224
/* Handles compositing with a clip surface when we have to do the operation
225
 * in two pieces and combine them together.
226
 */
227
static cairo_status_t
228
_clip_and_composite_combine (cairo_clip_t                  *clip,
229
			     cairo_operator_t               op,
230
			     const cairo_pattern_t         *src,
231
			     cairo_draw_func_t              draw_func,
232
			     void                          *draw_closure,
233
			     cairo_surface_t               *dst,
234
			     const cairo_rectangle_int_t   *extents)
235
{
236
    cairo_surface_t *intermediate;
237
    cairo_surface_pattern_t pattern;
238
    cairo_surface_pattern_t clip_pattern;
239
    cairo_surface_t *clip_surface;
240
    int clip_x, clip_y;
241
    cairo_status_t status;
242
 
243
    /* We'd be better off here creating a surface identical in format
244
     * to dst, but we have no way of getting that information. Instead
245
     * we ask the backend to create a similar surface of identical content,
246
     * in the belief that the backend will do something useful - like use
247
     * an identical format. For example, the xlib backend will endeavor to
248
     * use a compatible depth to enable core protocol routines.
249
     */
250
    intermediate =
251
	_cairo_surface_create_similar_scratch (dst, dst->content,
252
					       extents->width,
253
					       extents->height);
254
    if (intermediate == NULL) {
255
	intermediate =
256
	    _cairo_image_surface_create_with_content (dst->content,
257
						      extents->width,
258
						      extents->width);
259
    }
260
    if (unlikely (intermediate->status))
261
	return intermediate->status;
262
 
263
    /* Initialize the intermediate surface from the destination surface */
264
    _cairo_pattern_init_for_surface (&pattern, dst);
265
    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
266
				       &pattern.base, NULL, intermediate,
267
				       extents->x,     extents->y,
268
				       0,              0,
269
				       0,              0,
270
				       extents->width, extents->height,
271
				       NULL);
272
    _cairo_pattern_fini (&pattern.base);
273
    if (unlikely (status))
274
	goto CLEANUP_SURFACE;
275
 
276
    status = (*draw_func) (draw_closure, op,
277
			   src, intermediate,
278
			   extents->x, extents->y,
279
			   extents,
280
			   NULL);
281
    if (unlikely (status))
282
	goto CLEANUP_SURFACE;
283
 
284
    assert (clip->path != NULL);
285
    clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
286
    if (unlikely (clip_surface->status))
287
	goto CLEANUP_SURFACE;
288
 
289
    _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
290
 
291
    /* Combine that with the clip */
292
    status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
293
				       &clip_pattern.base, NULL, intermediate,
294
				       extents->x - clip_x,
295
				       extents->y - clip_y,
296
				       0, 0,
297
				       0, 0,
298
				       extents->width, extents->height,
299
				       NULL);
300
    if (unlikely (status))
301
	goto CLEANUP_CLIP;
302
 
303
    /* Punch the clip out of the destination */
304
    status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
305
				       &clip_pattern.base, NULL, dst,
306
				       extents->x - clip_x,
307
				       extents->y - clip_y,
308
				       0, 0,
309
				       extents->x, extents->y,
310
				       extents->width, extents->height,
311
				       NULL);
312
    if (unlikely (status))
313
	goto CLEANUP_CLIP;
314
 
315
    /* Now add the two results together */
316
    _cairo_pattern_init_for_surface (&pattern, intermediate);
317
    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
318
				       &pattern.base, NULL, dst,
319
				       0,              0,
320
				       0,              0,
321
				       extents->x,     extents->y,
322
				       extents->width, extents->height,
323
				       NULL);
324
    _cairo_pattern_fini (&pattern.base);
325
 
326
 CLEANUP_CLIP:
327
    _cairo_pattern_fini (&clip_pattern.base);
328
 CLEANUP_SURFACE:
329
    cairo_surface_destroy (intermediate);
330
 
331
    return status;
332
}
333
 
334
/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
335
 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
336
 */
337
static cairo_status_t
338
_clip_and_composite_source (cairo_clip_t                  *clip,
339
			    const cairo_pattern_t         *src,
340
			    cairo_draw_func_t              draw_func,
341
			    void                          *draw_closure,
342
			    cairo_surface_t               *dst,
343
			    const cairo_rectangle_int_t   *extents)
344
{
345
    cairo_surface_pattern_t mask_pattern;
346
    cairo_region_t *clip_region = NULL;
347
    cairo_status_t status;
348
 
349
    if (clip != NULL) {
350
	status = _cairo_clip_get_region (clip, &clip_region);
351
	if (unlikely (_cairo_status_is_error (status) ||
352
		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
353
	{
354
	    return status;
355
	}
356
    }
357
 
358
    /* Create a surface that is mask IN clip */
359
    status = _create_composite_mask_pattern (&mask_pattern,
360
					     clip,
361
					     draw_func, draw_closure,
362
					     dst, extents);
363
    if (unlikely (status))
364
	return status;
365
 
366
    /* Compute dest' = dest OUT (mask IN clip) */
367
    status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
368
				       &mask_pattern.base, NULL, dst,
369
				       0,              0,
370
				       0,              0,
371
				       extents->x,     extents->y,
372
				       extents->width, extents->height,
373
				       clip_region);
374
 
375
    if (unlikely (status))
376
	goto CLEANUP_MASK_PATTERN;
377
 
378
    /* Now compute (src IN (mask IN clip)) ADD dest' */
379
    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
380
				       src, &mask_pattern.base, dst,
381
				       extents->x,     extents->y,
382
				       0,              0,
383
				       extents->x,     extents->y,
384
				       extents->width, extents->height,
385
				       clip_region);
386
 
387
 CLEANUP_MASK_PATTERN:
388
    _cairo_pattern_fini (&mask_pattern.base);
389
    return status;
390
}
391
 
392
static int
393
_cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
394
{
395
    return rect->width == 0 || rect->height == 0;
396
}
397
 
398
/**
399
 * _clip_and_composite:
400
 * @clip: a #cairo_clip_t
401
 * @op: the operator to draw with
402
 * @src: source pattern
403
 * @draw_func: function that can be called to draw with the mask onto a surface.
404
 * @draw_closure: data to pass to @draw_func.
405
 * @dst: destination surface
406
 * @extents: rectangle holding a bounding box for the operation; this
407
 *           rectangle will be used as the size for the temporary
408
 *           surface.
409
 *
410
 * When there is a surface clip, we typically need to create an intermediate
411
 * surface. This function handles the logic of creating a temporary surface
412
 * drawing to it, then compositing the result onto the target surface.
413
 *
414
 * @draw_func is to called to draw the mask; it will be called no more
415
 * than once.
416
 *
417
 * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
418
 **/
419
static cairo_status_t
420
_clip_and_composite (cairo_clip_t                  *clip,
421
		     cairo_operator_t               op,
422
		     const cairo_pattern_t         *src,
423
		     cairo_draw_func_t              draw_func,
424
		     void                          *draw_closure,
425
		     cairo_surface_t               *dst,
426
		     const cairo_rectangle_int_t   *extents)
427
{
428
    cairo_status_t status;
429
 
430
    if (_cairo_rectangle_empty (extents))
431
	/* Nothing to do */
432
	return CAIRO_STATUS_SUCCESS;
433
 
434
    if (op == CAIRO_OPERATOR_CLEAR) {
435
	src = &_cairo_pattern_white.base;
436
	op = CAIRO_OPERATOR_DEST_OUT;
437
    }
438
 
439
    if (op == CAIRO_OPERATOR_SOURCE) {
440
	status = _clip_and_composite_source (clip,
441
					     src,
442
					     draw_func, draw_closure,
443
					     dst, extents);
444
    } else {
445
	cairo_bool_t clip_surface = FALSE;
446
	cairo_region_t *clip_region = NULL;
447
 
448
	if (clip != NULL) {
449
	    status = _cairo_clip_get_region (clip, &clip_region);
450
	    if (unlikely (_cairo_status_is_error (status) ||
451
			  status == CAIRO_INT_STATUS_NOTHING_TO_DO))
452
	    {
453
		return status;
454
	    }
455
 
456
	    clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
457
	}
458
 
459
	if (clip_surface) {
460
	    if (_cairo_operator_bounded_by_mask (op)) {
461
		status = _clip_and_composite_with_mask (clip, op,
462
							src,
463
							draw_func, draw_closure,
464
							dst, extents);
465
	    } else {
466
		status = _clip_and_composite_combine (clip, op,
467
						      src,
468
						      draw_func, draw_closure,
469
						      dst, extents);
470
	    }
471
	} else {
472
	    status = draw_func (draw_closure, op,
473
				src, dst,
474
				0, 0,
475
				extents,
476
				clip_region);
477
	}
478
    }
479
 
480
    return status;
481
}
482
 
483
/* Composites a region representing a set of trapezoids.
484
 */
485
static cairo_status_t
486
_composite_trap_region (cairo_clip_t            *clip,
487
			const cairo_pattern_t	*src,
488
			cairo_operator_t         op,
489
			cairo_surface_t         *dst,
490
			cairo_region_t          *trap_region,
491
			const cairo_rectangle_int_t   *extents)
492
{
493
    cairo_status_t status;
494
    cairo_surface_pattern_t mask_pattern;
495
    cairo_pattern_t *mask = NULL;
496
    int mask_x = 0, mask_y =0;
497
 
498
    if (clip != NULL) {
499
	cairo_surface_t *clip_surface = NULL;
500
	int clip_x, clip_y;
501
 
502
	clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
503
	if (unlikely (clip_surface->status))
504
	    return clip_surface->status;
505
 
506
	if (op == CAIRO_OPERATOR_CLEAR) {
507
	    src = &_cairo_pattern_white.base;
508
	    op = CAIRO_OPERATOR_DEST_OUT;
509
	}
510
 
511
	_cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
512
	mask_x = extents->x - clip_x;
513
	mask_y = extents->y - clip_y;
514
	mask = &mask_pattern.base;
515
    }
516
 
517
    status = _cairo_surface_composite (op, src, mask, dst,
518
				       extents->x, extents->y,
519
				       mask_x, mask_y,
520
				       extents->x, extents->y,
521
				       extents->width, extents->height,
522
				       trap_region);
523
 
524
    if (mask != NULL)
525
      _cairo_pattern_fini (mask);
526
 
527
    return status;
528
}
529
 
530
typedef struct {
531
    cairo_traps_t *traps;
532
    cairo_antialias_t antialias;
533
} cairo_composite_traps_info_t;
534
 
535
static cairo_status_t
536
_composite_traps_draw_func (void                          *closure,
537
			    cairo_operator_t               op,
538
			    const cairo_pattern_t         *src,
539
			    cairo_surface_t               *dst,
540
			    int                            dst_x,
541
			    int                            dst_y,
542
			    const cairo_rectangle_int_t   *extents,
543
			    cairo_region_t		  *clip_region)
544
{
545
    cairo_composite_traps_info_t *info = closure;
546
    cairo_status_t status;
547
    cairo_region_t *extents_region = NULL;
548
 
549
    if (dst_x != 0 || dst_y != 0)
550
	_cairo_traps_translate (info->traps, - dst_x, - dst_y);
551
 
552
    if (clip_region == NULL &&
553
        !_cairo_operator_bounded_by_source (op)) {
554
        extents_region = cairo_region_create_rectangle (extents);
555
        if (unlikely (extents_region->status))
556
            return extents_region->status;
557
        cairo_region_translate (extents_region, -dst_x, -dst_y);
558
        clip_region = extents_region;
559
    }
560
 
561
    status = _cairo_surface_composite_trapezoids (op,
562
                                                  src, dst, info->antialias,
563
                                                  extents->x,         extents->y,
564
                                                  extents->x - dst_x, extents->y - dst_y,
565
                                                  extents->width,     extents->height,
566
                                                  info->traps->traps,
567
                                                  info->traps->num_traps,
568
                                                  clip_region);
569
 
570
    if (extents_region)
571
        cairo_region_destroy (extents_region);
572
 
573
    return status;
574
}
575
 
576
enum {
577
    HAS_CLEAR_REGION = 0x1,
578
};
579
 
580
static cairo_status_t
581
_clip_and_composite_region (const cairo_pattern_t *src,
582
			    cairo_operator_t op,
583
			    cairo_surface_t *dst,
584
			    cairo_region_t *trap_region,
585
			    cairo_clip_t *clip,
586
			    cairo_rectangle_int_t *extents)
587
{
588
    cairo_region_t clear_region;
589
    unsigned int has_region = 0;
590
    cairo_status_t status;
591
 
592
    if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
593
	/* If we optimize drawing with an unbounded operator to
594
	 * _cairo_surface_fill_rectangles() or to drawing with a
595
	 * clip region, then we have an additional region to clear.
596
	 */
597
	_cairo_region_init_rectangle (&clear_region, extents);
598
	status = cairo_region_subtract (&clear_region, trap_region);
599
	if (unlikely (status))
600
	    return status;
601
 
602
	if (! cairo_region_is_empty (&clear_region))
603
	    has_region |= HAS_CLEAR_REGION;
604
    }
605
 
606
    if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
607
	clip == NULL)
608
    {
609
	const cairo_color_t *color;
610
 
611
	if (op == CAIRO_OPERATOR_CLEAR)
612
	    color = CAIRO_COLOR_TRANSPARENT;
613
	else
614
	    color = &((cairo_solid_pattern_t *)src)->color;
615
 
616
	/* Solid rectangles special case */
617
	status = _cairo_surface_fill_region (dst, op, color, trap_region);
618
    } else {
619
	/* For a simple rectangle, we can just use composite(), for more
620
	 * rectangles, we have to set a clip region. The cost of rasterizing
621
	 * trapezoids is pretty high for most backends currently, so it's
622
	 * worthwhile even if a region is needed.
623
	 *
624
	 * If we have a clip surface, we set it as the mask; this only works
625
	 * for bounded operators other than SOURCE; for unbounded operators,
626
	 * clip and mask cannot be interchanged. For SOURCE, the operator
627
	 * as implemented by the backends is different in its handling
628
	 * of the mask then what we want.
629
	 *
630
	 * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
631
	 * more than rectangle and the destination doesn't support clip
632
	 * regions. In that case, we fall through.
633
	 */
634
	status = _composite_trap_region (clip, src, op, dst,
635
					 trap_region, extents);
636
    }
637
 
638
    if (has_region & HAS_CLEAR_REGION) {
639
	if (status == CAIRO_STATUS_SUCCESS) {
640
	    status = _cairo_surface_fill_region (dst,
641
						 CAIRO_OPERATOR_CLEAR,
642
						 CAIRO_COLOR_TRANSPARENT,
643
						 &clear_region);
644
	}
645
	_cairo_region_fini (&clear_region);
646
    }
647
 
648
    return status;
649
}
650
 
651
/* avoid using region code to re-validate boxes */
652
static cairo_status_t
653
_fill_rectangles (cairo_surface_t *dst,
654
		  cairo_operator_t op,
655
		  const cairo_pattern_t *src,
656
		  cairo_traps_t *traps,
657
		  cairo_clip_t *clip)
658
{
659
    const cairo_color_t *color;
660
    cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
661
    cairo_rectangle_int_t *rects = stack_rects;
662
    cairo_status_t status;
663
    int i;
664
 
665
    if (! traps->is_rectilinear || ! traps->maybe_region)
666
	return CAIRO_INT_STATUS_UNSUPPORTED;
667
 
668
    /* XXX: convert clip region to geometric boxes? */
669
    if (clip != NULL)
670
	return CAIRO_INT_STATUS_UNSUPPORTED;
671
 
672
    /* XXX: fallback for the region_subtract() operation */
673
    if (! _cairo_operator_bounded_by_mask (op))
674
	return CAIRO_INT_STATUS_UNSUPPORTED;
675
 
676
    if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
677
	return CAIRO_INT_STATUS_UNSUPPORTED;
678
 
679
    if (traps->has_intersections) {
680
	if (traps->is_rectangular) {
681
	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
682
	} else {
683
	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
684
	}
685
	if (unlikely (status))
686
	    return status;
687
    }
688
 
689
    for (i = 0; i < traps->num_traps; i++) {
690
	if (! _cairo_fixed_is_integer (traps->traps[i].top)          ||
691
	    ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
692
	    ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
693
	    ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
694
	{
695
	    traps->maybe_region = FALSE;
696
	    return CAIRO_INT_STATUS_UNSUPPORTED;
697
	}
698
    }
699
 
700
    if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
701
	rects = _cairo_malloc_ab (traps->num_traps,
702
				  sizeof (cairo_rectangle_int_t));
703
	if (unlikely (rects == NULL))
704
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
705
    }
706
 
707
    for (i = 0; i < traps->num_traps; i++) {
708
	int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
709
	int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
710
	int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
711
	int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
712
 
713
	rects[i].x = x1;
714
	rects[i].y = y1;
715
	rects[i].width = x2 - x1;
716
	rects[i].height = y2 - y1;
717
    }
718
 
719
    if (op == CAIRO_OPERATOR_CLEAR)
720
	color = CAIRO_COLOR_TRANSPARENT;
721
    else
722
	color = &((cairo_solid_pattern_t *)src)->color;
723
 
724
    status =  _cairo_surface_fill_rectangles (dst, op, color, rects, i);
725
 
726
    if (rects != stack_rects)
727
	free (rects);
728
 
729
    return status;
730
}
731
 
732
/* fast-path for very common composite of a single rectangle */
733
static cairo_status_t
734
_composite_rectangle (cairo_surface_t *dst,
735
		      cairo_operator_t op,
736
		      const cairo_pattern_t *src,
737
		      cairo_traps_t *traps,
738
		      cairo_clip_t *clip)
739
{
740
    cairo_rectangle_int_t rect;
741
 
742
    if (clip != NULL)
743
	return CAIRO_INT_STATUS_UNSUPPORTED;
744
 
745
    if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
746
	return CAIRO_INT_STATUS_UNSUPPORTED;
747
 
748
    if (! _cairo_fixed_is_integer (traps->traps[0].top)          ||
749
	! _cairo_fixed_is_integer (traps->traps[0].bottom)       ||
750
	! _cairo_fixed_is_integer (traps->traps[0].left.p1.x)    ||
751
	! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
752
    {
753
	traps->maybe_region = FALSE;
754
	return CAIRO_INT_STATUS_UNSUPPORTED;
755
    }
756
 
757
    rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
758
    rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
759
    rect.width  = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
760
    rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
761
 
762
    return _cairo_surface_composite (op, src, NULL, dst,
763
				     rect.x, rect.y,
764
				     0, 0,
765
				     rect.x, rect.y,
766
				     rect.width, rect.height,
767
				     NULL);
768
}
769
 
770
/* Warning: This call modifies the coordinates of traps */
771
static cairo_status_t
772
_clip_and_composite_trapezoids (const cairo_pattern_t *src,
773
				cairo_operator_t op,
774
				cairo_surface_t *dst,
775
				cairo_traps_t *traps,
776
				cairo_antialias_t antialias,
777
				cairo_clip_t *clip,
778
				cairo_rectangle_int_t *extents)
779
{
780
    cairo_composite_traps_info_t traps_info;
781
    cairo_region_t *clip_region = NULL;
782
    cairo_bool_t clip_surface = FALSE;
783
    cairo_status_t status;
784
 
785
    if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
786
	return CAIRO_STATUS_SUCCESS;
787
 
788
    if (clip != NULL) {
789
	status = _cairo_clip_get_region (clip, &clip_region);
790
	if (unlikely (_cairo_status_is_error (status)))
791
	    return status;
792
	if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
793
	    return CAIRO_STATUS_SUCCESS;
794
 
795
	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
796
    }
797
 
798
    /* Use a fast path if the trapezoids consist of a simple region,
799
     * but we can only do this if we do not have a clip surface, or can
800
     * substitute the mask with the clip.
801
     */
802
    if (! clip_surface ||
803
	(_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
804
    {
805
	cairo_region_t *trap_region = NULL;
806
 
807
        if (_cairo_operator_bounded_by_source (op)) {
808
            status = _fill_rectangles (dst, op, src, traps, clip);
809
            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
810
                return status;
811
 
812
            status = _composite_rectangle (dst, op, src, traps, clip);
813
            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
814
                return status;
815
        }
816
 
817
	status = _cairo_traps_extract_region (traps, &trap_region);
818
	if (unlikely (_cairo_status_is_error (status)))
819
	    return status;
820
 
821
	if (trap_region != NULL) {
822
	    status = cairo_region_intersect_rectangle (trap_region, extents);
823
	    if (unlikely (status)) {
824
		cairo_region_destroy (trap_region);
825
		return status;
826
	    }
827
 
828
	    if (clip_region != NULL) {
829
		status = cairo_region_intersect (trap_region, clip_region);
830
		if (unlikely (status)) {
831
		    cairo_region_destroy (trap_region);
832
		    return status;
833
		}
834
	    }
835
 
836
	    if (_cairo_operator_bounded_by_mask (op)) {
837
		cairo_rectangle_int_t trap_extents;
838
 
839
		cairo_region_get_extents (trap_region, &trap_extents);
840
		if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
841
		    cairo_region_destroy (trap_region);
842
		    return CAIRO_STATUS_SUCCESS;
843
		}
844
	    }
845
 
846
	    status = _clip_and_composite_region (src, op, dst,
847
						 trap_region,
848
						 clip_surface ? clip : NULL,
849
						 extents);
850
	    cairo_region_destroy (trap_region);
851
 
852
	    if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
853
		return status;
854
	}
855
    }
856
 
857
    /* No fast path, exclude self-intersections and clip trapezoids. */
858
    if (traps->has_intersections) {
859
	if (traps->is_rectangular)
860
	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
861
	else if (traps->is_rectilinear)
862
	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
863
	else
864
	    status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
865
	if (unlikely (status))
866
	    return status;
867
    }
868
 
869
    /* Otherwise render the trapezoids to a mask and composite in the usual
870
     * fashion.
871
     */
872
    traps_info.traps = traps;
873
    traps_info.antialias = antialias;
874
 
875
    return _clip_and_composite (clip, op, src,
876
				_composite_traps_draw_func,
877
				&traps_info, dst, extents);
878
}
879
 
880
cairo_status_t
881
_cairo_surface_fallback_paint (cairo_surface_t		*surface,
882
			       cairo_operator_t		 op,
883
			       const cairo_pattern_t	*source,
884
			       cairo_clip_t		*clip)
885
{
886
    cairo_composite_rectangles_t extents;
887
    cairo_rectangle_int_t rect;
888
    cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
889
    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
890
    cairo_boxes_t  boxes;
891
    int num_boxes = ARRAY_LENGTH (boxes_stack);
892
    cairo_status_t status;
893
    cairo_traps_t traps;
894
 
895
    if (!_cairo_surface_get_extents (surface, &rect))
896
        ASSERT_NOT_REACHED;
897
 
898
    status = _cairo_composite_rectangles_init_for_paint (&extents,
899
							 rect.width,
900
							 rect.height,
901
							 op, source,
902
							 clip);
903
    if (unlikely (status))
904
	return status;
905
 
906
    if (_cairo_clip_contains_extents (clip, &extents))
907
	clip = NULL;
908
 
909
    status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
910
    if (unlikely (status))
911
	return status;
912
 
913
    /* If the clip cannot be reduced to a set of boxes, we will need to
914
     * use a clipmask. Paint is special as it is the only operation that
915
     * does not implicitly use a mask, so we may be able to reduce this
916
     * operation to a fill...
917
     */
918
    if (clip != NULL && clip_path->prev == NULL &&
919
	_cairo_operator_bounded_by_mask (op))
920
    {
921
	return _cairo_surface_fill (surface, op, source,
922
				    &clip_path->path,
923
				    clip_path->fill_rule,
924
				    clip_path->tolerance,
925
				    clip_path->antialias,
926
				    NULL);
927
    }
928
 
929
    /* meh, surface-fallback is dying anyway... */
930
    _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
931
    status = _cairo_traps_init_boxes (&traps, &boxes);
932
    if (unlikely (status))
933
	goto CLEANUP_BOXES;
934
 
935
    status = _clip_and_composite_trapezoids (source, op, surface,
936
					     &traps, CAIRO_ANTIALIAS_DEFAULT,
937
					     clip,
938
                                             extents.is_bounded ? &extents.bounded : &extents.unbounded);
939
    _cairo_traps_fini (&traps);
940
 
941
CLEANUP_BOXES:
942
    if (clip_boxes != boxes_stack)
943
	free (clip_boxes);
944
 
945
    return status;
946
}
947
 
948
static cairo_status_t
949
_cairo_surface_mask_draw_func (void                        *closure,
950
			       cairo_operator_t             op,
951
			       const cairo_pattern_t       *src,
952
			       cairo_surface_t             *dst,
953
			       int                          dst_x,
954
			       int                          dst_y,
955
			       const cairo_rectangle_int_t *extents,
956
			       cairo_region_t		   *clip_region)
957
{
958
    cairo_pattern_t *mask = closure;
959
    cairo_status_t status;
960
    cairo_region_t *extents_region = NULL;
961
 
962
    if (clip_region == NULL &&
963
        !_cairo_operator_bounded_by_source (op)) {
964
        extents_region = cairo_region_create_rectangle (extents);
965
        if (unlikely (extents_region->status))
966
            return extents_region->status;
967
        cairo_region_translate (extents_region, -dst_x, -dst_y);
968
        clip_region = extents_region;
969
    }
970
 
971
    if (src) {
972
	status = _cairo_surface_composite (op,
973
                                           src, mask, dst,
974
                                           extents->x,         extents->y,
975
                                           extents->x,         extents->y,
976
                                           extents->x - dst_x, extents->y - dst_y,
977
                                           extents->width,     extents->height,
978
                                           clip_region);
979
    } else {
980
	status = _cairo_surface_composite (op,
981
                                           mask, NULL, dst,
982
                                           extents->x,         extents->y,
983
                                           0,                  0, /* unused */
984
                                           extents->x - dst_x, extents->y - dst_y,
985
                                           extents->width,     extents->height,
986
                                           clip_region);
987
    }
988
 
989
    if (extents_region)
990
        cairo_region_destroy (extents_region);
991
 
992
    return status;
993
}
994
 
995
cairo_status_t
996
_cairo_surface_fallback_mask (cairo_surface_t		*surface,
997
			      cairo_operator_t		 op,
998
			      const cairo_pattern_t	*source,
999
			      const cairo_pattern_t	*mask,
1000
			      cairo_clip_t		*clip)
1001
{
1002
    cairo_composite_rectangles_t extents;
1003
    cairo_rectangle_int_t rect;
1004
    cairo_status_t status;
1005
 
1006
    if (!_cairo_surface_get_extents (surface, &rect))
1007
        ASSERT_NOT_REACHED;
1008
 
1009
    status = _cairo_composite_rectangles_init_for_mask (&extents,
1010
							rect.width, rect.height,
1011
							op, source, mask, clip);
1012
    if (unlikely (status))
1013
	return status;
1014
 
1015
    if (_cairo_clip_contains_extents (clip, &extents))
1016
	clip = NULL;
1017
 
1018
    if (clip != NULL && extents.is_bounded) {
1019
	status = _cairo_clip_rectangle (clip, &extents.bounded);
1020
	if (unlikely (status))
1021
	    return status;
1022
    }
1023
 
1024
    return _clip_and_composite (clip, op, source,
1025
				_cairo_surface_mask_draw_func,
1026
				(void *) mask,
1027
				surface,
1028
                                extents.is_bounded ? &extents.bounded : &extents.unbounded);
1029
}
1030
 
1031
cairo_status_t
1032
_cairo_surface_fallback_stroke (cairo_surface_t		*surface,
1033
				cairo_operator_t	 op,
1034
				const cairo_pattern_t	*source,
1035
				cairo_path_fixed_t	*path,
1036
				const cairo_stroke_style_t	*stroke_style,
1037
				const cairo_matrix_t		*ctm,
1038
				const cairo_matrix_t		*ctm_inverse,
1039
				double			 tolerance,
1040
				cairo_antialias_t	 antialias,
1041
				cairo_clip_t		*clip)
1042
{
1043
    cairo_polygon_t polygon;
1044
    cairo_traps_t traps;
1045
    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1046
    int num_boxes = ARRAY_LENGTH (boxes_stack);
1047
    cairo_composite_rectangles_t extents;
1048
    cairo_rectangle_int_t rect;
1049
    cairo_status_t status;
1050
 
1051
    if (!_cairo_surface_get_extents (surface, &rect))
1052
        ASSERT_NOT_REACHED;
1053
 
1054
    status = _cairo_composite_rectangles_init_for_stroke (&extents,
1055
							  rect.width,
1056
							  rect.height,
1057
							  op, source,
1058
							  path, stroke_style, ctm,
1059
							  clip);
1060
    if (unlikely (status))
1061
	return status;
1062
 
1063
    if (_cairo_clip_contains_extents (clip, &extents))
1064
	clip = NULL;
1065
 
1066
    status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1067
    if (unlikely (status))
1068
	return status;
1069
 
1070
    _cairo_polygon_init (&polygon);
1071
    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1072
 
1073
    _cairo_traps_init (&traps);
1074
    _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1075
 
1076
    if (path->is_rectilinear) {
1077
	status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
1078
								stroke_style,
1079
								ctm,
1080
								&traps);
1081
	if (likely (status == CAIRO_STATUS_SUCCESS))
1082
	    goto DO_TRAPS;
1083
 
1084
	if (_cairo_status_is_error (status))
1085
	    goto CLEANUP;
1086
    }
1087
 
1088
    status = _cairo_path_fixed_stroke_to_polygon (path,
1089
						  stroke_style,
1090
						  ctm, ctm_inverse,
1091
						  tolerance,
1092
						  &polygon);
1093
    if (unlikely (status))
1094
	goto CLEANUP;
1095
 
1096
    if (polygon.num_edges == 0)
1097
	goto DO_TRAPS;
1098
 
1099
    if (_cairo_operator_bounded_by_mask (op)) {
1100
	_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1101
	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1102
	    goto CLEANUP;
1103
    }
1104
 
1105
    /* Fall back to trapezoid fills. */
1106
    status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1107
							&polygon,
1108
							CAIRO_FILL_RULE_WINDING);
1109
    if (unlikely (status))
1110
	goto CLEANUP;
1111
 
1112
  DO_TRAPS:
1113
    status = _clip_and_composite_trapezoids (source, op, surface,
1114
					     &traps, antialias,
1115
					     clip,
1116
                                             extents.is_bounded ? &extents.bounded : &extents.unbounded);
1117
  CLEANUP:
1118
    _cairo_traps_fini (&traps);
1119
    _cairo_polygon_fini (&polygon);
1120
    if (clip_boxes != boxes_stack)
1121
	free (clip_boxes);
1122
 
1123
    return status;
1124
}
1125
 
1126
cairo_status_t
1127
_cairo_surface_fallback_fill (cairo_surface_t		*surface,
1128
			      cairo_operator_t		 op,
1129
			      const cairo_pattern_t	*source,
1130
			      cairo_path_fixed_t	*path,
1131
			      cairo_fill_rule_t		 fill_rule,
1132
			      double			 tolerance,
1133
			      cairo_antialias_t		 antialias,
1134
			      cairo_clip_t		*clip)
1135
{
1136
    cairo_polygon_t polygon;
1137
    cairo_traps_t traps;
1138
    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1139
    int num_boxes = ARRAY_LENGTH (boxes_stack);
1140
    cairo_bool_t is_rectilinear;
1141
    cairo_composite_rectangles_t extents;
1142
    cairo_rectangle_int_t rect;
1143
    cairo_status_t status;
1144
 
1145
    if (!_cairo_surface_get_extents (surface, &rect))
1146
        ASSERT_NOT_REACHED;
1147
 
1148
    status = _cairo_composite_rectangles_init_for_fill (&extents,
1149
							rect.width,
1150
							rect.height,
1151
							op, source, path,
1152
							clip);
1153
    if (unlikely (status))
1154
	return status;
1155
 
1156
    if (_cairo_clip_contains_extents (clip, &extents))
1157
	clip = NULL;
1158
 
1159
    status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1160
    if (unlikely (status))
1161
	return status;
1162
 
1163
    _cairo_traps_init (&traps);
1164
    _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1165
 
1166
    _cairo_polygon_init (&polygon);
1167
    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1168
 
1169
    if (path->is_empty_fill)
1170
	goto DO_TRAPS;
1171
 
1172
    is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path);
1173
    if (is_rectilinear) {
1174
	status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
1175
							      fill_rule,
1176
							      &traps);
1177
	if (likely (status == CAIRO_STATUS_SUCCESS))
1178
	    goto DO_TRAPS;
1179
 
1180
	if (_cairo_status_is_error (status))
1181
	    goto CLEANUP;
1182
    }
1183
 
1184
    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1185
    if (unlikely (status))
1186
	goto CLEANUP;
1187
 
1188
    if (polygon.num_edges == 0)
1189
	goto DO_TRAPS;
1190
 
1191
    if (_cairo_operator_bounded_by_mask (op)) {
1192
	_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1193
	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1194
	    goto CLEANUP;
1195
    }
1196
 
1197
    if (is_rectilinear) {
1198
	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
1199
									&polygon,
1200
									fill_rule);
1201
	if (likely (status == CAIRO_STATUS_SUCCESS))
1202
	    goto DO_TRAPS;
1203
 
1204
	if (unlikely (_cairo_status_is_error (status)))
1205
	    goto CLEANUP;
1206
    }
1207
 
1208
    /* Fall back to trapezoid fills. */
1209
    status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1210
							&polygon,
1211
							fill_rule);
1212
    if (unlikely (status))
1213
	goto CLEANUP;
1214
 
1215
  DO_TRAPS:
1216
    status = _clip_and_composite_trapezoids (source, op, surface,
1217
					     &traps, antialias,
1218
					     clip,
1219
                                             extents.is_bounded ? &extents.bounded : &extents.unbounded);
1220
  CLEANUP:
1221
    _cairo_traps_fini (&traps);
1222
    _cairo_polygon_fini (&polygon);
1223
    if (clip_boxes != boxes_stack)
1224
	free (clip_boxes);
1225
 
1226
    return status;
1227
}
1228
 
1229
typedef struct {
1230
    cairo_scaled_font_t *font;
1231
    cairo_glyph_t *glyphs;
1232
    int num_glyphs;
1233
} cairo_show_glyphs_info_t;
1234
 
1235
static cairo_status_t
1236
_cairo_surface_old_show_glyphs_draw_func (void                          *closure,
1237
					  cairo_operator_t               op,
1238
					  const cairo_pattern_t         *src,
1239
					  cairo_surface_t               *dst,
1240
					  int                            dst_x,
1241
					  int                            dst_y,
1242
					  const cairo_rectangle_int_t	*extents,
1243
					  cairo_region_t		*clip_region)
1244
{
1245
    cairo_show_glyphs_info_t *glyph_info = closure;
1246
    cairo_status_t status;
1247
    cairo_region_t *extents_region = NULL;
1248
 
1249
    if (clip_region == NULL &&
1250
        !_cairo_operator_bounded_by_source (op)) {
1251
        extents_region = cairo_region_create_rectangle (extents);
1252
        if (unlikely (extents_region->status))
1253
            return extents_region->status;
1254
        cairo_region_translate (extents_region, -dst_x, -dst_y);
1255
        clip_region = extents_region;
1256
    }
1257
 
1258
    /* Modifying the glyph array is fine because we know that this function
1259
     * will be called only once, and we've already made a copy of the
1260
     * glyphs in the wrapper.
1261
     */
1262
    if (dst_x != 0 || dst_y != 0) {
1263
	int i;
1264
 
1265
	for (i = 0; i < glyph_info->num_glyphs; ++i) {
1266
	    ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
1267
	    ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
1268
	}
1269
    }
1270
 
1271
    status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
1272
					     dst,
1273
					     extents->x, extents->y,
1274
					     extents->x - dst_x,
1275
					     extents->y - dst_y,
1276
					     extents->width,
1277
					     extents->height,
1278
					     glyph_info->glyphs,
1279
					     glyph_info->num_glyphs,
1280
					     clip_region);
1281
 
1282
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1283
	status = _cairo_scaled_font_show_glyphs (glyph_info->font,
1284
                                                 op,
1285
                                                 src, dst,
1286
                                                 extents->x,         extents->y,
1287
                                                 extents->x - dst_x,
1288
                                                 extents->y - dst_y,
1289
                                                 extents->width,     extents->height,
1290
                                                 glyph_info->glyphs,
1291
                                                 glyph_info->num_glyphs,
1292
                                                 clip_region);
1293
    }
1294
 
1295
    if (extents_region)
1296
        cairo_region_destroy (extents_region);
1297
 
1298
    return status;
1299
}
1300
 
1301
cairo_status_t
1302
_cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
1303
				     cairo_operator_t		 op,
1304
				     const cairo_pattern_t	*source,
1305
				     cairo_glyph_t		*glyphs,
1306
				     int			 num_glyphs,
1307
				     cairo_scaled_font_t	*scaled_font,
1308
				     cairo_clip_t		*clip)
1309
{
1310
    cairo_show_glyphs_info_t glyph_info;
1311
    cairo_composite_rectangles_t extents;
1312
    cairo_rectangle_int_t rect;
1313
    cairo_status_t status;
1314
 
1315
    if (!_cairo_surface_get_extents (surface, &rect))
1316
        ASSERT_NOT_REACHED;
1317
 
1318
    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
1319
							  rect.width,
1320
							  rect.height,
1321
							  op, source,
1322
							  scaled_font,
1323
							  glyphs, num_glyphs,
1324
							  clip,
1325
							  NULL);
1326
    if (unlikely (status))
1327
	return status;
1328
 
1329
    if (_cairo_clip_contains_rectangle (clip, &extents.mask))
1330
	clip = NULL;
1331
 
1332
    if (clip != NULL && extents.is_bounded) {
1333
	status = _cairo_clip_rectangle (clip, &extents.bounded);
1334
	if (unlikely (status))
1335
	    return status;
1336
    }
1337
 
1338
    glyph_info.font = scaled_font;
1339
    glyph_info.glyphs = glyphs;
1340
    glyph_info.num_glyphs = num_glyphs;
1341
 
1342
    return _clip_and_composite (clip, op, source,
1343
				_cairo_surface_old_show_glyphs_draw_func,
1344
				&glyph_info,
1345
				surface,
1346
                                extents.is_bounded ? &extents.bounded : &extents.unbounded);
1347
}
1348
 
1349
cairo_surface_t *
1350
_cairo_surface_fallback_snapshot (cairo_surface_t *surface)
1351
{
1352
    cairo_surface_t *snapshot;
1353
    cairo_status_t status;
1354
    cairo_format_t format;
1355
    cairo_surface_pattern_t pattern;
1356
    cairo_image_surface_t *image;
1357
    void *image_extra;
1358
 
1359
    status = _cairo_surface_acquire_source_image (surface,
1360
						  &image, &image_extra);
1361
    if (unlikely (status))
1362
	return _cairo_surface_create_in_error (status);
1363
 
1364
    format = image->format;
1365
    if (format == CAIRO_FORMAT_INVALID) {
1366
	/* Non-standard images formats can be generated when retrieving
1367
	 * images from unusual xservers, for example.
1368
	 */
1369
	format = _cairo_format_from_content (image->base.content);
1370
    }
1371
    snapshot = cairo_image_surface_create (format,
1372
					   image->width,
1373
					   image->height);
1374
    if (cairo_surface_status (snapshot)) {
1375
	_cairo_surface_release_source_image (surface, image, image_extra);
1376
	return snapshot;
1377
    }
1378
 
1379
    _cairo_pattern_init_for_surface (&pattern, &image->base);
1380
    status = _cairo_surface_paint (snapshot,
1381
				   CAIRO_OPERATOR_SOURCE,
1382
				   &pattern.base,
1383
				   NULL);
1384
    _cairo_pattern_fini (&pattern.base);
1385
    _cairo_surface_release_source_image (surface, image, image_extra);
1386
    if (unlikely (status)) {
1387
	cairo_surface_destroy (snapshot);
1388
	return _cairo_surface_create_in_error (status);
1389
    }
1390
 
1391
    return snapshot;
1392
}
1393
 
1394
cairo_status_t
1395
_cairo_surface_fallback_composite (cairo_operator_t		 op,
1396
				   const cairo_pattern_t	*src,
1397
				   const cairo_pattern_t	*mask,
1398
				   cairo_surface_t		*dst,
1399
				   int				 src_x,
1400
				   int				 src_y,
1401
				   int				 mask_x,
1402
				   int				 mask_y,
1403
				   int				 dst_x,
1404
				   int				 dst_y,
1405
				   unsigned int			 width,
1406
				   unsigned int			 height,
1407
				   cairo_region_t		*clip_region)
1408
{
1409
    fallback_state_t state;
1410
    cairo_region_t *fallback_region = NULL;
1411
    cairo_status_t status;
1412
 
1413
    status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1414
    if (unlikely (status))
1415
	return status;
1416
 
1417
    /* We know this will never fail with the image backend; but
1418
     * instead of calling into it directly, we call
1419
     * _cairo_surface_composite so that we get the correct device
1420
     * offset handling.
1421
     */
1422
 
1423
    if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
1424
	fallback_region = cairo_region_copy (clip_region);
1425
	status = fallback_region->status;
1426
	if (unlikely (status))
1427
	    goto FAIL;
1428
 
1429
	cairo_region_translate (fallback_region,
1430
				-state.image_rect.x,
1431
				-state.image_rect.y);
1432
	clip_region = fallback_region;
1433
    }
1434
 
1435
    status = _cairo_surface_composite (op, src, mask,
1436
				       &state.image->base,
1437
				       src_x, src_y, mask_x, mask_y,
1438
				       dst_x - state.image_rect.x,
1439
				       dst_y - state.image_rect.y,
1440
				       width, height,
1441
				       clip_region);
1442
  FAIL:
1443
    if (fallback_region != NULL)
1444
	cairo_region_destroy (fallback_region);
1445
    _fallback_fini (&state);
1446
 
1447
    return status;
1448
}
1449
 
1450
cairo_status_t
1451
_cairo_surface_fallback_fill_rectangles (cairo_surface_t         *surface,
1452
					 cairo_operator_t	  op,
1453
					 const cairo_color_t	 *color,
1454
					 cairo_rectangle_int_t   *rects,
1455
					 int			  num_rects)
1456
{
1457
    fallback_state_t state;
1458
    cairo_rectangle_int_t *offset_rects = NULL;
1459
    cairo_status_t status;
1460
    int x1, y1, x2, y2;
1461
    int i;
1462
 
1463
    assert (surface->snapshot_of == NULL);
1464
 
1465
    if (num_rects <= 0)
1466
	return CAIRO_STATUS_SUCCESS;
1467
 
1468
    /* Compute the bounds of the rectangles, so that we know what area of the
1469
     * destination surface to fetch
1470
     */
1471
    x1 = rects[0].x;
1472
    y1 = rects[0].y;
1473
    x2 = rects[0].x + rects[0].width;
1474
    y2 = rects[0].y + rects[0].height;
1475
 
1476
    for (i = 1; i < num_rects; i++) {
1477
	if (rects[i].x < x1)
1478
	    x1 = rects[i].x;
1479
	if (rects[i].y < y1)
1480
	    y1 = rects[i].y;
1481
 
1482
	if ((int) (rects[i].x + rects[i].width) > x2)
1483
	    x2 = rects[i].x + rects[i].width;
1484
	if ((int) (rects[i].y + rects[i].height) > y2)
1485
	    y2 = rects[i].y + rects[i].height;
1486
    }
1487
 
1488
    status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
1489
    if (unlikely (status))
1490
	return status;
1491
 
1492
    /* If the fetched image isn't at 0,0, we need to offset the rectangles */
1493
 
1494
    if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1495
	offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
1496
	if (unlikely (offset_rects == NULL)) {
1497
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1498
	    goto DONE;
1499
	}
1500
 
1501
	for (i = 0; i < num_rects; i++) {
1502
	    offset_rects[i].x = rects[i].x - state.image_rect.x;
1503
	    offset_rects[i].y = rects[i].y - state.image_rect.y;
1504
	    offset_rects[i].width = rects[i].width;
1505
	    offset_rects[i].height = rects[i].height;
1506
	}
1507
 
1508
	rects = offset_rects;
1509
    }
1510
 
1511
    status = _cairo_surface_fill_rectangles (&state.image->base,
1512
					     op, color,
1513
					     rects, num_rects);
1514
 
1515
    free (offset_rects);
1516
 
1517
 DONE:
1518
    _fallback_fini (&state);
1519
 
1520
    return status;
1521
}
1522
 
1523
cairo_status_t
1524
_cairo_surface_fallback_composite_trapezoids (cairo_operator_t		op,
1525
					      const cairo_pattern_t    *pattern,
1526
					      cairo_surface_t	       *dst,
1527
					      cairo_antialias_t		antialias,
1528
					      int			src_x,
1529
					      int			src_y,
1530
					      int			dst_x,
1531
					      int			dst_y,
1532
					      unsigned int		width,
1533
					      unsigned int		height,
1534
					      cairo_trapezoid_t	       *traps,
1535
					      int			num_traps,
1536
					      cairo_region_t		*clip_region)
1537
{
1538
    fallback_state_t state;
1539
    cairo_region_t *fallback_region = NULL;
1540
    cairo_trapezoid_t *offset_traps = NULL;
1541
    cairo_status_t status;
1542
 
1543
    status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1544
    if (unlikely (status))
1545
	return status;
1546
 
1547
    /* If the destination image isn't at 0,0, we need to offset the trapezoids */
1548
 
1549
    if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1550
	offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
1551
	if (offset_traps == NULL) {
1552
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1553
	    goto FAIL;
1554
	}
1555
 
1556
	_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
1557
                                                    - state.image_rect.x, - state.image_rect.y,
1558
                                                    1.0, 1.0);
1559
	traps = offset_traps;
1560
 
1561
	/* similarly we need to adjust the region */
1562
	if (clip_region != NULL) {
1563
	    fallback_region = cairo_region_copy (clip_region);
1564
	    status = fallback_region->status;
1565
	    if (unlikely (status))
1566
		goto FAIL;
1567
 
1568
	    cairo_region_translate (fallback_region,
1569
				    -state.image_rect.x,
1570
				    -state.image_rect.y);
1571
	    clip_region = fallback_region;
1572
	}
1573
    }
1574
 
1575
    status = _cairo_surface_composite_trapezoids (op, pattern,
1576
					          &state.image->base,
1577
						  antialias,
1578
						  src_x, src_y,
1579
						  dst_x - state.image_rect.x,
1580
						  dst_y - state.image_rect.y,
1581
						  width, height,
1582
						  traps, num_traps,
1583
						  clip_region);
1584
 FAIL:
1585
    if (offset_traps != NULL)
1586
	free (offset_traps);
1587
 
1588
    if (fallback_region != NULL)
1589
	cairo_region_destroy (fallback_region);
1590
 
1591
    _fallback_fini (&state);
1592
 
1593
    return status;
1594
}
1595
 
1596
cairo_status_t
1597
_cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
1598
				       cairo_surface_t	*src,
1599
				       int		 src_x,
1600
				       int		 src_y,
1601
				       int		 width,
1602
				       int		 height,
1603
				       int		*clone_offset_x,
1604
				       int		*clone_offset_y,
1605
				       cairo_surface_t **clone_out)
1606
{
1607
    cairo_surface_t *new_surface;
1608
    cairo_surface_pattern_t pattern;
1609
    cairo_status_t status;
1610
 
1611
    new_surface = _cairo_surface_create_similar_scratch (surface,
1612
							 src->content,
1613
							 width, height);
1614
    if (new_surface == NULL)
1615
	return CAIRO_INT_STATUS_UNSUPPORTED;
1616
    if (unlikely (new_surface->status))
1617
	return new_surface->status;
1618
 
1619
    /* We have to copy these here, so that the coordinate spaces are correct */
1620
    new_surface->device_transform = src->device_transform;
1621
    new_surface->device_transform_inverse = src->device_transform_inverse;
1622
 
1623
    _cairo_pattern_init_for_surface (&pattern, src);
1624
    cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
1625
    pattern.base.filter = CAIRO_FILTER_NEAREST;
1626
 
1627
    status = _cairo_surface_paint (new_surface,
1628
				   CAIRO_OPERATOR_SOURCE,
1629
				   &pattern.base,
1630
				   NULL);
1631
    _cairo_pattern_fini (&pattern.base);
1632
 
1633
    if (unlikely (status)) {
1634
	cairo_surface_destroy (new_surface);
1635
	return status;
1636
    }
1637
 
1638
    *clone_offset_x = src_x;
1639
    *clone_offset_y = src_y;
1640
    *clone_out = new_surface;
1641
    return CAIRO_STATUS_SUCCESS;
1642
}