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
_cairo_image_surface_is_size_valid(int width,int height)92 _cairo_image_surface_is_size_valid (int width, int height)
93 {
94 return 0 <= width && width <= MAX_IMAGE_SIZE &&
95 0 <= height && height <= MAX_IMAGE_SIZE;
96 }
97
98 cairo_format_t
_cairo_format_from_pixman_format(pixman_format_code_t pixman_format)99 _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
100 {
101 switch (pixman_format) {
102 case PIXMAN_a8r8g8b8:
103 return CAIRO_FORMAT_ARGB32;
104 case PIXMAN_x8r8g8b8:
105 return CAIRO_FORMAT_RGB24;
106 case PIXMAN_a8:
107 return CAIRO_FORMAT_A8;
108 case PIXMAN_a1:
109 return CAIRO_FORMAT_A1;
110 case PIXMAN_r5g6b5:
111 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 return CAIRO_FORMAT_INVALID;
131 }
132
133 return CAIRO_FORMAT_INVALID;
134 }
135
136 cairo_content_t
_cairo_content_from_pixman_format(pixman_format_code_t pixman_format)137 _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
138 {
139 cairo_content_t content;
140
141 content = 0;
142 if (PIXMAN_FORMAT_RGB (pixman_format))
143 content |= CAIRO_CONTENT_COLOR;
144 if (PIXMAN_FORMAT_A (pixman_format))
145 content |= CAIRO_CONTENT_ALPHA;
146
147 return content;
148 }
149
150 cairo_surface_t *
_cairo_image_surface_create_for_pixman_image(pixman_image_t * pixman_image,pixman_format_code_t pixman_format)151 _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 int width = pixman_image_get_width (pixman_image);
156 int height = pixman_image_get_height (pixman_image);
157
158 surface = malloc (sizeof (cairo_image_surface_t));
159 if (unlikely (surface == NULL))
160 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
161
162 _cairo_surface_init (&surface->base,
163 &_cairo_image_surface_backend,
164 NULL, /* device */
165 _cairo_content_from_pixman_format (pixman_format));
166
167 surface->pixman_image = pixman_image;
168
169 surface->pixman_format = pixman_format;
170 surface->format = _cairo_format_from_pixman_format (pixman_format);
171 surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
172 surface->owns_data = FALSE;
173 surface->transparency = CAIRO_IMAGE_UNKNOWN;
174
175 surface->width = width;
176 surface->height = height;
177 surface->stride = pixman_image_get_stride (pixman_image);
178 surface->depth = pixman_image_get_depth (pixman_image);
179
180 return &surface->base;
181 }
182
183 cairo_bool_t
_pixman_format_from_masks(cairo_format_masks_t * masks,pixman_format_code_t * format_ret)184 _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 a = _cairo_popcount (masks->alpha_mask);
193 r = _cairo_popcount (masks->red_mask);
194 g = _cairo_popcount (masks->green_mask);
195 b = _cairo_popcount (masks->blue_mask);
196
197 if (masks->red_mask) {
198 if (masks->red_mask > masks->blue_mask)
199 format_type = PIXMAN_TYPE_ARGB;
200 else
201 format_type = PIXMAN_TYPE_ABGR;
202 } else if (masks->alpha_mask) {
203 format_type = PIXMAN_TYPE_A;
204 } else {
205 return FALSE;
206 }
207
208 format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b);
209
210 if (! pixman_format_supported_destination (format))
211 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 if (!_pixman_format_to_masks (format, &format_masks) ||
218 masks->bpp != format_masks.bpp ||
219 masks->red_mask != format_masks.red_mask ||
220 masks->green_mask != format_masks.green_mask ||
221 masks->blue_mask != format_masks.blue_mask)
222 {
223 return FALSE;
224 }
225
226 *format_ret = format;
227 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
_pixman_format_to_masks(pixman_format_code_t format,cairo_format_masks_t * masks)234 _pixman_format_to_masks (pixman_format_code_t format,
235 cairo_format_masks_t *masks)
236 {
237 int a, r, g, b;
238
239 masks->bpp = PIXMAN_FORMAT_BPP (format);
240
241 /* Number of bits in each channel */
242 a = PIXMAN_FORMAT_A (format);
243 r = PIXMAN_FORMAT_R (format);
244 g = PIXMAN_FORMAT_G (format);
245 b = PIXMAN_FORMAT_B (format);
246
247 switch (PIXMAN_FORMAT_TYPE (format)) {
248 case PIXMAN_TYPE_ARGB:
249 masks->alpha_mask = MASK (a) << (r + g + b);
250 masks->red_mask = MASK (r) << (g + b);
251 masks->green_mask = MASK (g) << (b);
252 masks->blue_mask = MASK (b);
253 return TRUE;
254 case PIXMAN_TYPE_ABGR:
255 masks->alpha_mask = MASK (a) << (b + g + r);
256 masks->blue_mask = MASK (b) << (g + r);
257 masks->green_mask = MASK (g) << (r);
258 masks->red_mask = MASK (r);
259 return TRUE;
260 #ifdef PIXMAN_TYPE_BGRA
261 case PIXMAN_TYPE_BGRA:
262 masks->blue_mask = MASK (b) << (masks->bpp - b);
263 masks->green_mask = MASK (g) << (masks->bpp - b - g);
264 masks->red_mask = MASK (r) << (masks->bpp - b - g - r);
265 masks->alpha_mask = MASK (a);
266 return TRUE;
267 #endif
268 case PIXMAN_TYPE_A:
269 masks->alpha_mask = MASK (a);
270 masks->red_mask = 0;
271 masks->green_mask = 0;
272 masks->blue_mask = 0;
273 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 masks->alpha_mask = 0;
281 masks->red_mask = 0;
282 masks->green_mask = 0;
283 masks->blue_mask = 0;
284 return FALSE;
285 }
286 }
287
288 pixman_format_code_t
_cairo_format_to_pixman_format_code(cairo_format_t format)289 _cairo_format_to_pixman_format_code (cairo_format_t format)
290 {
291 pixman_format_code_t ret;
292 switch (format) {
293 case CAIRO_FORMAT_A1:
294 ret = PIXMAN_a1;
295 break;
296 case CAIRO_FORMAT_A8:
297 ret = PIXMAN_a8;
298 break;
299 case CAIRO_FORMAT_RGB24:
300 ret = PIXMAN_x8r8g8b8;
301 break;
302 case CAIRO_FORMAT_RGB16_565:
303 ret = PIXMAN_r5g6b5;
304 break;
305 case CAIRO_FORMAT_ARGB32:
306 case CAIRO_FORMAT_INVALID:
307 default:
308 ret = PIXMAN_a8r8g8b8;
309 break;
310 }
311 return ret;
312 }
313
314 cairo_surface_t *
_cairo_image_surface_create_with_pixman_format(unsigned char * data,pixman_format_code_t pixman_format,int width,int height,int stride)315 _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 if (! _cairo_image_surface_is_size_valid (width, height))
325 {
326 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
327 }
328
329 pixman_image = pixman_image_create_bits (pixman_format, width, height,
330 (uint32_t *) data, stride);
331
332 if (unlikely (pixman_image == NULL))
333 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
334
335 surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
336 pixman_format);
337 if (unlikely (surface->status)) {
338 pixman_image_unref (pixman_image);
339 return surface;
340 }
341
342 /* we can not make any assumptions about the initial state of user data */
343 surface->is_clear = data == NULL;
344 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 *
cairo_image_surface_create(cairo_format_t format,int width,int height)368 cairo_image_surface_create (cairo_format_t format,
369 int width,
370 int height)
371 {
372 pixman_format_code_t pixman_format;
373
374 if (! CAIRO_FORMAT_VALID (format))
375 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
376
377 pixman_format = _cairo_format_to_pixman_format_code (format);
378
379 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 *
_cairo_image_surface_create_with_content(cairo_content_t content,int width,int height)385 _cairo_image_surface_create_with_content (cairo_content_t content,
386 int width,
387 int height)
388 {
389 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
cairo_format_stride_for_width(cairo_format_t format,int width)421 cairo_format_stride_for_width (cairo_format_t format,
422 int width)
423 {
424 int bpp;
425
426 if (! CAIRO_FORMAT_VALID (format)) {
427 _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
428 return -1;
429 }
430
431 bpp = _cairo_format_bits_per_pixel (format);
432 if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp))
433 return -1;
434
435 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 *
cairo_image_surface_create_for_data(unsigned char * data,cairo_format_t format,int width,int height,int stride)483 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 if (! CAIRO_FORMAT_VALID (format))
493 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
494
495 if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
496 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
497
498 if (! _cairo_image_surface_is_size_valid (width, height))
499 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
500
501 minstride = cairo_format_stride_for_width (format, width);
502 if (stride < 0) {
503 if (stride > -minstride) {
504 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
505 }
506 } else {
507 if (stride < minstride) {
508 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
509 }
510 }
511
512 pixman_format = _cairo_format_to_pixman_format_code (format);
513 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 *
cairo_image_surface_get_data(cairo_surface_t * surface)534 cairo_image_surface_get_data (cairo_surface_t *surface)
535 {
536 cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
537
538 if (! _cairo_surface_is_image (surface)) {
539 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
540 return NULL;
541 }
542
543 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
cairo_image_surface_get_format(cairo_surface_t * surface)558 cairo_image_surface_get_format (cairo_surface_t *surface)
559 {
560 cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
561
562 if (! _cairo_surface_is_image (surface)) {
563 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
564 return CAIRO_FORMAT_INVALID;
565 }
566
567 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
cairo_image_surface_get_width(cairo_surface_t * surface)580 cairo_image_surface_get_width (cairo_surface_t *surface)
581 {
582 cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
583
584 if (! _cairo_surface_is_image (surface)) {
585 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
586 return 0;
587 }
588
589 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
cairo_image_surface_get_height(cairo_surface_t * surface)602 cairo_image_surface_get_height (cairo_surface_t *surface)
603 {
604 cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
605
606 if (! _cairo_surface_is_image (surface)) {
607 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
608 return 0;
609 }
610
611 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
cairo_image_surface_get_stride(cairo_surface_t * surface)629 cairo_image_surface_get_stride (cairo_surface_t *surface)
630 {
631
632 cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
633
634 if (! _cairo_surface_is_image (surface)) {
635 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
636 return 0;
637 }
638
639 return image_surface->stride;
640 }
641 slim_hidden_def (cairo_image_surface_get_stride);
642
643 cairo_format_t
_cairo_format_from_content(cairo_content_t content)644 _cairo_format_from_content (cairo_content_t content)
645 {
646 switch (content) {
647 case CAIRO_CONTENT_COLOR:
648 return CAIRO_FORMAT_RGB24;
649 case CAIRO_CONTENT_ALPHA:
650 return CAIRO_FORMAT_A8;
651 case CAIRO_CONTENT_COLOR_ALPHA:
652 return CAIRO_FORMAT_ARGB32;
653 }
654
655 ASSERT_NOT_REACHED;
656 return CAIRO_FORMAT_INVALID;
657 }
658
659 cairo_content_t
_cairo_content_from_format(cairo_format_t format)660 _cairo_content_from_format (cairo_format_t format)
661 {
662 switch (format) {
663 case CAIRO_FORMAT_ARGB32:
664 return CAIRO_CONTENT_COLOR_ALPHA;
665 case CAIRO_FORMAT_RGB24:
666 return CAIRO_CONTENT_COLOR;
667 case CAIRO_FORMAT_RGB16_565:
668 return CAIRO_CONTENT_COLOR;
669 case CAIRO_FORMAT_A8:
670 case CAIRO_FORMAT_A1:
671 return CAIRO_CONTENT_ALPHA;
672 case CAIRO_FORMAT_INVALID:
673 break;
674 }
675
676 ASSERT_NOT_REACHED;
677 return CAIRO_CONTENT_COLOR_ALPHA;
678 }
679
680 int
_cairo_format_bits_per_pixel(cairo_format_t format)681 _cairo_format_bits_per_pixel (cairo_format_t format)
682 {
683 switch (format) {
684 case CAIRO_FORMAT_ARGB32:
685 return 32;
686 case CAIRO_FORMAT_RGB24:
687 return 32;
688 case CAIRO_FORMAT_RGB16_565:
689 return 16;
690 case CAIRO_FORMAT_A8:
691 return 8;
692 case CAIRO_FORMAT_A1:
693 return 1;
694 case CAIRO_FORMAT_INVALID:
695 default:
696 ASSERT_NOT_REACHED;
697 return 0;
698 }
699 }
700
701 static cairo_surface_t *
_cairo_image_surface_create_similar(void * abstract_other,cairo_content_t content,int width,int height)702 _cairo_image_surface_create_similar (void *abstract_other,
703 cairo_content_t content,
704 int width,
705 int height)
706 {
707 cairo_image_surface_t *other = abstract_other;
708
709 if (! _cairo_image_surface_is_size_valid (width, height))
710 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
711
712 if (content == other->base.content) {
713 return _cairo_image_surface_create_with_pixman_format (NULL,
714 other->pixman_format,
715 width, height,
716 0);
717 }
718
719 return _cairo_image_surface_create_with_content (content,
720 width, height);
721 }
722
723 static cairo_status_t
_cairo_image_surface_finish(void * abstract_surface)724 _cairo_image_surface_finish (void *abstract_surface)
725 {
726 cairo_image_surface_t *surface = abstract_surface;
727
728 if (surface->pixman_image) {
729 pixman_image_unref (surface->pixman_image);
730 surface->pixman_image = NULL;
731 }
732
733 if (surface->owns_data) {
734 free (surface->data);
735 surface->data = NULL;
736 }
737
738 return CAIRO_STATUS_SUCCESS;
739 }
740
741 void
_cairo_image_surface_assume_ownership_of_data(cairo_image_surface_t * surface)742 _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
743 {
744 surface->owns_data = TRUE;
745 }
746
747 static cairo_status_t
_cairo_image_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)748 _cairo_image_surface_acquire_source_image (void *abstract_surface,
749 cairo_image_surface_t **image_out,
750 void **image_extra)
751 {
752 *image_out = abstract_surface;
753 *image_extra = NULL;
754
755 return CAIRO_STATUS_SUCCESS;
756 }
757
758 static void
_cairo_image_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)759 _cairo_image_surface_release_source_image (void *abstract_surface,
760 cairo_image_surface_t *image,
761 void *image_extra)
762 {
763 }
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
_pixman_operator(cairo_operator_t op)771 _pixman_operator (cairo_operator_t op)
772 {
773 switch (op) {
774 case CAIRO_OPERATOR_CLEAR:
775 return PIXMAN_OP_CLEAR;
776
777 case CAIRO_OPERATOR_SOURCE:
778 return PIXMAN_OP_SRC;
779 case CAIRO_OPERATOR_OVER:
780 return PIXMAN_OP_OVER;
781 case CAIRO_OPERATOR_IN:
782 return PIXMAN_OP_IN;
783 case CAIRO_OPERATOR_OUT:
784 return PIXMAN_OP_OUT;
785 case CAIRO_OPERATOR_ATOP:
786 return PIXMAN_OP_ATOP;
787
788 case CAIRO_OPERATOR_DEST:
789 return PIXMAN_OP_DST;
790 case CAIRO_OPERATOR_DEST_OVER:
791 return PIXMAN_OP_OVER_REVERSE;
792 case CAIRO_OPERATOR_DEST_IN:
793 return PIXMAN_OP_IN_REVERSE;
794 case CAIRO_OPERATOR_DEST_OUT:
795 return PIXMAN_OP_OUT_REVERSE;
796 case CAIRO_OPERATOR_DEST_ATOP:
797 return PIXMAN_OP_ATOP_REVERSE;
798
799 case CAIRO_OPERATOR_XOR:
800 return PIXMAN_OP_XOR;
801 case CAIRO_OPERATOR_ADD:
802 return PIXMAN_OP_ADD;
803 case CAIRO_OPERATOR_SATURATE:
804 return PIXMAN_OP_SATURATE;
805
806 case CAIRO_OPERATOR_MULTIPLY:
807 return PIXMAN_OP_MULTIPLY;
808 case CAIRO_OPERATOR_SCREEN:
809 return PIXMAN_OP_SCREEN;
810 case CAIRO_OPERATOR_OVERLAY:
811 return PIXMAN_OP_OVERLAY;
812 case CAIRO_OPERATOR_DARKEN:
813 return PIXMAN_OP_DARKEN;
814 case CAIRO_OPERATOR_LIGHTEN:
815 return PIXMAN_OP_LIGHTEN;
816 case CAIRO_OPERATOR_COLOR_DODGE:
817 return PIXMAN_OP_COLOR_DODGE;
818 case CAIRO_OPERATOR_COLOR_BURN:
819 return PIXMAN_OP_COLOR_BURN;
820 case CAIRO_OPERATOR_HARD_LIGHT:
821 return PIXMAN_OP_HARD_LIGHT;
822 case CAIRO_OPERATOR_SOFT_LIGHT:
823 return PIXMAN_OP_SOFT_LIGHT;
824 case CAIRO_OPERATOR_DIFFERENCE:
825 return PIXMAN_OP_DIFFERENCE;
826 case CAIRO_OPERATOR_EXCLUSION:
827 return PIXMAN_OP_EXCLUSION;
828 case CAIRO_OPERATOR_HSL_HUE:
829 return PIXMAN_OP_HSL_HUE;
830 case CAIRO_OPERATOR_HSL_SATURATION:
831 return PIXMAN_OP_HSL_SATURATION;
832 case CAIRO_OPERATOR_HSL_COLOR:
833 return PIXMAN_OP_HSL_COLOR;
834 case CAIRO_OPERATOR_HSL_LUMINOSITY:
835 return PIXMAN_OP_HSL_LUMINOSITY;
836
837 default:
838 ASSERT_NOT_REACHED;
839 return PIXMAN_OP_OVER;
840 }
841 }
842
843 static cairo_status_t
_cairo_image_surface_set_clip_region(cairo_image_surface_t * surface,cairo_region_t * region)844 _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
845 cairo_region_t *region)
846 {
847 if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->rgn))
848 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
849
850 return CAIRO_STATUS_SUCCESS;
851 }
852
853 static void
_cairo_image_surface_unset_clip_region(cairo_image_surface_t * surface)854 _cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
855 {
856 pixman_image_set_clip_region32 (surface->pixman_image, NULL);
857 }
858
859 static double
_pixman_nearest_sample(double d)860 _pixman_nearest_sample (double d)
861 {
862 return ceil (d - .5);
863 }
864
865 static cairo_bool_t
_nearest_sample(cairo_filter_t filter,double * tx,double * ty)866 _nearest_sample (cairo_filter_t filter, double *tx, double *ty)
867 {
868 if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
869 *tx = _pixman_nearest_sample (*tx);
870 *ty = _pixman_nearest_sample (*ty);
871 } else {
872 if (*tx != floor (*tx) || *ty != floor (*ty))
873 return FALSE;
874 }
875 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 *
_pixman_transparent_image(void)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 *
_pixman_black_image(void)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 *
_pixman_white_image(void)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 *
_pixman_transparent_image(void)974 _pixman_transparent_image (void)
975 {
976 return _pixman_image_for_solid (&_cairo_pattern_clear);
977 }
978 static pixman_image_t *
_pixman_black_image(void)979 _pixman_black_image (void)
980 {
981 return _pixman_image_for_solid (&_cairo_pattern_black);
982 }
983 static pixman_image_t *
_pixman_white_image(void)984 _pixman_white_image (void)
985 {
986 return _pixman_image_for_solid (&_cairo_pattern_white);
987 }
988 #endif
989
990 static uint32_t
hars_petruska_f54_1_random(void)991 hars_petruska_f54_1_random (void)
992 {
993 #define rol(x,k) ((x << k) | (x >> (32-k)))
994 static uint32_t x;
995 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
_cairo_image_reset_static_data(void)1006 _cairo_image_reset_static_data (void)
1007 {
1008 while (n_cached)
1009 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 }
1028
1029 static pixman_image_t *
_pixman_image_for_solid(const cairo_solid_pattern_t * pattern)1030 _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 for (i = 0; i < n_cached; i++) {
1059 if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
1060 image = pixman_image_ref (cache[i].image);
1061 goto UNLOCK;
1062 }
1063 }
1064
1065 color.red = pattern->color.red_short;
1066 color.green = pattern->color.green_short;
1067 color.blue = pattern->color.blue_short;
1068 color.alpha = pattern->color.alpha_short;
1069
1070 image = pixman_image_create_solid_fill (&color);
1071 if (image == NULL)
1072 goto UNLOCK;
1073
1074 if (n_cached < ARRAY_LENGTH (cache)) {
1075 i = n_cached++;
1076 } else {
1077 i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
1078 pixman_image_unref (cache[i].image);
1079 }
1080 cache[i].image = pixman_image_ref (image);
1081 cache[i].color = pattern->color;
1082
1083 UNLOCK:
1084 CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
1085 return image;
1086 }
1087
1088 static pixman_image_t *
_pixman_image_for_gradient(const cairo_gradient_pattern_t * pattern,const cairo_rectangle_int_t * extents,int * ix,int * iy)1089 _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 pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
1096 cairo_matrix_t matrix = pattern->base.matrix;
1097 double tx, ty;
1098 unsigned int i;
1099
1100 if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
1101 pixman_stops = _cairo_malloc_ab (pattern->n_stops,
1102 sizeof(pixman_gradient_stop_t));
1103 if (unlikely (pixman_stops == NULL))
1104 return NULL;
1105 }
1106
1107 for (i = 0; i < pattern->n_stops; i++) {
1108 pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
1109 pixman_stops[i].color.red = pattern->stops[i].color.red_short;
1110 pixman_stops[i].color.green = pattern->stops[i].color.green_short;
1111 pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
1112 pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
1113 }
1114
1115 if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1116 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 xdim = fabs (linear->p2.x - linear->p1.x);
1121 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 if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
1134 _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
1135 {
1136 double sf;
1137
1138 if (xdim > ydim)
1139 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
1140 else
1141 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
1142
1143 p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
1144 p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
1145 p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
1146 p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
1147
1148 cairo_matrix_scale (&matrix, sf, sf);
1149 }
1150 else
1151 {
1152 p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
1153 p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
1154 p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
1155 p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
1156 }
1157
1158 pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
1159 pixman_stops,
1160 pattern->n_stops);
1161 } else {
1162 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 c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
1167 c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
1168 r1 = _cairo_fixed_to_16_16 (radial->r1);
1169
1170 c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
1171 c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
1172 r2 = _cairo_fixed_to_16_16 (radial->r2);
1173
1174 pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
1175 pixman_stops,
1176 pattern->n_stops);
1177 }
1178
1179 if (pixman_stops != pixman_stops_static)
1180 free (pixman_stops);
1181
1182 if (unlikely (pixman_image == NULL))
1183 return NULL;
1184
1185 tx = pattern->base.matrix.x0;
1186 ty = pattern->base.matrix.y0;
1187 if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
1188 ! _nearest_sample (pattern->base.filter, &tx, &ty))
1189 {
1190 pixman_transform_t pixman_transform;
1191
1192 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 inv = pattern->base.matrix;
1201 status = cairo_matrix_invert (&inv);
1202 assert (status == CAIRO_STATUS_SUCCESS);
1203
1204 x = floor (inv.x0 / 2);
1205 y = floor (inv.y0 / 2);
1206 tx = -x;
1207 ty = -y;
1208 cairo_matrix_init_translate (&inv, x, y);
1209 cairo_matrix_multiply (&m, &inv, &pattern->base.matrix);
1210 _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
1211 extents->x + extents->width/2.,
1212 extents->y + extents->height/2.);
1213 } else {
1214 tx = ty = 0;
1215 _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
1216 &pixman_transform,
1217 extents->x + extents->width/2.,
1218 extents->y + extents->height/2.);
1219 }
1220
1221 if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
1222 pixman_image_unref (pixman_image);
1223 return NULL;
1224 }
1225 }
1226 *ix = tx;
1227 *iy = ty;
1228
1229 {
1230 pixman_repeat_t pixman_repeat;
1231
1232 switch (pattern->base.extend) {
1233 default:
1234 case CAIRO_EXTEND_NONE:
1235 pixman_repeat = PIXMAN_REPEAT_NONE;
1236 break;
1237 case CAIRO_EXTEND_REPEAT:
1238 pixman_repeat = PIXMAN_REPEAT_NORMAL;
1239 break;
1240 case CAIRO_EXTEND_REFLECT:
1241 pixman_repeat = PIXMAN_REPEAT_REFLECT;
1242 break;
1243 case CAIRO_EXTEND_PAD:
1244 pixman_repeat = PIXMAN_REPEAT_PAD;
1245 break;
1246 }
1247
1248 pixman_image_set_repeat (pixman_image, pixman_repeat);
1249 }
1250
1251 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
_acquire_source_cleanup(pixman_image_t * pixman_image,void * closure)1261 _acquire_source_cleanup (pixman_image_t *pixman_image,
1262 void *closure)
1263 {
1264 struct acquire_source_cleanup *data = closure;
1265
1266 _cairo_surface_release_source_image (data->surface,
1267 data->image,
1268 data->image_extra);
1269 free (data);
1270 }
1271
1272 static cairo_filter_t
sampled_area(const cairo_surface_pattern_t * pattern,const cairo_rectangle_int_t * extents,cairo_rectangle_int_t * sample)1273 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 x1 = extents->x;
1282 y1 = extents->y;
1283 x2 = extents->x + (int) extents->width;
1284 y2 = extents->y + (int) extents->height;
1285
1286 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
1287 &x1, &y1, &x2, &y2,
1288 NULL);
1289
1290 filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
1291 sample->x = floor (x1 - pad);
1292 sample->y = floor (y1 - pad);
1293 sample->width = ceil (x2 + pad) - sample->x;
1294 sample->height = ceil (y2 + pad) - sample->y;
1295
1296 return filter;
1297 }
1298
1299 static uint16_t
expand_channel(uint16_t v,uint32_t bits)1300 expand_channel (uint16_t v, uint32_t bits)
1301 {
1302 int offset = 16 - bits;
1303 while (offset > 0) {
1304 v |= v >> bits;
1305 offset -= bits;
1306 bits += bits;
1307 }
1308 return v;
1309 }
1310
1311 static pixman_image_t *
_pixel_to_solid(cairo_image_surface_t * image,int x,int y)1312 _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
1313 {
1314 uint32_t pixel;
1315 pixman_color_t color;
1316
1317 switch (image->format) {
1318 default:
1319 case CAIRO_FORMAT_INVALID:
1320 ASSERT_NOT_REACHED;
1321 return NULL;
1322
1323 case CAIRO_FORMAT_A1:
1324 pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
1325 return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
1326
1327 case CAIRO_FORMAT_A8:
1328 color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
1329 color.alpha |= color.alpha << 8;
1330 if (color.alpha == 0)
1331 return _pixman_transparent_image ();
1332
1333 color.red = color.green = color.blue = 0;
1334 return pixman_image_create_solid_fill (&color);
1335
1336 case CAIRO_FORMAT_RGB16_565:
1337 pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
1338 if (pixel == 0)
1339 return _pixman_black_image ();
1340 if (pixel == 0xffff)
1341 return _pixman_white_image ();
1342
1343 color.alpha = 0xffff;
1344 color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
1345 color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
1346 color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
1347 return pixman_image_create_solid_fill (&color);
1348
1349 case CAIRO_FORMAT_ARGB32:
1350 case CAIRO_FORMAT_RGB24:
1351 pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
1352 color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
1353 if (color.alpha == 0)
1354 return _pixman_transparent_image ();
1355 if (pixel == 0xffffffff)
1356 return _pixman_white_image ();
1357 if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
1358 return _pixman_black_image ();
1359
1360 color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
1361 color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
1362 color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
1363 return pixman_image_create_solid_fill (&color);
1364 }
1365 }
1366
1367 static pixman_image_t *
_pixman_image_for_surface(const cairo_surface_pattern_t * pattern,cairo_bool_t is_mask,const cairo_rectangle_int_t * extents,int * ix,int * iy)1368 _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 tx = pattern->base.matrix.x0;
1380 ty = pattern->base.matrix.y0;
1381
1382 extend = pattern->base.extend;
1383 filter = sampled_area (pattern, extents, &sample);
1384
1385 pixman_image = NULL;
1386 if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
1387 (! is_mask || ! pattern->base.has_component_alpha ||
1388 (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
1389 {
1390 cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
1391 cairo_surface_type_t type;
1392
1393 if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
1394 source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
1395
1396 type = source->base.backend->type;
1397 if (type == CAIRO_SURFACE_TYPE_IMAGE) {
1398 if (extend != CAIRO_EXTEND_NONE &&
1399 sample.x >= 0 &&
1400 sample.y >= 0 &&
1401 sample.x + sample.width <= source->width &&
1402 sample.y + sample.height <= source->height)
1403 {
1404 extend = CAIRO_EXTEND_NONE;
1405 }
1406
1407 if (sample.width == 1 && sample.height == 1) {
1408 if (sample.x < 0 ||
1409 sample.y < 0 ||
1410 sample.x >= source->width ||
1411 sample.y >= source->height)
1412 {
1413 if (extend == CAIRO_EXTEND_NONE)
1414 return _pixman_transparent_image ();
1415 }
1416 else
1417 {
1418 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 if (extend == CAIRO_EXTEND_NONE &&
1424 _cairo_matrix_is_translation (&pattern->base.matrix) &&
1425 _nearest_sample (filter, &tx, &ty))
1426 {
1427 *ix = tx;
1428 *iy = ty;
1429 return pixman_image_ref (source->pixman_image);
1430 }
1431
1432 pixman_image = pixman_image_create_bits (source->pixman_format,
1433 source->width,
1434 source->height,
1435 (uint32_t *) source->data,
1436 source->stride);
1437 if (unlikely (pixman_image == NULL))
1438 return NULL;
1439 } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1440 cairo_surface_subsurface_t *sub;
1441 cairo_bool_t is_contained = FALSE;
1442
1443 sub = (cairo_surface_subsurface_t *) source;
1444 source = (cairo_image_surface_t *) sub->target;
1445
1446 if (sample.x >= 0 &&
1447 sample.y >= 0 &&
1448 sample.x + sample.width <= sub->extents.width &&
1449 sample.y + sample.height <= sub->extents.height)
1450 {
1451 is_contained = TRUE;
1452 }
1453
1454 if (sample.width == 1 && sample.height == 1) {
1455 if (is_contained) {
1456 return _pixel_to_solid (source,
1457 sub->extents.x + sample.x,
1458 sub->extents.y + sample.y);
1459 } else {
1460 if (extend == CAIRO_EXTEND_NONE)
1461 return _pixman_transparent_image ();
1462 }
1463 }
1464
1465 if (is_contained &&
1466 _cairo_matrix_is_translation (&pattern->base.matrix) &&
1467 _nearest_sample (filter, &tx, &ty))
1468 {
1469 *ix = tx + sub->extents.x;
1470 *iy = ty + sub->extents.y;
1471 return pixman_image_ref (source->pixman_image);
1472 }
1473
1474 /* Avoid sub-byte offsets, force a copy in that case. */
1475 if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
1476 pixman_image = pixman_image_create_bits (source->pixman_format,
1477 sub->extents.width,
1478 sub->extents.height,
1479 (uint32_t *) (source->data + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + sub->extents.y * source->stride),
1480 source->stride);
1481 if (unlikely (pixman_image == NULL))
1482 return NULL;
1483 }
1484 }
1485 }
1486
1487 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 status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
1494 if (unlikely (status))
1495 return NULL;
1496
1497 if (sample.width == 1 && sample.height == 1) {
1498 if (sample.x < 0 ||
1499 sample.y < 0 ||
1500 sample.x >= image->width ||
1501 sample.y >= image->height)
1502 {
1503 if (extend == CAIRO_EXTEND_NONE) {
1504 pixman_image = _pixman_transparent_image ();
1505 _cairo_surface_release_source_image (pattern->surface, image, extra);
1506 return pixman_image;
1507 }
1508 }
1509 else
1510 {
1511 pixman_image = _pixel_to_solid (image, sample.x, sample.y);
1512 _cairo_surface_release_source_image (pattern->surface, image, extra);
1513 return pixman_image;
1514 }
1515 }
1516
1517 pixman_image = pixman_image_create_bits (image->pixman_format,
1518 image->width,
1519 image->height,
1520 (uint32_t *) image->data,
1521 image->stride);
1522 if (unlikely (pixman_image == NULL)) {
1523 _cairo_surface_release_source_image (pattern->surface, image, extra);
1524 return NULL;
1525 }
1526
1527 cleanup = malloc (sizeof (*cleanup));
1528 if (unlikely (cleanup == NULL)) {
1529 _cairo_surface_release_source_image (pattern->surface, image, extra);
1530 pixman_image_unref (pixman_image);
1531 return NULL;
1532 }
1533
1534 cleanup->surface = pattern->surface;
1535 cleanup->image = image;
1536 cleanup->image_extra = extra;
1537 pixman_image_set_destroy_function (pixman_image,
1538 _acquire_source_cleanup, cleanup);
1539 }
1540
1541 if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
1542 ! _nearest_sample (filter, &tx, &ty))
1543 {
1544 pixman_transform_t pixman_transform;
1545 cairo_matrix_t m;
1546
1547 m = pattern->base.matrix;
1548 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 inv = m;
1557 status = cairo_matrix_invert (&inv);
1558 assert (status == CAIRO_STATUS_SUCCESS);
1559
1560 x = floor (inv.x0 / 2);
1561 y = floor (inv.y0 / 2);
1562 tx = -x;
1563 ty = -y;
1564 cairo_matrix_init_translate (&inv, x, y);
1565 cairo_matrix_multiply (&m, &inv, &m);
1566 } else {
1567 tx = ty = 0;
1568 }
1569
1570 _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
1571 extents->x + extents->width/2.,
1572 extents->y + extents->height/2.);
1573 if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
1574 pixman_image_unref (pixman_image);
1575 return NULL;
1576 }
1577 }
1578 *ix = tx;
1579 *iy = ty;
1580
1581 if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
1582 tx == pattern->base.matrix.x0 &&
1583 ty == pattern->base.matrix.y0)
1584 {
1585 pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
1586 }
1587 else
1588 {
1589 pixman_filter_t pixman_filter;
1590
1591 switch (filter) {
1592 case CAIRO_FILTER_FAST:
1593 pixman_filter = PIXMAN_FILTER_FAST;
1594 break;
1595 case CAIRO_FILTER_GOOD:
1596 pixman_filter = PIXMAN_FILTER_GOOD;
1597 break;
1598 case CAIRO_FILTER_BEST:
1599 pixman_filter = PIXMAN_FILTER_BEST;
1600 break;
1601 case CAIRO_FILTER_NEAREST:
1602 pixman_filter = PIXMAN_FILTER_NEAREST;
1603 break;
1604 case CAIRO_FILTER_BILINEAR:
1605 pixman_filter = PIXMAN_FILTER_BILINEAR;
1606 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 pixman_filter = PIXMAN_FILTER_BEST;
1615 }
1616
1617 pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
1618 }
1619
1620 {
1621 pixman_repeat_t pixman_repeat;
1622
1623 switch (extend) {
1624 default:
1625 case CAIRO_EXTEND_NONE:
1626 pixman_repeat = PIXMAN_REPEAT_NONE;
1627 break;
1628 case CAIRO_EXTEND_REPEAT:
1629 pixman_repeat = PIXMAN_REPEAT_NORMAL;
1630 break;
1631 case CAIRO_EXTEND_REFLECT:
1632 pixman_repeat = PIXMAN_REPEAT_REFLECT;
1633 break;
1634 case CAIRO_EXTEND_PAD:
1635 pixman_repeat = PIXMAN_REPEAT_PAD;
1636 break;
1637 }
1638
1639 pixman_image_set_repeat (pixman_image, pixman_repeat);
1640 }
1641
1642 if (pattern->base.has_component_alpha)
1643 pixman_image_set_component_alpha (pixman_image, TRUE);
1644
1645 return pixman_image;
1646 }
1647
1648 static pixman_image_t *
_pixman_image_for_pattern(const cairo_pattern_t * pattern,cairo_bool_t is_mask,const cairo_rectangle_int_t * extents,int * tx,int * ty)1649 _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 *tx = *ty = 0;
1655
1656 if (pattern == NULL)
1657 return _pixman_white_image ();
1658
1659 switch (pattern->type) {
1660 default:
1661 ASSERT_NOT_REACHED;
1662 case CAIRO_PATTERN_TYPE_SOLID:
1663 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 return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
1668 extents, tx, ty);
1669
1670 case CAIRO_PATTERN_TYPE_SURFACE:
1671 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
_cairo_image_surface_fixup_unbounded(cairo_image_surface_t * dst,const cairo_composite_rectangles_t * rects,cairo_clip_t * clip)1677 _cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
1678 const cairo_composite_rectangles_t *rects,
1679 cairo_clip_t *clip)
1680 {
1681 pixman_image_t *mask = NULL;
1682 pixman_box32_t boxes[4];
1683 int i, mask_x = 0, mask_y = 0, n_boxes = 0;
1684
1685 if (clip != NULL) {
1686 cairo_surface_t *clip_surface;
1687 int clip_x, clip_y;
1688
1689 clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
1690 if (unlikely (clip_surface->status))
1691 return clip_surface->status;
1692
1693 mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
1694 mask_x = -clip_x;
1695 mask_y = -clip_y;
1696 } else {
1697 if (rects->bounded.width == rects->unbounded.width &&
1698 rects->bounded.height == rects->unbounded.height)
1699 {
1700 return CAIRO_STATUS_SUCCESS;
1701 }
1702 }
1703
1704 /* wholly unbounded? */
1705 if (rects->bounded.width == 0 || rects->bounded.height == 0) {
1706 int x = rects->unbounded.x;
1707 int y = rects->unbounded.y;
1708 int width = rects->unbounded.width;
1709 int height = rects->unbounded.height;
1710
1711 if (mask != NULL) {
1712 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 pixman_color_t color = { 0, };
1720 pixman_box32_t box = { x, y, x + width, y + height };
1721
1722 if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
1723 dst->pixman_image,
1724 &color,
1725 1, &box))
1726 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1727 }
1728
1729 return CAIRO_STATUS_SUCCESS;
1730 }
1731
1732 /* top */
1733 if (rects->bounded.y != rects->unbounded.y) {
1734 boxes[n_boxes].x1 = rects->unbounded.x;
1735 boxes[n_boxes].y1 = rects->unbounded.y;
1736 boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1737 boxes[n_boxes].y2 = rects->bounded.y;
1738 n_boxes++;
1739 }
1740
1741 /* left */
1742 if (rects->bounded.x != rects->unbounded.x) {
1743 boxes[n_boxes].x1 = rects->unbounded.x;
1744 boxes[n_boxes].y1 = rects->bounded.y;
1745 boxes[n_boxes].x2 = rects->bounded.x;
1746 boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
1747 n_boxes++;
1748 }
1749
1750 /* right */
1751 if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
1752 boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
1753 boxes[n_boxes].y1 = rects->bounded.y;
1754 boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1755 boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
1756 n_boxes++;
1757 }
1758
1759 /* bottom */
1760 if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
1761 boxes[n_boxes].x1 = rects->unbounded.x;
1762 boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
1763 boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
1764 boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
1765 n_boxes++;
1766 }
1767
1768 if (mask != NULL) {
1769 for (i = 0; i < n_boxes; i++) {
1770 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
1771 mask, NULL, dst->pixman_image,
1772 boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
1773 0, 0,
1774 boxes[i].x1, boxes[i].y1,
1775 boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
1776 }
1777 } else {
1778 pixman_color_t color = { 0, };
1779
1780 if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
1781 dst->pixman_image,
1782 &color,
1783 n_boxes,
1784 boxes))
1785 {
1786 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1787 }
1788 }
1789
1790 return CAIRO_STATUS_SUCCESS;
1791 }
1792
1793 static cairo_status_t
_cairo_image_surface_fixup_unbounded_boxes(cairo_image_surface_t * dst,const cairo_composite_rectangles_t * extents,cairo_region_t * clip_region,cairo_boxes_t * boxes)1794 _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 if (boxes->num_boxes <= 1 && clip_region == NULL)
1806 return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
1807
1808 _cairo_boxes_init (&clear);
1809
1810 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
1811 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
1812 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
1813 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
1814
1815 if (clip_region == NULL) {
1816 cairo_boxes_t tmp;
1817
1818 _cairo_boxes_init (&tmp);
1819
1820 status = _cairo_boxes_add (&tmp, &box);
1821 assert (status == CAIRO_STATUS_SUCCESS);
1822
1823 tmp.chunks.next = &boxes->chunks;
1824 tmp.num_boxes += boxes->num_boxes;
1825
1826 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
1827 CAIRO_FILL_RULE_WINDING,
1828 &clear);
1829
1830 tmp.chunks.next = NULL;
1831 } else {
1832 pixman_box32_t *pbox;
1833
1834 pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
1835 _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
1836
1837 status = _cairo_boxes_add (&clear, &box);
1838 assert (status == CAIRO_STATUS_SUCCESS);
1839
1840 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
1841 for (i = 0; i < chunk->count; i++) {
1842 status = _cairo_boxes_add (&clear, &chunk->base[i]);
1843 if (unlikely (status)) {
1844 _cairo_boxes_fini (&clear);
1845 return status;
1846 }
1847 }
1848 }
1849
1850 status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
1851 CAIRO_FILL_RULE_WINDING,
1852 &clear);
1853 }
1854
1855 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1856 for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
1857 for (i = 0; i < chunk->count; i++) {
1858 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
1859 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
1860 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
1861 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
1862
1863 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
1864 PIXMAN_FORMAT_BPP (dst->pixman_format),
1865 x1, y1, x2 - x1, y2 - y1,
1866 0);
1867 }
1868 }
1869 }
1870
1871 _cairo_boxes_fini (&clear);
1872
1873 return status;
1874 }
1875
1876 static cairo_bool_t
can_reduce_alpha_op(cairo_operator_t op)1877 can_reduce_alpha_op (cairo_operator_t op)
1878 {
1879 int iop = op;
1880 switch (iop) {
1881 case CAIRO_OPERATOR_OVER:
1882 case CAIRO_OPERATOR_SOURCE:
1883 case CAIRO_OPERATOR_ADD:
1884 return TRUE;
1885 default:
1886 return FALSE;
1887 }
1888 }
1889
1890 static cairo_bool_t
reduce_alpha_op(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern)1891 reduce_alpha_op (cairo_image_surface_t *dst,
1892 cairo_operator_t op,
1893 const cairo_pattern_t *pattern)
1894 {
1895 return dst->base.is_clear &&
1896 dst->base.content == CAIRO_CONTENT_ALPHA &&
1897 _cairo_pattern_is_opaque_solid (pattern) &&
1898 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 *
_create_composite_mask_pattern(cairo_clip_t * clip,image_draw_func_t draw_func,void * draw_closure,cairo_image_surface_t * dst,const cairo_rectangle_int_t * extents)1914 _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 cairo_region_t *clip_region = NULL;
1921 pixman_image_t *mask;
1922 cairo_status_t status;
1923 cairo_bool_t need_clip_surface = FALSE;
1924
1925 if (clip != NULL) {
1926 status = _cairo_clip_get_region (clip, &clip_region);
1927 assert (! _cairo_status_is_error (status));
1928
1929 /* The all-clipped state should never propagate this far. */
1930 assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
1931
1932 need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
1933
1934 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
1935 clip_region = NULL;
1936 }
1937
1938 mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
1939 NULL, 0);
1940 if (unlikely (mask == NULL))
1941 return NULL;
1942
1943 /* Is it worth setting the clip region here? */
1944 if (clip_region != NULL) {
1945 pixman_bool_t ret;
1946
1947 pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
1948 ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
1949 pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
1950
1951 if (! ret) {
1952 pixman_image_unref (mask);
1953 return NULL;
1954 }
1955 }
1956
1957 status = draw_func (draw_closure,
1958 mask, PIXMAN_a8,
1959 CAIRO_OPERATOR_ADD, NULL,
1960 extents->x, extents->y,
1961 extents, NULL);
1962 if (unlikely (status)) {
1963 pixman_image_unref (mask);
1964 return NULL;
1965 }
1966
1967 if (need_clip_surface) {
1968 cairo_surface_t *tmp;
1969
1970 tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
1971 if (unlikely (tmp->status)) {
1972 pixman_image_unref (mask);
1973 return NULL;
1974 }
1975
1976 pixman_image_ref (mask);
1977
1978 status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
1979 cairo_surface_destroy (tmp);
1980 if (unlikely (status)) {
1981 pixman_image_unref (mask);
1982 return NULL;
1983 }
1984 }
1985
1986 if (clip_region != NULL)
1987 pixman_image_set_clip_region (mask, NULL);
1988
1989 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
_clip_and_composite_with_mask(cairo_clip_t * clip,cairo_operator_t op,const cairo_pattern_t * pattern,image_draw_func_t draw_func,void * draw_closure,cairo_image_surface_t * dst,const cairo_rectangle_int_t * extents)1996 _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 mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
2007 if (unlikely (mask == NULL))
2008 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2009
2010 if (pattern == NULL) {
2011 if (dst->pixman_format == PIXMAN_a8) {
2012 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 src = _pixman_white_image ();
2021 if (unlikely (src == NULL)) {
2022 pixman_image_unref (mask);
2023 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2024 }
2025
2026 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 pixman_image_unref (src);
2032 }
2033 } else {
2034 pixman_image_t *src;
2035 int src_x, src_y;
2036
2037 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2038 if (unlikely (src == NULL)) {
2039 pixman_image_unref (mask);
2040 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2041 }
2042
2043 pixman_image_composite32 (_pixman_operator (op),
2044 src, mask, dst->pixman_image,
2045 extents->x + src_x, extents->y + src_y,
2046 0, 0,
2047 extents->x, extents->y,
2048 extents->width, extents->height);
2049 pixman_image_unref (src);
2050 }
2051
2052 pixman_image_unref (mask);
2053
2054 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
_clip_and_composite_combine(cairo_clip_t * clip,cairo_operator_t op,const cairo_pattern_t * src,image_draw_func_t draw_func,void * draw_closure,cairo_image_surface_t * dst,const cairo_rectangle_int_t * extents)2061 _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 tmp = pixman_image_create_bits (dst->pixman_format,
2075 extents->width, extents->height,
2076 NULL, 0);
2077 if (unlikely (tmp == NULL))
2078 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2079
2080 if (src == NULL) {
2081 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 if (! dst->base.is_clear) {
2089 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 status = (*draw_func) (draw_closure,
2098 tmp, dst->pixman_format,
2099 op, src,
2100 extents->x, extents->y,
2101 extents, NULL);
2102 }
2103 if (unlikely (status))
2104 goto CLEANUP_SURFACE;
2105
2106 assert (clip->path != NULL);
2107 clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
2108 if (unlikely (clip_surface->status))
2109 goto CLEANUP_SURFACE;
2110
2111 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 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2125 ((cairo_image_surface_t *) clip_surface)->pixman_image,
2126 NULL, dst->pixman_image,
2127 extents->x - clip_x,
2128 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 pixman_image_composite32 (PIXMAN_OP_ADD,
2135 tmp,
2136 ((cairo_image_surface_t *) clip_surface)->pixman_image,
2137 dst->pixman_image,
2138 0, 0,
2139 extents->x - clip_x,
2140 extents->y - clip_y,
2141 extents->x, extents->y,
2142 extents->width, extents->height);
2143 #endif
2144 } else {
2145 pixman_image_composite32 (PIXMAN_OP_SRC,
2146 tmp,
2147 ((cairo_image_surface_t *) clip_surface)->pixman_image,
2148 dst->pixman_image,
2149 0, 0,
2150 extents->x - clip_x,
2151 extents->y - clip_y,
2152 extents->x, extents->y,
2153 extents->width, extents->height);
2154 }
2155
2156 CLEANUP_SURFACE:
2157 pixman_image_unref (tmp);
2158
2159 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
_clip_and_composite_source(cairo_clip_t * clip,const cairo_pattern_t * pattern,image_draw_func_t draw_func,void * draw_closure,cairo_image_surface_t * dst,const cairo_rectangle_int_t * extents)2166 _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 if (pattern == NULL) {
2177 cairo_region_t *clip_region;
2178 cairo_status_t status;
2179
2180 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 if (unlikely (status))
2186 return status;
2187
2188 if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
2189 status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
2190
2191 return status;
2192 }
2193
2194 /* Create a surface that is mask IN clip */
2195 mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
2196 if (unlikely (mask == NULL))
2197 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2198
2199 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2200 if (unlikely (src == NULL)) {
2201 pixman_image_unref (mask);
2202 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2203 }
2204
2205 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 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 pixman_image_composite32 (PIXMAN_OP_ADD,
2223 src, mask, dst->pixman_image,
2224 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 pixman_image_composite32 (PIXMAN_OP_SRC,
2231 src, mask, dst->pixman_image,
2232 extents->x + src_x, extents->y + src_y,
2233 0, 0,
2234 extents->x, extents->y,
2235 extents->width, extents->height);
2236 }
2237
2238 pixman_image_unref (src);
2239 pixman_image_unref (mask);
2240
2241 return CAIRO_STATUS_SUCCESS;
2242 }
2243
2244 static cairo_status_t
_clip_and_composite(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,image_draw_func_t draw_func,void * draw_closure,cairo_composite_rectangles_t * extents,cairo_clip_t * clip)2245 _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 cairo_region_t *clip_region = NULL;
2255 cairo_bool_t need_clip_surface = FALSE;
2256
2257 if (clip != NULL) {
2258 status = _cairo_clip_get_region (clip, &clip_region);
2259 if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
2260 return CAIRO_STATUS_SUCCESS;
2261 if (unlikely (_cairo_status_is_error (status)))
2262 return status;
2263
2264 need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
2265
2266 if (clip_region != NULL) {
2267 cairo_rectangle_int_t rect;
2268 cairo_bool_t is_empty;
2269
2270 cairo_region_get_extents (clip_region, &rect);
2271 is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect);
2272 if (unlikely (is_empty))
2273 return CAIRO_STATUS_SUCCESS;
2274
2275 is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect);
2276 if (unlikely (is_empty && extents->is_bounded))
2277 return CAIRO_STATUS_SUCCESS;
2278
2279 if (cairo_region_num_rectangles (clip_region) == 1)
2280 clip_region = NULL;
2281 }
2282 }
2283
2284 if (clip_region != NULL) {
2285 status = _cairo_image_surface_set_clip_region (dst, clip_region);
2286 if (unlikely (status))
2287 return status;
2288 }
2289
2290 if (reduce_alpha_op (dst, op, src)) {
2291 op = CAIRO_OPERATOR_ADD;
2292 src = NULL;
2293 }
2294
2295 if (op == CAIRO_OPERATOR_SOURCE) {
2296 status = _clip_and_composite_source (clip, src,
2297 draw_func, draw_closure,
2298 dst, &extents->bounded);
2299 } else {
2300 if (op == CAIRO_OPERATOR_CLEAR) {
2301 src = NULL;
2302 op = CAIRO_OPERATOR_DEST_OUT;
2303 }
2304
2305 if (need_clip_surface) {
2306 if (extents->is_bounded) {
2307 status = _clip_and_composite_with_mask (clip, op, src,
2308 draw_func, draw_closure,
2309 dst, &extents->bounded);
2310 } else {
2311 status = _clip_and_composite_combine (clip, op, src,
2312 draw_func, draw_closure,
2313 dst, &extents->bounded);
2314 }
2315 } else {
2316 status = draw_func (draw_closure,
2317 dst->pixman_image, dst->pixman_format,
2318 op, src,
2319 0, 0,
2320 &extents->bounded,
2321 clip_region);
2322 }
2323 }
2324
2325 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
2326 status = _cairo_image_surface_fixup_unbounded (dst, extents,
2327 need_clip_surface ? clip : NULL);
2328 }
2329
2330 if (clip_region != NULL)
2331 _cairo_image_surface_unset_clip_region (dst);
2332
2333 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
_line_exceeds_16_16(const cairo_line_t * line)2340 _line_exceeds_16_16 (const cairo_line_t *line)
2341 {
2342 return
2343 line->p1.x <= CAIRO_FIXED_16_16_MIN ||
2344 line->p1.x >= CAIRO_FIXED_16_16_MAX ||
2345
2346 line->p2.x <= CAIRO_FIXED_16_16_MIN ||
2347 line->p2.x >= CAIRO_FIXED_16_16_MAX ||
2348
2349 line->p1.y <= CAIRO_FIXED_16_16_MIN ||
2350 line->p1.y >= CAIRO_FIXED_16_16_MAX ||
2351
2352 line->p2.y <= CAIRO_FIXED_16_16_MIN ||
2353 line->p2.y >= CAIRO_FIXED_16_16_MAX;
2354 }
2355
2356 static void
_project_line_x_onto_16_16(const cairo_line_t * line,cairo_fixed_t top,cairo_fixed_t bottom,pixman_line_fixed_t * out)2357 _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 p1.x = _cairo_fixed_to_double (line->p1.x);
2366 p1.y = _cairo_fixed_to_double (line->p1.y);
2367
2368 p2.x = _cairo_fixed_to_double (line->p2.x);
2369 p2.y = _cairo_fixed_to_double (line->p2.y);
2370
2371 m = (p2.x - p1.x) / (p2.y - p1.y);
2372 out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
2373 out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
2374 }
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
_pixman_image_add_traps(pixman_image_t * image,int dst_x,int dst_y,composite_traps_info_t * info)2384 _pixman_image_add_traps (pixman_image_t *image,
2385 int dst_x, int dst_y,
2386 composite_traps_info_t *info)
2387 {
2388 cairo_trapezoid_t *t = info->traps;
2389 int num_traps = info->num_traps;
2390 while (num_traps--) {
2391 pixman_trapezoid_t trap;
2392
2393 /* top/bottom will be clamped to surface bounds */
2394 trap.top = _cairo_fixed_to_16_16 (t->top);
2395 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 if (unlikely (_line_exceeds_16_16 (&t->left))) {
2402 _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
2403 trap.left.p1.y = trap.top;
2404 trap.left.p2.y = trap.bottom;
2405 } else {
2406 trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
2407 trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
2408 trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
2409 trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
2410 }
2411
2412 if (unlikely (_line_exceeds_16_16 (&t->right))) {
2413 _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
2414 trap.right.p1.y = trap.top;
2415 trap.right.p2.y = trap.bottom;
2416 } else {
2417 trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
2418 trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
2419 trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
2420 trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
2421 }
2422
2423 pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
2424
2425 t++;
2426 }
2427 }
2428
2429 static cairo_status_t
_composite_traps(void * closure,pixman_image_t * dst,pixman_format_code_t dst_format,cairo_operator_t op,const cairo_pattern_t * pattern,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)2430 _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 composite_traps_info_t *info = closure;
2441 pixman_image_t *src, *mask;
2442 pixman_format_code_t format;
2443 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 format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
2454 if (dst_format == format &&
2455 (pattern == NULL ||
2456 (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
2457 {
2458 _pixman_image_add_traps (dst, dst_x, dst_y, info);
2459 return CAIRO_STATUS_SUCCESS;
2460 }
2461
2462 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
2463 if (unlikely (src == NULL))
2464 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2465
2466 mask = pixman_image_create_bits (format, extents->width, extents->height,
2467 NULL, 0);
2468 if (unlikely (mask == NULL)) {
2469 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2470 goto CLEANUP_SOURCE;
2471 }
2472
2473 _pixman_image_add_traps (mask, extents->x, extents->y, info);
2474 pixman_image_composite32 (_pixman_operator (op),
2475 src, mask, dst,
2476 extents->x + src_x, extents->y + src_y,
2477 0, 0,
2478 extents->x - dst_x, extents->y - dst_y,
2479 extents->width, extents->height);
2480
2481 pixman_image_unref (mask);
2482
2483 status = CAIRO_STATUS_SUCCESS;
2484 CLEANUP_SOURCE:
2485 pixman_image_unref (src);
2486
2487 return status;
2488 }
2489
2490 static inline uint32_t
color_to_uint32(const cairo_color_t * color)2491 color_to_uint32 (const cairo_color_t *color)
2492 {
2493 return
2494 (color->alpha_short >> 8 << 24) |
2495 (color->red_short >> 8 << 16) |
2496 (color->green_short & 0xff00) |
2497 (color->blue_short >> 8);
2498 }
2499
2500 static inline cairo_bool_t
color_to_pixel(const cairo_color_t * color,pixman_format_code_t format,uint32_t * pixel)2501 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 if (!(format == PIXMAN_a8r8g8b8 ||
2508 format == PIXMAN_x8r8g8b8 ||
2509 format == PIXMAN_a8b8g8r8 ||
2510 format == PIXMAN_x8b8g8r8 ||
2511 format == PIXMAN_b8g8r8a8 ||
2512 format == PIXMAN_b8g8r8x8 ||
2513 format == PIXMAN_r5g6b5 ||
2514 format == PIXMAN_b5g6r5 ||
2515 format == PIXMAN_a8))
2516 {
2517 return FALSE;
2518 }
2519
2520 c = color_to_uint32 (color);
2521
2522 if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
2523 c = ((c & 0xff000000) >> 0) |
2524 ((c & 0x00ff0000) >> 16) |
2525 ((c & 0x0000ff00) >> 0) |
2526 ((c & 0x000000ff) << 16);
2527 }
2528
2529 if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
2530 c = ((c & 0xff000000) >> 24) |
2531 ((c & 0x00ff0000) >> 8) |
2532 ((c & 0x0000ff00) << 8) |
2533 ((c & 0x000000ff) << 24);
2534 }
2535
2536 if (format == PIXMAN_a8) {
2537 c = c >> 24;
2538 } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
2539 c = ((((c) >> 3) & 0x001f) |
2540 (((c) >> 5) & 0x07e0) |
2541 (((c) >> 8) & 0xf800));
2542 }
2543
2544 *pixel = c;
2545 return TRUE;
2546 }
2547
2548 static inline cairo_bool_t
pattern_to_pixel(const cairo_solid_pattern_t * solid,cairo_operator_t op,pixman_format_code_t format,uint32_t * pixel)2549 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 if (op == CAIRO_OPERATOR_CLEAR) {
2555 *pixel = 0;
2556 return TRUE;
2557 }
2558
2559 if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
2560 return FALSE;
2561
2562 if (op == CAIRO_OPERATOR_OVER) {
2563 if (solid->color.alpha_short >= 0xff00)
2564 op = CAIRO_OPERATOR_SOURCE;
2565 }
2566
2567 if (op != CAIRO_OPERATOR_SOURCE)
2568 return FALSE;
2569
2570 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
_fill_span(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)2581 _fill_span (void *abstract_renderer,
2582 int y, int height,
2583 const cairo_half_open_span_t *spans,
2584 unsigned num_spans)
2585 {
2586 fill_span_renderer_t *renderer = abstract_renderer;
2587 uint8_t *row;
2588 unsigned i;
2589
2590 if (num_spans == 0)
2591 return CAIRO_STATUS_SUCCESS;
2592
2593 row = renderer->mask_data - spans[0].x;
2594 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 if (spans[i+1].x == spans[i].x + 1) {
2601 row[spans[i].x] = spans[i].coverage;
2602 } else {
2603 memset (row + spans[i].x,
2604 spans[i].coverage,
2605 spans[i+1].x - spans[i].x);
2606 }
2607 }
2608
2609 do {
2610 pixman_image_composite32 (PIXMAN_OP_OVER,
2611 renderer->src, renderer->mask, renderer->dst,
2612 0, 0, 0, 0,
2613 spans[0].x, y++,
2614 spans[i].x - spans[0].x, 1);
2615 } while (--height);
2616
2617 return CAIRO_STATUS_SUCCESS;
2618 }
2619
2620 /* avoid using region code to re-validate boxes */
2621 static cairo_status_t
_fill_unaligned_boxes(cairo_image_surface_t * dst,const cairo_pattern_t * pattern,uint32_t pixel,const cairo_boxes_t * boxes,const cairo_composite_rectangles_t * extents)2622 _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 renderer.base.render_rows = _fill_span;
2651 renderer.dst = dst->pixman_image;
2652
2653 if ((unsigned) extents->bounded.width <= sizeof (buf)) {
2654 renderer.mask = pixman_image_create_bits (PIXMAN_a8,
2655 extents->bounded.width, 1,
2656 (uint32_t *) buf,
2657 sizeof (buf));
2658 } else {
2659 renderer.mask = pixman_image_create_bits (PIXMAN_a8,
2660 extents->bounded.width, 1,
2661 NULL, 0);
2662 }
2663 if (unlikely (renderer.mask == NULL))
2664 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2665
2666 renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
2667
2668 renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
2669 if (unlikely (renderer.src == NULL)) {
2670 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2671 goto CLEANUP_MASK;
2672 }
2673
2674 _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
2675
2676 /* first blit any aligned part of the boxes */
2677 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2678 const cairo_box_t *box = chunk->base;
2679
2680 for (i = 0; i < chunk->count; i++) {
2681 int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
2682 int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
2683 int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
2684 int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
2685
2686 if (x2 > x1 && y2 > y1) {
2687 cairo_box_t b;
2688
2689 pixman_fill ((uint32_t *) dst->data,
2690 dst->stride / sizeof (uint32_t),
2691 PIXMAN_FORMAT_BPP (dst->pixman_format),
2692 x1, y1, x2 - x1, y2 - y1,
2693 pixel);
2694
2695 /*
2696 * Corners have to be included only once if the rects
2697 * are passed to the rectangular scan converter
2698 * because it can only handle disjoint rectangles.
2699 */
2700
2701 /* top (including top-left and top-right corners) */
2702 if (! _cairo_fixed_is_integer (box[i].p1.y)) {
2703 b.p1.x = box[i].p1.x;
2704 b.p1.y = box[i].p1.y;
2705 b.p2.x = box[i].p2.x;
2706 b.p2.y = _cairo_fixed_from_int (y1);
2707
2708 status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2709 if (unlikely (status))
2710 goto CLEANUP_CONVERTER;
2711 }
2712
2713 /* left (no corners) */
2714 if (! _cairo_fixed_is_integer (box[i].p1.x)) {
2715 b.p1.x = box[i].p1.x;
2716 b.p1.y = _cairo_fixed_from_int (y1);
2717 b.p2.x = _cairo_fixed_from_int (x1);
2718 b.p2.y = _cairo_fixed_from_int (y2);
2719
2720 status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2721 if (unlikely (status))
2722 goto CLEANUP_CONVERTER;
2723 }
2724
2725 /* right (no corners) */
2726 if (! _cairo_fixed_is_integer (box[i].p2.x)) {
2727 b.p1.x = _cairo_fixed_from_int (x2);
2728 b.p1.y = _cairo_fixed_from_int (y1);
2729 b.p2.x = box[i].p2.x;
2730 b.p2.y = _cairo_fixed_from_int (y2);
2731
2732 status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2733 if (unlikely (status))
2734 goto CLEANUP_CONVERTER;
2735 }
2736
2737 /* bottom (including bottom-left and bottom-right corners) */
2738 if (! _cairo_fixed_is_integer (box[i].p2.y)) {
2739 b.p1.x = box[i].p1.x;
2740 b.p1.y = _cairo_fixed_from_int (y2);
2741 b.p2.x = box[i].p2.x;
2742 b.p2.y = box[i].p2.y;
2743
2744 status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
2745 if (unlikely (status))
2746 goto CLEANUP_CONVERTER;
2747 }
2748 } else {
2749 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
2750 if (unlikely (status))
2751 goto CLEANUP_CONVERTER;
2752 }
2753 }
2754 }
2755
2756 status = converter.base.generate (&converter.base, &renderer.base);
2757
2758 CLEANUP_CONVERTER:
2759 converter.base.destroy (&converter.base);
2760 pixman_image_unref (renderer.src);
2761 CLEANUP_MASK:
2762 pixman_image_unref (renderer.mask);
2763
2764 return status;
2765 }
2766
2767 typedef struct _cairo_image_surface_span_renderer {
2768 cairo_span_renderer_t base;
2769
2770 uint8_t *mask_data;
2771 uint32_t mask_stride;
2772 } cairo_image_surface_span_renderer_t;
2773
2774 static cairo_status_t
_cairo_image_surface_span(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)2775 _cairo_image_surface_span (void *abstract_renderer,
2776 int y, int height,
2777 const cairo_half_open_span_t *spans,
2778 unsigned num_spans)
2779 {
2780 cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
2781 uint8_t *row;
2782 unsigned i;
2783
2784 if (num_spans == 0)
2785 return CAIRO_STATUS_SUCCESS;
2786
2787 /* XXX will it be quicker to repeat the sparse memset,
2788 * or perform a simpler memcpy?
2789 * The fairly dense spiral benchmarks suggests that the sparse
2790 * memset is a win there as well.
2791 */
2792 row = renderer->mask_data + y * renderer->mask_stride;
2793 do {
2794 for (i = 0; i < num_spans - 1; i++) {
2795 if (! spans[i].coverage)
2796 continue;
2797
2798 /* We implement setting rendering the most common single
2799 * pixel wide span case to avoid the overhead of a memset
2800 * call. Open coding setting longer spans didn't show a
2801 * noticeable improvement over memset. */
2802 if (spans[i+1].x == spans[i].x + 1) {
2803 row[spans[i].x] = spans[i].coverage;
2804 } else {
2805 memset (row + spans[i].x,
2806 spans[i].coverage,
2807 spans[i+1].x - spans[i].x);
2808 }
2809 }
2810 row += renderer->mask_stride;
2811 } while (--height);
2812
2813 return CAIRO_STATUS_SUCCESS;
2814 }
2815
2816 static cairo_status_t
_composite_unaligned_boxes(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,const cairo_boxes_t * boxes,const cairo_composite_rectangles_t * extents)2817 _composite_unaligned_boxes (cairo_image_surface_t *dst,
2818 cairo_operator_t op,
2819 const cairo_pattern_t *pattern,
2820 const cairo_boxes_t *boxes,
2821 const cairo_composite_rectangles_t *extents)
2822 {
2823 uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
2824 cairo_image_surface_span_renderer_t renderer;
2825 cairo_rectangular_scan_converter_t converter;
2826 pixman_image_t *mask, *src;
2827 cairo_status_t status;
2828 const struct _cairo_boxes_chunk *chunk;
2829 int i, src_x, src_y;
2830
2831 i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
2832 if ((unsigned) i <= sizeof (buf)) {
2833 mask = pixman_image_create_bits (PIXMAN_a8,
2834 extents->bounded.width,
2835 extents->bounded.height,
2836 (uint32_t *) buf,
2837 CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
2838 memset (buf, 0, i);
2839 } else {
2840 mask = pixman_image_create_bits (PIXMAN_a8,
2841 extents->bounded.width,
2842 extents->bounded.height,
2843 NULL, 0);
2844 }
2845 if (unlikely (mask == NULL))
2846 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2847
2848 renderer.base.render_rows = _cairo_image_surface_span;
2849 renderer.mask_stride = pixman_image_get_stride (mask);
2850 renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
2851 renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
2852
2853 _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
2854
2855 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2856 const cairo_box_t *box = chunk->base;
2857
2858 for (i = 0; i < chunk->count; i++) {
2859 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
2860 if (unlikely (status))
2861 goto CLEANUP;
2862 }
2863 }
2864
2865 status = converter.base.generate (&converter.base, &renderer.base);
2866 if (unlikely (status))
2867 goto CLEANUP;
2868
2869 src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
2870 if (unlikely (src == NULL)) {
2871 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2872 goto CLEANUP;
2873 }
2874
2875 pixman_image_composite32 (_pixman_operator (op),
2876 src, mask, dst->pixman_image,
2877 extents->bounded.x + src_x, extents->bounded.y + src_y,
2878 0, 0,
2879 extents->bounded.x, extents->bounded.y,
2880 extents->bounded.width, extents->bounded.height);
2881 pixman_image_unref (src);
2882
2883 CLEANUP:
2884 converter.base.destroy (&converter.base);
2885 pixman_image_unref (mask);
2886
2887 return status;
2888 }
2889
2890 static cairo_status_t
_composite_boxes(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_boxes_t * boxes,cairo_antialias_t antialias,cairo_clip_t * clip,const cairo_composite_rectangles_t * extents)2891 _composite_boxes (cairo_image_surface_t *dst,
2892 cairo_operator_t op,
2893 const cairo_pattern_t *pattern,
2894 cairo_boxes_t *boxes,
2895 cairo_antialias_t antialias,
2896 cairo_clip_t *clip,
2897 const cairo_composite_rectangles_t *extents)
2898 {
2899 cairo_region_t *clip_region = NULL;
2900 cairo_bool_t need_clip_mask = FALSE;
2901 cairo_status_t status;
2902 struct _cairo_boxes_chunk *chunk;
2903 uint32_t pixel;
2904 int i;
2905
2906 if (clip != NULL) {
2907 status = _cairo_clip_get_region (clip, &clip_region);
2908 need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
2909 if (need_clip_mask &&
2910 (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
2911 {
2912 return CAIRO_INT_STATUS_UNSUPPORTED;
2913 }
2914
2915 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
2916 clip_region = NULL;
2917 }
2918
2919 if (antialias != CAIRO_ANTIALIAS_NONE) {
2920 if (! boxes->is_pixel_aligned) {
2921 if (need_clip_mask)
2922 return CAIRO_INT_STATUS_UNSUPPORTED;
2923
2924 if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
2925 dst->pixman_format, &pixel))
2926 {
2927 return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
2928 }
2929 else
2930 {
2931 return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
2932 }
2933 }
2934 }
2935
2936 status = CAIRO_STATUS_SUCCESS;
2937 if (! need_clip_mask &&
2938 pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
2939 &pixel))
2940 {
2941 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2942 cairo_box_t *box = chunk->base;
2943
2944 for (i = 0; i < chunk->count; i++) {
2945 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
2946 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
2947 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
2948 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
2949
2950 if (x2 == x1 || y2 == y1)
2951 continue;
2952
2953 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
2954 PIXMAN_FORMAT_BPP (dst->pixman_format),
2955 x1, y1, x2 - x1, y2 - y1,
2956 pixel);
2957 }
2958 }
2959 }
2960 else
2961 {
2962 pixman_image_t *src = NULL, *mask = NULL;
2963 int src_x, src_y, mask_x = 0, mask_y = 0;
2964 pixman_op_t pixman_op = _pixman_operator (op);
2965
2966 if (need_clip_mask) {
2967 cairo_surface_t *clip_surface;
2968 int clip_x, clip_y;
2969
2970 clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
2971 if (unlikely (clip_surface->status))
2972 return clip_surface->status;
2973
2974 mask_x = -clip_x;
2975 mask_y = -clip_y;
2976
2977 if (op == CAIRO_OPERATOR_CLEAR) {
2978 pattern = NULL;
2979 pixman_op = PIXMAN_OP_OUT_REVERSE;
2980 }
2981
2982 mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
2983 }
2984
2985 if (pattern != NULL) {
2986 src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
2987 if (unlikely (src == NULL))
2988 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2989 } else {
2990 src = mask;
2991 src_x = mask_x;
2992 src_y = mask_y;
2993 mask = NULL;
2994 }
2995
2996 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
2997 const cairo_box_t *box = chunk->base;
2998
2999 for (i = 0; i < chunk->count; i++) {
3000 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
3001 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
3002 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
3003 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
3004
3005 if (x2 == x1 || y2 == y1)
3006 continue;
3007
3008 pixman_image_composite32 (pixman_op,
3009 src, mask, dst->pixman_image,
3010 x1 + src_x, y1 + src_y,
3011 x1 + mask_x, y1 + mask_y,
3012 x1, y1,
3013 x2 - x1, y2 - y1);
3014 }
3015 }
3016
3017 if (pattern != NULL)
3018 pixman_image_unref (src);
3019
3020 if (! extents->is_bounded) {
3021 status =
3022 _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
3023 clip_region, boxes);
3024 }
3025 }
3026
3027 return status;
3028 }
3029
3030 static cairo_status_t
_clip_and_composite_boxes(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_boxes_t * boxes,cairo_antialias_t antialias,cairo_composite_rectangles_t * extents,cairo_clip_t * clip)3031 _clip_and_composite_boxes (cairo_image_surface_t *dst,
3032 cairo_operator_t op,
3033 const cairo_pattern_t *src,
3034 cairo_boxes_t *boxes,
3035 cairo_antialias_t antialias,
3036 cairo_composite_rectangles_t *extents,
3037 cairo_clip_t *clip)
3038 {
3039 cairo_traps_t traps;
3040 cairo_status_t status;
3041 composite_traps_info_t info;
3042
3043 if (boxes->num_boxes == 0 && extents->is_bounded)
3044 return CAIRO_STATUS_SUCCESS;
3045
3046 /* Use a fast path if the boxes are pixel aligned */
3047 status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
3048 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3049 return status;
3050
3051 /* Otherwise render via a mask and composite in the usual fashion. */
3052 status = _cairo_traps_init_boxes (&traps, boxes);
3053 if (unlikely (status))
3054 return status;
3055
3056 info.num_traps = traps.num_traps;
3057 info.traps = traps.traps;
3058 info.antialias = antialias;
3059 status = _clip_and_composite (dst, op, src,
3060 _composite_traps, &info,
3061 extents, clip);
3062
3063 _cairo_traps_fini (&traps);
3064 return status;
3065 }
3066
3067 static cairo_bool_t
_mono_edge_is_vertical(const cairo_line_t * line)3068 _mono_edge_is_vertical (const cairo_line_t *line)
3069 {
3070 return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
3071 }
3072
3073 static cairo_bool_t
_traps_are_pixel_aligned(cairo_traps_t * traps,cairo_antialias_t antialias)3074 _traps_are_pixel_aligned (cairo_traps_t *traps,
3075 cairo_antialias_t antialias)
3076 {
3077 int i;
3078
3079 if (antialias == CAIRO_ANTIALIAS_NONE) {
3080 for (i = 0; i < traps->num_traps; i++) {
3081 if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
3082 ! _mono_edge_is_vertical (&traps->traps[i].right))
3083 {
3084 traps->maybe_region = FALSE;
3085 return FALSE;
3086 }
3087 }
3088 } else {
3089 for (i = 0; i < traps->num_traps; i++) {
3090 if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
3091 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
3092 ! _cairo_fixed_is_integer (traps->traps[i].top) ||
3093 ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
3094 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
3095 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
3096 {
3097 traps->maybe_region = FALSE;
3098 return FALSE;
3099 }
3100 }
3101 }
3102
3103 return TRUE;
3104 }
3105
3106 static void
_boxes_for_traps(cairo_boxes_t * boxes,cairo_traps_t * traps,cairo_antialias_t antialias)3107 _boxes_for_traps (cairo_boxes_t *boxes,
3108 cairo_traps_t *traps,
3109 cairo_antialias_t antialias)
3110 {
3111 int i;
3112
3113 _cairo_boxes_init (boxes);
3114
3115 boxes->num_boxes = traps->num_traps;
3116 boxes->chunks.base = (cairo_box_t *) traps->traps;
3117 boxes->chunks.count = traps->num_traps;
3118 boxes->chunks.size = traps->num_traps;
3119
3120 if (antialias != CAIRO_ANTIALIAS_NONE) {
3121 for (i = 0; i < traps->num_traps; i++) {
3122 /* Note the traps and boxes alias so we need to take the local copies first. */
3123 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3124 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3125 cairo_fixed_t y1 = traps->traps[i].top;
3126 cairo_fixed_t y2 = traps->traps[i].bottom;
3127
3128 boxes->chunks.base[i].p1.x = x1;
3129 boxes->chunks.base[i].p1.y = y1;
3130 boxes->chunks.base[i].p2.x = x2;
3131 boxes->chunks.base[i].p2.y = y2;
3132
3133 if (boxes->is_pixel_aligned) {
3134 boxes->is_pixel_aligned =
3135 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
3136 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
3137 }
3138 }
3139 } else {
3140 boxes->is_pixel_aligned = TRUE;
3141
3142 for (i = 0; i < traps->num_traps; i++) {
3143 /* Note the traps and boxes alias so we need to take the local copies first. */
3144 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
3145 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
3146 cairo_fixed_t y1 = traps->traps[i].top;
3147 cairo_fixed_t y2 = traps->traps[i].bottom;
3148
3149 /* round down here to match Pixman's behavior when using traps. */
3150 boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
3151 boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
3152 boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
3153 boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
3154 }
3155 }
3156 }
3157
3158 static cairo_status_t
_clip_and_composite_trapezoids(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_traps_t * traps,cairo_antialias_t antialias,cairo_composite_rectangles_t * extents,cairo_clip_t * clip)3159 _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
3160 cairo_operator_t op,
3161 const cairo_pattern_t *src,
3162 cairo_traps_t *traps,
3163 cairo_antialias_t antialias,
3164 cairo_composite_rectangles_t *extents,
3165 cairo_clip_t *clip)
3166 {
3167 composite_traps_info_t info;
3168 cairo_bool_t need_clip_surface = FALSE;
3169 cairo_status_t status;
3170
3171 if (traps->num_traps == 0 && extents->is_bounded)
3172 return CAIRO_STATUS_SUCCESS;
3173
3174 if (clip != NULL) {
3175 cairo_region_t *clip_region;
3176
3177 status = _cairo_clip_get_region (clip, &clip_region);
3178 need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
3179 }
3180
3181 if (traps->has_intersections) {
3182 if (traps->is_rectangular)
3183 status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
3184 else if (traps->is_rectilinear)
3185 status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
3186 else
3187 status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
3188 if (unlikely (status))
3189 return status;
3190 }
3191
3192 /* Use a fast path if the trapezoids consist of a simple region,
3193 * but we can only do this if we do not have a clip surface, or can
3194 * substitute the mask with the clip.
3195 */
3196 if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
3197 (! need_clip_surface ||
3198 (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
3199 {
3200 cairo_boxes_t boxes;
3201
3202 _boxes_for_traps (&boxes, traps, antialias);
3203 return _clip_and_composite_boxes (dst, op, src,
3204 &boxes, antialias,
3205 extents, clip);
3206 }
3207
3208 /* No fast path, exclude self-intersections and clip trapezoids. */
3209 /* Otherwise render the trapezoids to a mask and composite in the usual
3210 * fashion.
3211 */
3212 info.traps = traps->traps;
3213 info.num_traps = traps->num_traps;
3214 info.antialias = antialias;
3215 return _clip_and_composite (dst, op, src,
3216 _composite_traps, &info,
3217 extents, clip);
3218 }
3219
3220 static cairo_clip_path_t *
_clip_get_single_path(cairo_clip_t * clip)3221 _clip_get_single_path (cairo_clip_t *clip)
3222 {
3223 cairo_clip_path_t *iter = clip->path;
3224 cairo_clip_path_t *path = NULL;
3225
3226 do {
3227 if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
3228 if (path != NULL)
3229 return FALSE;
3230
3231 path = iter;
3232 }
3233 iter = iter->prev;
3234 } while (iter != NULL);
3235
3236 return path;
3237 }
3238
3239 /* high level image interface */
3240
3241 static cairo_int_status_t
_cairo_image_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)3242 _cairo_image_surface_paint (void *abstract_surface,
3243 cairo_operator_t op,
3244 const cairo_pattern_t *source,
3245 cairo_clip_t *clip)
3246 {
3247 cairo_image_surface_t *surface = abstract_surface;
3248 cairo_composite_rectangles_t extents;
3249 cairo_clip_path_t *clip_path;
3250 cairo_clip_t local_clip;
3251 cairo_bool_t have_clip = FALSE;
3252 cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3253 int num_boxes = ARRAY_LENGTH (boxes_stack);
3254 cairo_status_t status;
3255
3256 status = _cairo_composite_rectangles_init_for_paint (&extents,
3257 surface->width,
3258 surface->height,
3259 op, source,
3260 clip);
3261 if (unlikely (status))
3262 return status;
3263
3264 if (_cairo_clip_contains_extents (clip, &extents))
3265 clip = NULL;
3266
3267 if (clip != NULL) {
3268 clip = _cairo_clip_init_copy (&local_clip, clip);
3269 have_clip = TRUE;
3270 }
3271
3272 status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3273 if (unlikely (status)) {
3274 if (have_clip)
3275 _cairo_clip_fini (&local_clip);
3276
3277 return status;
3278 }
3279
3280 /* If the clip cannot be reduced to a set of boxes, we will need to
3281 * use a clipmask. Paint is special as it is the only operation that
3282 * does not implicitly use a mask, so we may be able to reduce this
3283 * operation to a fill...
3284 */
3285 if (clip != NULL &&
3286 extents.is_bounded &&
3287 (clip_path = _clip_get_single_path (clip)) != NULL)
3288 {
3289 status = _cairo_image_surface_fill (surface, op, source,
3290 &clip_path->path,
3291 clip_path->fill_rule,
3292 clip_path->tolerance,
3293 clip_path->antialias,
3294 NULL);
3295 }
3296 else
3297 {
3298 cairo_boxes_t boxes;
3299
3300 _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
3301 status = _clip_and_composite_boxes (surface, op, source,
3302 &boxes, CAIRO_ANTIALIAS_DEFAULT,
3303 &extents, clip);
3304 }
3305
3306 if (clip_boxes != boxes_stack)
3307 free (clip_boxes);
3308
3309 if (have_clip)
3310 _cairo_clip_fini (&local_clip);
3311
3312 return status;
3313 }
3314
3315 static cairo_status_t
_composite_mask(void * closure,pixman_image_t * dst,pixman_format_code_t dst_format,cairo_operator_t op,const cairo_pattern_t * src_pattern,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)3316 _composite_mask (void *closure,
3317 pixman_image_t *dst,
3318 pixman_format_code_t dst_format,
3319 cairo_operator_t op,
3320 const cairo_pattern_t *src_pattern,
3321 int dst_x,
3322 int dst_y,
3323 const cairo_rectangle_int_t *extents,
3324 cairo_region_t *clip_region)
3325 {
3326 const cairo_pattern_t *mask_pattern = closure;
3327 pixman_image_t *src, *mask = NULL;
3328 int src_x = 0, src_y = 0;
3329 int mask_x = 0, mask_y = 0;
3330
3331 if (src_pattern != NULL) {
3332 src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y);
3333 if (unlikely (src == NULL))
3334 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3335
3336 mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y);
3337 if (unlikely (mask == NULL)) {
3338 pixman_image_unref (src);
3339 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3340 }
3341
3342 if (mask_pattern->has_component_alpha)
3343 pixman_image_set_component_alpha (mask, TRUE);
3344 } else {
3345 src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y);
3346 if (unlikely (src == NULL))
3347 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3348 }
3349
3350 pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
3351 extents->x + src_x, extents->y + src_y,
3352 extents->x + mask_x, extents->y + mask_y,
3353 extents->x - dst_x, extents->y - dst_y,
3354 extents->width, extents->height);
3355
3356 if (mask != NULL)
3357 pixman_image_unref (mask);
3358 pixman_image_unref (src);
3359
3360 return CAIRO_STATUS_SUCCESS;
3361 }
3362
3363 static cairo_int_status_t
_cairo_image_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_clip_t * clip)3364 _cairo_image_surface_mask (void *abstract_surface,
3365 cairo_operator_t op,
3366 const cairo_pattern_t *source,
3367 const cairo_pattern_t *mask,
3368 cairo_clip_t *clip)
3369 {
3370 cairo_image_surface_t *surface = abstract_surface;
3371 cairo_composite_rectangles_t extents;
3372 cairo_clip_t local_clip;
3373 cairo_bool_t have_clip = FALSE;
3374 cairo_status_t status;
3375
3376 status = _cairo_composite_rectangles_init_for_mask (&extents,
3377 surface->width, surface->height,
3378 op, source, mask, clip);
3379 if (unlikely (status))
3380 return status;
3381
3382 if (_cairo_clip_contains_extents (clip, &extents))
3383 clip = NULL;
3384
3385 if (clip != NULL && extents.is_bounded) {
3386 clip = _cairo_clip_init_copy (&local_clip, clip);
3387 status = _cairo_clip_rectangle (clip, &extents.bounded);
3388 if (unlikely (status)) {
3389 _cairo_clip_fini (&local_clip);
3390 return status;
3391 }
3392
3393 have_clip = TRUE;
3394 }
3395
3396 status = _clip_and_composite (surface, op, source,
3397 _composite_mask, (void *) mask,
3398 &extents, clip);
3399
3400 if (have_clip)
3401 _cairo_clip_fini (&local_clip);
3402
3403 return status;
3404 }
3405
3406 typedef struct {
3407 cairo_polygon_t *polygon;
3408 cairo_fill_rule_t fill_rule;
3409 cairo_antialias_t antialias;
3410 } composite_spans_info_t;
3411
3412 //#define USE_BOTOR_SCAN_CONVERTER
3413 static cairo_status_t
_composite_spans(void * closure,pixman_image_t * dst,pixman_format_code_t dst_format,cairo_operator_t op,const cairo_pattern_t * pattern,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)3414 _composite_spans (void *closure,
3415 pixman_image_t *dst,
3416 pixman_format_code_t dst_format,
3417 cairo_operator_t op,
3418 const cairo_pattern_t *pattern,
3419 int dst_x,
3420 int dst_y,
3421 const cairo_rectangle_int_t *extents,
3422 cairo_region_t *clip_region)
3423 {
3424 uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
3425 composite_spans_info_t *info = closure;
3426 cairo_image_surface_span_renderer_t renderer;
3427 #if USE_BOTOR_SCAN_CONVERTER
3428 cairo_box_t box;
3429 cairo_botor_scan_converter_t converter;
3430 #else
3431 cairo_scan_converter_t *converter;
3432 #endif
3433 pixman_image_t *mask;
3434 cairo_status_t status;
3435
3436 #if USE_BOTOR_SCAN_CONVERTER
3437 box.p1.x = _cairo_fixed_from_int (extents->x);
3438 box.p1.y = _cairo_fixed_from_int (extents->y);
3439 box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
3440 box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
3441 _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
3442 status = converter.base.add_polygon (&converter.base, info->polygon);
3443 #else
3444 converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
3445 extents->x + extents->width,
3446 extents->y + extents->height,
3447 info->fill_rule);
3448 status = converter->add_polygon (converter, info->polygon);
3449 #endif
3450 if (unlikely (status))
3451 goto CLEANUP_CONVERTER;
3452
3453 /* TODO: support rendering to A1 surfaces (or: go add span
3454 * compositing to pixman.) */
3455
3456 if (pattern == NULL &&
3457 dst_format == PIXMAN_a8 &&
3458 op == CAIRO_OPERATOR_SOURCE)
3459 {
3460 mask = dst;
3461 dst = NULL;
3462 }
3463 else
3464 {
3465 int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
3466 uint8_t *data = mask_buf;
3467
3468 if (extents->height * stride <= (int) sizeof (mask_buf))
3469 memset (data, 0, extents->height * stride);
3470 else
3471 data = NULL, stride = 0;
3472
3473 mask = pixman_image_create_bits (PIXMAN_a8,
3474 extents->width,
3475 extents->height,
3476 (uint32_t *) data,
3477 stride);
3478 if (unlikely (mask == NULL)) {
3479 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3480 goto CLEANUP_CONVERTER;
3481 }
3482 }
3483
3484 renderer.base.render_rows = _cairo_image_surface_span;
3485 renderer.mask_stride = pixman_image_get_stride (mask);
3486 renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
3487 if (dst != NULL)
3488 renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
3489 else
3490 renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
3491
3492 #if USE_BOTOR_SCAN_CONVERTER
3493 status = converter.base.generate (&converter.base, &renderer.base);
3494 #else
3495 status = converter->generate (converter, &renderer.base);
3496 #endif
3497 if (unlikely (status))
3498 goto CLEANUP_RENDERER;
3499
3500 if (dst != NULL) {
3501 pixman_image_t *src;
3502 int src_x, src_y;
3503
3504 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
3505 if (unlikely (src == NULL)) {
3506 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3507 goto CLEANUP_RENDERER;
3508 }
3509
3510 pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
3511 extents->x + src_x, extents->y + src_y,
3512 0, 0, /* mask.x, mask.y */
3513 extents->x - dst_x, extents->y - dst_y,
3514 extents->width, extents->height);
3515 pixman_image_unref (src);
3516 }
3517
3518 CLEANUP_RENDERER:
3519 if (dst != NULL)
3520 pixman_image_unref (mask);
3521 CLEANUP_CONVERTER:
3522 #if USE_BOTOR_SCAN_CONVERTER
3523 converter.base.destroy (&converter.base);
3524 #else
3525 converter->destroy (converter);
3526 #endif
3527 return status;
3528 }
3529
3530 static cairo_status_t
_clip_and_composite_polygon(cairo_image_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_polygon_t * polygon,cairo_fill_rule_t fill_rule,cairo_antialias_t antialias,cairo_composite_rectangles_t * extents,cairo_clip_t * clip)3531 _clip_and_composite_polygon (cairo_image_surface_t *dst,
3532 cairo_operator_t op,
3533 const cairo_pattern_t *src,
3534 cairo_polygon_t *polygon,
3535 cairo_fill_rule_t fill_rule,
3536 cairo_antialias_t antialias,
3537 cairo_composite_rectangles_t *extents,
3538 cairo_clip_t *clip)
3539 {
3540 cairo_status_t status;
3541
3542 if (polygon->num_edges == 0) {
3543 cairo_traps_t traps;
3544
3545 if (extents->is_bounded)
3546 return CAIRO_STATUS_SUCCESS;
3547
3548 _cairo_traps_init (&traps);
3549 status = _clip_and_composite_trapezoids (dst, op, src,
3550 &traps, antialias,
3551 extents, clip);
3552 _cairo_traps_fini (&traps);
3553
3554 return status;
3555 }
3556
3557 _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
3558 if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
3559 return CAIRO_STATUS_SUCCESS;
3560
3561 if (antialias != CAIRO_ANTIALIAS_NONE) {
3562 composite_spans_info_t info;
3563
3564 info.polygon = polygon;
3565 info.fill_rule = fill_rule;
3566 info.antialias = antialias;
3567
3568 status = _clip_and_composite (dst, op, src,
3569 _composite_spans, &info,
3570 extents, clip);
3571 } else {
3572 cairo_traps_t traps;
3573
3574 _cairo_traps_init (&traps);
3575
3576 /* Fall back to trapezoid fills. */
3577 status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
3578 polygon,
3579 fill_rule);
3580 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3581 status = _clip_and_composite_trapezoids (dst, op, src,
3582 &traps, antialias,
3583 extents, clip);
3584 }
3585
3586 _cairo_traps_fini (&traps);
3587 }
3588
3589 return status;
3590 }
3591
3592 static cairo_int_status_t
_cairo_image_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)3593 _cairo_image_surface_stroke (void *abstract_surface,
3594 cairo_operator_t op,
3595 const cairo_pattern_t *source,
3596 cairo_path_fixed_t *path,
3597 const cairo_stroke_style_t *style,
3598 const cairo_matrix_t *ctm,
3599 const cairo_matrix_t *ctm_inverse,
3600 double tolerance,
3601 cairo_antialias_t antialias,
3602 cairo_clip_t *clip)
3603 {
3604 cairo_image_surface_t *surface = abstract_surface;
3605 cairo_composite_rectangles_t extents;
3606 cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3607 int num_boxes = ARRAY_LENGTH (boxes_stack);
3608 cairo_clip_t local_clip;
3609 cairo_bool_t have_clip = FALSE;
3610 cairo_status_t status;
3611
3612 status = _cairo_composite_rectangles_init_for_stroke (&extents,
3613 surface->width,
3614 surface->height,
3615 op, source,
3616 path, style, ctm,
3617 clip);
3618 if (unlikely (status))
3619 return status;
3620
3621 if (_cairo_clip_contains_extents (clip, &extents))
3622 clip = NULL;
3623
3624 if (clip != NULL) {
3625 clip = _cairo_clip_init_copy (&local_clip, clip);
3626 have_clip = TRUE;
3627 }
3628
3629 status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3630 if (unlikely (status)) {
3631 if (have_clip)
3632 _cairo_clip_fini (&local_clip);
3633
3634 return status;
3635 }
3636
3637 status = CAIRO_INT_STATUS_UNSUPPORTED;
3638 if (path->is_rectilinear) {
3639 cairo_boxes_t boxes;
3640
3641 _cairo_boxes_init (&boxes);
3642 _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
3643
3644 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
3645 style,
3646 ctm,
3647 &boxes);
3648 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3649 status = _clip_and_composite_boxes (surface, op, source,
3650 &boxes, antialias,
3651 &extents, clip);
3652 }
3653
3654 _cairo_boxes_fini (&boxes);
3655 }
3656
3657 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
3658 cairo_polygon_t polygon;
3659
3660 _cairo_polygon_init (&polygon);
3661 _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
3662
3663 status = _cairo_path_fixed_stroke_to_polygon (path,
3664 style,
3665 ctm, ctm_inverse,
3666 tolerance,
3667 &polygon);
3668 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3669 status = _clip_and_composite_polygon (surface, op, source, &polygon,
3670 CAIRO_FILL_RULE_WINDING, antialias,
3671 &extents, clip);
3672 }
3673
3674 _cairo_polygon_fini (&polygon);
3675 }
3676
3677 if (clip_boxes != boxes_stack)
3678 free (clip_boxes);
3679
3680 if (have_clip)
3681 _cairo_clip_fini (&local_clip);
3682
3683 return status;
3684 }
3685
3686 static cairo_int_status_t
_cairo_image_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)3687 _cairo_image_surface_fill (void *abstract_surface,
3688 cairo_operator_t op,
3689 const cairo_pattern_t *source,
3690 cairo_path_fixed_t *path,
3691 cairo_fill_rule_t fill_rule,
3692 double tolerance,
3693 cairo_antialias_t antialias,
3694 cairo_clip_t *clip)
3695 {
3696 cairo_image_surface_t *surface = abstract_surface;
3697 cairo_composite_rectangles_t extents;
3698 cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
3699 cairo_clip_t local_clip;
3700 cairo_bool_t have_clip = FALSE;
3701 int num_boxes = ARRAY_LENGTH (boxes_stack);
3702 cairo_status_t status;
3703
3704 status = _cairo_composite_rectangles_init_for_fill (&extents,
3705 surface->width,
3706 surface->height,
3707 op, source, path,
3708 clip);
3709 if (unlikely (status))
3710 return status;
3711
3712 if (_cairo_clip_contains_extents (clip, &extents))
3713 clip = NULL;
3714
3715 if (extents.is_bounded && clip != NULL) {
3716 cairo_clip_path_t *clip_path;
3717
3718 if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
3719 _cairo_path_fixed_equal (&clip_path->path, path))
3720 {
3721 clip = NULL;
3722 }
3723 }
3724
3725 if (clip != NULL) {
3726 clip = _cairo_clip_init_copy (&local_clip, clip);
3727 have_clip = TRUE;
3728 }
3729
3730 status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
3731 if (unlikely (status)) {
3732 if (have_clip)
3733 _cairo_clip_fini (&local_clip);
3734
3735 return status;
3736 }
3737
3738 if (_cairo_path_fixed_is_rectilinear_fill (path)) {
3739 cairo_boxes_t boxes;
3740
3741 _cairo_boxes_init (&boxes);
3742 _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
3743
3744 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
3745 fill_rule,
3746 &boxes);
3747 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3748 status = _clip_and_composite_boxes (surface, op, source,
3749 &boxes, antialias,
3750 &extents, clip);
3751 }
3752
3753 _cairo_boxes_fini (&boxes);
3754 } else {
3755 cairo_polygon_t polygon;
3756
3757 assert (! path->is_empty_fill);
3758
3759 _cairo_polygon_init (&polygon);
3760 _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
3761
3762 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
3763 if (likely (status == CAIRO_STATUS_SUCCESS)) {
3764 status = _clip_and_composite_polygon (surface, op, source, &polygon,
3765 fill_rule, antialias,
3766 &extents, clip);
3767 }
3768
3769 _cairo_polygon_fini (&polygon);
3770 }
3771
3772 if (clip_boxes != boxes_stack)
3773 free (clip_boxes);
3774
3775 if (have_clip)
3776 _cairo_clip_fini (&local_clip);
3777
3778 return status;
3779 }
3780
3781 typedef struct {
3782 cairo_scaled_font_t *font;
3783 cairo_glyph_t *glyphs;
3784 int num_glyphs;
3785 } composite_glyphs_info_t;
3786
3787 static cairo_status_t
_composite_glyphs_via_mask(void * closure,pixman_image_t * dst,pixman_format_code_t dst_format,cairo_operator_t op,const cairo_pattern_t * pattern,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)3788 _composite_glyphs_via_mask (void *closure,
3789 pixman_image_t *dst,
3790 pixman_format_code_t dst_format,
3791 cairo_operator_t op,
3792 const cairo_pattern_t *pattern,
3793 int dst_x,
3794 int dst_y,
3795 const cairo_rectangle_int_t *extents,
3796 cairo_region_t *clip_region)
3797 {
3798 composite_glyphs_info_t *info = closure;
3799 cairo_scaled_font_t *font = info->font;
3800 cairo_glyph_t *glyphs = info->glyphs;
3801 int num_glyphs = info->num_glyphs;
3802 pixman_image_t *mask = NULL;
3803 pixman_image_t *src;
3804 pixman_image_t *white;
3805 pixman_format_code_t mask_format = 0; /* silence gcc */
3806 cairo_status_t status;
3807 int src_x, src_y;
3808 int i;
3809
3810 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
3811 if (unlikely (src == NULL))
3812 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3813
3814 white = _pixman_white_image ();
3815 if (unlikely (white == NULL)) {
3816 pixman_image_unref (src);
3817 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3818 }
3819
3820 _cairo_scaled_font_freeze_cache (font);
3821
3822 for (i = 0; i < num_glyphs; i++) {
3823 int x, y;
3824 cairo_image_surface_t *glyph_surface;
3825 cairo_scaled_glyph_t *scaled_glyph;
3826
3827 status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
3828 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3829 &scaled_glyph);
3830
3831 if (unlikely (status))
3832 goto CLEANUP;
3833
3834 glyph_surface = scaled_glyph->surface;
3835
3836 if (glyph_surface->width == 0 || glyph_surface->height == 0)
3837 continue;
3838
3839 /* To start, create the mask using the format from the first
3840 * glyph. Later we'll deal with different formats. */
3841 if (mask == NULL) {
3842 mask_format = glyph_surface->pixman_format;
3843 mask = pixman_image_create_bits (mask_format,
3844 extents->width, extents->height,
3845 NULL, 0);
3846 if (unlikely (mask == NULL)) {
3847 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3848 goto CLEANUP;
3849 }
3850
3851 if (PIXMAN_FORMAT_RGB (mask_format))
3852 pixman_image_set_component_alpha (mask, TRUE);
3853 }
3854
3855 /* If we have glyphs of different formats, we "upgrade" the mask
3856 * to the wider of the formats. */
3857 if (glyph_surface->pixman_format != mask_format &&
3858 PIXMAN_FORMAT_BPP (mask_format) <
3859 PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
3860 {
3861 pixman_image_t *new_mask;
3862
3863 mask_format = glyph_surface->pixman_format;
3864 new_mask = pixman_image_create_bits (mask_format,
3865 extents->width, extents->height,
3866 NULL, 0);
3867 if (unlikely (new_mask == NULL)) {
3868 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3869 goto CLEANUP;
3870 }
3871
3872 pixman_image_composite32 (PIXMAN_OP_SRC,
3873 white, mask, new_mask,
3874 0, 0, 0, 0, 0, 0,
3875 extents->width, extents->height);
3876
3877 pixman_image_unref (mask);
3878 mask = new_mask;
3879 if (PIXMAN_FORMAT_RGB (mask_format))
3880 pixman_image_set_component_alpha (mask, TRUE);
3881 }
3882
3883 /* round glyph locations to the nearest pixel */
3884 /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
3885 x = _cairo_lround (glyphs[i].x -
3886 glyph_surface->base.device_transform.x0);
3887 y = _cairo_lround (glyphs[i].y -
3888 glyph_surface->base.device_transform.y0);
3889 if (glyph_surface->pixman_format == mask_format) {
3890 pixman_image_composite32 (PIXMAN_OP_ADD,
3891 glyph_surface->pixman_image, NULL, mask,
3892 0, 0, 0, 0,
3893 x - extents->x, y - extents->y,
3894 glyph_surface->width,
3895 glyph_surface->height);
3896 } else {
3897 pixman_image_composite32 (PIXMAN_OP_ADD,
3898 white, glyph_surface->pixman_image, mask,
3899 0, 0, 0, 0,
3900 x - extents->x, y - extents->y,
3901 glyph_surface->width,
3902 glyph_surface->height);
3903 }
3904 }
3905
3906 pixman_image_composite32 (_pixman_operator (op),
3907 src, mask, dst,
3908 extents->x + src_x, extents->y + src_y,
3909 0, 0,
3910 extents->x - dst_x, extents->y - dst_y,
3911 extents->width, extents->height);
3912
3913 CLEANUP:
3914 _cairo_scaled_font_thaw_cache (font);
3915 if (mask != NULL)
3916 pixman_image_unref (mask);
3917 pixman_image_unref (src);
3918 pixman_image_unref (white);
3919
3920 return status;
3921 }
3922
3923 static cairo_status_t
_composite_glyphs(void * closure,pixman_image_t * dst,pixman_format_code_t dst_format,cairo_operator_t op,const cairo_pattern_t * pattern,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)3924 _composite_glyphs (void *closure,
3925 pixman_image_t *dst,
3926 pixman_format_code_t dst_format,
3927 cairo_operator_t op,
3928 const cairo_pattern_t *pattern,
3929 int dst_x,
3930 int dst_y,
3931 const cairo_rectangle_int_t *extents,
3932 cairo_region_t *clip_region)
3933 {
3934 composite_glyphs_info_t *info = closure;
3935 cairo_scaled_glyph_t *glyph_cache[64];
3936 pixman_op_t pixman_op = _pixman_operator (op);
3937 pixman_image_t *src = NULL;
3938 int src_x = 0, src_y = 0;
3939 cairo_status_t status;
3940 int i;
3941
3942 if (pattern != NULL) {
3943 src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
3944 src_x -= dst_x;
3945 src_y -= dst_y;
3946 } else {
3947 src = _pixman_white_image ();
3948 }
3949 if (unlikely (src == NULL))
3950 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3951
3952 memset (glyph_cache, 0, sizeof (glyph_cache));
3953 status = CAIRO_STATUS_SUCCESS;
3954
3955 _cairo_scaled_font_freeze_cache (info->font);
3956 for (i = 0; i < info->num_glyphs; i++) {
3957 int x, y;
3958 cairo_image_surface_t *glyph_surface;
3959 cairo_scaled_glyph_t *scaled_glyph;
3960 unsigned long glyph_index = info->glyphs[i].index;
3961 int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
3962
3963 scaled_glyph = glyph_cache[cache_index];
3964 if (scaled_glyph == NULL ||
3965 _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
3966 {
3967 status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
3968 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3969 &scaled_glyph);
3970
3971 if (unlikely (status))
3972 break;
3973
3974 glyph_cache[cache_index] = scaled_glyph;
3975 }
3976
3977 glyph_surface = scaled_glyph->surface;
3978 if (glyph_surface->width && glyph_surface->height) {
3979 int x1, y1, x2, y2;
3980
3981 /* round glyph locations to the nearest pixel */
3982 /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
3983 x = _cairo_lround (info->glyphs[i].x -
3984 glyph_surface->base.device_transform.x0);
3985 y = _cairo_lround (info->glyphs[i].y -
3986 glyph_surface->base.device_transform.y0);
3987
3988 x1 = x;
3989 if (x1 < extents->x)
3990 x1 = extents->x;
3991 x2 = x + glyph_surface->width;
3992 if (x2 > extents->x + extents->width)
3993 x2 = extents->x + extents->width;
3994
3995 y1 = y;
3996 if (y1 < extents->y)
3997 y1 = extents->y;
3998 y2 = y + glyph_surface->height;
3999 if (y2 > extents->y + extents->height)
4000 y2 = extents->y + extents->height;
4001
4002 pixman_image_composite32 (pixman_op,
4003 src, glyph_surface->pixman_image, dst,
4004 x1 + src_x, y1 + src_y,
4005 x1 - x, y1 - y,
4006 x1 - dst_x, y1 - dst_y,
4007 x2 - x1, y2 - y1);
4008 }
4009 }
4010 _cairo_scaled_font_thaw_cache (info->font);
4011
4012 pixman_image_unref (src);
4013
4014 return status;
4015 }
4016
4017 static cairo_int_status_t
_cairo_image_surface_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * num_remaining)4018 _cairo_image_surface_glyphs (void *abstract_surface,
4019 cairo_operator_t op,
4020 const cairo_pattern_t *source,
4021 cairo_glyph_t *glyphs,
4022 int num_glyphs,
4023 cairo_scaled_font_t *scaled_font,
4024 cairo_clip_t *clip,
4025 int *num_remaining)
4026 {
4027 cairo_image_surface_t *surface = abstract_surface;
4028 cairo_composite_rectangles_t extents;
4029 composite_glyphs_info_t glyph_info;
4030 cairo_clip_t local_clip;
4031 cairo_bool_t have_clip = FALSE;
4032 cairo_bool_t overlap;
4033 cairo_status_t status;
4034
4035 status = _cairo_composite_rectangles_init_for_glyphs (&extents,
4036 surface->width,
4037 surface->height,
4038 op, source,
4039 scaled_font,
4040 glyphs, num_glyphs,
4041 clip,
4042 &overlap);
4043 if (unlikely (status))
4044 return status;
4045
4046 if (_cairo_clip_contains_rectangle (clip, &extents.mask))
4047 clip = NULL;
4048
4049 if (clip != NULL && extents.is_bounded) {
4050 clip = _cairo_clip_init_copy (&local_clip, clip);
4051 status = _cairo_clip_rectangle (clip, &extents.bounded);
4052 if (unlikely (status))
4053 return status;
4054
4055 have_clip = TRUE;
4056 }
4057
4058 glyph_info.font = scaled_font;
4059 glyph_info.glyphs = glyphs;
4060 glyph_info.num_glyphs = num_glyphs;
4061
4062 status = _clip_and_composite (surface, op, source,
4063 overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
4064 &glyph_info,
4065 &extents, clip);
4066
4067 if (have_clip)
4068 _cairo_clip_fini (&local_clip);
4069
4070 *num_remaining = 0;
4071 return status;
4072 }
4073
4074 static cairo_bool_t
_cairo_image_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)4075 _cairo_image_surface_get_extents (void *abstract_surface,
4076 cairo_rectangle_int_t *rectangle)
4077 {
4078 cairo_image_surface_t *surface = abstract_surface;
4079
4080 rectangle->x = 0;
4081 rectangle->y = 0;
4082 rectangle->width = surface->width;
4083 rectangle->height = surface->height;
4084
4085 return TRUE;
4086 }
4087
4088 static void
_cairo_image_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)4089 _cairo_image_surface_get_font_options (void *abstract_surface,
4090 cairo_font_options_t *options)
4091 {
4092 _cairo_font_options_init_default (options);
4093
4094 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
4095 }
4096
4097 /* legacy interface kept for compatibility until surface-fallback is removed */
4098 static cairo_status_t
_cairo_image_surface_acquire_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t ** image_out,cairo_rectangle_int_t * image_rect_out,void ** image_extra)4099 _cairo_image_surface_acquire_dest_image (void *abstract_surface,
4100 cairo_rectangle_int_t *interest_rect,
4101 cairo_image_surface_t **image_out,
4102 cairo_rectangle_int_t *image_rect_out,
4103 void **image_extra)
4104 {
4105 cairo_image_surface_t *surface = abstract_surface;
4106
4107 image_rect_out->x = 0;
4108 image_rect_out->y = 0;
4109 image_rect_out->width = surface->width;
4110 image_rect_out->height = surface->height;
4111
4112 *image_out = surface;
4113 *image_extra = NULL;
4114
4115 return CAIRO_STATUS_SUCCESS;
4116 }
4117
4118 static void
_cairo_image_surface_release_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t * image,cairo_rectangle_int_t * image_rect,void * image_extra)4119 _cairo_image_surface_release_dest_image (void *abstract_surface,
4120 cairo_rectangle_int_t *interest_rect,
4121 cairo_image_surface_t *image,
4122 cairo_rectangle_int_t *image_rect,
4123 void *image_extra)
4124 {
4125 }
4126
4127 static cairo_status_t
_cairo_image_surface_clone_similar(void * abstract_surface,cairo_surface_t * src,int src_x,int src_y,int width,int height,int * clone_offset_x,int * clone_offset_y,cairo_surface_t ** clone_out)4128 _cairo_image_surface_clone_similar (void *abstract_surface,
4129 cairo_surface_t *src,
4130 int src_x,
4131 int src_y,
4132 int width,
4133 int height,
4134 int *clone_offset_x,
4135 int *clone_offset_y,
4136 cairo_surface_t **clone_out)
4137 {
4138 cairo_image_surface_t *surface = abstract_surface;
4139
4140 if (src->backend == surface->base.backend) {
4141 *clone_offset_x = *clone_offset_y = 0;
4142 *clone_out = cairo_surface_reference (src);
4143
4144 return CAIRO_STATUS_SUCCESS;
4145 }
4146
4147 return CAIRO_INT_STATUS_UNSUPPORTED;
4148 }
4149
4150 static cairo_int_status_t
_cairo_image_surface_composite(cairo_operator_t op,const cairo_pattern_t * src_pattern,const cairo_pattern_t * mask_pattern,void * abstract_dst,int src_x,int src_y,int mask_x,int mask_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_region_t * clip_region)4151 _cairo_image_surface_composite (cairo_operator_t op,
4152 const cairo_pattern_t *src_pattern,
4153 const cairo_pattern_t *mask_pattern,
4154 void *abstract_dst,
4155 int src_x,
4156 int src_y,
4157 int mask_x,
4158 int mask_y,
4159 int dst_x,
4160 int dst_y,
4161 unsigned int width,
4162 unsigned int height,
4163 cairo_region_t *clip_region)
4164 {
4165 cairo_image_surface_t *dst = abstract_dst;
4166 cairo_composite_rectangles_t extents;
4167 pixman_image_t *src;
4168 int src_offset_x, src_offset_y;
4169 cairo_status_t status;
4170
4171 if (clip_region != NULL) {
4172 status = _cairo_image_surface_set_clip_region (dst, clip_region);
4173 if (unlikely (status))
4174 return status;
4175 }
4176
4177 extents.source.x = src_x;
4178 extents.source.y = src_y;
4179 extents.source.width = width;
4180 extents.source.height = height;
4181
4182 extents.mask.x = mask_x;
4183 extents.mask.y = mask_y;
4184 extents.mask.width = width;
4185 extents.mask.height = height;
4186
4187 extents.bounded.x = dst_x;
4188 extents.bounded.y = dst_y;
4189 extents.bounded.width = width;
4190 extents.bounded.height = height;
4191
4192 extents.unbounded.x = 0;
4193 extents.unbounded.y = 0;
4194 extents.unbounded.width = dst->width;
4195 extents.unbounded.height = dst->height;
4196
4197 if (clip_region != NULL) {
4198 cairo_rectangle_int_t rect;
4199
4200 cairo_region_get_extents (clip_region, &rect);
4201 if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
4202 return CAIRO_STATUS_SUCCESS;
4203 }
4204
4205 extents.is_bounded = _cairo_operator_bounded_by_either (op);
4206
4207 src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y);
4208 if (unlikely (src == NULL))
4209 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4210
4211 status = CAIRO_STATUS_SUCCESS;
4212 if (mask_pattern != NULL) {
4213 pixman_image_t *mask;
4214 int mask_offset_x, mask_offset_y;
4215
4216 mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y);
4217 if (unlikely (mask == NULL)) {
4218 pixman_image_unref (src);
4219 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4220 }
4221
4222 pixman_image_composite32 (_pixman_operator (op),
4223 src, mask, dst->pixman_image,
4224 src_x + src_offset_x,
4225 src_y + src_offset_y,
4226 mask_x + mask_offset_x,
4227 mask_y + mask_offset_y,
4228 dst_x, dst_y, width, height);
4229
4230 pixman_image_unref (mask);
4231 } else {
4232 pixman_image_composite32 (_pixman_operator (op),
4233 src, NULL, dst->pixman_image,
4234 src_x + src_offset_x,
4235 src_y + src_offset_y,
4236 0, 0,
4237 dst_x, dst_y, width, height);
4238 }
4239
4240 pixman_image_unref (src);
4241
4242 if (! extents.is_bounded)
4243 status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
4244
4245 if (clip_region != NULL)
4246 _cairo_image_surface_unset_clip_region (dst);
4247
4248 return status;
4249 }
4250
4251 static cairo_int_status_t
_cairo_image_surface_fill_rectangles(void * abstract_surface,cairo_operator_t op,const cairo_color_t * color,cairo_rectangle_int_t * rects,int num_rects)4252 _cairo_image_surface_fill_rectangles (void *abstract_surface,
4253 cairo_operator_t op,
4254 const cairo_color_t *color,
4255 cairo_rectangle_int_t *rects,
4256 int num_rects)
4257 {
4258 cairo_image_surface_t *surface = abstract_surface;
4259
4260 pixman_color_t pixman_color;
4261 pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
4262 pixman_box32_t *pixman_boxes = stack_boxes;
4263 int i;
4264
4265 cairo_int_status_t status;
4266
4267 if (CAIRO_INJECT_FAULT ())
4268 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4269
4270 pixman_color.red = color->red_short;
4271 pixman_color.green = color->green_short;
4272 pixman_color.blue = color->blue_short;
4273 pixman_color.alpha = color->alpha_short;
4274
4275 if (num_rects > ARRAY_LENGTH (stack_boxes)) {
4276 pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
4277 if (unlikely (pixman_boxes == NULL))
4278 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4279 }
4280
4281 for (i = 0; i < num_rects; i++) {
4282 pixman_boxes[i].x1 = rects[i].x;
4283 pixman_boxes[i].y1 = rects[i].y;
4284 pixman_boxes[i].x2 = rects[i].x + rects[i].width;
4285 pixman_boxes[i].y2 = rects[i].y + rects[i].height;
4286 }
4287
4288 status = CAIRO_STATUS_SUCCESS;
4289 if (! pixman_image_fill_boxes (_pixman_operator (op),
4290 surface->pixman_image,
4291 &pixman_color,
4292 num_rects,
4293 pixman_boxes))
4294 {
4295 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4296 }
4297
4298 if (pixman_boxes != stack_boxes)
4299 free (pixman_boxes);
4300
4301 return status;
4302 }
4303
4304 static cairo_int_status_t
_cairo_image_surface_composite_trapezoids(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias,int src_x,int src_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_trapezoid_t * traps,int num_traps,cairo_region_t * clip_region)4305 _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
4306 const cairo_pattern_t *pattern,
4307 void *abstract_dst,
4308 cairo_antialias_t antialias,
4309 int src_x,
4310 int src_y,
4311 int dst_x,
4312 int dst_y,
4313 unsigned int width,
4314 unsigned int height,
4315 cairo_trapezoid_t *traps,
4316 int num_traps,
4317 cairo_region_t *clip_region)
4318 {
4319 cairo_image_surface_t *dst = abstract_dst;
4320 cairo_composite_rectangles_t extents;
4321 cairo_pattern_union_t source_pattern;
4322 composite_traps_info_t info;
4323 cairo_status_t status;
4324
4325 if (height == 0 || width == 0)
4326 return CAIRO_STATUS_SUCCESS;
4327
4328 if (CAIRO_INJECT_FAULT ())
4329 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4330
4331 extents.source.x = src_x;
4332 extents.source.y = src_y;
4333 extents.source.width = width;
4334 extents.source.height = height;
4335
4336 extents.mask.x = dst_x;
4337 extents.mask.y = dst_y;
4338 extents.mask.width = width;
4339 extents.mask.height = height;
4340
4341 extents.bounded.x = dst_x;
4342 extents.bounded.y = dst_y;
4343 extents.bounded.width = width;
4344 extents.bounded.height = height;
4345
4346 extents.unbounded.x = 0;
4347 extents.unbounded.y = 0;
4348 extents.unbounded.width = dst->width;
4349 extents.unbounded.height = dst->height;
4350
4351 if (clip_region != NULL) {
4352 cairo_rectangle_int_t rect;
4353
4354 cairo_region_get_extents (clip_region, &rect);
4355 if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
4356 return CAIRO_STATUS_SUCCESS;
4357 }
4358
4359 extents.is_bounded = _cairo_operator_bounded_by_either (op);
4360
4361 if (clip_region != NULL) {
4362 status = _cairo_image_surface_set_clip_region (dst, clip_region);
4363 if (unlikely (status))
4364 return status;
4365 }
4366
4367 _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
4368 cairo_matrix_translate (&source_pattern.base.matrix,
4369 src_x - extents.bounded.x,
4370 src_y - extents.bounded.y);
4371
4372 info.traps = traps;
4373 info.num_traps = num_traps;
4374 info.antialias = antialias;
4375 status = _composite_traps (&info,
4376 dst->pixman_image,
4377 dst->pixman_format,
4378 op,
4379 &source_pattern.base,
4380 0, 0,
4381 &extents.bounded,
4382 clip_region);
4383
4384 if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
4385 status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
4386
4387 if (clip_region != NULL)
4388 _cairo_image_surface_unset_clip_region (dst);
4389
4390 return status;
4391 }
4392
4393 typedef struct _legacy_image_surface_span_renderer {
4394 cairo_span_renderer_t base;
4395
4396 cairo_operator_t op;
4397 const cairo_pattern_t *pattern;
4398 cairo_antialias_t antialias;
4399 cairo_region_t *clip_region;
4400
4401 pixman_image_t *mask;
4402 uint8_t *mask_data;
4403 uint32_t mask_stride;
4404
4405 cairo_image_surface_t *dst;
4406 cairo_composite_rectangles_t composite_rectangles;
4407 } legacy_image_surface_span_renderer_t;
4408
4409 void
_cairo_image_surface_span_render_row(int y,const cairo_half_open_span_t * spans,unsigned num_spans,uint8_t * data,uint32_t stride)4410 _cairo_image_surface_span_render_row (
4411 int y,
4412 const cairo_half_open_span_t *spans,
4413 unsigned num_spans,
4414 uint8_t *data,
4415 uint32_t stride)
4416 {
4417 uint8_t *row;
4418 unsigned i;
4419
4420 if (num_spans == 0)
4421 return;
4422
4423 row = data + y * stride;
4424 for (i = 0; i < num_spans - 1; i++) {
4425 if (! spans[i].coverage)
4426 continue;
4427
4428 /* We implement setting the most common single pixel wide
4429 * span case to avoid the overhead of a memset call.
4430 * Open coding setting longer spans didn't show a
4431 * noticeable improvement over memset.
4432 */
4433 if (spans[i+1].x == spans[i].x + 1) {
4434 row[spans[i].x] = spans[i].coverage;
4435 } else {
4436 memset (row + spans[i].x,
4437 spans[i].coverage,
4438 spans[i+1].x - spans[i].x);
4439 }
4440 }
4441 }
4442
4443 static cairo_status_t
_cairo_image_surface_span_renderer_render_rows(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)4444 _cairo_image_surface_span_renderer_render_rows (
4445 void *abstract_renderer,
4446 int y,
4447 int height,
4448 const cairo_half_open_span_t *spans,
4449 unsigned num_spans)
4450 {
4451 legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4452 while (height--)
4453 _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
4454 return CAIRO_STATUS_SUCCESS;
4455 }
4456
4457 static void
_cairo_image_surface_span_renderer_destroy(void * abstract_renderer)4458 _cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
4459 {
4460 legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4461 if (renderer == NULL)
4462 return;
4463
4464 pixman_image_unref (renderer->mask);
4465
4466 free (renderer);
4467 }
4468
4469 static cairo_status_t
_cairo_image_surface_span_renderer_finish(void * abstract_renderer)4470 _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
4471 {
4472 legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
4473 cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
4474 cairo_image_surface_t *dst = renderer->dst;
4475 pixman_image_t *src;
4476 int src_x, src_y;
4477 cairo_status_t status;
4478
4479 if (renderer->clip_region != NULL) {
4480 status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
4481 if (unlikely (status))
4482 return status;
4483 }
4484
4485 src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y);
4486 if (src == NULL)
4487 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4488
4489 status = CAIRO_STATUS_SUCCESS;
4490 pixman_image_composite32 (_pixman_operator (renderer->op),
4491 src,
4492 renderer->mask,
4493 dst->pixman_image,
4494 rects->bounded.x + src_x,
4495 rects->bounded.y + src_y,
4496 0, 0,
4497 rects->bounded.x, rects->bounded.y,
4498 rects->bounded.width, rects->bounded.height);
4499
4500 if (! rects->is_bounded)
4501 status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
4502
4503 if (renderer->clip_region != NULL)
4504 _cairo_image_surface_unset_clip_region (dst);
4505
4506 return status;
4507 }
4508
4509 static cairo_bool_t
_cairo_image_surface_check_span_renderer(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias)4510 _cairo_image_surface_check_span_renderer (cairo_operator_t op,
4511 const cairo_pattern_t *pattern,
4512 void *abstract_dst,
4513 cairo_antialias_t antialias)
4514 {
4515 return TRUE;
4516 (void) op;
4517 (void) pattern;
4518 (void) abstract_dst;
4519 (void) antialias;
4520 }
4521
4522 static cairo_span_renderer_t *
_cairo_image_surface_create_span_renderer(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias,const cairo_composite_rectangles_t * rects,cairo_region_t * clip_region)4523 _cairo_image_surface_create_span_renderer (cairo_operator_t op,
4524 const cairo_pattern_t *pattern,
4525 void *abstract_dst,
4526 cairo_antialias_t antialias,
4527 const cairo_composite_rectangles_t *rects,
4528 cairo_region_t *clip_region)
4529 {
4530 cairo_image_surface_t *dst = abstract_dst;
4531 legacy_image_surface_span_renderer_t *renderer;
4532
4533 renderer = calloc(1, sizeof(*renderer));
4534 if (unlikely (renderer == NULL))
4535 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
4536
4537 renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
4538 renderer->base.finish = _cairo_image_surface_span_renderer_finish;
4539 renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
4540 renderer->op = op;
4541 renderer->pattern = pattern;
4542 renderer->antialias = antialias;
4543 renderer->dst = dst;
4544 renderer->clip_region = clip_region;
4545
4546 renderer->composite_rectangles = *rects;
4547
4548 /* TODO: support rendering to A1 surfaces (or: go add span
4549 * compositing to pixman.) */
4550 renderer->mask = pixman_image_create_bits (PIXMAN_a8,
4551 rects->bounded.width,
4552 rects->bounded.height,
4553 NULL, 0);
4554 if (renderer->mask == NULL) {
4555 free (renderer);
4556 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
4557 }
4558
4559 renderer->mask_stride = pixman_image_get_stride (renderer->mask);
4560 renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
4561
4562 return &renderer->base;
4563 }
4564
4565 /**
4566 * _cairo_surface_is_image:
4567 * @surface: a #cairo_surface_t
4568 *
4569 * Checks if a surface is an #cairo_image_surface_t
4570 *
4571 * Return value: %TRUE if the surface is an image surface
4572 **/
4573 cairo_bool_t
_cairo_surface_is_image(const cairo_surface_t * surface)4574 _cairo_surface_is_image (const cairo_surface_t *surface)
4575 {
4576 return surface->backend == &_cairo_image_surface_backend;
4577 }
4578
4579 const cairo_surface_backend_t _cairo_image_surface_backend = {
4580 CAIRO_SURFACE_TYPE_IMAGE,
4581 _cairo_image_surface_create_similar,
4582 _cairo_image_surface_finish,
4583 _cairo_image_surface_acquire_source_image,
4584 _cairo_image_surface_release_source_image,
4585 _cairo_image_surface_acquire_dest_image,
4586 _cairo_image_surface_release_dest_image,
4587 _cairo_image_surface_clone_similar,
4588 _cairo_image_surface_composite,
4589 _cairo_image_surface_fill_rectangles,
4590 _cairo_image_surface_composite_trapezoids,
4591 _cairo_image_surface_create_span_renderer,
4592 _cairo_image_surface_check_span_renderer,
4593
4594 NULL, /* copy_page */
4595 NULL, /* show_page */
4596 _cairo_image_surface_get_extents,
4597 NULL, /* old_show_glyphs */
4598 _cairo_image_surface_get_font_options,
4599 NULL, /* flush */
4600 NULL, /* mark dirty */
4601 NULL, /* font_fini */
4602 NULL, /* glyph_fini */
4603
4604 _cairo_image_surface_paint,
4605 _cairo_image_surface_mask,
4606 _cairo_image_surface_stroke,
4607 _cairo_image_surface_fill,
4608 _cairo_image_surface_glyphs,
4609 NULL, /* show_text_glyphs */
4610 NULL, /* snapshot */
4611 NULL, /* is_similar */
4612 };
4613
4614 /* A convenience function for when one needs to coerce an image
4615 * surface to an alternate format. */
4616 cairo_image_surface_t *
_cairo_image_surface_coerce(cairo_image_surface_t * surface)4617 _cairo_image_surface_coerce (cairo_image_surface_t *surface)
4618 {
4619 return _cairo_image_surface_coerce_to_format (surface,
4620 _cairo_format_from_content (surface->base.content));
4621
4622 }
4623
4624 /* A convenience function for when one needs to coerce an image
4625 * surface to an alternate format. */
4626 cairo_image_surface_t *
_cairo_image_surface_coerce_to_format(cairo_image_surface_t * surface,cairo_format_t format)4627 _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
4628 cairo_format_t format)
4629 {
4630 cairo_image_surface_t *clone;
4631 cairo_status_t status;
4632
4633 status = surface->base.status;
4634 if (unlikely (status))
4635 return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
4636
4637 if (surface->format == format)
4638 return (cairo_image_surface_t *)cairo_surface_reference(&surface->base);
4639
4640 clone = (cairo_image_surface_t *)
4641 cairo_image_surface_create (format, surface->width, surface->height);
4642 if (unlikely (clone->base.status))
4643 return clone;
4644
4645 pixman_image_composite32 (PIXMAN_OP_SRC,
4646 surface->pixman_image, NULL, clone->pixman_image,
4647 0, 0,
4648 0, 0,
4649 0, 0,
4650 surface->width, surface->height);
4651 clone->base.is_clear = FALSE;
4652
4653 clone->base.device_transform =
4654 surface->base.device_transform;
4655 clone->base.device_transform_inverse =
4656 surface->base.device_transform_inverse;
4657
4658 return clone;
4659 }
4660
4661 cairo_image_transparency_t
_cairo_image_analyze_transparency(cairo_image_surface_t * image)4662 _cairo_image_analyze_transparency (cairo_image_surface_t *image)
4663 {
4664 int x, y;
4665
4666 if (image->transparency != CAIRO_IMAGE_UNKNOWN)
4667 return image->transparency;
4668
4669 if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
4670 return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4671
4672 if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
4673 if (image->format == CAIRO_FORMAT_A1)
4674 return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
4675 else
4676 return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4677 }
4678
4679 if (image->format == CAIRO_FORMAT_RGB16_565) {
4680 image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4681 return CAIRO_IMAGE_IS_OPAQUE;
4682 }
4683
4684 if (image->format != CAIRO_FORMAT_ARGB32)
4685 return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4686
4687 image->transparency = CAIRO_IMAGE_IS_OPAQUE;
4688 for (y = 0; y < image->height; y++) {
4689 uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
4690
4691 for (x = 0; x < image->width; x++, pixel++) {
4692 int a = (*pixel & 0xff000000) >> 24;
4693 if (a > 0 && a < 255) {
4694 return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
4695 } else if (a == 0) {
4696 image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
4697 }
4698 }
4699 }
4700
4701 return image->transparency;
4702 }
4703