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 © 2003 University of Southern California
5 : * Copyright © 2009,2010 Intel Corporation
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 : * Chris Wilson <chris@chris-wilson.co.uk>
38 : */
39 :
40 : #include "cairoint.h"
41 :
42 : #include "cairo-boxes-private.h"
43 : #include "cairo-clip-private.h"
44 : #include "cairo-composite-rectangles-private.h"
45 : #include "cairo-error-private.h"
46 : #include "cairo-region-private.h"
47 : #include "cairo-scaled-font-private.h"
48 : #include "cairo-surface-snapshot-private.h"
49 : #include "cairo-surface-subsurface-private.h"
50 :
51 : /* Limit on the width / height of an image surface in pixels. This is
52 : * mainly determined by coordinates of things sent to pixman at the
53 : * moment being in 16.16 format. */
54 : #define MAX_IMAGE_SIZE 32767
55 : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
56 :
57 : /**
58 : * SECTION:cairo-image
59 : * @Title: Image Surfaces
60 : * @Short_Description: Rendering to memory buffers
61 : * @See_Also: #cairo_surface_t
62 : *
63 : * Image surfaces provide the ability to render to memory buffers
64 : * either allocated by cairo or by the calling code. The supported
65 : * image formats are those defined in #cairo_format_t.
66 : */
67 :
68 : /**
69 : * CAIRO_HAS_IMAGE_SURFACE:
70 : *
71 : * Defined if the image surface backend is available.
72 : * The image surface backend is always built in.
73 : * This macro was added for completeness in cairo 1.8.
74 : *
75 : * @Since: 1.8
76 : */
77 :
78 : static cairo_int_status_t
79 : _cairo_image_surface_fill (void *dst,
80 : cairo_operator_t op,
81 : const cairo_pattern_t *source,
82 : cairo_path_fixed_t *path,
83 : cairo_fill_rule_t fill_rule,
84 : double tolerance,
85 : cairo_antialias_t antialias,
86 : cairo_clip_t *clip);
87 :
88 : static pixman_image_t *
89 : _pixman_image_for_solid (const cairo_solid_pattern_t *pattern);
90 :
91 : static cairo_bool_t
92 6 : _cairo_image_surface_is_size_valid (int width, int height)
93 : {
94 6 : return 0 <= width && width <= MAX_IMAGE_SIZE &&
95 12 : 0 <= height && height <= MAX_IMAGE_SIZE;
96 : }
97 :
98 : cairo_format_t
99 3 : _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
100 : {
101 3 : switch (pixman_format) {
102 : case PIXMAN_a8r8g8b8:
103 3 : return CAIRO_FORMAT_ARGB32;
104 : case PIXMAN_x8r8g8b8:
105 0 : return CAIRO_FORMAT_RGB24;
106 : case PIXMAN_a8:
107 0 : return CAIRO_FORMAT_A8;
108 : case PIXMAN_a1:
109 0 : return CAIRO_FORMAT_A1;
110 : case PIXMAN_r5g6b5:
111 0 : return CAIRO_FORMAT_RGB16_565;
112 : case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8:
113 : case PIXMAN_b8g8r8: case PIXMAN_b5g6r5:
114 : case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5:
115 : case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4:
116 : case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2:
117 : case PIXMAN_b2g3r3: case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2:
118 : case PIXMAN_c8: case PIXMAN_g8: case PIXMAN_x4a4:
119 : case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1:
120 : case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4:
121 : case PIXMAN_g4: case PIXMAN_g1:
122 : case PIXMAN_yuy2: case PIXMAN_yv12:
123 : case PIXMAN_b8g8r8x8:
124 : case PIXMAN_b8g8r8a8:
125 : case PIXMAN_x2b10g10r10:
126 : case PIXMAN_a2b10g10r10:
127 : case PIXMAN_x2r10g10b10:
128 : case PIXMAN_a2r10g10b10:
129 : default:
130 0 : return CAIRO_FORMAT_INVALID;
131 : }
132 :
133 : return CAIRO_FORMAT_INVALID;
134 : }
135 :
136 : cairo_content_t
137 3 : _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
138 : {
139 : cairo_content_t content;
140 :
141 3 : content = 0;
142 3 : if (PIXMAN_FORMAT_RGB (pixman_format))
143 3 : content |= CAIRO_CONTENT_COLOR;
144 3 : if (PIXMAN_FORMAT_A (pixman_format))
145 3 : content |= CAIRO_CONTENT_ALPHA;
146 :
147 3 : return content;
148 : }
149 :
150 : cairo_surface_t *
151 3 : _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
152 : pixman_format_code_t pixman_format)
153 : {
154 : cairo_image_surface_t *surface;
155 3 : int width = pixman_image_get_width (pixman_image);
156 3 : int height = pixman_image_get_height (pixman_image);
157 :
158 3 : surface = malloc (sizeof (cairo_image_surface_t));
159 3 : if (unlikely (surface == NULL))
160 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
161 :
162 3 : _cairo_surface_init (&surface->base,
163 : &_cairo_image_surface_backend,
164 : NULL, /* device */
165 : _cairo_content_from_pixman_format (pixman_format));
166 :
167 3 : surface->pixman_image = pixman_image;
168 :
169 3 : surface->pixman_format = pixman_format;
170 3 : surface->format = _cairo_format_from_pixman_format (pixman_format);
171 3 : surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
172 3 : surface->owns_data = FALSE;
173 3 : surface->transparency = CAIRO_IMAGE_UNKNOWN;
174 :
175 3 : surface->width = width;
176 3 : surface->height = height;
177 3 : surface->stride = pixman_image_get_stride (pixman_image);
178 3 : surface->depth = pixman_image_get_depth (pixman_image);
179 :
180 3 : return &surface->base;
181 : }
182 :
183 : cairo_bool_t
184 0 : _pixman_format_from_masks (cairo_format_masks_t *masks,
185 : pixman_format_code_t *format_ret)
186 : {
187 : pixman_format_code_t format;
188 : int format_type;
189 : int a, r, g, b;
190 : cairo_format_masks_t format_masks;
191 :
192 0 : a = _cairo_popcount (masks->alpha_mask);
193 0 : r = _cairo_popcount (masks->red_mask);
194 0 : g = _cairo_popcount (masks->green_mask);
195 0 : b = _cairo_popcount (masks->blue_mask);
196 :
197 0 : if (masks->red_mask) {
198 0 : if (masks->red_mask > masks->blue_mask)
199 0 : format_type = PIXMAN_TYPE_ARGB;
200 : else
201 0 : format_type = PIXMAN_TYPE_ABGR;
202 0 : } else if (masks->alpha_mask) {
203 0 : format_type = PIXMAN_TYPE_A;
204 : } else {
205 0 : return FALSE;
206 : }
207 :
208 0 : format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b);
209 :
210 0 : if (! pixman_format_supported_destination (format))
211 0 : return FALSE;
212 :
213 : /* Sanity check that we got out of PIXMAN_FORMAT exactly what we
214 : * expected. This avoid any problems from something bizarre like
215 : * alpha in the least-significant bits, or insane channel order,
216 : * or whatever. */
217 0 : if (!_pixman_format_to_masks (format, &format_masks) ||
218 0 : masks->bpp != format_masks.bpp ||
219 0 : masks->red_mask != format_masks.red_mask ||
220 0 : masks->green_mask != format_masks.green_mask ||
221 0 : masks->blue_mask != format_masks.blue_mask)
222 : {
223 0 : return FALSE;
224 : }
225 :
226 0 : *format_ret = format;
227 0 : return TRUE;
228 : }
229 :
230 : /* A mask consisting of N bits set to 1. */
231 : #define MASK(N) ((1UL << (N))-1)
232 :
233 : cairo_bool_t
234 0 : _pixman_format_to_masks (pixman_format_code_t format,
235 : cairo_format_masks_t *masks)
236 : {
237 : int a, r, g, b;
238 :
239 0 : masks->bpp = PIXMAN_FORMAT_BPP (format);
240 :
241 : /* Number of bits in each channel */
242 0 : a = PIXMAN_FORMAT_A (format);
243 0 : r = PIXMAN_FORMAT_R (format);
244 0 : g = PIXMAN_FORMAT_G (format);
245 0 : b = PIXMAN_FORMAT_B (format);
246 :
247 0 : switch (PIXMAN_FORMAT_TYPE (format)) {
248 : case PIXMAN_TYPE_ARGB:
249 0 : masks->alpha_mask = MASK (a) << (r + g + b);
250 0 : masks->red_mask = MASK (r) << (g + b);
251 0 : masks->green_mask = MASK (g) << (b);
252 0 : masks->blue_mask = MASK (b);
253 0 : return TRUE;
254 : case PIXMAN_TYPE_ABGR:
255 0 : masks->alpha_mask = MASK (a) << (b + g + r);
256 0 : masks->blue_mask = MASK (b) << (g + r);
257 0 : masks->green_mask = MASK (g) << (r);
258 0 : masks->red_mask = MASK (r);
259 0 : return TRUE;
260 : #ifdef PIXMAN_TYPE_BGRA
261 : case PIXMAN_TYPE_BGRA:
262 0 : masks->blue_mask = MASK (b) << (masks->bpp - b);
263 0 : masks->green_mask = MASK (g) << (masks->bpp - b - g);
264 0 : masks->red_mask = MASK (r) << (masks->bpp - b - g - r);
265 0 : masks->alpha_mask = MASK (a);
266 0 : return TRUE;
267 : #endif
268 : case PIXMAN_TYPE_A:
269 0 : masks->alpha_mask = MASK (a);
270 0 : masks->red_mask = 0;
271 0 : masks->green_mask = 0;
272 0 : masks->blue_mask = 0;
273 0 : return TRUE;
274 : case PIXMAN_TYPE_OTHER:
275 : case PIXMAN_TYPE_COLOR:
276 : case PIXMAN_TYPE_GRAY:
277 : case PIXMAN_TYPE_YUY2:
278 : case PIXMAN_TYPE_YV12:
279 : default:
280 0 : masks->alpha_mask = 0;
281 0 : masks->red_mask = 0;
282 0 : masks->green_mask = 0;
283 0 : masks->blue_mask = 0;
284 0 : return FALSE;
285 : }
286 : }
287 :
288 : pixman_format_code_t
289 3 : _cairo_format_to_pixman_format_code (cairo_format_t format)
290 : {
291 : pixman_format_code_t ret;
292 3 : switch (format) {
293 : case CAIRO_FORMAT_A1:
294 0 : ret = PIXMAN_a1;
295 0 : break;
296 : case CAIRO_FORMAT_A8:
297 0 : ret = PIXMAN_a8;
298 0 : break;
299 : case CAIRO_FORMAT_RGB24:
300 0 : ret = PIXMAN_x8r8g8b8;
301 0 : break;
302 : case CAIRO_FORMAT_RGB16_565:
303 0 : ret = PIXMAN_r5g6b5;
304 0 : break;
305 : case CAIRO_FORMAT_ARGB32:
306 : case CAIRO_FORMAT_INVALID:
307 : default:
308 3 : ret = PIXMAN_a8r8g8b8;
309 3 : break;
310 : }
311 3 : return ret;
312 : }
313 :
314 : cairo_surface_t *
315 3 : _cairo_image_surface_create_with_pixman_format (unsigned char *data,
316 : pixman_format_code_t pixman_format,
317 : int width,
318 : int height,
319 : int stride)
320 : {
321 : cairo_surface_t *surface;
322 : pixman_image_t *pixman_image;
323 :
324 3 : if (! _cairo_image_surface_is_size_valid (width, height))
325 : {
326 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
327 : }
328 :
329 3 : pixman_image = pixman_image_create_bits (pixman_format, width, height,
330 : (uint32_t *) data, stride ? stride : 4);
331 :
332 3 : if (unlikely (pixman_image == NULL))
333 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
334 :
335 3 : surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
336 : pixman_format);
337 3 : if (unlikely (surface->status)) {
338 0 : pixman_image_unref (pixman_image);
339 0 : return surface;
340 : }
341 :
342 : /* we can not make any assumptions about the initial state of user data */
343 3 : surface->is_clear = data == NULL;
344 3 : return surface;
345 : }
346 :
347 : /**
348 : * cairo_image_surface_create:
349 : * @format: format of pixels in the surface to create
350 : * @width: width of the surface, in pixels
351 : * @height: height of the surface, in pixels
352 : *
353 : * Creates an image surface of the specified format and
354 : * dimensions. Initially the surface contents are all
355 : * 0. (Specifically, within each pixel, each color or alpha channel
356 : * belonging to format will be 0. The contents of bits within a pixel,
357 : * but not belonging to the given format are undefined).
358 : *
359 : * Return value: a pointer to the newly created surface. The caller
360 : * owns the surface and should call cairo_surface_destroy() when done
361 : * with it.
362 : *
363 : * This function always returns a valid pointer, but it will return a
364 : * pointer to a "nil" surface if an error such as out of memory
365 : * occurs. You can use cairo_surface_status() to check for this.
366 : **/
367 : cairo_surface_t *
368 0 : cairo_image_surface_create (cairo_format_t format,
369 : int width,
370 : int height)
371 : {
372 : pixman_format_code_t pixman_format;
373 :
374 0 : if (! CAIRO_FORMAT_VALID (format))
375 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
376 :
377 0 : pixman_format = _cairo_format_to_pixman_format_code (format);
378 :
379 0 : return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format,
380 : width, height, -1);
381 : }
382 : slim_hidden_def (cairo_image_surface_create);
383 :
384 : cairo_surface_t *
385 0 : _cairo_image_surface_create_with_content (cairo_content_t content,
386 : int width,
387 : int height)
388 : {
389 0 : return cairo_image_surface_create (_cairo_format_from_content (content),
390 : width, height);
391 : }
392 :
393 : /**
394 : * cairo_format_stride_for_width:
395 : * @format: A #cairo_format_t value
396 : * @width: The desired width of an image surface to be created.
397 : *
398 : * This function provides a stride value that will respect all
399 : * alignment requirements of the accelerated image-rendering code
400 : * within cairo. Typical usage will be of the form:
401 : *
402 : * <informalexample><programlisting>
403 : * int stride;
404 : * unsigned char *data;
405 : * #cairo_surface_t *surface;
406 : *
407 : * stride = cairo_format_stride_for_width (format, width);
408 : * data = malloc (stride * height);
409 : * surface = cairo_image_surface_create_for_data (data, format,
410 : * width, height,
411 : * stride);
412 : * </programlisting></informalexample>
413 : *
414 : * Return value: the appropriate stride to use given the desired
415 : * format and width, or -1 if either the format is invalid or the width
416 : * too large.
417 : *
418 : * Since: 1.6
419 : **/
420 : int
421 3 : cairo_format_stride_for_width (cairo_format_t format,
422 : int width)
423 : {
424 : int bpp;
425 :
426 3 : if (! CAIRO_FORMAT_VALID (format)) {
427 0 : _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
428 0 : return -1;
429 : }
430 :
431 3 : bpp = _cairo_format_bits_per_pixel (format);
432 3 : if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp))
433 0 : return -1;
434 :
435 3 : return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
436 : }
437 : slim_hidden_def (cairo_format_stride_for_width);
438 :
439 : /**
440 : * cairo_image_surface_create_for_data:
441 : * @data: a pointer to a buffer supplied by the application in which
442 : * to write contents. This pointer must be suitably aligned for any
443 : * kind of variable, (for example, a pointer returned by malloc).
444 : * @format: the format of pixels in the buffer
445 : * @width: the width of the image to be stored in the buffer
446 : * @height: the height of the image to be stored in the buffer
447 : * @stride: the number of bytes between the start of rows in the
448 : * buffer as allocated. This value should always be computed by
449 : * cairo_format_stride_for_width() before allocating the data
450 : * buffer.
451 : *
452 : * Creates an image surface for the provided pixel data. The output
453 : * buffer must be kept around until the #cairo_surface_t is destroyed
454 : * or cairo_surface_finish() is called on the surface. The initial
455 : * contents of @data will be used as the initial image contents; you
456 : * must explicitly clear the buffer, using, for example,
457 : * cairo_rectangle() and cairo_fill() if you want it cleared.
458 : *
459 : * Note that the stride may be larger than
460 : * width*bytes_per_pixel to provide proper alignment for each pixel
461 : * and row. This alignment is required to allow high-performance rendering
462 : * within cairo. The correct way to obtain a legal stride value is to
463 : * call cairo_format_stride_for_width() with the desired format and
464 : * maximum image width value, and then use the resulting stride value
465 : * to allocate the data and to create the image surface. See
466 : * cairo_format_stride_for_width() for example code.
467 : *
468 : * Return value: a pointer to the newly created surface. The caller
469 : * owns the surface and should call cairo_surface_destroy() when done
470 : * with it.
471 : *
472 : * This function always returns a valid pointer, but it will return a
473 : * pointer to a "nil" surface in the case of an error such as out of
474 : * memory or an invalid stride value. In case of invalid stride value
475 : * the error status of the returned surface will be
476 : * %CAIRO_STATUS_INVALID_STRIDE. You can use
477 : * cairo_surface_status() to check for this.
478 : *
479 : * See cairo_surface_set_user_data() for a means of attaching a
480 : * destroy-notification fallback to the surface if necessary.
481 : **/
482 : cairo_surface_t *
483 3 : cairo_image_surface_create_for_data (unsigned char *data,
484 : cairo_format_t format,
485 : int width,
486 : int height,
487 : int stride)
488 : {
489 : pixman_format_code_t pixman_format;
490 : int minstride;
491 :
492 3 : if (! CAIRO_FORMAT_VALID (format))
493 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
494 :
495 3 : if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
496 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
497 :
498 3 : if (! _cairo_image_surface_is_size_valid (width, height))
499 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
500 :
501 3 : minstride = cairo_format_stride_for_width (format, width);
502 3 : if (stride < 0) {
503 0 : if (stride > -minstride) {
504 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
505 : }
506 : } else {
507 3 : if (stride < minstride) {
508 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
509 : }
510 : }
511 :
512 3 : pixman_format = _cairo_format_to_pixman_format_code (format);
513 3 : return _cairo_image_surface_create_with_pixman_format (data,
514 : pixman_format,
515 : width, height,
516 : stride);
517 : }
518 : slim_hidden_def (cairo_image_surface_create_for_data);
519 :
520 : /**
521 : * cairo_image_surface_get_data:
522 : * @surface: a #cairo_image_surface_t
523 : *
524 : * Get a pointer to the data of the image surface, for direct
525 : * inspection or modification.
526 : *
527 : * Return value: a pointer to the image data of this surface or %NULL
528 : * if @surface is not an image surface, or if cairo_surface_finish()
529 : * has been called.
530 : *
531 : * Since: 1.2
532 : **/
533 : unsigned char *
534 0 : cairo_image_surface_get_data (cairo_surface_t *surface)
535 : {
536 0 : cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
537 :
538 0 : if (! _cairo_surface_is_image (surface)) {
539 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
540 0 : return NULL;
541 : }
542 :
543 0 : return image_surface->data;
544 : }
545 : slim_hidden_def (cairo_image_surface_get_data);
546 :
547 : /**
548 : * cairo_image_surface_get_format:
549 : * @surface: a #cairo_image_surface_t
550 : *
551 : * Get the format of the surface.
552 : *
553 : * Return value: the format of the surface
554 : *
555 : * Since: 1.2
556 : **/
557 : cairo_format_t
558 0 : cairo_image_surface_get_format (cairo_surface_t *surface)
559 : {
560 0 : cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
561 :
562 0 : if (! _cairo_surface_is_image (surface)) {
563 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
564 0 : return CAIRO_FORMAT_INVALID;
565 : }
566 :
567 0 : return image_surface->format;
568 : }
569 : slim_hidden_def (cairo_image_surface_get_format);
570 :
571 : /**
572 : * cairo_image_surface_get_width:
573 : * @surface: a #cairo_image_surface_t
574 : *
575 : * Get the width of the image surface in pixels.
576 : *
577 : * Return value: the width of the surface in pixels.
578 : **/
579 : int
580 0 : cairo_image_surface_get_width (cairo_surface_t *surface)
581 : {
582 0 : cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
583 :
584 0 : if (! _cairo_surface_is_image (surface)) {
585 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
586 0 : return 0;
587 : }
588 :
589 0 : return image_surface->width;
590 : }
591 : slim_hidden_def (cairo_image_surface_get_width);
592 :
593 : /**
594 : * cairo_image_surface_get_height:
595 : * @surface: a #cairo_image_surface_t
596 : *
597 : * Get the height of the image surface in pixels.
598 : *
599 : * Return value: the height of the surface in pixels.
600 : **/
601 : int
602 0 : cairo_image_surface_get_height (cairo_surface_t *surface)
603 : {
604 0 : cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
605 :
606 0 : if (! _cairo_surface_is_image (surface)) {
607 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
608 0 : return 0;
609 : }
610 :
611 0 : return image_surface->height;
612 : }
613 : slim_hidden_def (cairo_image_surface_get_height);
614 :
615 : /**
616 : * cairo_image_surface_get_stride:
617 : * @surface: a #cairo_image_surface_t
618 : *
619 : * Get the stride of the image surface in bytes
620 : *
621 : * Return value: the stride of the image surface in bytes (or 0 if
622 : * @surface is not an image surface). The stride is the distance in
623 : * bytes from the beginning of one row of the image data to the
624 : * beginning of the next row.
625 : *
626 : * Since: 1.2
627 : **/
628 : int
629 0 : cairo_image_surface_get_stride (cairo_surface_t *surface)
630 : {
631 :
632 0 : cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
633 :
634 0 : if (! _cairo_surface_is_image (surface)) {
635 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
636 0 : return 0;
637 : }
638 :
639 0 : return image_surface->stride;
640 : }
641 : slim_hidden_def (cairo_image_surface_get_stride);
642 :
643 : cairo_format_t
644 0 : _cairo_format_from_content (cairo_content_t content)
645 : {
646 0 : switch (content) {
647 : case CAIRO_CONTENT_COLOR:
648 0 : return CAIRO_FORMAT_RGB24;
649 : case CAIRO_CONTENT_ALPHA:
650 0 : return CAIRO_FORMAT_A8;
651 : case CAIRO_CONTENT_COLOR_ALPHA:
652 0 : return CAIRO_FORMAT_ARGB32;
653 : }
654 :
655 0 : ASSERT_NOT_REACHED;
656 0 : return CAIRO_FORMAT_INVALID;
657 : }
658 :
659 : cairo_content_t
660 0 : _cairo_content_from_format (cairo_format_t format)
661 : {
662 0 : switch (format) {
663 : case CAIRO_FORMAT_ARGB32:
664 0 : return CAIRO_CONTENT_COLOR_ALPHA;
665 : case CAIRO_FORMAT_RGB24:
666 0 : return CAIRO_CONTENT_COLOR;
667 : case CAIRO_FORMAT_RGB16_565:
668 0 : return CAIRO_CONTENT_COLOR;
669 : case CAIRO_FORMAT_A8:
670 : case CAIRO_FORMAT_A1:
671 0 : return CAIRO_CONTENT_ALPHA;
672 : case CAIRO_FORMAT_INVALID:
673 0 : break;
674 : }
675 :
676 0 : ASSERT_NOT_REACHED;
677 0 : return CAIRO_CONTENT_COLOR_ALPHA;
678 : }
679 :
680 : int
681 3 : _cairo_format_bits_per_pixel (cairo_format_t format)
682 : {
683 3 : switch (format) {
684 : case CAIRO_FORMAT_ARGB32:
685 3 : return 32;
686 : case CAIRO_FORMAT_RGB24:
687 0 : return 32;
688 : case CAIRO_FORMAT_RGB16_565:
689 0 : return 16;
690 : case CAIRO_FORMAT_A8:
691 0 : return 8;
692 : case CAIRO_FORMAT_A1:
693 0 : return 1;
694 : case CAIRO_FORMAT_INVALID:
695 : default:
696 0 : ASSERT_NOT_REACHED;
697 0 : return 0;
698 : }
699 : }
700 :
701 : static cairo_surface_t *
702 0 : _cairo_image_surface_create_similar (void *abstract_other,
703 : cairo_content_t content,
704 : int width,
705 : int height)
706 : {
707 0 : cairo_image_surface_t *other = abstract_other;
708 :
709 0 : if (! _cairo_image_surface_is_size_valid (width, height))
710 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
711 :
712 0 : if (content == other->base.content) {
713 0 : return _cairo_image_surface_create_with_pixman_format (NULL,
714 : other->pixman_format,
715 : width, height,
716 : 0);
717 : }
718 :
719 0 : return _cairo_image_surface_create_with_content (content,
720 : width, height);
721 : }
722 :
723 : static cairo_status_t
724 0 : _cairo_image_surface_finish (void *abstract_surface)
725 : {
726 0 : cairo_image_surface_t *surface = abstract_surface;
727 :
728 0 : if (surface->pixman_image) {
729 0 : pixman_image_unref (surface->pixman_image);
730 0 : surface->pixman_image = NULL;
731 : }
732 :
733 0 : if (surface->owns_data) {
734 0 : free (surface->data);
735 0 : surface->data = NULL;
736 : }
737 :
738 0 : return CAIRO_STATUS_SUCCESS;
739 : }
740 :
741 : void
742 0 : _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
743 : {
744 0 : surface->owns_data = TRUE;
745 0 : }
746 :
747 : static cairo_status_t
748 0 : _cairo_image_surface_acquire_source_image (void *abstract_surface,
749 : cairo_image_surface_t **image_out,
750 : void **image_extra)
751 : {
752 0 : *image_out = abstract_surface;
753 0 : *image_extra = NULL;
754 :
755 0 : return CAIRO_STATUS_SUCCESS;
756 : }
757 :
758 : static void
759 0 : _cairo_image_surface_release_source_image (void *abstract_surface,
760 : cairo_image_surface_t *image,
761 : void *image_extra)
762 : {
763 0 : }
764 :
765 : /* XXX: I think we should fix pixman to match the names/order of the
766 : * cairo operators, but that will likely be better done at the same
767 : * time the X server is ported to pixman, (which will change a lot of
768 : * things in pixman I think).
769 : */
770 : static pixman_op_t
771 0 : _pixman_operator (cairo_operator_t op)
772 : {
773 0 : switch (op) {
774 : case CAIRO_OPERATOR_CLEAR:
775 0 : return PIXMAN_OP_CLEAR;
776 :
777 : case CAIRO_OPERATOR_SOURCE:
778 0 : return PIXMAN_OP_SRC;
779 : case CAIRO_OPERATOR_OVER:
780 0 : return PIXMAN_OP_OVER;
781 : case CAIRO_OPERATOR_IN:
782 0 : return PIXMAN_OP_IN;
783 : case CAIRO_OPERATOR_OUT:
784 0 : return PIXMAN_OP_OUT;
785 : case CAIRO_OPERATOR_ATOP:
786 0 : return PIXMAN_OP_ATOP;
787 :
788 : case CAIRO_OPERATOR_DEST:
789 0 : return PIXMAN_OP_DST;
790 : case CAIRO_OPERATOR_DEST_OVER:
791 0 : return PIXMAN_OP_OVER_REVERSE;
792 : case CAIRO_OPERATOR_DEST_IN:
793 0 : return PIXMAN_OP_IN_REVERSE;
794 : case CAIRO_OPERATOR_DEST_OUT:
795 0 : return PIXMAN_OP_OUT_REVERSE;
796 : case CAIRO_OPERATOR_DEST_ATOP:
797 0 : return PIXMAN_OP_ATOP_REVERSE;
798 :
799 : case CAIRO_OPERATOR_XOR:
800 0 : return PIXMAN_OP_XOR;
801 : case CAIRO_OPERATOR_ADD:
802 0 : return PIXMAN_OP_ADD;
803 : case CAIRO_OPERATOR_SATURATE:
804 0 : return PIXMAN_OP_SATURATE;
805 :
806 : case CAIRO_OPERATOR_MULTIPLY:
807 0 : return PIXMAN_OP_MULTIPLY;
808 : case CAIRO_OPERATOR_SCREEN:
809 0 : return PIXMAN_OP_SCREEN;
810 : case CAIRO_OPERATOR_OVERLAY:
811 0 : return PIXMAN_OP_OVERLAY;
812 : case CAIRO_OPERATOR_DARKEN:
813 0 : return PIXMAN_OP_DARKEN;
814 : case CAIRO_OPERATOR_LIGHTEN:
815 0 : return PIXMAN_OP_LIGHTEN;
816 : case CAIRO_OPERATOR_COLOR_DODGE:
817 0 : return PIXMAN_OP_COLOR_DODGE;
818 : case CAIRO_OPERATOR_COLOR_BURN:
819 0 : return PIXMAN_OP_COLOR_BURN;
820 : case CAIRO_OPERATOR_HARD_LIGHT:
821 0 : return PIXMAN_OP_HARD_LIGHT;
822 : case CAIRO_OPERATOR_SOFT_LIGHT:
823 0 : return PIXMAN_OP_SOFT_LIGHT;
824 : case CAIRO_OPERATOR_DIFFERENCE:
825 0 : return PIXMAN_OP_DIFFERENCE;
826 : case CAIRO_OPERATOR_EXCLUSION:
827 0 : return PIXMAN_OP_EXCLUSION;
828 : case CAIRO_OPERATOR_HSL_HUE:
829 0 : return PIXMAN_OP_HSL_HUE;
830 : case CAIRO_OPERATOR_HSL_SATURATION:
831 0 : return PIXMAN_OP_HSL_SATURATION;
832 : case CAIRO_OPERATOR_HSL_COLOR:
833 0 : return PIXMAN_OP_HSL_COLOR;
834 : case CAIRO_OPERATOR_HSL_LUMINOSITY:
835 0 : return PIXMAN_OP_HSL_LUMINOSITY;
836 :
837 : default:
838 0 : ASSERT_NOT_REACHED;
839 0 : return PIXMAN_OP_OVER;
840 : }
841 : }
842 :
843 : static cairo_status_t
844 0 : _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
845 : cairo_region_t *region)
846 : {
847 0 : if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->rgn))
848 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
849 :
850 0 : return CAIRO_STATUS_SUCCESS;
851 : }
852 :
853 : static void
854 0 : _cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
855 : {
856 0 : pixman_image_set_clip_region32 (surface->pixman_image, NULL);
857 0 : }
858 :
859 : static double
860 0 : _pixman_nearest_sample (double d)
861 : {
862 0 : return ceil (d - .5);
863 : }
864 :
865 : static cairo_bool_t
866 0 : _nearest_sample (cairo_filter_t filter, double *tx, double *ty)
867 : {
868 0 : if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
869 0 : *tx = _pixman_nearest_sample (*tx);
870 0 : *ty = _pixman_nearest_sample (*ty);
871 : } else {
872 0 : if (*tx != floor (*tx) || *ty != floor (*ty))
873 0 : return FALSE;
874 : }
875 0 : return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
876 : }
877 :
878 : #if PIXMAN_HAS_ATOMIC_OPS
879 : static pixman_image_t *__pixman_transparent_image;
880 : static pixman_image_t *__pixman_black_image;
881 : static pixman_image_t *__pixman_white_image;
882 :
883 : static pixman_image_t *
884 : _pixman_transparent_image (void)
885 : {
886 : pixman_image_t *image;
887 :
888 : image = __pixman_transparent_image;
889 : if (unlikely (image == NULL)) {
890 : pixman_color_t color;
891 :
892 : color.red = 0x00;
893 : color.green = 0x00;
894 : color.blue = 0x00;
895 : color.alpha = 0x00;
896 :
897 : image = pixman_image_create_solid_fill (&color);
898 : if (unlikely (image == NULL))
899 : return NULL;
900 :
901 : if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
902 : NULL, image))
903 : {
904 : pixman_image_ref (image);
905 : }
906 : } else {
907 : pixman_image_ref (image);
908 : }
909 :
910 : return image;
911 : }
912 :
913 : static pixman_image_t *
914 : _pixman_black_image (void)
915 : {
916 : pixman_image_t *image;
917 :
918 : image = __pixman_black_image;
919 : if (unlikely (image == NULL)) {
920 : pixman_color_t color;
921 :
922 : color.red = 0x00;
923 : color.green = 0x00;
924 : color.blue = 0x00;
925 : color.alpha = 0xffff;
926 :
927 : image = pixman_image_create_solid_fill (&color);
928 : if (unlikely (image == NULL))
929 : return NULL;
930 :
931 : if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
932 : NULL, image))
933 : {
934 : pixman_image_ref (image);
935 : }
936 : } else {
937 : pixman_image_ref (image);
938 : }
939 :
940 : return image;
941 : }
942 :
943 : static pixman_image_t *
944 : _pixman_white_image (void)
945 : {
946 : pixman_image_t *image;
947 :
948 : image = __pixman_white_image;
949 : if (unlikely (image == NULL)) {
950 : pixman_color_t color;
951 :
952 : color.red = 0xffff;
953 : color.green = 0xffff;
954 : color.blue = 0xffff;
955 : color.alpha = 0xffff;
956 :
957 : image = pixman_image_create_solid_fill (&color);
958 : if (unlikely (image == NULL))
959 : return NULL;
960 :
961 : if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
962 : NULL, image))
963 : {
964 : pixman_image_ref (image);
965 : }
966 : } else {
967 : pixman_image_ref (image);
968 : }
969 :
970 : return image;
971 : }
972 :
973 : static uint32_t
974 : hars_petruska_f54_1_random (void)
975 : {
976 : #define rol(x,k) ((x << k) | (x >> (32-k)))
977 : static uint32_t x;
978 : return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
979 : #undef rol
980 : }
981 :
982 : static struct {
983 : cairo_color_t color;
984 : pixman_image_t *image;
985 : } cache[16];
986 : static int n_cached;
987 :
988 : #else /* !PIXMAN_HAS_ATOMIC_OPS */
989 : static pixman_image_t *
990 0 : _pixman_transparent_image (void)
991 : {
992 0 : return _pixman_image_for_solid (&_cairo_pattern_clear);
993 : }
994 :
995 : static pixman_image_t *
996 0 : _pixman_black_image (void)
997 : {
998 0 : return _pixman_image_for_solid (&_cairo_pattern_black);
999 : }
1000 :
1001 : static pixman_image_t *
1002 0 : _pixman_white_image (void)
1003 : {
1004 0 : return _pixman_image_for_solid (&_cairo_pattern_white);
1005 : }
1006 : #endif /* !PIXMAN_HAS_ATOMIC_OPS */
1007 :
1008 : void
1009 0 : _cairo_image_reset_static_data (void)
1010 : {
1011 : #if PIXMAN_HAS_ATOMIC_OPS
1012 : while (n_cached)
1013 : pixman_image_unref (cache[--n_cached].image);
1014 :
1015 : if (__pixman_transparent_image) {
1016 : pixman_image_unref (__pixman_transparent_image);
1017 : __pixman_transparent_image = NULL;
1018 : }
1019 :
1020 : if (__pixman_black_image) {
1021 : pixman_image_unref (__pixman_black_image);
1022 : __pixman_black_image = NULL;
1023 : }
1024 :
1025 : if (__pixman_white_image) {
1026 : pixman_image_unref (__pixman_white_image);
1027 : __pixman_white_image = NULL;
1028 : }
1029 : #endif
1030 0 : }
1031 :
1032 : static pixman_image_t *
1033 0 : _pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
1034 : {
1035 : pixman_color_t color;
1036 : pixman_image_t *image;
1037 :
1038 : #if PIXMAN_HAS_ATOMIC_OPS
1039 : int i;
1040 :
1041 : if (pattern->color.alpha_short <= 0x00ff)
1042 : return _pixman_transparent_image ();
1043 :
1044 : if (pattern->color.alpha_short >= 0xff00) {
1045 : if (pattern->color.red_short <= 0x00ff &&
1046 : pattern->color.green_short <= 0x00ff &&
1047 : pattern->color.blue_short <= 0x00ff)
1048 : {
1049 : return _pixman_black_image ();
1050 : }
1051 :
1052 : if (pattern->color.red_short >= 0xff00 &&
1053 : pattern->color.green_short >= 0xff00 &&
1054 : pattern->color.blue_short >= 0xff00)
1055 : {
1056 : return _pixman_white_image ();
1057 : }
1058 : }
1059 :
1060 : CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
1061 : for (i = 0; i < n_cached; i++) {
1062 : if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
1063 : image = pixman_image_ref (cache[i].image);
1064 : goto UNLOCK;
1065 : }
1066 : }
1067 : #endif
1068 :
1069 0 : color.red = pattern->color.red_short;
1070 0 : color.green = pattern->color.green_short;
1071 0 : color.blue = pattern->color.blue_short;
1072 0 : color.alpha = pattern->color.alpha_short;
1073 :
1074 0 : image = pixman_image_create_solid_fill (&color);
1075 : #if PIXMAN_HAS_ATOMIC_OPS
1076 : if (image == NULL)
1077 : goto UNLOCK;
1078 :
1079 : if (n_cached < ARRAY_LENGTH (cache)) {
1080 : i = n_cached++;
1081 : } else {
1082 : i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
1083 : pixman_image_unref (cache[i].image);
1084 : }
1085 : cache[i].image = pixman_image_ref (image);
1086 : cache[i].color = pattern->color;
1087 :
1088 : UNLOCK:
1089 : CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
1090 : #endif
1091 0 : return image;
1092 : }
1093 :
1094 : static double
1095 0 : clamp (double val, double min, double max)
1096 : {
1097 0 : return val < min ? min : (val > max ? max : val);
1098 : }
1099 :
1100 : static pixman_image_t *
1101 0 : _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
1102 : const cairo_rectangle_int_t *extents,
1103 : int *ix, int *iy)
1104 : {
1105 : pixman_image_t *pixman_image;
1106 : pixman_gradient_stop_t pixman_stops_static[2];
1107 0 : pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
1108 0 : cairo_matrix_t matrix = pattern->base.matrix;
1109 : double tx, ty;
1110 : unsigned int i;
1111 :
1112 0 : if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
1113 0 : pixman_stops = _cairo_malloc_ab (pattern->n_stops,
1114 : sizeof(pixman_gradient_stop_t));
1115 0 : if (unlikely (pixman_stops == NULL))
1116 0 : return NULL;
1117 : }
1118 :
1119 0 : for (i = 0; i < pattern->n_stops; i++) {
1120 0 : pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
1121 0 : pixman_stops[i].color.red = pattern->stops[i].color.red_short;
1122 0 : pixman_stops[i].color.green = pattern->stops[i].color.green_short;
1123 0 : pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
1124 0 : pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
1125 : }
1126 :
1127 0 : if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1128 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
1129 : pixman_point_fixed_t p1, p2;
1130 : double x0, y0, x1, y1, maxabs;
1131 :
1132 : /*
1133 : * Transform the matrix to avoid overflow when converting between
1134 : * cairo_fixed_t and pixman_fixed_t (without incurring performance
1135 : * loss when the transformation is unnecessary).
1136 : *
1137 : * Having a function to compute the required transformation to
1138 : * "normalize" a given bounding box would be generally useful -
1139 : * cf linear patterns, gradient patterns, surface patterns...
1140 : */
1141 0 : x0 = _cairo_fixed_to_double (linear->p1.x);
1142 0 : y0 = _cairo_fixed_to_double (linear->p1.y);
1143 0 : x1 = _cairo_fixed_to_double (linear->p2.x);
1144 0 : y1 = _cairo_fixed_to_double (linear->p2.y);
1145 0 : cairo_matrix_transform_point (&matrix, &x0, &y0);
1146 0 : cairo_matrix_transform_point (&matrix, &x1, &y1);
1147 0 : maxabs = MAX (MAX (fabs (x0), fabs (x1)), MAX (fabs (y0), fabs (y1)));
1148 :
1149 0 : if (maxabs > PIXMAN_MAX_INT)
1150 : {
1151 : double sf;
1152 : cairo_matrix_t scale;
1153 :
1154 0 : sf = PIXMAN_MAX_INT / maxabs;
1155 :
1156 0 : p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
1157 0 : p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
1158 0 : p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
1159 0 : p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
1160 :
1161 : /* cairo_matrix_scale does a pre-scale, we want a post-scale */
1162 0 : cairo_matrix_init_scale (&scale, sf, sf);
1163 0 : cairo_matrix_multiply (&matrix, &matrix, &scale);
1164 : }
1165 : else
1166 : {
1167 0 : p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
1168 0 : p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
1169 0 : p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
1170 0 : p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
1171 : }
1172 :
1173 0 : pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
1174 : pixman_stops,
1175 0 : pattern->n_stops);
1176 : } else {
1177 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
1178 : pixman_point_fixed_t c1, c2;
1179 : pixman_fixed_t r1, r2;
1180 :
1181 0 : c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
1182 0 : c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
1183 0 : r1 = _cairo_fixed_to_16_16 (radial->r1);
1184 :
1185 0 : c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
1186 0 : c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
1187 0 : r2 = _cairo_fixed_to_16_16 (radial->r2);
1188 :
1189 0 : pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
1190 : pixman_stops,
1191 0 : pattern->n_stops);
1192 : }
1193 :
1194 0 : if (pixman_stops != pixman_stops_static)
1195 0 : free (pixman_stops);
1196 :
1197 0 : if (unlikely (pixman_image == NULL))
1198 0 : return NULL;
1199 :
1200 0 : tx = matrix.x0;
1201 0 : ty = matrix.y0;
1202 0 : if (! _cairo_matrix_is_translation (&matrix) ||
1203 0 : ! _nearest_sample (pattern->base.filter, &tx, &ty))
1204 : {
1205 : pixman_transform_t pixman_transform;
1206 :
1207 0 : if (tx != 0. || ty != 0.) {
1208 : cairo_matrix_t m, inv;
1209 : cairo_status_t status;
1210 : double x, y, max_x, max_y;
1211 :
1212 : /* Pixman also limits the [xy]_offset to 16 bits. We try to evenly
1213 : * spread the bits between the two, but we need to ensure that
1214 : * fabs (tx + extents->x + extents->width) < PIXMAN_MAX_INT &&
1215 : * fabs (ty + extents->y + extents->height) < PIXMAN_MAX_INT,
1216 : * otherwise the gradient won't render.
1217 : */
1218 0 : inv = matrix;
1219 0 : status = cairo_matrix_invert (&inv);
1220 0 : assert (status == CAIRO_STATUS_SUCCESS);
1221 :
1222 0 : x = _cairo_lround (inv.x0 / 2);
1223 0 : y = _cairo_lround (inv.y0 / 2);
1224 :
1225 0 : max_x = PIXMAN_MAX_INT - 1 - fabs (extents->x + extents->width);
1226 0 : x = clamp(x, -max_x, max_x);
1227 0 : max_y = PIXMAN_MAX_INT - 1 - fabs (extents->y + extents->height);
1228 0 : y = clamp(y, -max_y, max_y);
1229 :
1230 0 : tx = -x;
1231 0 : ty = -y;
1232 0 : cairo_matrix_init_translate (&inv, x, y);
1233 0 : cairo_matrix_multiply (&m, &inv, &matrix);
1234 0 : _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
1235 0 : extents->x + extents->width/2.,
1236 0 : extents->y + extents->height/2.);
1237 : } else {
1238 0 : tx = ty = 0;
1239 0 : _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
1240 : &pixman_transform,
1241 0 : extents->x + extents->width/2.,
1242 0 : extents->y + extents->height/2.);
1243 : }
1244 :
1245 0 : if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
1246 0 : pixman_image_unref (pixman_image);
1247 0 : return NULL;
1248 : }
1249 : }
1250 0 : *ix = tx;
1251 0 : *iy = ty;
1252 :
1253 : {
1254 : pixman_repeat_t pixman_repeat;
1255 :
1256 0 : switch (pattern->base.extend) {
1257 : default:
1258 : case CAIRO_EXTEND_NONE:
1259 0 : pixman_repeat = PIXMAN_REPEAT_NONE;
1260 0 : break;
1261 : case CAIRO_EXTEND_REPEAT:
1262 0 : pixman_repeat = PIXMAN_REPEAT_NORMAL;
1263 0 : break;
1264 : case CAIRO_EXTEND_REFLECT:
1265 0 : pixman_repeat = PIXMAN_REPEAT_REFLECT;
1266 0 : break;
1267 : case CAIRO_EXTEND_PAD:
1268 0 : pixman_repeat = PIXMAN_REPEAT_PAD;
1269 0 : break;
1270 : }
1271 :
1272 0 : pixman_image_set_repeat (pixman_image, pixman_repeat);
1273 : }
1274 :
1275 0 : return pixman_image;
1276 : }
1277 :
1278 : struct acquire_source_cleanup {
1279 : cairo_surface_t *surface;
1280 : cairo_image_surface_t *image;
1281 : void *image_extra;
1282 : };
1283 :
1284 : static void
1285 0 : _acquire_source_cleanup (pixman_image_t *pixman_image,
1286 : void *closure)
1287 : {
1288 0 : struct acquire_source_cleanup *data = closure;
1289 :
1290 0 : _cairo_surface_release_source_image (data->surface,
1291 : data->image,
1292 : data->image_extra);
1293 0 : free (data);
1294 0 : }
1295 :
1296 : static cairo_filter_t
1297 0 : sampled_area (const cairo_surface_pattern_t *pattern,
1298 : const cairo_rectangle_int_t *extents,
1299 : cairo_rectangle_int_t *sample)
1300 : {
1301 : cairo_filter_t filter;
1302 : double x1, x2, y1, y2;
1303 : double pad;
1304 :
1305 0 : x1 = extents->x;
1306 0 : y1 = extents->y;
1307 0 : x2 = extents->x + (int) extents->width;
1308 0 : y2 = extents->y + (int) extents->height;
1309 :
1310 0 : _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
1311 : &x1, &y1, &x2, &y2,
1312 : NULL);
1313 :
1314 0 : filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
1315 0 : sample->x = floor (x1 - pad);
1316 0 : sample->y = floor (y1 - pad);
1317 0 : sample->width = ceil (x2 + pad) - sample->x;
1318 0 : sample->height = ceil (y2 + pad) - sample->y;
1319 :
1320 0 : return filter;
1321 : }
1322 :
1323 : static uint16_t
1324 0 : expand_channel (uint16_t v, uint32_t bits)
1325 : {
1326 0 : int offset = 16 - bits;
1327 0 : while (offset > 0) {
1328 0 : v |= v >> bits;
1329 0 : offset -= bits;
1330 0 : bits += bits;
1331 : }
1332 0 : return v;
1333 : }
1334 :
1335 : static pixman_image_t *
1336 0 : _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
1337 : {
1338 : uint32_t pixel;
1339 : pixman_color_t color;
1340 :
1341 0 : switch (image->format) {
1342 : default:
1343 : case CAIRO_FORMAT_INVALID:
1344 0 : ASSERT_NOT_REACHED;
1345 0 : return NULL;
1346 :
1347 : case CAIRO_FORMAT_A1:
1348 0 : pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
1349 0 : return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
1350 :
1351 : case CAIRO_FORMAT_A8:
1352 0 : color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
1353 0 : color.alpha |= color.alpha << 8;
1354 0 : if (color.alpha == 0)
1355 0 : return _pixman_transparent_image ();
1356 :
1357 0 : color.red = color.green = color.blue = 0;
1358 0 : return pixman_image_create_solid_fill (&color);
1359 :
1360 : case CAIRO_FORMAT_RGB16_565:
1361 0 : pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
1362 0 : if (pixel == 0)
1363 0 : return _pixman_black_image ();
1364 0 : if (pixel == 0xffff)
1365 0 : return _pixman_white_image ();
1366 :
1367 0 : color.alpha = 0xffff;
1368 0 : color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
1369 0 : color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
1370 0 : color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
1371 0 : return pixman_image_create_solid_fill (&color);
1372 :
1373 : case CAIRO_FORMAT_ARGB32:
1374 : case CAIRO_FORMAT_RGB24:
1375 0 : pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
1376 0 : color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
1377 0 : if (color.alpha == 0)
1378 0 : return _pixman_transparent_image ();
1379 0 : if (pixel == 0xffffffff)
1380 0 : return _pixman_white_image ();
1381 0 : if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
1382 0 : return _pixman_black_image ();
1383 :
1384 0 : color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
1385 0 : color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
1386 0 : color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
1387 0 : return pixman_image_create_solid_fill (&color);
1388 : }
1389 : }
1390 :
1391 : static pixman_image_t *
1392 0 : _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
1393 : cairo_bool_t is_mask,
1394 : const cairo_rectangle_int_t *extents,
1395 : int *ix, int *iy)
1396 : {
1397 : pixman_image_t *pixman_image;
1398 : cairo_rectangle_int_t sample;
1399 : cairo_extend_t extend;
1400 : cairo_filter_t filter;
1401 : double tx, ty;
1402 :
1403 0 : tx = pattern->base.matrix.x0;
1404 0 : ty = pattern->base.matrix.y0;
1405 :
1406 0 : extend = pattern->base.extend;
1407 0 : filter = sampled_area (pattern, extents, &sample);
1408 :
1409 0 : pixman_image = NULL;
1410 0 : if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
1411 0 : (! is_mask || ! pattern->base.has_component_alpha ||
1412 0 : (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
1413 : {
1414 0 : cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
1415 : cairo_surface_type_t type;
1416 :
1417 0 : if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
1418 0 : source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
1419 :
1420 0 : type = source->base.backend->type;
1421 0 : if (type == CAIRO_SURFACE_TYPE_IMAGE) {
1422 0 : if (sample.width == 1 && sample.height == 1) {
1423 0 : if (sample.x < 0 ||
1424 0 : sample.y < 0 ||
1425 0 : sample.x >= source->width ||
1426 0 : sample.y >= source->height)
1427 : {
1428 0 : if (extend == CAIRO_EXTEND_NONE)
1429 0 : return _pixman_transparent_image ();
1430 : }
1431 : else
1432 : {
1433 0 : return _pixel_to_solid (source, sample.x, sample.y);
1434 : }
1435 : }
1436 :
1437 : #if PIXMAN_HAS_ATOMIC_OPS
1438 : /* avoid allocating a 'pattern' image if we can reuse the original */
1439 : if (extend == CAIRO_EXTEND_NONE &&
1440 : _cairo_matrix_is_translation (&pattern->base.matrix) &&
1441 : _nearest_sample (filter, &tx, &ty))
1442 : {
1443 : *ix = tx;
1444 : *iy = ty;
1445 : return pixman_image_ref (source->pixman_image);
1446 : }
1447 : #endif
1448 :
1449 0 : pixman_image = pixman_image_create_bits (source->pixman_format,
1450 : source->width,
1451 : source->height,
1452 0 : (uint32_t *) source->data,
1453 : source->stride);
1454 0 : if (unlikely (pixman_image == NULL))
1455 0 : return NULL;
1456 0 : } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1457 : cairo_surface_subsurface_t *sub;
1458 0 : cairo_bool_t is_contained = FALSE;
1459 :
1460 0 : sub = (cairo_surface_subsurface_t *) source;
1461 0 : source = (cairo_image_surface_t *) sub->target;
1462 :
1463 0 : if (sample.x >= 0 &&
1464 0 : sample.y >= 0 &&
1465 0 : sample.x + sample.width <= sub->extents.width &&
1466 0 : sample.y + sample.height <= sub->extents.height)
1467 : {
1468 0 : is_contained = TRUE;
1469 : }
1470 :
1471 0 : if (sample.width == 1 && sample.height == 1) {
1472 0 : if (is_contained) {
1473 0 : return _pixel_to_solid (source,
1474 0 : sub->extents.x + sample.x,
1475 0 : sub->extents.y + sample.y);
1476 : } else {
1477 0 : if (extend == CAIRO_EXTEND_NONE)
1478 0 : return _pixman_transparent_image ();
1479 : }
1480 : }
1481 :
1482 : #if PIXMAN_HAS_ATOMIC_OPS
1483 : if (is_contained &&
1484 : _cairo_matrix_is_translation (&pattern->base.matrix) &&
1485 : _nearest_sample (filter, &tx, &ty))
1486 : {
1487 : *ix = tx + sub->extents.x;
1488 : *iy = ty + sub->extents.y;
1489 : return pixman_image_ref (source->pixman_image);
1490 : }
1491 : #endif
1492 :
1493 : /* Avoid sub-byte offsets, force a copy in that case. */
1494 0 : if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
1495 0 : void *data = source->data
1496 0 : + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
1497 0 : + sub->extents.y * source->stride;
1498 0 : pixman_image = pixman_image_create_bits (source->pixman_format,
1499 : sub->extents.width,
1500 : sub->extents.height,
1501 : data,
1502 : source->stride);
1503 0 : if (unlikely (pixman_image == NULL))
1504 0 : return NULL;
1505 : }
1506 : }
1507 : }
1508 :
1509 0 : if (pixman_image == NULL) {
1510 : struct acquire_source_cleanup *cleanup;
1511 : cairo_image_surface_t *image;
1512 : void *extra;
1513 : cairo_status_t status;
1514 :
1515 0 : status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
1516 0 : if (unlikely (status))
1517 0 : return NULL;
1518 :
1519 0 : if (sample.width == 1 && sample.height == 1) {
1520 0 : if (sample.x < 0 ||
1521 0 : sample.y < 0 ||
1522 0 : sample.x >= image->width ||
1523 0 : sample.y >= image->height)
1524 : {
1525 0 : if (extend == CAIRO_EXTEND_NONE) {
1526 0 : pixman_image = _pixman_transparent_image ();
1527 0 : _cairo_surface_release_source_image (pattern->surface, image, extra);
1528 0 : return pixman_image;
1529 : }
1530 : }
1531 : else
1532 : {
1533 0 : pixman_image = _pixel_to_solid (image, sample.x, sample.y);
1534 0 : _cairo_surface_release_source_image (pattern->surface, image, extra);
1535 0 : return pixman_image;
1536 : }
1537 : }
1538 :
1539 0 : pixman_image = pixman_image_create_bits (image->pixman_format,
1540 0 : image->width,
1541 0 : image->height,
1542 0 : (uint32_t *) image->data,
1543 0 : image->stride);
1544 0 : if (unlikely (pixman_image == NULL)) {
1545 0 : _cairo_surface_release_source_image (pattern->surface, image, extra);
1546 0 : return NULL;
1547 : }
1548 :
1549 0 : cleanup = malloc (sizeof (*cleanup));
1550 0 : if (unlikely (cleanup == NULL)) {
1551 0 : _cairo_surface_release_source_image (pattern->surface, image, extra);
1552 0 : pixman_image_unref (pixman_image);
1553 0 : return NULL;
1554 : }
1555 :
1556 0 : cleanup->surface = pattern->surface;
1557 0 : cleanup->image = image;
1558 0 : cleanup->image_extra = extra;
1559 0 : pixman_image_set_destroy_function (pixman_image,
1560 : _acquire_source_cleanup, cleanup);
1561 : }
1562 :
1563 0 : if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
1564 0 : ! _nearest_sample (filter, &tx, &ty))
1565 : {
1566 : pixman_transform_t pixman_transform;
1567 : cairo_matrix_t m;
1568 :
1569 0 : m = pattern->base.matrix;
1570 0 : if (m.x0 != 0. || m.y0 != 0.) {
1571 : cairo_matrix_t inv;
1572 : cairo_status_t status;
1573 : double x, y;
1574 :
1575 : /* pixman also limits the [xy]_offset to 16 bits so evenly
1576 : * spread the bits between the two.
1577 : */
1578 0 : inv = m;
1579 0 : status = cairo_matrix_invert (&inv);
1580 0 : assert (status == CAIRO_STATUS_SUCCESS);
1581 :
1582 0 : x = floor (inv.x0 / 2);
1583 0 : y = floor (inv.y0 / 2);
1584 0 : tx = -x;
1585 0 : ty = -y;
1586 0 : cairo_matrix_init_translate (&inv, x, y);
1587 0 : cairo_matrix_multiply (&m, &inv, &m);
1588 : } else {
1589 0 : tx = ty = 0;
1590 : }
1591 :
1592 0 : _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
1593 0 : extents->x + extents->width/2.,
1594 0 : extents->y + extents->height/2.);
1595 0 : if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
1596 0 : pixman_image_unref (pixman_image);
1597 0 : return NULL;
1598 : }
1599 : }
1600 0 : *ix = tx;
1601 0 : *iy = ty;
1602 :
1603 0 : if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
1604 0 : tx == pattern->base.matrix.x0 &&
1605 0 : ty == pattern->base.matrix.y0)
1606 : {
1607 0 : pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
1608 : }
1609 : else
1610 : {
1611 : pixman_filter_t pixman_filter;
1612 :
1613 0 : switch (filter) {
1614 : case CAIRO_FILTER_FAST:
1615 0 : pixman_filter = PIXMAN_FILTER_FAST;
1616 0 : break;
1617 : case CAIRO_FILTER_GOOD:
1618 0 : pixman_filter = PIXMAN_FILTER_GOOD;
1619 0 : break;
1620 : case CAIRO_FILTER_BEST:
1621 0 : pixman_filter = PIXMAN_FILTER_BEST;
1622 0 : break;
1623 : case CAIRO_FILTER_NEAREST:
1624 0 : pixman_filter = PIXMAN_FILTER_NEAREST;
1625 0 : break;
1626 : case CAIRO_FILTER_BILINEAR:
1627 0 : pixman_filter = PIXMAN_FILTER_BILINEAR;
1628 0 : break;
1629 : case CAIRO_FILTER_GAUSSIAN:
1630 : /* XXX: The GAUSSIAN value has no implementation in cairo
1631 : * whatsoever, so it was really a mistake to have it in the
1632 : * API. We could fix this by officially deprecating it, or
1633 : * else inventing semantics and providing an actual
1634 : * implementation for it. */
1635 : default:
1636 0 : pixman_filter = PIXMAN_FILTER_BEST;
1637 : }
1638 :
1639 0 : pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
1640 : }
1641 :
1642 : {
1643 : pixman_repeat_t pixman_repeat;
1644 :
1645 0 : switch (extend) {
1646 : default:
1647 : case CAIRO_EXTEND_NONE:
1648 0 : pixman_repeat = PIXMAN_REPEAT_NONE;
1649 0 : break;
1650 : case CAIRO_EXTEND_REPEAT:
1651 0 : pixman_repeat = PIXMAN_REPEAT_NORMAL;
1652 0 : break;
1653 : case CAIRO_EXTEND_REFLECT:
1654 0 : pixman_repeat = PIXMAN_REPEAT_REFLECT;
1655 0 : break;
1656 : case CAIRO_EXTEND_PAD:
1657 0 : pixman_repeat = PIXMAN_REPEAT_PAD;
1658 0 : break;
1659 : }
1660 :
1661 0 : pixman_image_set_repeat (pixman_image, pixman_repeat);
1662 : }
1663 :
1664 0 : if (pattern->base.has_component_alpha)
1665 0 : pixman_image_set_component_alpha (pixman_image, TRUE);
1666 :
1667 0 : return pixman_image;
1668 : }
1669 :
1670 : static pixman_image_t *
1671 0 : _pixman_image_for_pattern (const cairo_pattern_t *pattern,
1672 : cairo_bool_t is_mask,
1673 : const cairo_rectangle_int_t *extents,
1674 : int *tx, int *ty)
1675 : {
1676 0 : *tx = *ty = 0;
1677 :
1678 0 : if (pattern == NULL)
1679 0 : return _pixman_white_image ();
1680 :
1681 0 : switch (pattern->type) {
1682 : default:
1683 0 : ASSERT_NOT_REACHED;
1684 : case CAIRO_PATTERN_TYPE_SOLID:
1685 0 : return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
1686 :
1687 : case CAIRO_PATTERN_TYPE_RADIAL:
1688 : case CAIRO_PATTERN_TYPE_LINEAR:
1689 0 : return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
1690 : extents, tx, ty);
1691 :
1692 : case CAIRO_PATTERN_TYPE_SURFACE:
1693 0 : return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
1694 : is_mask, extents, tx, ty);
1695 : }
1696 : }
1697 :
1698 : static cairo_status_t
1699 0 : _cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
1700 : const cairo_composite_rectangles_t *rects,
1701 : cairo_clip_t *clip)
1702 : {
1703 0 : pixman_image_t *mask = NULL;
1704 : pixman_box32_t boxes[4];
1705 0 : int i, mask_x = 0, mask_y = 0, n_boxes = 0;
1706 :
1707 0 : if (clip != NULL) {
1708 : cairo_surface_t *clip_surface;
1709 : int clip_x, clip_y;
1710 :
1711 0 : clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
1712 0 : if (unlikely (clip_surface->status))
1713 0 : return clip_surface->status;
1714 :
1715 0 : mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
1716 0 : mask_x = -clip_x;
1717 0 : mask_y = -clip_y;
1718 : } else {
1719 0 : if (rects->bounded.width == rects->unbounded.width &&
1720 0 : rects->bounded.height == rects->unbounded.height)
1721 : {
1722 0 : return CAIRO_STATUS_SUCCESS;
1723 : }
1724 : }
1725 :
1726 : /* wholly unbounded? */
1727 0 : if (rects->bounded.width == 0 || rects->bounded.height == 0) {
1728 0 : int x = rects->unbounded.x;
1729 0 : int y = rects->unbounded.y;
1730 0 : int width = rects->unbounded.width;
1731 0 : int height = rects->unbounded.height;
1732 :
1733 0 : if (mask != NULL) {
1734 0 : pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
1735 : mask, NULL, dst->pixman_image,
1736 : x + mask_x, y + mask_y,
1737 : 0, 0,
1738 : x, y,
1739 : width, height);
1740 : } else {
1741 0 : pixman_color_t color = { 0, };
1742 0 : pixman_box32_t box = { x, y, x + width, y + height };
1743 :
1744 0 : if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
1745 : dst->pixman_image,
1746 : &color,
1747 : 1, &box))
1748 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1749 : }
1750 :
1751 0 : return CAIRO_STATUS_SUCCESS;
1752 : }
1753 :
1754 : /* top */
1755 0 : if (rects->bounded.y != rects->unbounded.y) {
1756 0 : boxes[n_boxes].x1 = rects->unbounded.x;
1757 0 : boxes[n_boxes].y1 = rects->unbounded.y;
1758 0 : boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1759 0 : boxes[n_boxes].y2 = rects->bounded.y;
1760 0 : n_boxes++;
1761 : }
1762 :
1763 : /* left */
1764 0 : if (rects->bounded.x != rects->unbounded.x) {
1765 0 : boxes[n_boxes].x1 = rects->unbounded.x;
1766 0 : boxes[n_boxes].y1 = rects->bounded.y;
1767 0 : boxes[n_boxes].x2 = rects->bounded.x;
1768 0 : boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
1769 0 : n_boxes++;
1770 : }
1771 :
1772 : /* right */
1773 0 : if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
1774 0 : boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
1775 0 : boxes[n_boxes].y1 = rects->bounded.y;
1776 0 : boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1777 0 : boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
1778 0 : n_boxes++;
1779 : }
1780 :
1781 : /* bottom */
1782 0 : if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
1783 0 : boxes[n_boxes].x1 = rects->unbounded.x;
1784 0 : boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
1785 0 : boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1786 0 : boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
1787 0 : n_boxes++;
1788 : }
1789 :
1790 0 : if (mask != NULL) {
1791 0 : for (i = 0; i < n_boxes; i++) {
1792 0 : pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
1793 : mask, NULL, dst->pixman_image,
1794 0 : boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
1795 : 0, 0,
1796 : boxes[i].x1, boxes[i].y1,
1797 0 : boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
1798 : }
1799 : } else {
1800 0 : pixman_color_t color = { 0, };
1801 :
1802 0 : if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
1803 : dst->pixman_image,
1804 : &color,
1805 : n_boxes,
1806 : boxes))
1807 : {
1808 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1809 : }
1810 : }
1811 :
1812 0 : return CAIRO_STATUS_SUCCESS;
1813 : }
1814 :
1815 : static cairo_status_t
1816 0 : _cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
1817 : const cairo_composite_rectangles_t *extents,
1818 : cairo_region_t *clip_region,
1819 : cairo_boxes_t *boxes)
1820 : {
1821 : cairo_boxes_t clear;
1822 : cairo_box_t box;
1823 : cairo_status_t status;
1824 : struct _cairo_boxes_chunk *chunk;
1825 : int i;
1826 :
1827 : // If we have no boxes then we need to clear the entire extents
1828 : // because we have nothing to draw.
1829 0 : if (boxes->num_boxes < 1 && clip_region == NULL) {
1830 0 : int x = extents->unbounded.x;
1831 0 : int y = extents->unbounded.y;
1832 0 : int width = extents->unbounded.width;
1833 0 : int height = extents->unbounded.height;
1834 :
1835 0 : pixman_color_t color = { 0 };
1836 0 : pixman_box32_t box = { x, y, x + width, y + height };
1837 :
1838 0 : if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
1839 : dst->pixman_image,
1840 : &color,
1841 : 1, &box)) {
1842 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1843 : }
1844 0 : return CAIRO_STATUS_SUCCESS;
1845 : }
1846 :
1847 0 : _cairo_boxes_init (&clear);
1848 :
1849 0 : box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
1850 0 : box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
1851 0 : box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
1852 0 : box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
1853 :
1854 0 : if (clip_region == NULL) {
1855 : cairo_boxes_t tmp;
1856 :
1857 0 : _cairo_boxes_init (&tmp);
1858 :
1859 0 : status = _cairo_boxes_add (&tmp, &box);
1860 0 : assert (status == CAIRO_STATUS_SUCCESS);
1861 :
1862 0 : tmp.chunks.next = &boxes->chunks;
1863 0 : tmp.num_boxes += boxes->num_boxes;
1864 :
1865 0 : status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
1866 : CAIRO_FILL_RULE_WINDING,
1867 : &clear);
1868 :
1869 0 : tmp.chunks.next = NULL;
1870 : } else {
1871 : pixman_box32_t *pbox;
1872 :
1873 0 : pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
1874 0 : _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
1875 :
1876 0 : status = _cairo_boxes_add (&clear, &box);
1877 0 : assert (status == CAIRO_STATUS_SUCCESS);
1878 :
1879 0 : for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1880 0 : for (i = 0; i < chunk->count; i++) {
1881 0 : status = _cairo_boxes_add (&clear, &chunk->base[i]);
1882 0 : if (unlikely (status)) {
1883 0 : _cairo_boxes_fini (&clear);
1884 0 : return status;
1885 : }
1886 : }
1887 : }
1888 :
1889 0 : status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
1890 : CAIRO_FILL_RULE_WINDING,
1891 : &clear);
1892 : }
1893 :
1894 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
1895 0 : for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
1896 0 : for (i = 0; i < chunk->count; i++) {
1897 0 : int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
1898 0 : int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
1899 0 : int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
1900 0 : int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
1901 :
1902 0 : x1 = (x1 < 0 ? 0 : x1);
1903 0 : y1 = (y1 < 0 ? 0 : y1);
1904 0 : if (x2 <= x1 || y2 <= y1)
1905 0 : continue;
1906 0 : pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
1907 0 : PIXMAN_FORMAT_BPP (dst->pixman_format),
1908 : x1, y1, x2 - x1, y2 - y1,
1909 : 0);
1910 : }
1911 : }
1912 : }
1913 :
1914 0 : _cairo_boxes_fini (&clear);
1915 :
1916 0 : return status;
1917 : }
1918 :
1919 : static cairo_bool_t
1920 0 : can_reduce_alpha_op (cairo_operator_t op)
1921 : {
1922 0 : int iop = op;
1923 0 : switch (iop) {
1924 : case CAIRO_OPERATOR_OVER:
1925 : case CAIRO_OPERATOR_SOURCE:
1926 : case CAIRO_OPERATOR_ADD:
1927 0 : return TRUE;
1928 : default:
1929 0 : return FALSE;
1930 : }
1931 : }
1932 :
1933 : static cairo_bool_t
1934 0 : reduce_alpha_op (cairo_image_surface_t *dst,
1935 : cairo_operator_t op,
1936 : const cairo_pattern_t *pattern)
1937 : {
1938 0 : return dst->base.is_clear &&
1939 0 : dst->base.content == CAIRO_CONTENT_ALPHA &&
1940 0 : _cairo_pattern_is_opaque_solid (pattern) &&
1941 0 : can_reduce_alpha_op (op);
1942 : }
1943 :
1944 : /* low level compositor */
1945 : typedef cairo_status_t
1946 : (*image_draw_func_t) (void *closure,
1947 : pixman_image_t *dst,
1948 : pixman_format_code_t dst_format,
1949 : cairo_operator_t op,
1950 : const cairo_pattern_t *src,
1951 : int dst_x,
1952 : int dst_y,
1953 : const cairo_rectangle_int_t *extents,
1954 : cairo_region_t *clip_region);
1955 :
1956 : static pixman_image_t *
1957 0 : _create_composite_mask_pattern (cairo_clip_t *clip,
1958 : image_draw_func_t draw_func,
1959 : void *draw_closure,
1960 : cairo_image_surface_t *dst,
1961 : const cairo_rectangle_int_t *extents)
1962 : {
1963 0 : cairo_region_t *clip_region = NULL;
1964 : pixman_image_t *mask;
1965 : cairo_status_t status;
1966 0 : cairo_bool_t need_clip_surface = FALSE;
1967 :
1968 0 : if (clip != NULL) {
1969 0 : status = _cairo_clip_get_region (clip, &clip_region);
1970 0 : assert (! _cairo_status_is_error (status));
1971 :
1972 : /* The all-clipped state should never propagate this far. */
1973 0 : assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
1974 :
1975 0 : need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
1976 :
1977 0 : if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
1978 0 : clip_region = NULL;
1979 : }
1980 :
1981 0 : mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
1982 : NULL, 0);
1983 0 : if (unlikely (mask == NULL))
1984 0 : return NULL;
1985 :
1986 : /* Is it worth setting the clip region here? */
1987 0 : if (clip_region != NULL) {
1988 : pixman_bool_t ret;
1989 :
1990 0 : pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
1991 0 : ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
1992 0 : pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
1993 :
1994 0 : if (! ret) {
1995 0 : pixman_image_unref (mask);
1996 0 : return NULL;
1997 : }
1998 : }
1999 :
2000 0 : status = draw_func (draw_closure,
2001 : mask, PIXMAN_a8,
2002 : CAIRO_OPERATOR_ADD, NULL,
2003 : extents->x, extents->y,
2004 : extents, NULL);
2005 0 : if (unlikely (status)) {
2006 0 : pixman_image_unref (mask);
2007 0 : return NULL;
2008 : }
2009 :
2010 0 : if (need_clip_surface) {
2011 : cairo_surface_t *tmp;
2012 :
2013 0 : tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
2014 0 : if (unlikely (tmp->status)) {
2015 0 : pixman_image_unref (mask);
2016 0 : return NULL;
2017 : }
2018 :
2019 0 : pixman_image_ref (mask);
2020 :
2021 0 : status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
2022 0 : cairo_surface_destroy (tmp);
2023 0 : if (unlikely (status)) {
2024 0 : pixman_image_unref (mask);
2025 0 : return NULL;
2026 : }
2027 : }
2028 :
2029 0 : if (clip_region != NULL)
2030 0 : pixman_image_set_clip_region (mask, NULL);
2031 :
2032 0 : return mask;
2033 : }
2034 :
2035 : /* Handles compositing with a clip surface when the operator allows
2036 : * us to combine the clip with the mask
2037 : */
2038 : static cairo_status_t
2039 0 : _clip_and_composite_with_mask (cairo_clip_t *clip,
2040 : cairo_operator_t op,
2041 : const cairo_pattern_t *pattern,
2042 : image_draw_func_t draw_func,
2043 : void *draw_closure,
2044 : cairo_image_surface_t *dst,
2045 : const cairo_rectangle_int_t *extents)
2046 : {
2047 : pixman_image_t *mask;
2048 :
2049 0 : mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
2050 0 : if (unlikely (mask == NULL))
2051 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2052 :
2053 0 : if (pattern == NULL) {
2054 0 : if (dst->pixman_format == PIXMAN_a8) {
2055 0 : pixman_image_composite32 (_pixman_operator (op),
2056 : mask, NULL, dst->pixman_image,
2057 : 0, 0, 0, 0,
2058 : extents->x, extents->y,
2059 : extents->width, extents->height);
2060 : } else {
2061 : pixman_image_t *src;
2062 :
2063 0 : src = _pixman_white_image ();
2064 0 : if (unlikely (src == NULL)) {
2065 0 : pixman_image_unref (mask);
2066 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2067 : }
2068 :
2069 0 : pixman_image_composite32 (_pixman_operator (op),
2070 : src, mask, dst->pixman_image,
2071 : 0, 0, 0, 0,
2072 : extents->x, extents->y,
2073 : extents->width, extents->height);
2074 0 : pixman_image_unref (src);
2075 : }
2076 : } else {
2077 : pixman_image_t *src;
2078 : int src_x, src_y;
2079 :
2080 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2081 0 : if (unlikely (src == NULL)) {
2082 0 : pixman_image_unref (mask);
2083 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2084 : }
2085 :
2086 0 : pixman_image_composite32 (_pixman_operator (op),
2087 : src, mask, dst->pixman_image,
2088 0 : extents->x + src_x, extents->y + src_y,
2089 : 0, 0,
2090 : extents->x, extents->y,
2091 : extents->width, extents->height);
2092 0 : pixman_image_unref (src);
2093 : }
2094 :
2095 0 : pixman_image_unref (mask);
2096 :
2097 0 : return CAIRO_STATUS_SUCCESS;
2098 : }
2099 :
2100 : /* Handles compositing with a clip surface when we have to do the operation
2101 : * in two pieces and combine them together.
2102 : */
2103 : static cairo_status_t
2104 0 : _clip_and_composite_combine (cairo_clip_t *clip,
2105 : cairo_operator_t op,
2106 : const cairo_pattern_t *src,
2107 : image_draw_func_t draw_func,
2108 : void *draw_closure,
2109 : cairo_image_surface_t *dst,
2110 : const cairo_rectangle_int_t *extents)
2111 : {
2112 : pixman_image_t *tmp;
2113 : cairo_surface_t *clip_surface;
2114 : int clip_x, clip_y;
2115 : cairo_status_t status;
2116 :
2117 0 : tmp = pixman_image_create_bits (dst->pixman_format,
2118 : extents->width, extents->height,
2119 : NULL, 0);
2120 0 : if (unlikely (tmp == NULL))
2121 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2122 :
2123 0 : if (src == NULL) {
2124 0 : status = (*draw_func) (draw_closure,
2125 : tmp, dst->pixman_format,
2126 : CAIRO_OPERATOR_ADD, NULL,
2127 : extents->x, extents->y,
2128 : extents, NULL);
2129 : } else {
2130 : /* Initialize the temporary surface from the destination surface */
2131 0 : if (! dst->base.is_clear) {
2132 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
2133 : dst->pixman_image, NULL, tmp,
2134 : extents->x, extents->y,
2135 : 0, 0,
2136 : 0, 0,
2137 : extents->width, extents->height);
2138 : }
2139 :
2140 0 : status = (*draw_func) (draw_closure,
2141 : tmp, dst->pixman_format,
2142 : op, src,
2143 : extents->x, extents->y,
2144 : extents, NULL);
2145 : }
2146 0 : if (unlikely (status))
2147 0 : goto CLEANUP_SURFACE;
2148 :
2149 0 : assert (clip->path != NULL);
2150 0 : clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
2151 0 : if (unlikely (clip_surface->status))
2152 0 : goto CLEANUP_SURFACE;
2153 :
2154 0 : if (! dst->base.is_clear) {
2155 : #if PIXMAN_HAS_OP_LERP
2156 : pixman_image_composite32 (PIXMAN_OP_LERP,
2157 : tmp,
2158 : ((cairo_image_surface_t *) clip_surface)->pixman_image,
2159 : dst->pixman_image,
2160 : 0, 0,
2161 : extents->x - clip_x,
2162 : extents->y - clip_y,
2163 : extents->x, extents->y,
2164 : extents->width, extents->height);
2165 : #else
2166 : /* Punch the clip out of the destination */
2167 0 : pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2168 : ((cairo_image_surface_t *) clip_surface)->pixman_image,
2169 : NULL, dst->pixman_image,
2170 0 : extents->x - clip_x,
2171 0 : extents->y - clip_y,
2172 : 0, 0,
2173 : extents->x, extents->y,
2174 : extents->width, extents->height);
2175 :
2176 : /* Now add the two results together */
2177 0 : pixman_image_composite32 (PIXMAN_OP_ADD,
2178 : tmp,
2179 : ((cairo_image_surface_t *) clip_surface)->pixman_image,
2180 : dst->pixman_image,
2181 : 0, 0,
2182 0 : extents->x - clip_x,
2183 0 : extents->y - clip_y,
2184 : extents->x, extents->y,
2185 : extents->width, extents->height);
2186 : #endif
2187 : } else {
2188 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
2189 : tmp,
2190 : ((cairo_image_surface_t *) clip_surface)->pixman_image,
2191 : dst->pixman_image,
2192 : 0, 0,
2193 0 : extents->x - clip_x,
2194 0 : extents->y - clip_y,
2195 : extents->x, extents->y,
2196 : extents->width, extents->height);
2197 : }
2198 :
2199 : CLEANUP_SURFACE:
2200 0 : pixman_image_unref (tmp);
2201 :
2202 0 : return status;
2203 : }
2204 :
2205 : /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
2206 : * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
2207 : */
2208 : static cairo_status_t
2209 0 : _clip_and_composite_source (cairo_clip_t *clip,
2210 : const cairo_pattern_t *pattern,
2211 : image_draw_func_t draw_func,
2212 : void *draw_closure,
2213 : cairo_image_surface_t *dst,
2214 : const cairo_rectangle_int_t *extents)
2215 : {
2216 : pixman_image_t *mask, *src;
2217 : int src_x, src_y;
2218 :
2219 0 : if (pattern == NULL) {
2220 : cairo_region_t *clip_region;
2221 : cairo_status_t status;
2222 :
2223 0 : status = draw_func (draw_closure,
2224 : dst->pixman_image, dst->pixman_format,
2225 : CAIRO_OPERATOR_SOURCE, NULL,
2226 : extents->x, extents->y,
2227 : extents, NULL);
2228 0 : if (unlikely (status))
2229 0 : return status;
2230 :
2231 0 : if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
2232 0 : status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
2233 :
2234 0 : return status;
2235 : }
2236 :
2237 : /* Create a surface that is mask IN clip */
2238 0 : mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
2239 0 : if (unlikely (mask == NULL))
2240 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2241 :
2242 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2243 0 : if (unlikely (src == NULL)) {
2244 0 : pixman_image_unref (mask);
2245 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2246 : }
2247 :
2248 0 : if (! dst->base.is_clear) {
2249 : #if PIXMAN_HAS_OP_LERP
2250 : pixman_image_composite32 (PIXMAN_OP_LERP,
2251 : src, mask, dst->pixman_image,
2252 : extents->x + src_x, extents->y + src_y,
2253 : 0, 0,
2254 : extents->x, extents->y,
2255 : extents->width, extents->height);
2256 : #else
2257 : /* Compute dest' = dest OUT (mask IN clip) */
2258 0 : pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2259 : mask, NULL, dst->pixman_image,
2260 : 0, 0, 0, 0,
2261 : extents->x, extents->y,
2262 : extents->width, extents->height);
2263 :
2264 : /* Now compute (src IN (mask IN clip)) ADD dest' */
2265 0 : pixman_image_composite32 (PIXMAN_OP_ADD,
2266 : src, mask, dst->pixman_image,
2267 0 : extents->x + src_x, extents->y + src_y,
2268 : 0, 0,
2269 : extents->x, extents->y,
2270 : extents->width, extents->height);
2271 : #endif
2272 : } else {
2273 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
2274 : src, mask, dst->pixman_image,
2275 0 : extents->x + src_x, extents->y + src_y,
2276 : 0, 0,
2277 : extents->x, extents->y,
2278 : extents->width, extents->height);
2279 : }
2280 :
2281 0 : pixman_image_unref (src);
2282 0 : pixman_image_unref (mask);
2283 :
2284 0 : return CAIRO_STATUS_SUCCESS;
2285 : }
2286 :
2287 : static cairo_status_t
2288 0 : _clip_and_composite (cairo_image_surface_t *dst,
2289 : cairo_operator_t op,
2290 : const cairo_pattern_t *src,
2291 : image_draw_func_t draw_func,
2292 : void *draw_closure,
2293 : cairo_composite_rectangles_t*extents,
2294 : cairo_clip_t *clip)
2295 : {
2296 : cairo_status_t status;
2297 0 : cairo_region_t *clip_region = NULL;
2298 0 : cairo_bool_t need_clip_surface = FALSE;
2299 :
2300 0 : if (clip != NULL) {
2301 0 : status = _cairo_clip_get_region (clip, &clip_region);
2302 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
2303 0 : return CAIRO_STATUS_SUCCESS;
2304 0 : if (unlikely (_cairo_status_is_error (status)))
2305 0 : return status;
2306 :
2307 0 : need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
2308 :
2309 0 : if (clip_region != NULL) {
2310 : cairo_rectangle_int_t rect;
2311 : cairo_bool_t is_empty;
2312 :
2313 0 : cairo_region_get_extents (clip_region, &rect);
2314 0 : is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect);
2315 0 : if (unlikely (is_empty))
2316 0 : return CAIRO_STATUS_SUCCESS;
2317 :
2318 0 : is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect);
2319 0 : if (unlikely (is_empty && extents->is_bounded))
2320 0 : return CAIRO_STATUS_SUCCESS;
2321 :
2322 0 : if (cairo_region_num_rectangles (clip_region) == 1)
2323 0 : clip_region = NULL;
2324 : }
2325 : }
2326 :
2327 0 : if (clip_region != NULL) {
2328 0 : status = _cairo_image_surface_set_clip_region (dst, clip_region);
2329 0 : if (unlikely (status))
2330 0 : return status;
2331 : }
2332 :
2333 0 : if (reduce_alpha_op (dst, op, src)) {
2334 0 : op = CAIRO_OPERATOR_ADD;
2335 0 : src = NULL;
2336 : }
2337 :
2338 0 : if (op == CAIRO_OPERATOR_SOURCE) {
2339 0 : status = _clip_and_composite_source (clip, src,
2340 : draw_func, draw_closure,
2341 0 : dst, &extents->bounded);
2342 : } else {
2343 0 : if (op == CAIRO_OPERATOR_CLEAR) {
2344 0 : src = NULL;
2345 0 : op = CAIRO_OPERATOR_DEST_OUT;
2346 : }
2347 :
2348 0 : if (need_clip_surface) {
2349 0 : if (extents->is_bounded) {
2350 0 : status = _clip_and_composite_with_mask (clip, op, src,
2351 : draw_func, draw_closure,
2352 0 : dst, &extents->bounded);
2353 : } else {
2354 0 : status = _clip_and_composite_combine (clip, op, src,
2355 : draw_func, draw_closure,
2356 0 : dst, &extents->bounded);
2357 : }
2358 : } else {
2359 0 : status = draw_func (draw_closure,
2360 : dst->pixman_image, dst->pixman_format,
2361 : op, src,
2362 : 0, 0,
2363 0 : &extents->bounded,
2364 : clip_region);
2365 : }
2366 : }
2367 :
2368 0 : if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2369 0 : status = _cairo_image_surface_fixup_unbounded (dst, extents,
2370 : need_clip_surface ? clip : NULL);
2371 : }
2372 :
2373 0 : if (clip_region != NULL)
2374 0 : _cairo_image_surface_unset_clip_region (dst);
2375 :
2376 0 : return status;
2377 : }
2378 :
2379 : #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
2380 : #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
2381 :
2382 : static cairo_bool_t
2383 0 : _line_exceeds_16_16 (const cairo_line_t *line)
2384 : {
2385 : return
2386 0 : line->p1.x <= CAIRO_FIXED_16_16_MIN ||
2387 0 : line->p1.x >= CAIRO_FIXED_16_16_MAX ||
2388 :
2389 0 : line->p2.x <= CAIRO_FIXED_16_16_MIN ||
2390 0 : line->p2.x >= CAIRO_FIXED_16_16_MAX ||
2391 :
2392 0 : line->p1.y <= CAIRO_FIXED_16_16_MIN ||
2393 0 : line->p1.y >= CAIRO_FIXED_16_16_MAX ||
2394 :
2395 0 : line->p2.y <= CAIRO_FIXED_16_16_MIN ||
2396 0 : line->p2.y >= CAIRO_FIXED_16_16_MAX;
2397 : }
2398 :
2399 : static void
2400 0 : _project_line_x_onto_16_16 (const cairo_line_t *line,
2401 : cairo_fixed_t top,
2402 : cairo_fixed_t bottom,
2403 : pixman_line_fixed_t *out)
2404 : {
2405 : cairo_point_double_t p1, p2;
2406 : double m;
2407 :
2408 0 : p1.x = _cairo_fixed_to_double (line->p1.x);
2409 0 : p1.y = _cairo_fixed_to_double (line->p1.y);
2410 :
2411 0 : p2.x = _cairo_fixed_to_double (line->p2.x);
2412 0 : p2.y = _cairo_fixed_to_double (line->p2.y);
2413 :
2414 0 : m = (p2.x - p1.x) / (p2.y - p1.y);
2415 0 : out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
2416 0 : out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
2417 0 : }
2418 :
2419 :
2420 : typedef struct {
2421 : cairo_trapezoid_t *traps;
2422 : int num_traps;
2423 : cairo_antialias_t antialias;
2424 : } composite_traps_info_t;
2425 :
2426 : static void
2427 0 : _pixman_image_add_traps (pixman_image_t *image,
2428 : int dst_x, int dst_y,
2429 : composite_traps_info_t *info)
2430 : {
2431 0 : cairo_trapezoid_t *t = info->traps;
2432 0 : int num_traps = info->num_traps;
2433 0 : while (num_traps--) {
2434 : pixman_trapezoid_t trap;
2435 :
2436 : /* top/bottom will be clamped to surface bounds */
2437 0 : trap.top = _cairo_fixed_to_16_16 (t->top);
2438 0 : trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
2439 :
2440 : /* However, all the other coordinates will have been left untouched so
2441 : * as not to introduce numerical error. Recompute them if they
2442 : * exceed the 16.16 limits.
2443 : */
2444 0 : if (unlikely (_line_exceeds_16_16 (&t->left))) {
2445 0 : _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
2446 0 : trap.left.p1.y = trap.top;
2447 0 : trap.left.p2.y = trap.bottom;
2448 : } else {
2449 0 : trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
2450 0 : trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
2451 0 : trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
2452 0 : trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
2453 : }
2454 :
2455 0 : if (unlikely (_line_exceeds_16_16 (&t->right))) {
2456 0 : _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
2457 0 : trap.right.p1.y = trap.top;
2458 0 : trap.right.p2.y = trap.bottom;
2459 : } else {
2460 0 : trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
2461 0 : trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
2462 0 : trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
2463 0 : trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
2464 : }
2465 :
2466 0 : pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
2467 :
2468 0 : t++;
2469 : }
2470 0 : }
2471 :
2472 : static cairo_status_t
2473 0 : _composite_traps (void *closure,
2474 : pixman_image_t *dst,
2475 : pixman_format_code_t dst_format,
2476 : cairo_operator_t op,
2477 : const cairo_pattern_t *pattern,
2478 : int dst_x,
2479 : int dst_y,
2480 : const cairo_rectangle_int_t *extents,
2481 : cairo_region_t *clip_region)
2482 : {
2483 0 : composite_traps_info_t *info = closure;
2484 : pixman_image_t *src, *mask;
2485 : pixman_format_code_t format;
2486 0 : int src_x = 0, src_y = 0;
2487 : cairo_status_t status;
2488 :
2489 : /* Special case adding trapezoids onto a mask surface; we want to avoid
2490 : * creating an intermediate temporary mask unnecessarily.
2491 : *
2492 : * We make the assumption here that the portion of the trapezoids
2493 : * contained within the surface is bounded by [dst_x,dst_y,width,height];
2494 : * the Cairo core code passes bounds based on the trapezoid extents.
2495 : */
2496 0 : format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
2497 0 : if (dst_format == format &&
2498 0 : (pattern == NULL ||
2499 0 : (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
2500 : {
2501 0 : _pixman_image_add_traps (dst, dst_x, dst_y, info);
2502 0 : return CAIRO_STATUS_SUCCESS;
2503 : }
2504 :
2505 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2506 0 : if (unlikely (src == NULL))
2507 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2508 :
2509 0 : mask = pixman_image_create_bits (format, extents->width, extents->height,
2510 : NULL, 0);
2511 0 : if (unlikely (mask == NULL)) {
2512 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2513 0 : goto CLEANUP_SOURCE;
2514 : }
2515 :
2516 0 : _pixman_image_add_traps (mask, extents->x, extents->y, info);
2517 0 : pixman_image_composite32 (_pixman_operator (op),
2518 : src, mask, dst,
2519 0 : extents->x + src_x, extents->y + src_y,
2520 : 0, 0,
2521 0 : extents->x - dst_x, extents->y - dst_y,
2522 : extents->width, extents->height);
2523 :
2524 0 : pixman_image_unref (mask);
2525 :
2526 0 : status = CAIRO_STATUS_SUCCESS;
2527 : CLEANUP_SOURCE:
2528 0 : pixman_image_unref (src);
2529 :
2530 0 : return status;
2531 : }
2532 :
2533 : static inline uint32_t
2534 0 : color_to_uint32 (const cairo_color_t *color)
2535 : {
2536 : return
2537 0 : (color->alpha_short >> 8 << 24) |
2538 0 : (color->red_short >> 8 << 16) |
2539 0 : (color->green_short & 0xff00) |
2540 0 : (color->blue_short >> 8);
2541 : }
2542 :
2543 : static inline cairo_bool_t
2544 0 : color_to_pixel (const cairo_color_t *color,
2545 : pixman_format_code_t format,
2546 : uint32_t *pixel)
2547 : {
2548 : uint32_t c;
2549 :
2550 0 : if (!(format == PIXMAN_a8r8g8b8 ||
2551 0 : format == PIXMAN_x8r8g8b8 ||
2552 0 : format == PIXMAN_a8b8g8r8 ||
2553 0 : format == PIXMAN_x8b8g8r8 ||
2554 0 : format == PIXMAN_b8g8r8a8 ||
2555 0 : format == PIXMAN_b8g8r8x8 ||
2556 0 : format == PIXMAN_r5g6b5 ||
2557 : format == PIXMAN_b5g6r5 ||
2558 : format == PIXMAN_a8))
2559 : {
2560 0 : return FALSE;
2561 : }
2562 :
2563 0 : c = color_to_uint32 (color);
2564 :
2565 0 : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
2566 0 : c = ((c & 0xff000000) >> 0) |
2567 0 : ((c & 0x00ff0000) >> 16) |
2568 0 : ((c & 0x0000ff00) >> 0) |
2569 0 : ((c & 0x000000ff) << 16);
2570 : }
2571 :
2572 0 : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
2573 0 : c = ((c & 0xff000000) >> 24) |
2574 0 : ((c & 0x00ff0000) >> 8) |
2575 0 : ((c & 0x0000ff00) << 8) |
2576 0 : ((c & 0x000000ff) << 24);
2577 : }
2578 :
2579 0 : if (format == PIXMAN_a8) {
2580 0 : c = c >> 24;
2581 0 : } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
2582 0 : c = ((((c) >> 3) & 0x001f) |
2583 0 : (((c) >> 5) & 0x07e0) |
2584 0 : (((c) >> 8) & 0xf800));
2585 : }
2586 :
2587 0 : *pixel = c;
2588 0 : return TRUE;
2589 : }
2590 :
2591 : static inline cairo_bool_t
2592 0 : pattern_to_pixel (const cairo_solid_pattern_t *solid,
2593 : cairo_operator_t op,
2594 : pixman_format_code_t format,
2595 : uint32_t *pixel)
2596 : {
2597 0 : if (op == CAIRO_OPERATOR_CLEAR) {
2598 0 : *pixel = 0;
2599 0 : return TRUE;
2600 : }
2601 :
2602 0 : if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
2603 0 : return FALSE;
2604 :
2605 0 : if (op == CAIRO_OPERATOR_OVER) {
2606 0 : if (solid->color.alpha_short >= 0xff00)
2607 0 : op = CAIRO_OPERATOR_SOURCE;
2608 : }
2609 :
2610 0 : if (op != CAIRO_OPERATOR_SOURCE)
2611 0 : return FALSE;
2612 :
2613 0 : return color_to_pixel (&solid->color, format, pixel);
2614 : }
2615 :
2616 : typedef struct _fill_span {
2617 : cairo_span_renderer_t base;
2618 :
2619 : uint8_t *mask_data;
2620 : pixman_image_t *src, *dst, *mask;
2621 : } fill_span_renderer_t;
2622 :
2623 : static cairo_status_t
2624 0 : _fill_span (void *abstract_renderer,
2625 : int y, int height,
2626 : const cairo_half_open_span_t *spans,
2627 : unsigned num_spans)
2628 : {
2629 0 : fill_span_renderer_t *renderer = abstract_renderer;
2630 : uint8_t *row;
2631 : unsigned i;
2632 :
2633 0 : if (num_spans == 0)
2634 0 : return CAIRO_STATUS_SUCCESS;
2635 :
2636 0 : row = renderer->mask_data - spans[0].x;
2637 0 : for (i = 0; i < num_spans - 1; i++) {
2638 : /* We implement setting the most common single pixel wide
2639 : * span case to avoid the overhead of a memset call.
2640 : * Open coding setting longer spans didn't show a
2641 : * noticeable improvement over memset.
2642 : */
2643 0 : if (spans[i+1].x == spans[i].x + 1) {
2644 0 : row[spans[i].x] = spans[i].coverage;
2645 : } else {
2646 0 : memset (row + spans[i].x,
2647 0 : spans[i].coverage,
2648 0 : spans[i+1].x - spans[i].x);
2649 : }
2650 : }
2651 :
2652 : do {
2653 0 : pixman_image_composite32 (PIXMAN_OP_OVER,
2654 : renderer->src, renderer->mask, renderer->dst,
2655 : 0, 0, 0, 0,
2656 : spans[0].x, y++,
2657 0 : spans[i].x - spans[0].x, 1);
2658 0 : } while (--height);
2659 :
2660 0 : return CAIRO_STATUS_SUCCESS;
2661 : }
2662 :
2663 : /* avoid using region code to re-validate boxes */
2664 : static cairo_status_t
2665 0 : _fill_unaligned_boxes (cairo_image_surface_t *dst,
2666 : const cairo_pattern_t *pattern,
2667 : uint32_t pixel,
2668 : const cairo_boxes_t *boxes,
2669 : const cairo_composite_rectangles_t *extents)
2670 : {
2671 : uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
2672 : fill_span_renderer_t renderer;
2673 : cairo_rectangular_scan_converter_t converter;
2674 : const struct _cairo_boxes_chunk *chunk;
2675 : cairo_status_t status;
2676 : int i;
2677 :
2678 : /* XXX
2679 : * using composite for fill:
2680 : * spiral-box-nonalign-evenodd-fill.512 2201957 2.202
2681 : * spiral-box-nonalign-nonzero-fill.512 336726 0.337
2682 : * spiral-box-pixalign-evenodd-fill.512 352256 0.352
2683 : * spiral-box-pixalign-nonzero-fill.512 147056 0.147
2684 : * using fill:
2685 : * spiral-box-nonalign-evenodd-fill.512 3174565 3.175
2686 : * spiral-box-nonalign-nonzero-fill.512 182710 0.183
2687 : * spiral-box-pixalign-evenodd-fill.512 353863 0.354
2688 : * spiral-box-pixalign-nonzero-fill.512 147402 0.147
2689 : *
2690 : * cairo-perf-trace seems to favour using fill.
2691 : */
2692 :
2693 0 : renderer.base.render_rows = _fill_span;
2694 0 : renderer.dst = dst->pixman_image;
2695 :
2696 0 : if ((unsigned) extents->bounded.width <= sizeof (buf)) {
2697 0 : renderer.mask = pixman_image_create_bits (PIXMAN_a8,
2698 : extents->bounded.width, 1,
2699 : (uint32_t *) buf,
2700 : sizeof (buf));
2701 : } else {
2702 0 : renderer.mask = pixman_image_create_bits (PIXMAN_a8,
2703 : extents->bounded.width, 1,
2704 : NULL, 0);
2705 : }
2706 0 : if (unlikely (renderer.mask == NULL))
2707 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2708 :
2709 0 : renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
2710 :
2711 0 : renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
2712 0 : if (unlikely (renderer.src == NULL)) {
2713 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2714 0 : goto CLEANUP_MASK;
2715 : }
2716 :
2717 0 : _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
2718 :
2719 : /* first blit any aligned part of the boxes */
2720 0 : for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2721 0 : const cairo_box_t *box = chunk->base;
2722 :
2723 0 : for (i = 0; i < chunk->count; i++) {
2724 0 : int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
2725 0 : int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
2726 0 : int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
2727 0 : int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
2728 :
2729 0 : x1 = (x1 < 0 ? 0 : x1);
2730 0 : y1 = (y1 < 0 ? 0 : y1);
2731 0 : if (x2 > x1 && y2 > y1) {
2732 : cairo_box_t b;
2733 :
2734 0 : pixman_fill ((uint32_t *) dst->data,
2735 0 : dst->stride / sizeof (uint32_t),
2736 0 : PIXMAN_FORMAT_BPP (dst->pixman_format),
2737 : x1, y1, x2 - x1, y2 - y1,
2738 : pixel);
2739 :
2740 : /* top */
2741 0 : if (! _cairo_fixed_is_integer (box[i].p1.y)) {
2742 0 : b.p1.x = box[i].p1.x;
2743 0 : b.p1.y = box[i].p1.y;
2744 0 : b.p2.x = box[i].p2.x;
2745 0 : b.p2.y = _cairo_fixed_from_int (y1);
2746 :
2747 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2748 0 : if (unlikely (status))
2749 0 : goto CLEANUP_CONVERTER;
2750 : }
2751 :
2752 : /* left */
2753 0 : if (! _cairo_fixed_is_integer (box[i].p1.x)) {
2754 0 : b.p1.x = box[i].p1.x;
2755 0 : b.p1.y = box[i].p1.y;
2756 0 : b.p2.x = _cairo_fixed_from_int (x1);
2757 0 : b.p2.y = box[i].p2.y;
2758 :
2759 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2760 0 : if (unlikely (status))
2761 0 : goto CLEANUP_CONVERTER;
2762 : }
2763 :
2764 : /* right */
2765 0 : if (! _cairo_fixed_is_integer (box[i].p2.x)) {
2766 0 : b.p1.x = _cairo_fixed_from_int (x2);
2767 0 : b.p1.y = box[i].p1.y;
2768 0 : b.p2.x = box[i].p2.x;
2769 0 : b.p2.y = box[i].p2.y;
2770 :
2771 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2772 0 : if (unlikely (status))
2773 0 : goto CLEANUP_CONVERTER;
2774 : }
2775 :
2776 : /* bottom */
2777 0 : if (! _cairo_fixed_is_integer (box[i].p2.y)) {
2778 0 : b.p1.x = box[i].p1.x;
2779 0 : b.p1.y = _cairo_fixed_from_int (y2);
2780 0 : b.p2.x = box[i].p2.x;
2781 0 : b.p2.y = box[i].p2.y;
2782 :
2783 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2784 0 : if (unlikely (status))
2785 0 : goto CLEANUP_CONVERTER;
2786 : }
2787 : } else {
2788 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
2789 0 : if (unlikely (status))
2790 0 : goto CLEANUP_CONVERTER;
2791 : }
2792 : }
2793 : }
2794 :
2795 0 : status = converter.base.generate (&converter.base, &renderer.base);
2796 :
2797 : CLEANUP_CONVERTER:
2798 0 : converter.base.destroy (&converter.base);
2799 0 : pixman_image_unref (renderer.src);
2800 : CLEANUP_MASK:
2801 0 : pixman_image_unref (renderer.mask);
2802 :
2803 0 : return status;
2804 : }
2805 :
2806 : typedef struct _cairo_image_surface_span_renderer {
2807 : cairo_span_renderer_t base;
2808 :
2809 : uint8_t *mask_data;
2810 : uint32_t mask_stride;
2811 : } cairo_image_surface_span_renderer_t;
2812 :
2813 : cairo_status_t
2814 0 : _cairo_image_surface_span (void *abstract_renderer,
2815 : int y, int height,
2816 : const cairo_half_open_span_t *spans,
2817 : unsigned num_spans)
2818 : {
2819 0 : cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
2820 : uint8_t *row;
2821 : unsigned i;
2822 :
2823 0 : if (num_spans == 0)
2824 0 : return CAIRO_STATUS_SUCCESS;
2825 :
2826 : /* XXX will it be quicker to repeat the sparse memset,
2827 : * or perform a simpler memcpy?
2828 : * The fairly dense spiral benchmarks suggests that the sparse
2829 : * memset is a win there as well.
2830 : */
2831 0 : row = renderer->mask_data + y * renderer->mask_stride;
2832 : do {
2833 0 : for (i = 0; i < num_spans - 1; i++) {
2834 0 : if (! spans[i].coverage)
2835 0 : continue;
2836 :
2837 : /* We implement setting rendering the most common single
2838 : * pixel wide span case to avoid the overhead of a memset
2839 : * call. Open coding setting longer spans didn't show a
2840 : * noticeable improvement over memset. */
2841 0 : if (spans[i+1].x == spans[i].x + 1) {
2842 0 : row[spans[i].x] = spans[i].coverage;
2843 : } else {
2844 0 : memset (row + spans[i].x,
2845 0 : spans[i].coverage,
2846 0 : spans[i+1].x - spans[i].x);
2847 : }
2848 : }
2849 0 : row += renderer->mask_stride;
2850 0 : } while (--height);
2851 :
2852 0 : return CAIRO_STATUS_SUCCESS;
2853 : }
2854 :
2855 : static cairo_status_t
2856 0 : _composite_unaligned_boxes (cairo_image_surface_t *dst,
2857 : cairo_operator_t op,
2858 : const cairo_pattern_t *pattern,
2859 : const cairo_boxes_t *boxes,
2860 : const cairo_composite_rectangles_t *extents)
2861 : {
2862 : uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
2863 : cairo_image_surface_span_renderer_t renderer;
2864 : cairo_rectangular_scan_converter_t converter;
2865 : pixman_image_t *mask, *src;
2866 : cairo_status_t status;
2867 : const struct _cairo_boxes_chunk *chunk;
2868 : int i, src_x, src_y;
2869 :
2870 0 : i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
2871 0 : if ((unsigned) i <= sizeof (buf)) {
2872 0 : mask = pixman_image_create_bits (PIXMAN_a8,
2873 : extents->bounded.width,
2874 : extents->bounded.height,
2875 : (uint32_t *) buf,
2876 0 : CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
2877 0 : memset (buf, 0, i);
2878 : } else {
2879 0 : mask = pixman_image_create_bits (PIXMAN_a8,
2880 : extents->bounded.width,
2881 : extents->bounded.height,
2882 : NULL, 0);
2883 : }
2884 0 : if (unlikely (mask == NULL))
2885 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2886 :
2887 0 : renderer.base.render_rows = _cairo_image_surface_span;
2888 0 : renderer.mask_stride = pixman_image_get_stride (mask);
2889 0 : renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
2890 0 : renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
2891 :
2892 0 : _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
2893 :
2894 0 : for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2895 0 : const cairo_box_t *box = chunk->base;
2896 :
2897 0 : for (i = 0; i < chunk->count; i++) {
2898 0 : status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
2899 0 : if (unlikely (status))
2900 0 : goto CLEANUP;
2901 : }
2902 : }
2903 :
2904 0 : status = converter.base.generate (&converter.base, &renderer.base);
2905 0 : if (unlikely (status))
2906 0 : goto CLEANUP;
2907 :
2908 0 : src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
2909 0 : if (unlikely (src == NULL)) {
2910 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2911 0 : goto CLEANUP;
2912 : }
2913 :
2914 0 : pixman_image_composite32 (_pixman_operator (op),
2915 : src, mask, dst->pixman_image,
2916 0 : extents->bounded.x + src_x, extents->bounded.y + src_y,
2917 : 0, 0,
2918 : extents->bounded.x, extents->bounded.y,
2919 : extents->bounded.width, extents->bounded.height);
2920 0 : pixman_image_unref (src);
2921 :
2922 : CLEANUP:
2923 0 : converter.base.destroy (&converter.base);
2924 0 : pixman_image_unref (mask);
2925 :
2926 0 : return status;
2927 : }
2928 :
2929 : static cairo_status_t
2930 0 : _composite_boxes (cairo_image_surface_t *dst,
2931 : cairo_operator_t op,
2932 : const cairo_pattern_t *pattern,
2933 : cairo_boxes_t *boxes,
2934 : cairo_antialias_t antialias,
2935 : cairo_clip_t *clip,
2936 : const cairo_composite_rectangles_t *extents)
2937 : {
2938 0 : cairo_region_t *clip_region = NULL;
2939 0 : cairo_bool_t need_clip_mask = FALSE;
2940 : cairo_status_t status;
2941 : struct _cairo_boxes_chunk *chunk;
2942 : uint32_t pixel;
2943 : int i;
2944 :
2945 0 : if (clip != NULL) {
2946 0 : status = _cairo_clip_get_region (clip, &clip_region);
2947 0 : if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
2948 0 : return CAIRO_STATUS_SUCCESS;
2949 0 : need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
2950 0 : if (need_clip_mask &&
2951 0 : (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
2952 : {
2953 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2954 : }
2955 :
2956 0 : if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
2957 0 : clip_region = NULL;
2958 : }
2959 :
2960 0 : if (antialias != CAIRO_ANTIALIAS_NONE) {
2961 0 : if (! boxes->is_pixel_aligned) {
2962 0 : if (need_clip_mask)
2963 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2964 :
2965 0 : if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
2966 : dst->pixman_format, &pixel))
2967 : {
2968 0 : return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
2969 : }
2970 : else
2971 : {
2972 0 : return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
2973 : }
2974 : }
2975 : }
2976 :
2977 0 : status = CAIRO_STATUS_SUCCESS;
2978 0 : if (! need_clip_mask &&
2979 0 : pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
2980 : &pixel))
2981 : {
2982 0 : for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2983 0 : cairo_box_t *box = chunk->base;
2984 :
2985 0 : for (i = 0; i < chunk->count; i++) {
2986 0 : int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
2987 0 : int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
2988 0 : int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
2989 0 : int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
2990 :
2991 0 : x1 = (x1 < 0 ? 0 : x1);
2992 0 : y1 = (y1 < 0 ? 0 : y1);
2993 0 : if (x2 <= x1 || y2 <= y1)
2994 0 : continue;
2995 :
2996 0 : pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
2997 0 : PIXMAN_FORMAT_BPP (dst->pixman_format),
2998 : x1, y1, x2 - x1, y2 - y1,
2999 : pixel);
3000 : }
3001 : }
3002 : }
3003 : else
3004 : {
3005 0 : pixman_image_t *src = NULL, *mask = NULL;
3006 0 : int src_x, src_y, mask_x = 0, mask_y = 0;
3007 0 : pixman_op_t pixman_op = _pixman_operator (op);
3008 :
3009 0 : if (need_clip_mask) {
3010 : cairo_surface_t *clip_surface;
3011 : int clip_x, clip_y;
3012 :
3013 0 : clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
3014 0 : if (unlikely (clip_surface->status))
3015 0 : return clip_surface->status;
3016 :
3017 0 : mask_x = -clip_x;
3018 0 : mask_y = -clip_y;
3019 :
3020 0 : if (op == CAIRO_OPERATOR_CLEAR) {
3021 0 : pattern = NULL;
3022 0 : pixman_op = PIXMAN_OP_OUT_REVERSE;
3023 : }
3024 :
3025 0 : mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
3026 : }
3027 :
3028 0 : if (pattern != NULL) {
3029 0 : src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
3030 0 : if (unlikely (src == NULL))
3031 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3032 : } else {
3033 0 : src = mask;
3034 0 : src_x = mask_x;
3035 0 : src_y = mask_y;
3036 0 : mask = NULL;
3037 : }
3038 :
3039 0 : for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
3040 0 : const cairo_box_t *box = chunk->base;
3041 :
3042 0 : for (i = 0; i < chunk->count; i++) {
3043 0 : int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
3044 0 : int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
3045 0 : int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
3046 0 : int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
3047 :
3048 0 : if (x2 == x1 || y2 == y1)
3049 0 : continue;
3050 :
3051 0 : pixman_image_composite32 (pixman_op,
3052 : src, mask, dst->pixman_image,
3053 : x1 + src_x, y1 + src_y,
3054 : x1 + mask_x, y1 + mask_y,
3055 : x1, y1,
3056 : x2 - x1, y2 - y1);
3057 : }
3058 : }
3059 :
3060 0 : if (pattern != NULL)
3061 0 : pixman_image_unref (src);
3062 :
3063 0 : if (! extents->is_bounded) {
3064 0 : status =
3065 0 : _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
3066 : clip_region, boxes);
3067 : }
3068 : }
3069 :
3070 0 : return status;
3071 : }
3072 :
3073 : static cairo_status_t
3074 0 : _clip_and_composite_boxes (cairo_image_surface_t *dst,
3075 : cairo_operator_t op,
3076 : const cairo_pattern_t *src,
3077 : cairo_boxes_t *boxes,
3078 : cairo_antialias_t antialias,
3079 : cairo_composite_rectangles_t *extents,
3080 : cairo_clip_t *clip)
3081 : {
3082 : cairo_traps_t traps;
3083 : cairo_status_t status;
3084 : composite_traps_info_t info;
3085 :
3086 0 : if (boxes->num_boxes == 0 && extents->is_bounded)
3087 0 : return CAIRO_STATUS_SUCCESS;
3088 :
3089 : /* Use a fast path if the boxes are pixel aligned */
3090 0 : status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
3091 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3092 0 : return status;
3093 :
3094 : /* Otherwise render via a mask and composite in the usual fashion. */
3095 0 : status = _cairo_traps_init_boxes (&traps, boxes);
3096 0 : if (unlikely (status))
3097 0 : return status;
3098 :
3099 0 : info.num_traps = traps.num_traps;
3100 0 : info.traps = traps.traps;
3101 0 : info.antialias = antialias;
3102 0 : status = _clip_and_composite (dst, op, src,
3103 : _composite_traps, &info,
3104 : extents, clip);
3105 :
3106 0 : _cairo_traps_fini (&traps);
3107 0 : return status;
3108 : }
3109 :
3110 : static cairo_bool_t
3111 0 : _mono_edge_is_vertical (const cairo_line_t *line)
3112 : {
3113 0 : return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
3114 : }
3115 :
3116 : static cairo_bool_t
3117 0 : _traps_are_pixel_aligned (cairo_traps_t *traps,
3118 : cairo_antialias_t antialias)
3119 : {
3120 : int i;
3121 :
3122 0 : if (antialias == CAIRO_ANTIALIAS_NONE) {
3123 0 : for (i = 0; i < traps->num_traps; i++) {
3124 0 : if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
3125 0 : ! _mono_edge_is_vertical (&traps->traps[i].right))
3126 : {
3127 0 : traps->maybe_region = FALSE;
3128 0 : return FALSE;
3129 : }
3130 : }
3131 : } else {
3132 0 : for (i = 0; i < traps->num_traps; i++) {
3133 0 : if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
3134 0 : traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
3135 0 : ! _cairo_fixed_is_integer (traps->traps[i].top) ||
3136 0 : ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
3137 0 : ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
3138 0 : ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
3139 : {
3140 0 : traps->maybe_region = FALSE;
3141 0 : return FALSE;
3142 : }
3143 : }
3144 : }
3145 :
3146 0 : return TRUE;
3147 : }
3148 :
3149 : static void
3150 0 : _boxes_for_traps (cairo_boxes_t *boxes,
3151 : cairo_traps_t *traps,
3152 : cairo_antialias_t antialias)
3153 : {
3154 : int i;
3155 :
3156 0 : _cairo_boxes_init (boxes);
3157 :
3158 0 : boxes->num_boxes = traps->num_traps;
3159 0 : boxes->chunks.base = (cairo_box_t *) traps->traps;
3160 0 : boxes->chunks.count = traps->num_traps;
3161 0 : boxes->chunks.size = traps->num_traps;
3162 :
3163 0 : if (antialias != CAIRO_ANTIALIAS_NONE) {
3164 0 : for (i = 0; i < traps->num_traps; i++) {
3165 : /* Note the traps and boxes alias so we need to take the local copies first. */
3166 0 : cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3167 0 : cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3168 0 : cairo_fixed_t y1 = traps->traps[i].top;
3169 0 : cairo_fixed_t y2 = traps->traps[i].bottom;
3170 :
3171 0 : boxes->chunks.base[i].p1.x = x1;
3172 0 : boxes->chunks.base[i].p1.y = y1;
3173 0 : boxes->chunks.base[i].p2.x = x2;
3174 0 : boxes->chunks.base[i].p2.y = y2;
3175 :
3176 0 : if (boxes->is_pixel_aligned) {
3177 0 : boxes->is_pixel_aligned =
3178 0 : _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
3179 0 : _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
3180 : }
3181 : }
3182 : } else {
3183 0 : boxes->is_pixel_aligned = TRUE;
3184 :
3185 0 : for (i = 0; i < traps->num_traps; i++) {
3186 : /* Note the traps and boxes alias so we need to take the local copies first. */
3187 0 : cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3188 0 : cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3189 0 : cairo_fixed_t y1 = traps->traps[i].top;
3190 0 : cairo_fixed_t y2 = traps->traps[i].bottom;
3191 :
3192 : /* round down here to match Pixman's behavior when using traps. */
3193 0 : boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
3194 0 : boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
3195 0 : boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
3196 0 : boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
3197 : }
3198 : }
3199 0 : }
3200 :
3201 : static cairo_status_t
3202 0 : _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
3203 : cairo_operator_t op,
3204 : const cairo_pattern_t *src,
3205 : cairo_traps_t *traps,
3206 : cairo_antialias_t antialias,
3207 : cairo_composite_rectangles_t *extents,
3208 : cairo_clip_t *clip)
3209 : {
3210 : composite_traps_info_t info;
3211 0 : cairo_bool_t need_clip_surface = FALSE;
3212 : cairo_status_t status;
3213 :
3214 0 : if (traps->num_traps == 0 && extents->is_bounded)
3215 0 : return CAIRO_STATUS_SUCCESS;
3216 :
3217 0 : if (clip != NULL) {
3218 : cairo_region_t *clip_region;
3219 :
3220 0 : status = _cairo_clip_get_region (clip, &clip_region);
3221 0 : need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
3222 : }
3223 :
3224 0 : if (traps->has_intersections) {
3225 0 : if (traps->is_rectangular)
3226 0 : status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
3227 0 : else if (traps->is_rectilinear)
3228 0 : status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
3229 : else
3230 0 : status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
3231 0 : if (unlikely (status))
3232 0 : return status;
3233 : }
3234 :
3235 : /* Use a fast path if the trapezoids consist of a simple region,
3236 : * but we can only do this if we do not have a clip surface, or can
3237 : * substitute the mask with the clip.
3238 : */
3239 0 : if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
3240 0 : (! need_clip_surface ||
3241 0 : (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
3242 : {
3243 : cairo_boxes_t boxes;
3244 :
3245 0 : _boxes_for_traps (&boxes, traps, antialias);
3246 0 : return _clip_and_composite_boxes (dst, op, src,
3247 : &boxes, antialias,
3248 : extents, clip);
3249 : }
3250 :
3251 : /* No fast path, exclude self-intersections and clip trapezoids. */
3252 : /* Otherwise render the trapezoids to a mask and composite in the usual
3253 : * fashion.
3254 : */
3255 0 : info.traps = traps->traps;
3256 0 : info.num_traps = traps->num_traps;
3257 0 : info.antialias = antialias;
3258 0 : return _clip_and_composite (dst, op, src,
3259 : _composite_traps, &info,
3260 : extents, clip);
3261 : }
3262 :
3263 : static cairo_clip_path_t *
3264 0 : _clip_get_single_path (cairo_clip_t *clip)
3265 : {
3266 0 : if (clip->path->prev == NULL)
3267 0 : return clip->path;
3268 :
3269 0 : return NULL;
3270 : }
3271 :
3272 : /* high level image interface */
3273 :
3274 : static cairo_int_status_t
3275 0 : _cairo_image_surface_paint (void *abstract_surface,
3276 : cairo_operator_t op,
3277 : const cairo_pattern_t *source,
3278 : cairo_clip_t *clip)
3279 : {
3280 0 : cairo_image_surface_t *surface = abstract_surface;
3281 : cairo_composite_rectangles_t extents;
3282 : cairo_clip_path_t *clip_path;
3283 : cairo_clip_t local_clip;
3284 0 : cairo_bool_t have_clip = FALSE;
3285 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3286 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
3287 : cairo_status_t status;
3288 :
3289 : cairo_rectangle_int_t rect;
3290 0 : rect.x = rect.y = 0;
3291 0 : rect.width = surface->width;
3292 0 : rect.height = surface->height;
3293 :
3294 0 : status = _cairo_composite_rectangles_init_for_paint (&extents,
3295 : &rect,
3296 : op, source,
3297 : clip);
3298 0 : if (unlikely (status))
3299 0 : return status;
3300 :
3301 0 : if (_cairo_clip_contains_extents (clip, &extents))
3302 0 : clip = NULL;
3303 :
3304 0 : if (clip != NULL) {
3305 0 : clip = _cairo_clip_init_copy (&local_clip, clip);
3306 0 : have_clip = TRUE;
3307 : }
3308 :
3309 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3310 0 : if (unlikely (status)) {
3311 0 : if (have_clip)
3312 0 : _cairo_clip_fini (&local_clip);
3313 :
3314 0 : return status;
3315 : }
3316 :
3317 : /* If the clip cannot be reduced to a set of boxes, we will need to
3318 : * use a clipmask. Paint is special as it is the only operation that
3319 : * does not implicitly use a mask, so we may be able to reduce this
3320 : * operation to a fill...
3321 : */
3322 0 : if (clip != NULL &&
3323 0 : extents.is_bounded &&
3324 0 : (clip_path = _clip_get_single_path (clip)) != NULL)
3325 : {
3326 0 : status = _cairo_image_surface_fill (surface, op, source,
3327 : &clip_path->path,
3328 : clip_path->fill_rule,
3329 : clip_path->tolerance,
3330 : clip_path->antialias,
3331 : NULL);
3332 : }
3333 : else
3334 : {
3335 : cairo_boxes_t boxes;
3336 :
3337 0 : _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
3338 0 : status = _clip_and_composite_boxes (surface, op, source,
3339 : &boxes, CAIRO_ANTIALIAS_DEFAULT,
3340 : &extents, clip);
3341 : }
3342 :
3343 0 : if (clip_boxes != boxes_stack)
3344 0 : free (clip_boxes);
3345 :
3346 0 : if (have_clip)
3347 0 : _cairo_clip_fini (&local_clip);
3348 :
3349 0 : return status;
3350 : }
3351 :
3352 : static cairo_status_t
3353 0 : _composite_mask (void *closure,
3354 : pixman_image_t *dst,
3355 : pixman_format_code_t dst_format,
3356 : cairo_operator_t op,
3357 : const cairo_pattern_t *src_pattern,
3358 : int dst_x,
3359 : int dst_y,
3360 : const cairo_rectangle_int_t *extents,
3361 : cairo_region_t *clip_region)
3362 : {
3363 0 : const cairo_pattern_t *mask_pattern = closure;
3364 0 : pixman_image_t *src, *mask = NULL;
3365 0 : int src_x = 0, src_y = 0;
3366 0 : int mask_x = 0, mask_y = 0;
3367 :
3368 0 : if (src_pattern != NULL) {
3369 0 : src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y);
3370 0 : if (unlikely (src == NULL))
3371 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3372 :
3373 0 : mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y);
3374 0 : if (unlikely (mask == NULL)) {
3375 0 : pixman_image_unref (src);
3376 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3377 : }
3378 :
3379 0 : if (mask_pattern->has_component_alpha)
3380 0 : pixman_image_set_component_alpha (mask, TRUE);
3381 : } else {
3382 0 : src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y);
3383 0 : if (unlikely (src == NULL))
3384 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3385 : }
3386 :
3387 0 : pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
3388 0 : extents->x + src_x, extents->y + src_y,
3389 0 : extents->x + mask_x, extents->y + mask_y,
3390 0 : extents->x - dst_x, extents->y - dst_y,
3391 : extents->width, extents->height);
3392 :
3393 0 : if (mask != NULL)
3394 0 : pixman_image_unref (mask);
3395 0 : pixman_image_unref (src);
3396 :
3397 0 : return CAIRO_STATUS_SUCCESS;
3398 : }
3399 :
3400 : static cairo_int_status_t
3401 0 : _cairo_image_surface_mask (void *abstract_surface,
3402 : cairo_operator_t op,
3403 : const cairo_pattern_t *source,
3404 : const cairo_pattern_t *mask,
3405 : cairo_clip_t *clip)
3406 : {
3407 0 : cairo_image_surface_t *surface = abstract_surface;
3408 : cairo_composite_rectangles_t extents;
3409 : cairo_clip_t local_clip;
3410 0 : cairo_bool_t have_clip = FALSE;
3411 : cairo_status_t status;
3412 :
3413 : cairo_rectangle_int_t rect;
3414 0 : rect.x = rect.y = 0;
3415 0 : rect.width = surface->width;
3416 0 : rect.height = surface->height;
3417 :
3418 0 : status = _cairo_composite_rectangles_init_for_mask (&extents,
3419 : &rect,
3420 : op, source, mask, clip);
3421 0 : if (unlikely (status))
3422 0 : return status;
3423 :
3424 0 : if (_cairo_clip_contains_extents (clip, &extents))
3425 0 : clip = NULL;
3426 :
3427 0 : if (clip != NULL && extents.is_bounded) {
3428 0 : clip = _cairo_clip_init_copy (&local_clip, clip);
3429 0 : status = _cairo_clip_rectangle (clip, &extents.bounded);
3430 0 : if (unlikely (status)) {
3431 0 : _cairo_clip_fini (&local_clip);
3432 0 : return status;
3433 : }
3434 :
3435 0 : have_clip = TRUE;
3436 : }
3437 :
3438 0 : status = _clip_and_composite (surface, op, source,
3439 : _composite_mask, (void *) mask,
3440 : &extents, clip);
3441 :
3442 0 : if (have_clip)
3443 0 : _cairo_clip_fini (&local_clip);
3444 :
3445 0 : return status;
3446 : }
3447 :
3448 : typedef struct {
3449 : cairo_polygon_t *polygon;
3450 : cairo_fill_rule_t fill_rule;
3451 : cairo_antialias_t antialias;
3452 : } composite_spans_info_t;
3453 :
3454 : //#define USE_BOTOR_SCAN_CONVERTER
3455 : static cairo_status_t
3456 0 : _composite_spans (void *closure,
3457 : pixman_image_t *dst,
3458 : pixman_format_code_t dst_format,
3459 : cairo_operator_t op,
3460 : const cairo_pattern_t *pattern,
3461 : int dst_x,
3462 : int dst_y,
3463 : const cairo_rectangle_int_t *extents,
3464 : cairo_region_t *clip_region)
3465 : {
3466 : uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
3467 0 : composite_spans_info_t *info = closure;
3468 : cairo_image_surface_span_renderer_t renderer;
3469 : #if USE_BOTOR_SCAN_CONVERTER
3470 : cairo_box_t box;
3471 : cairo_botor_scan_converter_t converter;
3472 : #else
3473 : cairo_scan_converter_t *converter;
3474 : #endif
3475 : pixman_image_t *mask;
3476 : cairo_status_t status;
3477 :
3478 : #if USE_BOTOR_SCAN_CONVERTER
3479 : box.p1.x = _cairo_fixed_from_int (extents->x);
3480 : box.p1.y = _cairo_fixed_from_int (extents->y);
3481 : box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
3482 : box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
3483 : _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
3484 : status = converter.base.add_polygon (&converter.base, info->polygon);
3485 : #else
3486 0 : converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
3487 0 : extents->x + extents->width,
3488 0 : extents->y + extents->height,
3489 : info->fill_rule);
3490 0 : status = converter->add_polygon (converter, info->polygon);
3491 : #endif
3492 0 : if (unlikely (status))
3493 0 : goto CLEANUP_CONVERTER;
3494 :
3495 : /* TODO: support rendering to A1 surfaces (or: go add span
3496 : * compositing to pixman.) */
3497 :
3498 0 : if (pattern == NULL &&
3499 0 : dst_format == PIXMAN_a8 &&
3500 : op == CAIRO_OPERATOR_SOURCE)
3501 : {
3502 0 : mask = dst;
3503 0 : dst = NULL;
3504 : }
3505 : else
3506 : {
3507 0 : int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
3508 0 : uint8_t *data = mask_buf;
3509 :
3510 0 : if (extents->height * stride <= (int) sizeof (mask_buf))
3511 0 : memset (data, 0, extents->height * stride);
3512 : else
3513 0 : data = NULL, stride = 0;
3514 :
3515 0 : mask = pixman_image_create_bits (PIXMAN_a8,
3516 : extents->width,
3517 : extents->height,
3518 : (uint32_t *) data,
3519 : stride);
3520 0 : if (unlikely (mask == NULL)) {
3521 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3522 0 : goto CLEANUP_CONVERTER;
3523 : }
3524 : }
3525 :
3526 0 : renderer.base.render_rows = _cairo_image_surface_span;
3527 0 : renderer.mask_stride = pixman_image_get_stride (mask);
3528 0 : renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
3529 0 : if (dst != NULL)
3530 0 : renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
3531 : else
3532 0 : renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
3533 :
3534 : #if USE_BOTOR_SCAN_CONVERTER
3535 : status = converter.base.generate (&converter.base, &renderer.base);
3536 : #else
3537 0 : status = converter->generate (converter, &renderer.base);
3538 : #endif
3539 0 : if (unlikely (status))
3540 0 : goto CLEANUP_RENDERER;
3541 :
3542 0 : if (dst != NULL) {
3543 : pixman_image_t *src;
3544 : int src_x, src_y;
3545 :
3546 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
3547 0 : if (unlikely (src == NULL)) {
3548 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3549 0 : goto CLEANUP_RENDERER;
3550 : }
3551 :
3552 0 : pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
3553 0 : extents->x + src_x, extents->y + src_y,
3554 : 0, 0, /* mask.x, mask.y */
3555 0 : extents->x - dst_x, extents->y - dst_y,
3556 : extents->width, extents->height);
3557 0 : pixman_image_unref (src);
3558 : }
3559 :
3560 : CLEANUP_RENDERER:
3561 0 : if (dst != NULL)
3562 0 : pixman_image_unref (mask);
3563 : CLEANUP_CONVERTER:
3564 : #if USE_BOTOR_SCAN_CONVERTER
3565 : converter.base.destroy (&converter.base);
3566 : #else
3567 0 : converter->destroy (converter);
3568 : #endif
3569 0 : return status;
3570 : }
3571 :
3572 : static cairo_status_t
3573 0 : _clip_and_composite_polygon (cairo_image_surface_t *dst,
3574 : cairo_operator_t op,
3575 : const cairo_pattern_t *src,
3576 : cairo_polygon_t *polygon,
3577 : cairo_fill_rule_t fill_rule,
3578 : cairo_antialias_t antialias,
3579 : cairo_composite_rectangles_t *extents,
3580 : cairo_clip_t *clip)
3581 : {
3582 : cairo_status_t status;
3583 :
3584 0 : if (polygon->num_edges == 0) {
3585 : cairo_traps_t traps;
3586 :
3587 0 : if (extents->is_bounded)
3588 0 : return CAIRO_STATUS_SUCCESS;
3589 :
3590 0 : _cairo_traps_init (&traps);
3591 0 : status = _clip_and_composite_trapezoids (dst, op, src,
3592 : &traps, antialias,
3593 : extents, clip);
3594 0 : _cairo_traps_fini (&traps);
3595 :
3596 0 : return status;
3597 : }
3598 :
3599 0 : if (_cairo_operator_bounded_by_mask(op)) {
3600 0 : _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
3601 0 : if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
3602 0 : return CAIRO_STATUS_SUCCESS;
3603 : }
3604 :
3605 0 : if (antialias != CAIRO_ANTIALIAS_NONE) {
3606 : composite_spans_info_t info;
3607 :
3608 0 : info.polygon = polygon;
3609 0 : info.fill_rule = fill_rule;
3610 0 : info.antialias = antialias;
3611 :
3612 0 : status = _clip_and_composite (dst, op, src,
3613 : _composite_spans, &info,
3614 : extents, clip);
3615 : } else {
3616 : cairo_traps_t traps;
3617 :
3618 0 : _cairo_traps_init (&traps);
3619 :
3620 : /* Fall back to trapezoid fills. */
3621 0 : status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
3622 : polygon,
3623 : fill_rule);
3624 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
3625 0 : status = _clip_and_composite_trapezoids (dst, op, src,
3626 : &traps, antialias,
3627 : extents, clip);
3628 : }
3629 :
3630 0 : _cairo_traps_fini (&traps);
3631 : }
3632 :
3633 0 : return status;
3634 : }
3635 :
3636 : static cairo_int_status_t
3637 0 : _cairo_image_surface_stroke (void *abstract_surface,
3638 : cairo_operator_t op,
3639 : const cairo_pattern_t *source,
3640 : cairo_path_fixed_t *path,
3641 : const cairo_stroke_style_t *style,
3642 : const cairo_matrix_t *ctm,
3643 : const cairo_matrix_t *ctm_inverse,
3644 : double tolerance,
3645 : cairo_antialias_t antialias,
3646 : cairo_clip_t *clip)
3647 : {
3648 0 : cairo_image_surface_t *surface = abstract_surface;
3649 : cairo_composite_rectangles_t extents;
3650 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3651 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
3652 : cairo_clip_t local_clip;
3653 0 : cairo_bool_t have_clip = FALSE;
3654 : cairo_status_t status;
3655 :
3656 : cairo_rectangle_int_t rect;
3657 0 : rect.x = rect.y = 0;
3658 0 : rect.width = surface->width;
3659 0 : rect.height = surface->height;
3660 :
3661 0 : status = _cairo_composite_rectangles_init_for_stroke (&extents,
3662 : &rect,
3663 : op, source,
3664 : path, style, ctm,
3665 : clip);
3666 0 : if (unlikely (status))
3667 0 : return status;
3668 :
3669 0 : if (_cairo_clip_contains_extents (clip, &extents))
3670 0 : clip = NULL;
3671 :
3672 0 : if (clip != NULL) {
3673 0 : clip = _cairo_clip_init_copy (&local_clip, clip);
3674 0 : have_clip = TRUE;
3675 : }
3676 :
3677 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3678 0 : if (unlikely (status)) {
3679 0 : if (have_clip)
3680 0 : _cairo_clip_fini (&local_clip);
3681 :
3682 0 : return status;
3683 : }
3684 :
3685 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
3686 0 : if (path->is_rectilinear) {
3687 : cairo_boxes_t boxes;
3688 :
3689 0 : _cairo_boxes_init (&boxes);
3690 0 : _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
3691 :
3692 0 : status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
3693 : style,
3694 : ctm,
3695 : &boxes);
3696 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
3697 0 : status = _clip_and_composite_boxes (surface, op, source,
3698 : &boxes, antialias,
3699 : &extents, clip);
3700 : }
3701 :
3702 0 : _cairo_boxes_fini (&boxes);
3703 : }
3704 :
3705 0 : if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3706 : cairo_polygon_t polygon;
3707 :
3708 0 : _cairo_polygon_init (&polygon);
3709 0 : _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
3710 :
3711 0 : status = _cairo_path_fixed_stroke_to_polygon (path,
3712 : style,
3713 : ctm, ctm_inverse,
3714 : tolerance,
3715 : &polygon);
3716 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
3717 0 : status = _clip_and_composite_polygon (surface, op, source, &polygon,
3718 : CAIRO_FILL_RULE_WINDING, antialias,
3719 : &extents, clip);
3720 : }
3721 :
3722 0 : _cairo_polygon_fini (&polygon);
3723 : }
3724 :
3725 0 : if (clip_boxes != boxes_stack)
3726 0 : free (clip_boxes);
3727 :
3728 0 : if (have_clip)
3729 0 : _cairo_clip_fini (&local_clip);
3730 :
3731 0 : return status;
3732 : }
3733 :
3734 : static cairo_int_status_t
3735 0 : _cairo_image_surface_fill (void *abstract_surface,
3736 : cairo_operator_t op,
3737 : const cairo_pattern_t *source,
3738 : cairo_path_fixed_t *path,
3739 : cairo_fill_rule_t fill_rule,
3740 : double tolerance,
3741 : cairo_antialias_t antialias,
3742 : cairo_clip_t *clip)
3743 : {
3744 0 : cairo_image_surface_t *surface = abstract_surface;
3745 : cairo_composite_rectangles_t extents;
3746 0 : cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3747 : cairo_clip_t local_clip;
3748 0 : cairo_bool_t have_clip = FALSE;
3749 0 : int num_boxes = ARRAY_LENGTH (boxes_stack);
3750 : cairo_status_t status;
3751 :
3752 : cairo_rectangle_int_t rect;
3753 0 : rect.x = rect.y = 0;
3754 0 : rect.width = surface->width;
3755 0 : rect.height = surface->height;
3756 :
3757 0 : status = _cairo_composite_rectangles_init_for_fill (&extents,
3758 : &rect,
3759 : op, source, path,
3760 : clip);
3761 0 : if (unlikely (status))
3762 0 : return status;
3763 :
3764 0 : if (_cairo_clip_contains_extents (clip, &extents))
3765 0 : clip = NULL;
3766 :
3767 0 : if (extents.is_bounded && clip != NULL) {
3768 : cairo_clip_path_t *clip_path;
3769 :
3770 0 : if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
3771 0 : _cairo_path_fixed_equal (&clip_path->path, path))
3772 : {
3773 0 : clip = NULL;
3774 : }
3775 : }
3776 :
3777 0 : if (clip != NULL) {
3778 0 : clip = _cairo_clip_init_copy (&local_clip, clip);
3779 0 : have_clip = TRUE;
3780 : }
3781 :
3782 0 : status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3783 0 : if (unlikely (status)) {
3784 0 : if (have_clip)
3785 0 : _cairo_clip_fini (&local_clip);
3786 :
3787 0 : return status;
3788 : }
3789 :
3790 0 : if (_cairo_path_fixed_is_rectilinear_fill (path)) {
3791 : cairo_boxes_t boxes;
3792 :
3793 0 : _cairo_boxes_init (&boxes);
3794 0 : _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
3795 :
3796 0 : status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
3797 : fill_rule,
3798 : &boxes);
3799 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
3800 0 : status = _clip_and_composite_boxes (surface, op, source,
3801 : &boxes, antialias,
3802 : &extents, clip);
3803 : }
3804 :
3805 0 : _cairo_boxes_fini (&boxes);
3806 : } else {
3807 : cairo_polygon_t polygon;
3808 :
3809 0 : assert (! path->is_empty_fill);
3810 :
3811 0 : _cairo_polygon_init (&polygon);
3812 0 : _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
3813 :
3814 0 : status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
3815 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
3816 0 : status = _clip_and_composite_polygon (surface, op, source, &polygon,
3817 : fill_rule, antialias,
3818 : &extents, clip);
3819 : }
3820 :
3821 0 : _cairo_polygon_fini (&polygon);
3822 : }
3823 :
3824 0 : if (clip_boxes != boxes_stack)
3825 0 : free (clip_boxes);
3826 :
3827 0 : if (have_clip)
3828 0 : _cairo_clip_fini (&local_clip);
3829 :
3830 0 : return status;
3831 : }
3832 :
3833 : typedef struct {
3834 : cairo_scaled_font_t *font;
3835 : cairo_glyph_t *glyphs;
3836 : int num_glyphs;
3837 : } composite_glyphs_info_t;
3838 :
3839 : static cairo_status_t
3840 0 : _composite_glyphs_via_mask (void *closure,
3841 : pixman_image_t *dst,
3842 : pixman_format_code_t dst_format,
3843 : cairo_operator_t op,
3844 : const cairo_pattern_t *pattern,
3845 : int dst_x,
3846 : int dst_y,
3847 : const cairo_rectangle_int_t *extents,
3848 : cairo_region_t *clip_region)
3849 : {
3850 0 : composite_glyphs_info_t *info = closure;
3851 0 : cairo_scaled_font_t *font = info->font;
3852 0 : cairo_glyph_t *glyphs = info->glyphs;
3853 0 : int num_glyphs = info->num_glyphs;
3854 0 : pixman_image_t *mask = NULL;
3855 : pixman_image_t *src;
3856 : pixman_image_t *white;
3857 0 : pixman_format_code_t mask_format = 0; /* silence gcc */
3858 : cairo_status_t status;
3859 : int src_x, src_y;
3860 : int i;
3861 :
3862 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
3863 0 : if (unlikely (src == NULL))
3864 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3865 :
3866 0 : white = _pixman_white_image ();
3867 0 : if (unlikely (white == NULL)) {
3868 0 : pixman_image_unref (src);
3869 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3870 : }
3871 :
3872 0 : _cairo_scaled_font_freeze_cache (font);
3873 :
3874 0 : for (i = 0; i < num_glyphs; i++) {
3875 : int x, y;
3876 : cairo_image_surface_t *glyph_surface;
3877 : cairo_scaled_glyph_t *scaled_glyph;
3878 :
3879 0 : status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
3880 : CAIRO_SCALED_GLYPH_INFO_SURFACE,
3881 : &scaled_glyph);
3882 :
3883 0 : if (unlikely (status))
3884 0 : goto CLEANUP;
3885 :
3886 0 : glyph_surface = scaled_glyph->surface;
3887 :
3888 0 : if (glyph_surface->width == 0 || glyph_surface->height == 0)
3889 0 : continue;
3890 :
3891 : /* To start, create the mask using the format from the first
3892 : * glyph. Later we'll deal with different formats. */
3893 0 : if (mask == NULL) {
3894 0 : mask_format = glyph_surface->pixman_format;
3895 0 : mask = pixman_image_create_bits (mask_format,
3896 : extents->width, extents->height,
3897 : NULL, 0);
3898 0 : if (unlikely (mask == NULL)) {
3899 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3900 0 : goto CLEANUP;
3901 : }
3902 :
3903 0 : if (PIXMAN_FORMAT_RGB (mask_format))
3904 0 : pixman_image_set_component_alpha (mask, TRUE);
3905 : }
3906 :
3907 : /* If we have glyphs of different formats, we "upgrade" the mask
3908 : * to the wider of the formats. */
3909 0 : if (glyph_surface->pixman_format != mask_format &&
3910 0 : PIXMAN_FORMAT_BPP (mask_format) <
3911 0 : PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
3912 : {
3913 : pixman_image_t *new_mask;
3914 :
3915 0 : mask_format = glyph_surface->pixman_format;
3916 0 : new_mask = pixman_image_create_bits (mask_format,
3917 : extents->width, extents->height,
3918 : NULL, 0);
3919 0 : if (unlikely (new_mask == NULL)) {
3920 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3921 0 : goto CLEANUP;
3922 : }
3923 :
3924 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
3925 : white, mask, new_mask,
3926 : 0, 0, 0, 0, 0, 0,
3927 : extents->width, extents->height);
3928 :
3929 0 : pixman_image_unref (mask);
3930 0 : mask = new_mask;
3931 0 : if (PIXMAN_FORMAT_RGB (mask_format))
3932 0 : pixman_image_set_component_alpha (mask, TRUE);
3933 : }
3934 :
3935 : /* round glyph locations to the nearest pixel */
3936 : /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
3937 0 : x = _cairo_lround (glyphs[i].x -
3938 0 : glyph_surface->base.device_transform.x0);
3939 0 : y = _cairo_lround (glyphs[i].y -
3940 0 : glyph_surface->base.device_transform.y0);
3941 0 : if (glyph_surface->pixman_format == mask_format) {
3942 0 : pixman_image_composite32 (PIXMAN_OP_ADD,
3943 : glyph_surface->pixman_image, NULL, mask,
3944 : 0, 0, 0, 0,
3945 0 : x - extents->x, y - extents->y,
3946 : glyph_surface->width,
3947 : glyph_surface->height);
3948 : } else {
3949 0 : pixman_image_composite32 (PIXMAN_OP_ADD,
3950 : white, glyph_surface->pixman_image, mask,
3951 : 0, 0, 0, 0,
3952 0 : x - extents->x, y - extents->y,
3953 : glyph_surface->width,
3954 : glyph_surface->height);
3955 : }
3956 : }
3957 :
3958 0 : pixman_image_composite32 (_pixman_operator (op),
3959 : src, mask, dst,
3960 0 : extents->x + src_x, extents->y + src_y,
3961 : 0, 0,
3962 0 : extents->x - dst_x, extents->y - dst_y,
3963 : extents->width, extents->height);
3964 :
3965 : CLEANUP:
3966 0 : _cairo_scaled_font_thaw_cache (font);
3967 0 : if (mask != NULL)
3968 0 : pixman_image_unref (mask);
3969 0 : pixman_image_unref (src);
3970 0 : pixman_image_unref (white);
3971 :
3972 0 : return status;
3973 : }
3974 :
3975 : static cairo_status_t
3976 0 : _composite_glyphs (void *closure,
3977 : pixman_image_t *dst,
3978 : pixman_format_code_t dst_format,
3979 : cairo_operator_t op,
3980 : const cairo_pattern_t *pattern,
3981 : int dst_x,
3982 : int dst_y,
3983 : const cairo_rectangle_int_t *extents,
3984 : cairo_region_t *clip_region)
3985 : {
3986 0 : composite_glyphs_info_t *info = closure;
3987 : cairo_scaled_glyph_t *glyph_cache[64];
3988 0 : pixman_op_t pixman_op = _pixman_operator (op);
3989 0 : pixman_image_t *src = NULL;
3990 0 : int src_x = 0, src_y = 0;
3991 : cairo_status_t status;
3992 : int i;
3993 :
3994 0 : memset (glyph_cache, 0, sizeof (glyph_cache));
3995 0 : status = CAIRO_STATUS_SUCCESS;
3996 :
3997 0 : _cairo_scaled_font_freeze_cache (info->font);
3998 0 : for (i = 0; i < info->num_glyphs; i++) {
3999 : int x, y;
4000 : cairo_image_surface_t *glyph_surface;
4001 : cairo_scaled_glyph_t *scaled_glyph;
4002 0 : unsigned long glyph_index = info->glyphs[i].index;
4003 0 : int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
4004 :
4005 0 : scaled_glyph = glyph_cache[cache_index];
4006 0 : if (scaled_glyph == NULL ||
4007 0 : _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
4008 : {
4009 0 : status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
4010 : CAIRO_SCALED_GLYPH_INFO_SURFACE,
4011 : &scaled_glyph);
4012 :
4013 0 : if (unlikely (status))
4014 0 : break;
4015 :
4016 0 : glyph_cache[cache_index] = scaled_glyph;
4017 : }
4018 :
4019 0 : glyph_surface = scaled_glyph->surface;
4020 0 : if (glyph_surface->width && glyph_surface->height) {
4021 : int x1, y1, x2, y2;
4022 :
4023 : /* round glyph locations to the nearest pixel */
4024 : /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
4025 0 : x = _cairo_lround (info->glyphs[i].x -
4026 0 : glyph_surface->base.device_transform.x0);
4027 0 : y = _cairo_lround (info->glyphs[i].y -
4028 0 : glyph_surface->base.device_transform.y0);
4029 :
4030 0 : x1 = x;
4031 0 : if (x1 < extents->x)
4032 0 : x1 = extents->x;
4033 0 : x2 = x + glyph_surface->width;
4034 0 : if (x2 > extents->x + extents->width)
4035 0 : x2 = extents->x + extents->width;
4036 :
4037 0 : y1 = y;
4038 0 : if (y1 < extents->y)
4039 0 : y1 = extents->y;
4040 0 : y2 = y + glyph_surface->height;
4041 0 : if (y2 > extents->y + extents->height)
4042 0 : y2 = extents->y + extents->height;
4043 :
4044 0 : if (glyph_surface->format == CAIRO_FORMAT_A8 ||
4045 0 : glyph_surface->format == CAIRO_FORMAT_A1 ||
4046 0 : (glyph_surface->format == CAIRO_FORMAT_ARGB32 &&
4047 0 : pixman_image_get_component_alpha (glyph_surface->pixman_image)))
4048 : {
4049 0 : if (unlikely (src == NULL)) {
4050 0 : if (pattern != NULL) {
4051 0 : src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
4052 0 : src_x -= dst_x;
4053 0 : src_y -= dst_y;
4054 : } else {
4055 0 : src = _pixman_white_image ();
4056 : }
4057 0 : if (unlikely (src == NULL)) {
4058 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4059 0 : break;
4060 : }
4061 : }
4062 :
4063 0 : pixman_image_composite32 (pixman_op,
4064 : src, glyph_surface->pixman_image, dst,
4065 : x1 + src_x, y1 + src_y,
4066 : x1 - x, y1 - y,
4067 : x1 - dst_x, y1 - dst_y,
4068 : x2 - x1, y2 - y1);
4069 : } else {
4070 0 : pixman_image_composite32 (pixman_op,
4071 : glyph_surface->pixman_image, NULL, dst,
4072 : x1 - x, y1 - y,
4073 : 0, 0,
4074 : x1 - dst_x, y1 - dst_y,
4075 : x2 - x1, y2 - y1);
4076 : }
4077 : }
4078 : }
4079 0 : _cairo_scaled_font_thaw_cache (info->font);
4080 :
4081 0 : if (src != NULL)
4082 0 : pixman_image_unref (src);
4083 :
4084 0 : return status;
4085 : }
4086 :
4087 : static cairo_int_status_t
4088 0 : _cairo_image_surface_glyphs (void *abstract_surface,
4089 : cairo_operator_t op,
4090 : const cairo_pattern_t *source,
4091 : cairo_glyph_t *glyphs,
4092 : int num_glyphs,
4093 : cairo_scaled_font_t *scaled_font,
4094 : cairo_clip_t *clip,
4095 : int *num_remaining)
4096 : {
4097 0 : cairo_image_surface_t *surface = abstract_surface;
4098 : cairo_composite_rectangles_t extents;
4099 : composite_glyphs_info_t glyph_info;
4100 : cairo_clip_t local_clip;
4101 0 : cairo_bool_t have_clip = FALSE;
4102 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4103 : // For performance reasons we don't want to use two passes for overlapping glyphs
4104 : // on mobile
4105 : cairo_bool_t overlap = FALSE;
4106 : #else
4107 : cairo_bool_t overlap;
4108 : #endif
4109 : cairo_status_t status;
4110 :
4111 : cairo_rectangle_int_t rect;
4112 0 : rect.x = rect.y = 0;
4113 0 : rect.width = surface->width;
4114 0 : rect.height = surface->height;
4115 :
4116 0 : status = _cairo_composite_rectangles_init_for_glyphs (&extents,
4117 : &rect,
4118 : op, source,
4119 : scaled_font,
4120 : glyphs, num_glyphs,
4121 : clip,
4122 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
4123 : NULL);
4124 : #else
4125 : &overlap);
4126 : #endif
4127 :
4128 0 : if (unlikely (status))
4129 0 : return status;
4130 :
4131 0 : if (_cairo_clip_contains_rectangle (clip, &extents.mask))
4132 0 : clip = NULL;
4133 :
4134 0 : if (clip != NULL && extents.is_bounded) {
4135 0 : clip = _cairo_clip_init_copy (&local_clip, clip);
4136 0 : status = _cairo_clip_rectangle (clip, &extents.bounded);
4137 0 : if (unlikely (status))
4138 0 : return status;
4139 :
4140 0 : have_clip = TRUE;
4141 : }
4142 :
4143 0 : glyph_info.font = scaled_font;
4144 0 : glyph_info.glyphs = glyphs;
4145 0 : glyph_info.num_glyphs = num_glyphs;
4146 :
4147 0 : status = _clip_and_composite (surface, op, source,
4148 0 : overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
4149 : &glyph_info,
4150 : &extents, clip);
4151 :
4152 0 : if (have_clip)
4153 0 : _cairo_clip_fini (&local_clip);
4154 :
4155 0 : *num_remaining = 0;
4156 0 : return status;
4157 : }
4158 :
4159 : static cairo_bool_t
4160 0 : _cairo_image_surface_get_extents (void *abstract_surface,
4161 : cairo_rectangle_int_t *rectangle)
4162 : {
4163 0 : cairo_image_surface_t *surface = abstract_surface;
4164 :
4165 0 : rectangle->x = 0;
4166 0 : rectangle->y = 0;
4167 0 : rectangle->width = surface->width;
4168 0 : rectangle->height = surface->height;
4169 :
4170 0 : return TRUE;
4171 : }
4172 :
4173 : static void
4174 2 : _cairo_image_surface_get_font_options (void *abstract_surface,
4175 : cairo_font_options_t *options)
4176 : {
4177 2 : _cairo_font_options_init_default (options);
4178 :
4179 2 : cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
4180 2 : _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
4181 2 : }
4182 :
4183 : /* legacy interface kept for compatibility until surface-fallback is removed */
4184 : static cairo_status_t
4185 0 : _cairo_image_surface_acquire_dest_image (void *abstract_surface,
4186 : cairo_rectangle_int_t *interest_rect,
4187 : cairo_image_surface_t **image_out,
4188 : cairo_rectangle_int_t *image_rect_out,
4189 : void **image_extra)
4190 : {
4191 0 : cairo_image_surface_t *surface = abstract_surface;
4192 :
4193 0 : image_rect_out->x = 0;
4194 0 : image_rect_out->y = 0;
4195 0 : image_rect_out->width = surface->width;
4196 0 : image_rect_out->height = surface->height;
4197 :
4198 0 : *image_out = surface;
4199 0 : *image_extra = NULL;
4200 :
4201 0 : return CAIRO_STATUS_SUCCESS;
4202 : }
4203 :
4204 : static void
4205 0 : _cairo_image_surface_release_dest_image (void *abstract_surface,
4206 : cairo_rectangle_int_t *interest_rect,
4207 : cairo_image_surface_t *image,
4208 : cairo_rectangle_int_t *image_rect,
4209 : void *image_extra)
4210 : {
4211 0 : }
4212 :
4213 : static cairo_status_t
4214 0 : _cairo_image_surface_clone_similar (void *abstract_surface,
4215 : cairo_surface_t *src,
4216 : int src_x,
4217 : int src_y,
4218 : int width,
4219 : int height,
4220 : int *clone_offset_x,
4221 : int *clone_offset_y,
4222 : cairo_surface_t **clone_out)
4223 : {
4224 0 : cairo_image_surface_t *surface = abstract_surface;
4225 :
4226 0 : if (src->backend == surface->base.backend) {
4227 0 : *clone_offset_x = *clone_offset_y = 0;
4228 0 : *clone_out = cairo_surface_reference (src);
4229 :
4230 0 : return CAIRO_STATUS_SUCCESS;
4231 : }
4232 :
4233 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
4234 : }
4235 :
4236 : static cairo_int_status_t
4237 0 : _cairo_image_surface_composite (cairo_operator_t op,
4238 : const cairo_pattern_t *src_pattern,
4239 : const cairo_pattern_t *mask_pattern,
4240 : void *abstract_dst,
4241 : int src_x,
4242 : int src_y,
4243 : int mask_x,
4244 : int mask_y,
4245 : int dst_x,
4246 : int dst_y,
4247 : unsigned int width,
4248 : unsigned int height,
4249 : cairo_region_t *clip_region)
4250 : {
4251 0 : cairo_image_surface_t *dst = abstract_dst;
4252 : cairo_composite_rectangles_t extents;
4253 : pixman_image_t *src;
4254 : int src_offset_x, src_offset_y;
4255 : cairo_status_t status;
4256 :
4257 0 : if (clip_region != NULL) {
4258 0 : status = _cairo_image_surface_set_clip_region (dst, clip_region);
4259 0 : if (unlikely (status))
4260 0 : return status;
4261 : }
4262 :
4263 0 : extents.source.x = src_x;
4264 0 : extents.source.y = src_y;
4265 0 : extents.source.width = width;
4266 0 : extents.source.height = height;
4267 :
4268 0 : extents.mask.x = mask_x;
4269 0 : extents.mask.y = mask_y;
4270 0 : extents.mask.width = width;
4271 0 : extents.mask.height = height;
4272 :
4273 0 : extents.bounded.x = dst_x;
4274 0 : extents.bounded.y = dst_y;
4275 0 : extents.bounded.width = width;
4276 0 : extents.bounded.height = height;
4277 :
4278 0 : extents.unbounded.x = 0;
4279 0 : extents.unbounded.y = 0;
4280 0 : extents.unbounded.width = dst->width;
4281 0 : extents.unbounded.height = dst->height;
4282 :
4283 0 : if (clip_region != NULL) {
4284 : cairo_rectangle_int_t rect;
4285 :
4286 0 : cairo_region_get_extents (clip_region, &rect);
4287 0 : if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
4288 0 : return CAIRO_STATUS_SUCCESS;
4289 : }
4290 :
4291 0 : extents.is_bounded = _cairo_operator_bounded_by_either (op);
4292 :
4293 0 : src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y);
4294 0 : if (unlikely (src == NULL))
4295 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4296 :
4297 0 : status = CAIRO_STATUS_SUCCESS;
4298 0 : if (mask_pattern != NULL) {
4299 : pixman_image_t *mask;
4300 : int mask_offset_x, mask_offset_y;
4301 :
4302 0 : mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y);
4303 0 : if (unlikely (mask == NULL)) {
4304 0 : pixman_image_unref (src);
4305 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4306 : }
4307 :
4308 0 : pixman_image_composite32 (_pixman_operator (op),
4309 : src, mask, dst->pixman_image,
4310 : src_x + src_offset_x,
4311 : src_y + src_offset_y,
4312 : mask_x + mask_offset_x,
4313 : mask_y + mask_offset_y,
4314 : dst_x, dst_y, width, height);
4315 :
4316 0 : pixman_image_unref (mask);
4317 : } else {
4318 0 : pixman_image_composite32 (_pixman_operator (op),
4319 : src, NULL, dst->pixman_image,
4320 : src_x + src_offset_x,
4321 : src_y + src_offset_y,
4322 : 0, 0,
4323 : dst_x, dst_y, width, height);
4324 : }
4325 :
4326 0 : pixman_image_unref (src);
4327 :
4328 0 : if (! extents.is_bounded)
4329 0 : status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
4330 :
4331 0 : if (clip_region != NULL)
4332 0 : _cairo_image_surface_unset_clip_region (dst);
4333 :
4334 0 : return status;
4335 : }
4336 :
4337 : static cairo_int_status_t
4338 0 : _cairo_image_surface_fill_rectangles (void *abstract_surface,
4339 : cairo_operator_t op,
4340 : const cairo_color_t *color,
4341 : cairo_rectangle_int_t *rects,
4342 : int num_rects)
4343 : {
4344 0 : cairo_image_surface_t *surface = abstract_surface;
4345 :
4346 : pixman_color_t pixman_color;
4347 : pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
4348 0 : pixman_box32_t *pixman_boxes = stack_boxes;
4349 : int i;
4350 :
4351 : cairo_int_status_t status;
4352 :
4353 : if (CAIRO_INJECT_FAULT ())
4354 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4355 :
4356 0 : pixman_color.red = color->red_short;
4357 0 : pixman_color.green = color->green_short;
4358 0 : pixman_color.blue = color->blue_short;
4359 0 : pixman_color.alpha = color->alpha_short;
4360 :
4361 0 : if (num_rects > ARRAY_LENGTH (stack_boxes)) {
4362 0 : pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
4363 0 : if (unlikely (pixman_boxes == NULL))
4364 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4365 : }
4366 :
4367 0 : for (i = 0; i < num_rects; i++) {
4368 0 : pixman_boxes[i].x1 = rects[i].x;
4369 0 : pixman_boxes[i].y1 = rects[i].y;
4370 0 : pixman_boxes[i].x2 = rects[i].x + rects[i].width;
4371 0 : pixman_boxes[i].y2 = rects[i].y + rects[i].height;
4372 : }
4373 :
4374 0 : status = CAIRO_STATUS_SUCCESS;
4375 0 : if (! pixman_image_fill_boxes (_pixman_operator (op),
4376 : surface->pixman_image,
4377 : &pixman_color,
4378 : num_rects,
4379 : pixman_boxes))
4380 : {
4381 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4382 : }
4383 :
4384 0 : if (pixman_boxes != stack_boxes)
4385 0 : free (pixman_boxes);
4386 :
4387 0 : return status;
4388 : }
4389 :
4390 : static cairo_int_status_t
4391 0 : _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
4392 : const cairo_pattern_t *pattern,
4393 : void *abstract_dst,
4394 : cairo_antialias_t antialias,
4395 : int src_x,
4396 : int src_y,
4397 : int dst_x,
4398 : int dst_y,
4399 : unsigned int width,
4400 : unsigned int height,
4401 : cairo_trapezoid_t *traps,
4402 : int num_traps,
4403 : cairo_region_t *clip_region)
4404 : {
4405 0 : cairo_image_surface_t *dst = abstract_dst;
4406 : cairo_composite_rectangles_t extents;
4407 : cairo_pattern_union_t source_pattern;
4408 : composite_traps_info_t info;
4409 : cairo_status_t status;
4410 :
4411 0 : if (height == 0 || width == 0)
4412 0 : return CAIRO_STATUS_SUCCESS;
4413 :
4414 : if (CAIRO_INJECT_FAULT ())
4415 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4416 :
4417 0 : extents.source.x = src_x;
4418 0 : extents.source.y = src_y;
4419 0 : extents.source.width = width;
4420 0 : extents.source.height = height;
4421 :
4422 0 : extents.mask.x = dst_x;
4423 0 : extents.mask.y = dst_y;
4424 0 : extents.mask.width = width;
4425 0 : extents.mask.height = height;
4426 :
4427 0 : extents.bounded.x = dst_x;
4428 0 : extents.bounded.y = dst_y;
4429 0 : extents.bounded.width = width;
4430 0 : extents.bounded.height = height;
4431 :
4432 0 : extents.unbounded.x = 0;
4433 0 : extents.unbounded.y = 0;
4434 0 : extents.unbounded.width = dst->width;
4435 0 : extents.unbounded.height = dst->height;
4436 :
4437 0 : if (clip_region != NULL) {
4438 : cairo_rectangle_int_t rect;
4439 :
4440 0 : cairo_region_get_extents (clip_region, &rect);
4441 0 : if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
4442 0 : return CAIRO_STATUS_SUCCESS;
4443 : }
4444 :
4445 0 : extents.is_bounded = _cairo_operator_bounded_by_either (op);
4446 :
4447 0 : if (clip_region != NULL) {
4448 0 : status = _cairo_image_surface_set_clip_region (dst, clip_region);
4449 0 : if (unlikely (status))
4450 0 : return status;
4451 : }
4452 :
4453 0 : _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
4454 0 : cairo_matrix_translate (&source_pattern.base.matrix,
4455 0 : src_x - extents.bounded.x,
4456 0 : src_y - extents.bounded.y);
4457 :
4458 0 : info.traps = traps;
4459 0 : info.num_traps = num_traps;
4460 0 : info.antialias = antialias;
4461 0 : status = _composite_traps (&info,
4462 : dst->pixman_image,
4463 : dst->pixman_format,
4464 : op,
4465 : &source_pattern.base,
4466 : 0, 0,
4467 : &extents.bounded,
4468 : clip_region);
4469 :
4470 0 : if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
4471 0 : status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
4472 :
4473 0 : if (clip_region != NULL)
4474 0 : _cairo_image_surface_unset_clip_region (dst);
4475 :
4476 0 : return status;
4477 : }
4478 :
4479 : typedef struct _legacy_image_surface_span_renderer {
4480 : cairo_span_renderer_t base;
4481 :
4482 : cairo_operator_t op;
4483 : const cairo_pattern_t *pattern;
4484 : cairo_antialias_t antialias;
4485 : cairo_region_t *clip_region;
4486 :
4487 : pixman_image_t *mask;
4488 : uint8_t *mask_data;
4489 : uint32_t mask_stride;
4490 :
4491 : cairo_image_surface_t *dst;
4492 : cairo_composite_rectangles_t composite_rectangles;
4493 : } legacy_image_surface_span_renderer_t;
4494 :
4495 : void
4496 0 : _cairo_image_surface_span_render_row (
4497 : int y,
4498 : const cairo_half_open_span_t *spans,
4499 : unsigned num_spans,
4500 : uint8_t *data,
4501 : uint32_t stride)
4502 : {
4503 : uint8_t *row;
4504 : unsigned i;
4505 :
4506 0 : if (num_spans == 0)
4507 0 : return;
4508 :
4509 0 : row = data + y * stride;
4510 0 : for (i = 0; i < num_spans - 1; i++) {
4511 0 : if (! spans[i].coverage)
4512 0 : continue;
4513 :
4514 : /* We implement setting the most common single pixel wide
4515 : * span case to avoid the overhead of a memset call.
4516 : * Open coding setting longer spans didn't show a
4517 : * noticeable improvement over memset.
4518 : */
4519 0 : if (spans[i+1].x == spans[i].x + 1) {
4520 0 : row[spans[i].x] = spans[i].coverage;
4521 : } else {
4522 0 : memset (row + spans[i].x,
4523 0 : spans[i].coverage,
4524 0 : spans[i+1].x - spans[i].x);
4525 : }
4526 : }
4527 : }
4528 :
4529 : static cairo_status_t
4530 0 : _cairo_image_surface_span_renderer_render_rows (
4531 : void *abstract_renderer,
4532 : int y,
4533 : int height,
4534 : const cairo_half_open_span_t *spans,
4535 : unsigned num_spans)
4536 : {
4537 0 : legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4538 0 : while (height--)
4539 0 : _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
4540 0 : return CAIRO_STATUS_SUCCESS;
4541 : }
4542 :
4543 : static void
4544 0 : _cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
4545 : {
4546 0 : legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4547 0 : if (renderer == NULL)
4548 0 : return;
4549 :
4550 0 : pixman_image_unref (renderer->mask);
4551 :
4552 0 : free (renderer);
4553 : }
4554 :
4555 : static cairo_status_t
4556 0 : _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
4557 : {
4558 0 : legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4559 0 : cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
4560 0 : cairo_image_surface_t *dst = renderer->dst;
4561 : pixman_image_t *src;
4562 : int src_x, src_y;
4563 : cairo_status_t status;
4564 :
4565 0 : if (renderer->clip_region != NULL) {
4566 0 : status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
4567 0 : if (unlikely (status))
4568 0 : return status;
4569 : }
4570 :
4571 0 : src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y);
4572 0 : if (src == NULL)
4573 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4574 :
4575 0 : status = CAIRO_STATUS_SUCCESS;
4576 0 : pixman_image_composite32 (_pixman_operator (renderer->op),
4577 : src,
4578 : renderer->mask,
4579 : dst->pixman_image,
4580 0 : rects->bounded.x + src_x,
4581 0 : rects->bounded.y + src_y,
4582 : 0, 0,
4583 : rects->bounded.x, rects->bounded.y,
4584 : rects->bounded.width, rects->bounded.height);
4585 :
4586 0 : if (! rects->is_bounded)
4587 0 : status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
4588 :
4589 0 : if (renderer->clip_region != NULL)
4590 0 : _cairo_image_surface_unset_clip_region (dst);
4591 :
4592 0 : return status;
4593 : }
4594 :
4595 : static cairo_bool_t
4596 0 : _cairo_image_surface_check_span_renderer (cairo_operator_t op,
4597 : const cairo_pattern_t *pattern,
4598 : void *abstract_dst,
4599 : cairo_antialias_t antialias)
4600 : {
4601 0 : return TRUE;
4602 : (void) op;
4603 : (void) pattern;
4604 : (void) abstract_dst;
4605 : (void) antialias;
4606 : }
4607 :
4608 : static cairo_span_renderer_t *
4609 0 : _cairo_image_surface_create_span_renderer (cairo_operator_t op,
4610 : const cairo_pattern_t *pattern,
4611 : void *abstract_dst,
4612 : cairo_antialias_t antialias,
4613 : const cairo_composite_rectangles_t *rects,
4614 : cairo_region_t *clip_region)
4615 : {
4616 0 : cairo_image_surface_t *dst = abstract_dst;
4617 : legacy_image_surface_span_renderer_t *renderer;
4618 :
4619 0 : renderer = calloc(1, sizeof(*renderer));
4620 0 : if (unlikely (renderer == NULL))
4621 0 : return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
4622 :
4623 0 : renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
4624 0 : renderer->base.finish = _cairo_image_surface_span_renderer_finish;
4625 0 : renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
4626 0 : renderer->op = op;
4627 0 : renderer->pattern = pattern;
4628 0 : renderer->antialias = antialias;
4629 0 : renderer->dst = dst;
4630 0 : renderer->clip_region = clip_region;
4631 :
4632 0 : renderer->composite_rectangles = *rects;
4633 :
4634 : /* TODO: support rendering to A1 surfaces (or: go add span
4635 : * compositing to pixman.) */
4636 0 : renderer->mask = pixman_image_create_bits (PIXMAN_a8,
4637 : rects->bounded.width,
4638 : rects->bounded.height,
4639 : NULL, 0);
4640 0 : if (renderer->mask == NULL) {
4641 0 : free (renderer);
4642 0 : return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
4643 : }
4644 :
4645 0 : renderer->mask_stride = pixman_image_get_stride (renderer->mask);
4646 0 : renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
4647 :
4648 0 : return &renderer->base;
4649 : }
4650 :
4651 : /**
4652 : * _cairo_surface_is_image:
4653 : * @surface: a #cairo_surface_t
4654 : *
4655 : * Checks if a surface is an #cairo_image_surface_t
4656 : *
4657 : * Return value: %TRUE if the surface is an image surface
4658 : **/
4659 : cairo_bool_t
4660 0 : _cairo_surface_is_image (const cairo_surface_t *surface)
4661 : {
4662 0 : return surface->backend == &_cairo_image_surface_backend;
4663 : }
4664 :
4665 : const cairo_surface_backend_t _cairo_image_surface_backend = {
4666 : CAIRO_SURFACE_TYPE_IMAGE,
4667 : _cairo_image_surface_create_similar,
4668 : _cairo_image_surface_finish,
4669 : _cairo_image_surface_acquire_source_image,
4670 : _cairo_image_surface_release_source_image,
4671 : _cairo_image_surface_acquire_dest_image,
4672 : _cairo_image_surface_release_dest_image,
4673 : _cairo_image_surface_clone_similar,
4674 : _cairo_image_surface_composite,
4675 : _cairo_image_surface_fill_rectangles,
4676 : _cairo_image_surface_composite_trapezoids,
4677 : _cairo_image_surface_create_span_renderer,
4678 : _cairo_image_surface_check_span_renderer,
4679 :
4680 : NULL, /* copy_page */
4681 : NULL, /* show_page */
4682 : _cairo_image_surface_get_extents,
4683 : NULL, /* old_show_glyphs */
4684 : _cairo_image_surface_get_font_options,
4685 : NULL, /* flush */
4686 : NULL, /* mark dirty */
4687 : NULL, /* font_fini */
4688 : NULL, /* glyph_fini */
4689 :
4690 : _cairo_image_surface_paint,
4691 : _cairo_image_surface_mask,
4692 : _cairo_image_surface_stroke,
4693 : _cairo_image_surface_fill,
4694 : _cairo_image_surface_glyphs,
4695 : NULL, /* show_text_glyphs */
4696 : NULL, /* snapshot */
4697 : NULL, /* is_similar */
4698 : };
4699 :
4700 : /* A convenience function for when one needs to coerce an image
4701 : * surface to an alternate format. */
4702 : cairo_image_surface_t *
4703 0 : _cairo_image_surface_coerce (cairo_image_surface_t *surface)
4704 : {
4705 0 : return _cairo_image_surface_coerce_to_format (surface,
4706 : _cairo_format_from_content (surface->base.content));
4707 :
4708 : }
4709 :
4710 : /* A convenience function for when one needs to coerce an image
4711 : * surface to an alternate format. */
4712 : cairo_image_surface_t *
4713 0 : _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
4714 : cairo_format_t format)
4715 : {
4716 : cairo_image_surface_t *clone;
4717 : cairo_status_t status;
4718 :
4719 0 : status = surface->base.status;
4720 0 : if (unlikely (status))
4721 0 : return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
4722 :
4723 0 : if (surface->format == format)
4724 0 : return (cairo_image_surface_t *)cairo_surface_reference(&surface->base);
4725 :
4726 0 : clone = (cairo_image_surface_t *)
4727 0 : cairo_image_surface_create (format, surface->width, surface->height);
4728 0 : if (unlikely (clone->base.status))
4729 0 : return clone;
4730 :
4731 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
4732 : surface->pixman_image, NULL, clone->pixman_image,
4733 : 0, 0,
4734 : 0, 0,
4735 : 0, 0,
4736 : surface->width, surface->height);
4737 0 : clone->base.is_clear = FALSE;
4738 :
4739 0 : clone->base.device_transform =
4740 : surface->base.device_transform;
4741 0 : clone->base.device_transform_inverse =
4742 : surface->base.device_transform_inverse;
4743 :
4744 0 : return clone;
4745 : }
4746 :
4747 : cairo_image_transparency_t
4748 0 : _cairo_image_analyze_transparency (cairo_image_surface_t *image)
4749 : {
4750 : int x, y;
4751 :
4752 0 : if (image->transparency != CAIRO_IMAGE_UNKNOWN)
4753 0 : return image->transparency;
4754 :
4755 0 : if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
4756 0 : return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4757 :
4758 0 : if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
4759 0 : if (image->format == CAIRO_FORMAT_A1)
4760 0 : return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
4761 : else
4762 0 : return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4763 : }
4764 :
4765 0 : if (image->format == CAIRO_FORMAT_RGB16_565) {
4766 0 : image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4767 0 : return CAIRO_IMAGE_IS_OPAQUE;
4768 : }
4769 :
4770 0 : if (image->format != CAIRO_FORMAT_ARGB32)
4771 0 : return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4772 :
4773 0 : image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4774 0 : for (y = 0; y < image->height; y++) {
4775 0 : uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
4776 :
4777 0 : for (x = 0; x < image->width; x++, pixel++) {
4778 0 : int a = (*pixel & 0xff000000) >> 24;
4779 0 : if (a > 0 && a < 255) {
4780 0 : return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4781 0 : } else if (a == 0) {
4782 0 : image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
4783 : }
4784 : }
4785 : }
4786 :
4787 0 : return image->transparency;
4788 : }
|