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