Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
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 |
2 | /* cairo - a vector graphics library with display and print output |
3 | * |
3 | * |
4 | * Copyright © 2002 University of Southern California |
4 | * Copyright © 2002 University of Southern California |
5 | * Copyright © 2005 Red Hat, Inc. |
5 | * Copyright © 2005 Red Hat, Inc. |
- | 6 | * Copyright © 2011 Intel Corporation |
|
6 | * |
7 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * 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 | * 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 | * 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 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
Line 38... | Line 39... | ||
38 | * Chris Wilson |
39 | * Chris Wilson |
39 | */ |
40 | */ |
Line 40... | Line 41... | ||
40 | 41 | ||
Line 41... | Line -... | ||
41 | #include "cairoint.h" |
- | |
42 | - | ||
43 | #include "cairo-boxes-private.h" |
- | |
44 | #include "cairo-clip-private.h" |
- | |
45 | #include "cairo-composite-rectangles-private.h" |
42 | #include "cairoint.h" |
46 | #include "cairo-error-private.h" |
- | |
47 | #include "cairo-region-private.h" |
43 | |
Line 48... | Line -... | ||
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); |
44 | #include "cairo-compositor-private.h" |
878 | } |
45 | #include "cairo-surface-fallback-private.h" |
879 | 46 | ||
880 | cairo_status_t |
47 | cairo_int_status_t |
881 | _cairo_surface_fallback_paint (cairo_surface_t *surface, |
48 | _cairo_surface_fallback_paint (void *surface, |
882 | cairo_operator_t op, |
49 | 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)) |
50 | const cairo_pattern_t *source, |
896 | ASSERT_NOT_REACHED; |
- | |
897 | - | ||
898 | status = _cairo_composite_rectangles_init_for_paint (&extents, |
51 | const cairo_clip_t *clip) |
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); |
52 | { |
Line 991... | Line 53... | ||
991 | 53 | return _cairo_compositor_paint (&_cairo_fallback_compositor, |
|
992 | return status; |
54 | surface, op, source, clip); |
993 | } |
55 | } |
994 | 56 | ||
995 | cairo_status_t |
57 | cairo_int_status_t |
996 | _cairo_surface_fallback_mask (cairo_surface_t *surface, |
58 | _cairo_surface_fallback_mask (void *surface, |
997 | cairo_operator_t op, |
59 | 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 | 60 | const cairo_pattern_t *source, |
|
1006 | if (!_cairo_surface_get_extents (surface, &rect)) |
- | |
1007 | ASSERT_NOT_REACHED; |
61 | const cairo_pattern_t *mask, |
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, |
62 | const cairo_clip_t *clip) |
Line 1026... | Line 63... | ||
1026 | (void *) mask, |
63 | { |
1027 | surface, |
64 | return _cairo_compositor_mask (&_cairo_fallback_compositor, |
1028 | extents.is_bounded ? &extents.bounded : &extents.unbounded); |
65 | surface, op, source, mask, clip); |
1029 | } |
66 | } |
1030 | 67 | ||
1031 | cairo_status_t |
68 | cairo_int_status_t |
1032 | _cairo_surface_fallback_stroke (cairo_surface_t *surface, |
69 | _cairo_surface_fallback_stroke (void *surface, |
1033 | cairo_operator_t op, |
70 | cairo_operator_t op, |
1034 | const cairo_pattern_t *source, |
71 | const cairo_pattern_t *source, |
1035 | cairo_path_fixed_t *path, |
72 | const cairo_path_fixed_t*path, |
1036 | const cairo_stroke_style_t *stroke_style, |
73 | const cairo_stroke_style_t*style, |
1037 | const cairo_matrix_t *ctm, |
74 | 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; |
75 | const cairo_matrix_t *ctm_inverse, |
1050 | - | ||
1051 | if (!_cairo_surface_get_extents (surface, &rect)) |
- | |
1052 | ASSERT_NOT_REACHED; |
76 | double tolerance, |
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; |
77 | cairo_antialias_t antialias, |
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)) |
78 | const cairo_clip_t *clip) |
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); |
79 | { |
Line 1120... | Line 80... | ||
1120 | if (clip_boxes != boxes_stack) |
80 | return _cairo_compositor_stroke (&_cairo_fallback_compositor, |
1121 | free (clip_boxes); |
81 | surface, op, source, path, |
1122 | 82 | style, ctm,ctm_inverse, |
|
1123 | return status; |
83 | tolerance, antialias, clip); |
1124 | } |
84 | } |
1125 | 85 | ||
1126 | cairo_status_t |
86 | cairo_int_status_t |
1127 | _cairo_surface_fallback_fill (cairo_surface_t *surface, |
87 | _cairo_surface_fallback_fill (void *surface, |
1128 | cairo_operator_t op, |
88 | cairo_operator_t op, |
1129 | const cairo_pattern_t *source, |
89 | 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; |
90 | const cairo_path_fixed_t *path, |
1143 | cairo_status_t status; |
91 | cairo_fill_rule_t fill_rule, |
1144 | - | ||
1145 | if (!_cairo_surface_get_extents (surface, &rect)) |
92 | double tolerance, |
1146 | ASSERT_NOT_REACHED; |
93 | cairo_antialias_t antialias, |
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 | } |
94 | const cairo_clip_t *clip) |
Line 1294... | Line 95... | ||
1294 | 95 | { |
|
1295 | if (extents_region) |
96 | return _cairo_compositor_fill (&_cairo_fallback_compositor, |
1296 | cairo_region_destroy (extents_region); |
97 | surface, op, source, path, |
1297 | 98 | fill_rule, tolerance, antialias, |
|
1298 | return status; |
99 | clip); |
1299 | } |
100 | } |
1300 | 101 | ||
1301 | cairo_status_t |
102 | cairo_int_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 | 103 | _cairo_surface_fallback_glyphs (void *surface, |
|
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 */ |
104 | cairo_operator_t op, |
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); |
105 | const cairo_pattern_t *source, |
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, |
106 | cairo_glyph_t *glyphs, |
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); |
107 | int num_glyphs, |
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; |
108 | cairo_scaled_font_t *scaled_font, |