Line data Source code
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 <cworth@cworth.org>
37 : * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
38 : * Chris Wilson <chris@chris-wilson.co.uk>
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 0 : _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 0 : state->extents.x = x;
80 0 : state->extents.y = y;
81 0 : state->extents.width = width;
82 0 : state->extents.height = height;
83 :
84 0 : state->dst = dst;
85 :
86 0 : status = _cairo_surface_acquire_dest_image (dst, &state->extents,
87 : &state->image, &state->image_rect,
88 : &state->image_extra);
89 0 : if (unlikely (status))
90 0 : 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 0 : assert (state->image != NULL);
99 :
100 0 : return CAIRO_STATUS_SUCCESS;
101 : }
102 :
103 : static void
104 0 : _fallback_fini (fallback_state_t *state)
105 : {
106 0 : _cairo_surface_release_dest_image (state->dst, &state->extents,
107 : state->image, &state->image_rect,
108 : state->image_extra);
109 0 : }
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 0 : _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 0 : cairo_region_t *clip_region = NULL, *fallback_region = NULL;
131 : cairo_status_t status;
132 0 : cairo_bool_t clip_surface = FALSE;
133 :
134 0 : if (clip != NULL) {
135 0 : status = _cairo_clip_get_region (clip, &clip_region);
136 0 : if (unlikely (_cairo_status_is_error (status) ||
137 : status == CAIRO_INT_STATUS_NOTHING_TO_DO))
138 : {
139 0 : return status;
140 : }
141 :
142 0 : 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 0 : mask = _cairo_surface_create_similar_solid (dst,
149 : CAIRO_CONTENT_ALPHA,
150 : extents->width,
151 : extents->height,
152 : CAIRO_COLOR_TRANSPARENT,
153 : TRUE);
154 0 : if (unlikely (mask->status))
155 0 : return mask->status;
156 :
157 0 : if (clip_region && (extents->x || extents->y)) {
158 0 : fallback_region = cairo_region_copy (clip_region);
159 0 : status = fallback_region->status;
160 0 : if (unlikely (status))
161 0 : goto CLEANUP_SURFACE;
162 :
163 0 : cairo_region_translate (fallback_region,
164 0 : -extents->x,
165 0 : -extents->y);
166 0 : clip_region = fallback_region;
167 : }
168 :
169 0 : 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 0 : if (unlikely (status))
175 0 : goto CLEANUP_SURFACE;
176 :
177 0 : if (clip_surface)
178 0 : status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
179 :
180 0 : _cairo_pattern_init_for_surface (mask_pattern, mask);
181 :
182 : CLEANUP_SURFACE:
183 0 : if (fallback_region)
184 0 : cairo_region_destroy (fallback_region);
185 0 : cairo_surface_destroy (mask);
186 :
187 0 : 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 0 : _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 0 : status = _create_composite_mask_pattern (&mask_pattern,
206 : clip,
207 : draw_func, draw_closure,
208 : dst, extents);
209 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
210 0 : 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 0 : extents->width, extents->height,
216 : NULL);
217 :
218 0 : _cairo_pattern_fini (&mask_pattern.base);
219 : }
220 :
221 0 : 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 0 : _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 0 : intermediate =
251 0 : _cairo_surface_create_similar_scratch (dst, dst->content,
252 : extents->width,
253 : extents->height);
254 0 : if (intermediate == NULL) {
255 0 : intermediate =
256 0 : _cairo_image_surface_create_with_content (dst->content,
257 : extents->width,
258 : extents->width);
259 : }
260 0 : if (unlikely (intermediate->status))
261 0 : return intermediate->status;
262 :
263 : /* Initialize the intermediate surface from the destination surface */
264 0 : _cairo_pattern_init_for_surface (&pattern, dst);
265 0 : status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
266 : &pattern.base, NULL, intermediate,
267 : extents->x, extents->y,
268 : 0, 0,
269 : 0, 0,
270 0 : extents->width, extents->height,
271 : NULL);
272 0 : _cairo_pattern_fini (&pattern.base);
273 0 : if (unlikely (status))
274 0 : goto CLEANUP_SURFACE;
275 :
276 0 : status = (*draw_func) (draw_closure, op,
277 : src, intermediate,
278 : extents->x, extents->y,
279 : extents,
280 : NULL);
281 0 : if (unlikely (status))
282 0 : goto CLEANUP_SURFACE;
283 :
284 0 : assert (clip->path != NULL);
285 0 : clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
286 0 : if (unlikely (clip_surface->status))
287 0 : goto CLEANUP_SURFACE;
288 :
289 0 : _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
290 :
291 : /* Combine that with the clip */
292 0 : status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
293 : &clip_pattern.base, NULL, intermediate,
294 0 : extents->x - clip_x,
295 0 : extents->y - clip_y,
296 : 0, 0,
297 : 0, 0,
298 0 : extents->width, extents->height,
299 : NULL);
300 0 : if (unlikely (status))
301 0 : goto CLEANUP_CLIP;
302 :
303 : /* Punch the clip out of the destination */
304 0 : status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
305 : &clip_pattern.base, NULL, dst,
306 0 : extents->x - clip_x,
307 0 : extents->y - clip_y,
308 : 0, 0,
309 : extents->x, extents->y,
310 0 : extents->width, extents->height,
311 : NULL);
312 0 : if (unlikely (status))
313 0 : goto CLEANUP_CLIP;
314 :
315 : /* Now add the two results together */
316 0 : _cairo_pattern_init_for_surface (&pattern, intermediate);
317 0 : status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
318 : &pattern.base, NULL, dst,
319 : 0, 0,
320 : 0, 0,
321 : extents->x, extents->y,
322 0 : extents->width, extents->height,
323 : NULL);
324 0 : _cairo_pattern_fini (&pattern.base);
325 :
326 : CLEANUP_CLIP:
327 0 : _cairo_pattern_fini (&clip_pattern.base);
328 : CLEANUP_SURFACE:
329 0 : cairo_surface_destroy (intermediate);
330 :
331 0 : 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 0 : _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 0 : cairo_region_t *clip_region = NULL;
347 : cairo_status_t status;
348 :
349 0 : if (clip != NULL) {
350 0 : status = _cairo_clip_get_region (clip, &clip_region);
351 0 : if (unlikely (_cairo_status_is_error (status) ||
352 : status == CAIRO_INT_STATUS_NOTHING_TO_DO))
353 : {
354 0 : return status;
355 : }
356 : }
357 :
358 : /* Create a surface that is mask IN clip */
359 0 : status = _create_composite_mask_pattern (&mask_pattern,
360 : clip,
361 : draw_func, draw_closure,
362 : dst, extents);
363 0 : if (unlikely (status))
364 0 : return status;
365 :
366 : /* Compute dest' = dest OUT (mask IN clip) */
367 0 : 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 0 : extents->width, extents->height,
373 : clip_region);
374 :
375 0 : if (unlikely (status))
376 0 : goto CLEANUP_MASK_PATTERN;
377 :
378 : /* Now compute (src IN (mask IN clip)) ADD dest' */
379 0 : 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 0 : extents->width, extents->height,
385 : clip_region);
386 :
387 : CLEANUP_MASK_PATTERN:
388 0 : _cairo_pattern_fini (&mask_pattern.base);
389 0 : return status;
390 : }
391 :
392 : static int
393 0 : _cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
394 : {
395 0 : 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 0 : _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 0 : if (_cairo_rectangle_empty (extents))
431 : /* Nothing to do */
432 0 : return CAIRO_STATUS_SUCCESS;
433 :
434 0 : if (op == CAIRO_OPERATOR_CLEAR) {
435 0 : src = &_cairo_pattern_white.base;
436 0 : op = CAIRO_OPERATOR_DEST_OUT;
437 : }
438 :
439 0 : if (op == CAIRO_OPERATOR_SOURCE) {
440 0 : status = _clip_and_composite_source (clip,
441 : src,
442 : draw_func, draw_closure,
443 : dst, extents);
444 : } else {
445 0 : cairo_bool_t clip_surface = FALSE;
446 0 : cairo_region_t *clip_region = NULL;
447 :
448 0 : if (clip != NULL) {
449 0 : status = _cairo_clip_get_region (clip, &clip_region);
450 0 : if (unlikely (_cairo_status_is_error (status) ||
451 : status == CAIRO_INT_STATUS_NOTHING_TO_DO))
452 : {
453 0 : return status;
454 : }
455 :
456 0 : clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
457 : }
458 :
459 0 : if (clip_surface) {
460 0 : if (_cairo_operator_bounded_by_mask (op)) {
461 0 : status = _clip_and_composite_with_mask (clip, op,
462 : src,
463 : draw_func, draw_closure,
464 : dst, extents);
465 : } else {
466 0 : status = _clip_and_composite_combine (clip, op,
467 : src,
468 : draw_func, draw_closure,
469 : dst, extents);
470 : }
471 : } else {
472 0 : status = draw_func (draw_closure, op,
473 : src, dst,
474 : 0, 0,
475 : extents,
476 : clip_region);
477 : }
478 : }
479 :
480 0 : return status;
481 : }
482 :
483 : /* Composites a region representing a set of trapezoids.
484 : */
485 : static cairo_status_t
486 0 : _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 0 : cairo_pattern_t *mask = NULL;
496 0 : int mask_x = 0, mask_y =0;
497 :
498 0 : if (clip != NULL) {
499 0 : cairo_surface_t *clip_surface = NULL;
500 : int clip_x, clip_y;
501 :
502 0 : clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
503 0 : if (unlikely (clip_surface->status))
504 0 : return clip_surface->status;
505 :
506 0 : if (op == CAIRO_OPERATOR_CLEAR) {
507 0 : src = &_cairo_pattern_white.base;
508 0 : op = CAIRO_OPERATOR_DEST_OUT;
509 : }
510 :
511 0 : _cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
512 0 : mask_x = extents->x - clip_x;
513 0 : mask_y = extents->y - clip_y;
514 0 : mask = &mask_pattern.base;
515 : }
516 :
517 0 : status = _cairo_surface_composite (op, src, mask, dst,
518 : extents->x, extents->y,
519 : mask_x, mask_y,
520 : extents->x, extents->y,
521 0 : extents->width, extents->height,
522 : trap_region);
523 :
524 0 : if (mask != NULL)
525 0 : _cairo_pattern_fini (mask);
526 :
527 0 : 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 0 : _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 0 : cairo_composite_traps_info_t *info = closure;
546 : cairo_status_t status;
547 0 : cairo_region_t *extents_region = NULL;
548 :
549 0 : if (dst_x != 0 || dst_y != 0)
550 0 : _cairo_traps_translate (info->traps, - dst_x, - dst_y);
551 :
552 0 : if (clip_region == NULL &&
553 0 : !_cairo_operator_bounded_by_source (op)) {
554 0 : extents_region = cairo_region_create_rectangle (extents);
555 0 : if (unlikely (extents_region->status))
556 0 : return extents_region->status;
557 0 : cairo_region_translate (extents_region, -dst_x, -dst_y);
558 0 : clip_region = extents_region;
559 : }
560 :
561 0 : status = _cairo_surface_composite_trapezoids (op,
562 : src, dst, info->antialias,
563 : extents->x, extents->y,
564 0 : extents->x - dst_x, extents->y - dst_y,
565 0 : extents->width, extents->height,
566 0 : info->traps->traps,
567 0 : info->traps->num_traps,
568 : clip_region);
569 :
570 0 : if (extents_region)
571 0 : cairo_region_destroy (extents_region);
572 :
573 0 : return status;
574 : }
575 :
576 : enum {
577 : HAS_CLEAR_REGION = 0x1,
578 : };
579 :
580 : static cairo_status_t
581 0 : _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 0 : unsigned int has_region = 0;
590 : cairo_status_t status;
591 :
592 0 : 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 0 : _cairo_region_init_rectangle (&clear_region, extents);
598 0 : status = cairo_region_subtract (&clear_region, trap_region);
599 0 : if (unlikely (status))
600 0 : return status;
601 :
602 0 : if (! cairo_region_is_empty (&clear_region))
603 0 : has_region |= HAS_CLEAR_REGION;
604 : }
605 :
606 0 : if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
607 : clip == NULL)
608 0 : {
609 : const cairo_color_t *color;
610 :
611 0 : if (op == CAIRO_OPERATOR_CLEAR)
612 0 : color = CAIRO_COLOR_TRANSPARENT;
613 : else
614 0 : color = &((cairo_solid_pattern_t *)src)->color;
615 :
616 : /* Solid rectangles special case */
617 0 : 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 0 : status = _composite_trap_region (clip, src, op, dst,
635 : trap_region, extents);
636 : }
637 :
638 0 : if (has_region & HAS_CLEAR_REGION) {
639 0 : if (status == CAIRO_STATUS_SUCCESS) {
640 0 : status = _cairo_surface_fill_region (dst,
641 : CAIRO_OPERATOR_CLEAR,
642 : CAIRO_COLOR_TRANSPARENT,
643 : &clear_region);
644 : }
645 0 : _cairo_region_fini (&clear_region);
646 : }
647 :
648 0 : return status;
649 : }
650 :
651 : /* avoid using region code to re-validate boxes */
652 : static cairo_status_t
653 0 : _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 0 : cairo_rectangle_int_t *rects = stack_rects;
662 : cairo_status_t status;
663 : int i;
664 :
665 0 : if (! traps->is_rectilinear || ! traps->maybe_region)
666 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
667 :
668 : /* XXX: convert clip region to geometric boxes? */
669 0 : if (clip != NULL)
670 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
671 :
672 : /* XXX: fallback for the region_subtract() operation */
673 0 : if (! _cairo_operator_bounded_by_mask (op))
674 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
675 :
676 0 : if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
677 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
678 :
679 0 : if (traps->has_intersections) {
680 0 : if (traps->is_rectangular) {
681 0 : status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
682 : } else {
683 0 : status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
684 : }
685 0 : if (unlikely (status))
686 0 : return status;
687 : }
688 :
689 0 : for (i = 0; i < traps->num_traps; i++) {
690 0 : if (! _cairo_fixed_is_integer (traps->traps[i].top) ||
691 0 : ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
692 0 : ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
693 0 : ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
694 : {
695 0 : traps->maybe_region = FALSE;
696 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
697 : }
698 : }
699 :
700 0 : if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
701 0 : rects = _cairo_malloc_ab (traps->num_traps,
702 : sizeof (cairo_rectangle_int_t));
703 0 : if (unlikely (rects == NULL))
704 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
705 : }
706 :
707 0 : for (i = 0; i < traps->num_traps; i++) {
708 0 : int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
709 0 : int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
710 0 : int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
711 0 : int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
712 :
713 0 : rects[i].x = x1;
714 0 : rects[i].y = y1;
715 0 : rects[i].width = x2 - x1;
716 0 : rects[i].height = y2 - y1;
717 : }
718 :
719 0 : if (op == CAIRO_OPERATOR_CLEAR)
720 0 : color = CAIRO_COLOR_TRANSPARENT;
721 : else
722 0 : color = &((cairo_solid_pattern_t *)src)->color;
723 :
724 0 : status = _cairo_surface_fill_rectangles (dst, op, color, rects, i);
725 :
726 0 : if (rects != stack_rects)
727 0 : free (rects);
728 :
729 0 : return status;
730 : }
731 :
732 : /* fast-path for very common composite of a single rectangle */
733 : static cairo_status_t
734 0 : _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 0 : if (clip != NULL)
743 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
744 :
745 0 : if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
746 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
747 :
748 0 : if (! _cairo_fixed_is_integer (traps->traps[0].top) ||
749 0 : ! _cairo_fixed_is_integer (traps->traps[0].bottom) ||
750 0 : ! _cairo_fixed_is_integer (traps->traps[0].left.p1.x) ||
751 0 : ! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
752 : {
753 0 : traps->maybe_region = FALSE;
754 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
755 : }
756 :
757 0 : rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
758 0 : rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
759 0 : rect.width = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
760 0 : rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
761 :
762 0 : return _cairo_surface_composite (op, src, NULL, dst,
763 : rect.x, rect.y,
764 : 0, 0,
765 : rect.x, rect.y,
766 0 : rect.width, rect.height,
767 : NULL);
768 : }
769 :
770 : /* Warning: This call modifies the coordinates of traps */
771 : static cairo_status_t
772 0 : _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 0 : cairo_region_t *clip_region = NULL;
782 0 : cairo_bool_t clip_surface = FALSE;
783 : cairo_status_t status;
784 :
785 0 : if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
786 0 : return CAIRO_STATUS_SUCCESS;
787 :
788 0 : if (clip != NULL) {
789 0 : status = _cairo_clip_get_region (clip, &clip_region);
790 0 : if (unlikely (_cairo_status_is_error (status)))
791 0 : return status;
792 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
793 0 : return CAIRO_STATUS_SUCCESS;
794 :
795 0 : 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 0 : if (! clip_surface ||
803 0 : (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
804 : {
805 0 : cairo_region_t *trap_region = NULL;
806 :
807 0 : if (_cairo_operator_bounded_by_source (op)) {
808 0 : status = _fill_rectangles (dst, op, src, traps, clip);
809 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
810 0 : return status;
811 :
812 0 : status = _composite_rectangle (dst, op, src, traps, clip);
813 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
814 0 : return status;
815 : }
816 :
817 0 : status = _cairo_traps_extract_region (traps, &trap_region);
818 0 : if (unlikely (_cairo_status_is_error (status)))
819 0 : return status;
820 :
821 0 : if (trap_region != NULL) {
822 0 : status = cairo_region_intersect_rectangle (trap_region, extents);
823 0 : if (unlikely (status)) {
824 0 : cairo_region_destroy (trap_region);
825 0 : return status;
826 : }
827 :
828 0 : if (clip_region != NULL) {
829 0 : status = cairo_region_intersect (trap_region, clip_region);
830 0 : if (unlikely (status)) {
831 0 : cairo_region_destroy (trap_region);
832 0 : return status;
833 : }
834 : }
835 :
836 0 : if (_cairo_operator_bounded_by_mask (op)) {
837 : cairo_rectangle_int_t trap_extents;
838 :
839 0 : cairo_region_get_extents (trap_region, &trap_extents);
840 0 : if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
841 0 : cairo_region_destroy (trap_region);
842 0 : return CAIRO_STATUS_SUCCESS;
843 : }
844 : }
845 :
846 0 : status = _clip_and_composite_region (src, op, dst,
847 : trap_region,
848 : clip_surface ? clip : NULL,
849 : extents);
850 0 : cairo_region_destroy (trap_region);
851 :
852 0 : if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
853 0 : return status;
854 : }
855 : }
856 :
857 : /* No fast path, exclude self-intersections and clip trapezoids. */
858 0 : if (traps->has_intersections) {
859 0 : if (traps->is_rectangular)
860 0 : status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
861 0 : else if (traps->is_rectilinear)
862 0 : status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
863 : else
864 0 : status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
865 0 : if (unlikely (status))
866 0 : return status;
867 : }
868 :
869 : /* Otherwise render the trapezoids to a mask and composite in the usual
870 : * fashion.
871 : */
872 0 : traps_info.traps = traps;
873 0 : traps_info.antialias = antialias;
874 :
875 0 : return _clip_and_composite (clip, op, src,
876 : _composite_traps_draw_func,
877 : &traps_info, dst, extents);
878 : }
879 :
880 : cairo_status_t
881 0 : _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 0 : cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
889 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
890 : cairo_boxes_t boxes;
891 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
892 : cairo_status_t status;
893 : cairo_traps_t traps;
894 :
895 0 : if (!_cairo_surface_get_extents (surface, &rect))
896 0 : ASSERT_NOT_REACHED;
897 :
898 0 : status = _cairo_composite_rectangles_init_for_paint (&extents,
899 : &rect,
900 : op, source,
901 : clip);
902 0 : if (unlikely (status))
903 0 : return status;
904 :
905 0 : if (_cairo_clip_contains_extents (clip, &extents))
906 0 : clip = NULL;
907 :
908 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
909 0 : if (unlikely (status))
910 0 : return status;
911 :
912 : /* If the clip cannot be reduced to a set of boxes, we will need to
913 : * use a clipmask. Paint is special as it is the only operation that
914 : * does not implicitly use a mask, so we may be able to reduce this
915 : * operation to a fill...
916 : */
917 0 : if (clip != NULL && clip_path->prev == NULL &&
918 0 : _cairo_operator_bounded_by_mask (op))
919 : {
920 0 : return _cairo_surface_fill (surface, op, source,
921 : &clip_path->path,
922 : clip_path->fill_rule,
923 : clip_path->tolerance,
924 : clip_path->antialias,
925 : NULL);
926 : }
927 :
928 : /* meh, surface-fallback is dying anyway... */
929 0 : _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
930 0 : status = _cairo_traps_init_boxes (&traps, &boxes);
931 0 : if (unlikely (status))
932 0 : goto CLEANUP_BOXES;
933 :
934 0 : status = _clip_and_composite_trapezoids (source, op, surface,
935 : &traps, CAIRO_ANTIALIAS_DEFAULT,
936 : clip,
937 0 : extents.is_bounded ? &extents.bounded : &extents.unbounded);
938 0 : _cairo_traps_fini (&traps);
939 :
940 : CLEANUP_BOXES:
941 0 : if (clip_boxes != boxes_stack)
942 0 : free (clip_boxes);
943 :
944 0 : return status;
945 : }
946 :
947 : static cairo_status_t
948 0 : _cairo_surface_mask_draw_func (void *closure,
949 : cairo_operator_t op,
950 : const cairo_pattern_t *src,
951 : cairo_surface_t *dst,
952 : int dst_x,
953 : int dst_y,
954 : const cairo_rectangle_int_t *extents,
955 : cairo_region_t *clip_region)
956 : {
957 0 : cairo_pattern_t *mask = closure;
958 : cairo_status_t status;
959 0 : cairo_region_t *extents_region = NULL;
960 :
961 0 : if (clip_region == NULL &&
962 0 : !_cairo_operator_bounded_by_source (op)) {
963 0 : extents_region = cairo_region_create_rectangle (extents);
964 0 : if (unlikely (extents_region->status))
965 0 : return extents_region->status;
966 0 : cairo_region_translate (extents_region, -dst_x, -dst_y);
967 0 : clip_region = extents_region;
968 : }
969 :
970 0 : if (src) {
971 0 : status = _cairo_surface_composite (op,
972 : src, mask, dst,
973 : extents->x, extents->y,
974 : extents->x, extents->y,
975 0 : extents->x - dst_x, extents->y - dst_y,
976 0 : extents->width, extents->height,
977 : clip_region);
978 : } else {
979 0 : status = _cairo_surface_composite (op,
980 : mask, NULL, dst,
981 : extents->x, extents->y,
982 : 0, 0, /* unused */
983 0 : extents->x - dst_x, extents->y - dst_y,
984 0 : extents->width, extents->height,
985 : clip_region);
986 : }
987 :
988 0 : if (extents_region)
989 0 : cairo_region_destroy (extents_region);
990 :
991 0 : return status;
992 : }
993 :
994 : cairo_status_t
995 0 : _cairo_surface_fallback_mask (cairo_surface_t *surface,
996 : cairo_operator_t op,
997 : const cairo_pattern_t *source,
998 : const cairo_pattern_t *mask,
999 : cairo_clip_t *clip)
1000 : {
1001 : cairo_composite_rectangles_t extents;
1002 : cairo_rectangle_int_t rect;
1003 : cairo_status_t status;
1004 :
1005 0 : if (!_cairo_surface_get_extents (surface, &rect))
1006 0 : ASSERT_NOT_REACHED;
1007 :
1008 0 : status = _cairo_composite_rectangles_init_for_mask (&extents,
1009 : &rect,
1010 : op, source, mask, clip);
1011 0 : if (unlikely (status))
1012 0 : return status;
1013 :
1014 0 : if (_cairo_clip_contains_extents (clip, &extents))
1015 0 : clip = NULL;
1016 :
1017 0 : if (clip != NULL && extents.is_bounded) {
1018 0 : status = _cairo_clip_rectangle (clip, &extents.bounded);
1019 0 : if (unlikely (status))
1020 0 : return status;
1021 : }
1022 :
1023 0 : return _clip_and_composite (clip, op, source,
1024 : _cairo_surface_mask_draw_func,
1025 : (void *) mask,
1026 : surface,
1027 0 : extents.is_bounded ? &extents.bounded : &extents.unbounded);
1028 : }
1029 :
1030 : cairo_status_t
1031 0 : _cairo_surface_fallback_stroke (cairo_surface_t *surface,
1032 : cairo_operator_t op,
1033 : const cairo_pattern_t *source,
1034 : cairo_path_fixed_t *path,
1035 : const cairo_stroke_style_t *stroke_style,
1036 : const cairo_matrix_t *ctm,
1037 : const cairo_matrix_t *ctm_inverse,
1038 : double tolerance,
1039 : cairo_antialias_t antialias,
1040 : cairo_clip_t *clip)
1041 : {
1042 : cairo_polygon_t polygon;
1043 : cairo_traps_t traps;
1044 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1045 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
1046 : cairo_composite_rectangles_t extents;
1047 : cairo_rectangle_int_t rect;
1048 : cairo_status_t status;
1049 :
1050 0 : if (!_cairo_surface_get_extents (surface, &rect))
1051 0 : ASSERT_NOT_REACHED;
1052 :
1053 0 : status = _cairo_composite_rectangles_init_for_stroke (&extents,
1054 : &rect,
1055 : op, source,
1056 : path, stroke_style, ctm,
1057 : clip);
1058 0 : if (unlikely (status))
1059 0 : return status;
1060 :
1061 0 : if (_cairo_clip_contains_extents (clip, &extents))
1062 0 : clip = NULL;
1063 :
1064 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1065 0 : if (unlikely (status))
1066 0 : return status;
1067 :
1068 0 : _cairo_polygon_init (&polygon);
1069 0 : _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1070 :
1071 0 : _cairo_traps_init (&traps);
1072 0 : _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1073 :
1074 0 : if (path->is_rectilinear) {
1075 0 : status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
1076 : stroke_style,
1077 : ctm,
1078 : &traps);
1079 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1080 0 : goto DO_TRAPS;
1081 :
1082 0 : if (_cairo_status_is_error (status))
1083 0 : goto CLEANUP;
1084 : }
1085 :
1086 0 : status = _cairo_path_fixed_stroke_to_polygon (path,
1087 : stroke_style,
1088 : ctm, ctm_inverse,
1089 : tolerance,
1090 : &polygon);
1091 0 : if (unlikely (status))
1092 0 : goto CLEANUP;
1093 :
1094 0 : if (polygon.num_edges == 0)
1095 0 : goto DO_TRAPS;
1096 :
1097 0 : if (_cairo_operator_bounded_by_mask (op)) {
1098 0 : _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1099 0 : if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1100 0 : goto CLEANUP;
1101 : }
1102 :
1103 : /* Fall back to trapezoid fills. */
1104 0 : status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1105 : &polygon,
1106 : CAIRO_FILL_RULE_WINDING);
1107 0 : if (unlikely (status))
1108 0 : goto CLEANUP;
1109 :
1110 : DO_TRAPS:
1111 0 : status = _clip_and_composite_trapezoids (source, op, surface,
1112 : &traps, antialias,
1113 : clip,
1114 0 : extents.is_bounded ? &extents.bounded : &extents.unbounded);
1115 : CLEANUP:
1116 0 : _cairo_traps_fini (&traps);
1117 0 : _cairo_polygon_fini (&polygon);
1118 0 : if (clip_boxes != boxes_stack)
1119 0 : free (clip_boxes);
1120 :
1121 0 : return status;
1122 : }
1123 :
1124 : cairo_status_t
1125 0 : _cairo_surface_fallback_fill (cairo_surface_t *surface,
1126 : cairo_operator_t op,
1127 : const cairo_pattern_t *source,
1128 : cairo_path_fixed_t *path,
1129 : cairo_fill_rule_t fill_rule,
1130 : double tolerance,
1131 : cairo_antialias_t antialias,
1132 : cairo_clip_t *clip)
1133 : {
1134 : cairo_polygon_t polygon;
1135 : cairo_traps_t traps;
1136 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1137 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
1138 : cairo_bool_t is_rectilinear;
1139 : cairo_composite_rectangles_t extents;
1140 : cairo_rectangle_int_t rect;
1141 : cairo_status_t status;
1142 :
1143 0 : if (!_cairo_surface_get_extents (surface, &rect))
1144 0 : ASSERT_NOT_REACHED;
1145 :
1146 0 : status = _cairo_composite_rectangles_init_for_fill (&extents,
1147 : &rect,
1148 : op, source, path,
1149 : clip);
1150 0 : if (unlikely (status))
1151 0 : return status;
1152 :
1153 0 : if (_cairo_clip_contains_extents (clip, &extents))
1154 0 : clip = NULL;
1155 :
1156 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1157 0 : if (unlikely (status))
1158 0 : return status;
1159 :
1160 0 : _cairo_traps_init (&traps);
1161 0 : _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1162 :
1163 0 : _cairo_polygon_init (&polygon);
1164 0 : _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1165 :
1166 0 : if (path->is_empty_fill)
1167 0 : goto DO_TRAPS;
1168 :
1169 0 : is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path);
1170 0 : if (is_rectilinear) {
1171 0 : status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
1172 : fill_rule,
1173 : &traps);
1174 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1175 0 : goto DO_TRAPS;
1176 :
1177 0 : if (_cairo_status_is_error (status))
1178 0 : goto CLEANUP;
1179 : }
1180 :
1181 0 : status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1182 0 : if (unlikely (status))
1183 0 : goto CLEANUP;
1184 :
1185 0 : if (polygon.num_edges == 0)
1186 0 : goto DO_TRAPS;
1187 :
1188 0 : if (_cairo_operator_bounded_by_mask (op)) {
1189 0 : _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1190 0 : if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1191 0 : goto CLEANUP;
1192 : }
1193 :
1194 0 : if (is_rectilinear) {
1195 0 : status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
1196 : &polygon,
1197 : fill_rule);
1198 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1199 0 : goto DO_TRAPS;
1200 :
1201 0 : if (unlikely (_cairo_status_is_error (status)))
1202 0 : goto CLEANUP;
1203 : }
1204 :
1205 : /* Fall back to trapezoid fills. */
1206 0 : status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1207 : &polygon,
1208 : fill_rule);
1209 0 : if (unlikely (status))
1210 0 : goto CLEANUP;
1211 :
1212 : DO_TRAPS:
1213 0 : status = _clip_and_composite_trapezoids (source, op, surface,
1214 : &traps, antialias,
1215 : clip,
1216 0 : extents.is_bounded ? &extents.bounded : &extents.unbounded);
1217 : CLEANUP:
1218 0 : _cairo_traps_fini (&traps);
1219 0 : _cairo_polygon_fini (&polygon);
1220 0 : if (clip_boxes != boxes_stack)
1221 0 : free (clip_boxes);
1222 :
1223 0 : return status;
1224 : }
1225 :
1226 : typedef struct {
1227 : cairo_scaled_font_t *font;
1228 : cairo_glyph_t *glyphs;
1229 : int num_glyphs;
1230 : } cairo_show_glyphs_info_t;
1231 :
1232 : static cairo_status_t
1233 0 : _cairo_surface_old_show_glyphs_draw_func (void *closure,
1234 : cairo_operator_t op,
1235 : const cairo_pattern_t *src,
1236 : cairo_surface_t *dst,
1237 : int dst_x,
1238 : int dst_y,
1239 : const cairo_rectangle_int_t *extents,
1240 : cairo_region_t *clip_region)
1241 : {
1242 0 : cairo_show_glyphs_info_t *glyph_info = closure;
1243 : cairo_status_t status;
1244 0 : cairo_region_t *extents_region = NULL;
1245 :
1246 0 : if (clip_region == NULL &&
1247 0 : !_cairo_operator_bounded_by_source (op)) {
1248 0 : extents_region = cairo_region_create_rectangle (extents);
1249 0 : if (unlikely (extents_region->status))
1250 0 : return extents_region->status;
1251 0 : cairo_region_translate (extents_region, -dst_x, -dst_y);
1252 0 : clip_region = extents_region;
1253 : }
1254 :
1255 : /* Modifying the glyph array is fine because we know that this function
1256 : * will be called only once, and we've already made a copy of the
1257 : * glyphs in the wrapper.
1258 : */
1259 0 : if (dst_x != 0 || dst_y != 0) {
1260 : int i;
1261 :
1262 0 : for (i = 0; i < glyph_info->num_glyphs; ++i) {
1263 0 : ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
1264 0 : ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
1265 : }
1266 : }
1267 :
1268 0 : status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
1269 : dst,
1270 : extents->x, extents->y,
1271 0 : extents->x - dst_x,
1272 0 : extents->y - dst_y,
1273 0 : extents->width,
1274 0 : extents->height,
1275 : glyph_info->glyphs,
1276 : glyph_info->num_glyphs,
1277 : clip_region);
1278 :
1279 0 : if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1280 0 : status = _cairo_scaled_font_show_glyphs (glyph_info->font,
1281 : op,
1282 : src, dst,
1283 : extents->x, extents->y,
1284 0 : extents->x - dst_x,
1285 0 : extents->y - dst_y,
1286 0 : extents->width, extents->height,
1287 : glyph_info->glyphs,
1288 : glyph_info->num_glyphs,
1289 : clip_region);
1290 : }
1291 :
1292 0 : if (extents_region)
1293 0 : cairo_region_destroy (extents_region);
1294 :
1295 0 : return status;
1296 : }
1297 :
1298 : cairo_status_t
1299 0 : _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
1300 : cairo_operator_t op,
1301 : const cairo_pattern_t *source,
1302 : cairo_glyph_t *glyphs,
1303 : int num_glyphs,
1304 : cairo_scaled_font_t *scaled_font,
1305 : cairo_clip_t *clip)
1306 : {
1307 : cairo_show_glyphs_info_t glyph_info;
1308 : cairo_composite_rectangles_t extents;
1309 : cairo_rectangle_int_t rect;
1310 : cairo_status_t status;
1311 :
1312 0 : if (!_cairo_surface_get_extents (surface, &rect))
1313 0 : ASSERT_NOT_REACHED;
1314 :
1315 0 : status = _cairo_composite_rectangles_init_for_glyphs (&extents,
1316 : &rect,
1317 : op, source,
1318 : scaled_font,
1319 : glyphs, num_glyphs,
1320 : clip,
1321 : NULL);
1322 0 : if (unlikely (status))
1323 0 : return status;
1324 :
1325 0 : if (_cairo_clip_contains_rectangle (clip, &extents.mask))
1326 0 : clip = NULL;
1327 :
1328 0 : if (clip != NULL && extents.is_bounded) {
1329 0 : status = _cairo_clip_rectangle (clip, &extents.bounded);
1330 0 : if (unlikely (status))
1331 0 : return status;
1332 : }
1333 :
1334 0 : glyph_info.font = scaled_font;
1335 0 : glyph_info.glyphs = glyphs;
1336 0 : glyph_info.num_glyphs = num_glyphs;
1337 :
1338 0 : return _clip_and_composite (clip, op, source,
1339 : _cairo_surface_old_show_glyphs_draw_func,
1340 : &glyph_info,
1341 : surface,
1342 0 : extents.is_bounded ? &extents.bounded : &extents.unbounded);
1343 : }
1344 :
1345 : cairo_surface_t *
1346 0 : _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
1347 : {
1348 : cairo_surface_t *snapshot;
1349 : cairo_status_t status;
1350 : cairo_format_t format;
1351 : cairo_surface_pattern_t pattern;
1352 : cairo_image_surface_t *image;
1353 : void *image_extra;
1354 :
1355 0 : status = _cairo_surface_acquire_source_image (surface,
1356 : &image, &image_extra);
1357 0 : if (unlikely (status))
1358 0 : return _cairo_surface_create_in_error (status);
1359 :
1360 0 : format = image->format;
1361 0 : if (format == CAIRO_FORMAT_INVALID) {
1362 : /* Non-standard images formats can be generated when retrieving
1363 : * images from unusual xservers, for example.
1364 : */
1365 0 : format = _cairo_format_from_content (image->base.content);
1366 : }
1367 0 : snapshot = cairo_image_surface_create (format,
1368 0 : image->width,
1369 0 : image->height);
1370 0 : if (cairo_surface_status (snapshot)) {
1371 0 : _cairo_surface_release_source_image (surface, image, image_extra);
1372 0 : return snapshot;
1373 : }
1374 :
1375 0 : _cairo_pattern_init_for_surface (&pattern, &image->base);
1376 0 : status = _cairo_surface_paint (snapshot,
1377 : CAIRO_OPERATOR_SOURCE,
1378 : &pattern.base,
1379 : NULL);
1380 0 : _cairo_pattern_fini (&pattern.base);
1381 0 : _cairo_surface_release_source_image (surface, image, image_extra);
1382 0 : if (unlikely (status)) {
1383 0 : cairo_surface_destroy (snapshot);
1384 0 : return _cairo_surface_create_in_error (status);
1385 : }
1386 :
1387 0 : return snapshot;
1388 : }
1389 :
1390 : cairo_status_t
1391 0 : _cairo_surface_fallback_composite (cairo_operator_t op,
1392 : const cairo_pattern_t *src,
1393 : const cairo_pattern_t *mask,
1394 : cairo_surface_t *dst,
1395 : int src_x,
1396 : int src_y,
1397 : int mask_x,
1398 : int mask_y,
1399 : int dst_x,
1400 : int dst_y,
1401 : unsigned int width,
1402 : unsigned int height,
1403 : cairo_region_t *clip_region)
1404 : {
1405 : fallback_state_t state;
1406 0 : cairo_region_t *fallback_region = NULL;
1407 : cairo_status_t status;
1408 :
1409 0 : status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1410 0 : if (unlikely (status))
1411 0 : return status;
1412 :
1413 : /* We know this will never fail with the image backend; but
1414 : * instead of calling into it directly, we call
1415 : * _cairo_surface_composite so that we get the correct device
1416 : * offset handling.
1417 : */
1418 :
1419 0 : if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
1420 0 : fallback_region = cairo_region_copy (clip_region);
1421 0 : status = fallback_region->status;
1422 0 : if (unlikely (status))
1423 0 : goto FAIL;
1424 :
1425 0 : cairo_region_translate (fallback_region,
1426 0 : -state.image_rect.x,
1427 0 : -state.image_rect.y);
1428 0 : clip_region = fallback_region;
1429 : }
1430 :
1431 0 : status = _cairo_surface_composite (op, src, mask,
1432 0 : &state.image->base,
1433 : src_x, src_y, mask_x, mask_y,
1434 0 : dst_x - state.image_rect.x,
1435 0 : dst_y - state.image_rect.y,
1436 : width, height,
1437 : clip_region);
1438 : FAIL:
1439 0 : if (fallback_region != NULL)
1440 0 : cairo_region_destroy (fallback_region);
1441 0 : _fallback_fini (&state);
1442 :
1443 0 : return status;
1444 : }
1445 :
1446 : cairo_status_t
1447 0 : _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
1448 : cairo_operator_t op,
1449 : const cairo_color_t *color,
1450 : cairo_rectangle_int_t *rects,
1451 : int num_rects)
1452 : {
1453 : fallback_state_t state;
1454 0 : cairo_rectangle_int_t *offset_rects = NULL;
1455 : cairo_status_t status;
1456 : int x1, y1, x2, y2;
1457 : int i;
1458 :
1459 0 : assert (surface->snapshot_of == NULL);
1460 :
1461 0 : if (num_rects <= 0)
1462 0 : return CAIRO_STATUS_SUCCESS;
1463 :
1464 : /* Compute the bounds of the rectangles, so that we know what area of the
1465 : * destination surface to fetch
1466 : */
1467 0 : x1 = rects[0].x;
1468 0 : y1 = rects[0].y;
1469 0 : x2 = rects[0].x + rects[0].width;
1470 0 : y2 = rects[0].y + rects[0].height;
1471 :
1472 0 : for (i = 1; i < num_rects; i++) {
1473 0 : if (rects[i].x < x1)
1474 0 : x1 = rects[i].x;
1475 0 : if (rects[i].y < y1)
1476 0 : y1 = rects[i].y;
1477 :
1478 0 : if ((int) (rects[i].x + rects[i].width) > x2)
1479 0 : x2 = rects[i].x + rects[i].width;
1480 0 : if ((int) (rects[i].y + rects[i].height) > y2)
1481 0 : y2 = rects[i].y + rects[i].height;
1482 : }
1483 :
1484 0 : status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
1485 0 : if (unlikely (status))
1486 0 : return status;
1487 :
1488 : /* If the fetched image isn't at 0,0, we need to offset the rectangles */
1489 :
1490 0 : if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1491 0 : offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
1492 0 : if (unlikely (offset_rects == NULL)) {
1493 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1494 0 : goto DONE;
1495 : }
1496 :
1497 0 : for (i = 0; i < num_rects; i++) {
1498 0 : offset_rects[i].x = rects[i].x - state.image_rect.x;
1499 0 : offset_rects[i].y = rects[i].y - state.image_rect.y;
1500 0 : offset_rects[i].width = rects[i].width;
1501 0 : offset_rects[i].height = rects[i].height;
1502 : }
1503 :
1504 0 : rects = offset_rects;
1505 : }
1506 :
1507 0 : status = _cairo_surface_fill_rectangles (&state.image->base,
1508 : op, color,
1509 : rects, num_rects);
1510 :
1511 0 : free (offset_rects);
1512 :
1513 : DONE:
1514 0 : _fallback_fini (&state);
1515 :
1516 0 : return status;
1517 : }
1518 :
1519 : cairo_status_t
1520 0 : _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
1521 : const cairo_pattern_t *pattern,
1522 : cairo_surface_t *dst,
1523 : cairo_antialias_t antialias,
1524 : int src_x,
1525 : int src_y,
1526 : int dst_x,
1527 : int dst_y,
1528 : unsigned int width,
1529 : unsigned int height,
1530 : cairo_trapezoid_t *traps,
1531 : int num_traps,
1532 : cairo_region_t *clip_region)
1533 : {
1534 : fallback_state_t state;
1535 0 : cairo_region_t *fallback_region = NULL;
1536 0 : cairo_trapezoid_t *offset_traps = NULL;
1537 : cairo_status_t status;
1538 :
1539 0 : status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1540 0 : if (unlikely (status))
1541 0 : return status;
1542 :
1543 : /* If the destination image isn't at 0,0, we need to offset the trapezoids */
1544 :
1545 0 : if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1546 0 : offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
1547 0 : if (offset_traps == NULL) {
1548 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1549 0 : goto FAIL;
1550 : }
1551 :
1552 0 : _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
1553 0 : - state.image_rect.x, - state.image_rect.y,
1554 : 1.0, 1.0);
1555 0 : traps = offset_traps;
1556 :
1557 : /* similarly we need to adjust the region */
1558 0 : if (clip_region != NULL) {
1559 0 : fallback_region = cairo_region_copy (clip_region);
1560 0 : status = fallback_region->status;
1561 0 : if (unlikely (status))
1562 0 : goto FAIL;
1563 :
1564 0 : cairo_region_translate (fallback_region,
1565 0 : -state.image_rect.x,
1566 0 : -state.image_rect.y);
1567 0 : clip_region = fallback_region;
1568 : }
1569 : }
1570 :
1571 0 : status = _cairo_surface_composite_trapezoids (op, pattern,
1572 0 : &state.image->base,
1573 : antialias,
1574 : src_x, src_y,
1575 0 : dst_x - state.image_rect.x,
1576 0 : dst_y - state.image_rect.y,
1577 : width, height,
1578 : traps, num_traps,
1579 : clip_region);
1580 : FAIL:
1581 0 : if (offset_traps != NULL)
1582 0 : free (offset_traps);
1583 :
1584 0 : if (fallback_region != NULL)
1585 0 : cairo_region_destroy (fallback_region);
1586 :
1587 0 : _fallback_fini (&state);
1588 :
1589 0 : return status;
1590 : }
1591 :
1592 : cairo_status_t
1593 0 : _cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
1594 : cairo_surface_t *src,
1595 : int src_x,
1596 : int src_y,
1597 : int width,
1598 : int height,
1599 : int *clone_offset_x,
1600 : int *clone_offset_y,
1601 : cairo_surface_t **clone_out)
1602 : {
1603 : cairo_surface_t *new_surface;
1604 : cairo_surface_pattern_t pattern;
1605 : cairo_status_t status;
1606 :
1607 0 : new_surface = _cairo_surface_create_similar_scratch (surface,
1608 : src->content,
1609 : width, height);
1610 0 : if (new_surface == NULL)
1611 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1612 0 : if (unlikely (new_surface->status))
1613 0 : return new_surface->status;
1614 :
1615 : /* We have to copy these here, so that the coordinate spaces are correct */
1616 0 : new_surface->device_transform = src->device_transform;
1617 0 : new_surface->device_transform_inverse = src->device_transform_inverse;
1618 :
1619 0 : _cairo_pattern_init_for_surface (&pattern, src);
1620 0 : cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
1621 0 : pattern.base.filter = CAIRO_FILTER_NEAREST;
1622 :
1623 0 : status = _cairo_surface_paint (new_surface,
1624 : CAIRO_OPERATOR_SOURCE,
1625 : &pattern.base,
1626 : NULL);
1627 0 : _cairo_pattern_fini (&pattern.base);
1628 :
1629 0 : if (unlikely (status)) {
1630 0 : cairo_surface_destroy (new_surface);
1631 0 : return status;
1632 : }
1633 :
1634 0 : *clone_offset_x = src_x;
1635 0 : *clone_offset_y = src_y;
1636 0 : *clone_out = new_surface;
1637 0 : return CAIRO_STATUS_SUCCESS;
1638 : }
|