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