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