/src/cairo/src/cairo-image-surface.c
Line | Count | Source |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2003 University of Southern California |
5 | | * Copyright © 2009,2010,2011 Intel Corporation |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it either under the terms of the GNU Lesser General Public |
9 | | * License version 2.1 as published by the Free Software Foundation |
10 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
11 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
12 | | * notice, a recipient may use your version of this file under either |
13 | | * the MPL or the LGPL. |
14 | | * |
15 | | * You should have received a copy of the LGPL along with this library |
16 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
18 | | * You should have received a copy of the MPL along with this library |
19 | | * in the file COPYING-MPL-1.1 |
20 | | * |
21 | | * The contents of this file are subject to the Mozilla Public License |
22 | | * Version 1.1 (the "License"); you may not use this file except in |
23 | | * compliance with the License. You may obtain a copy of the License at |
24 | | * http://www.mozilla.org/MPL/ |
25 | | * |
26 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
27 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
28 | | * the specific language governing rights and limitations. |
29 | | * |
30 | | * The Original Code is the cairo graphics library. |
31 | | * |
32 | | * The Initial Developer of the Original Code is University of Southern |
33 | | * California. |
34 | | * |
35 | | * Contributor(s): |
36 | | * Carl D. Worth <cworth@cworth.org> |
37 | | * Chris Wilson <chris@chris-wilson.co.uk> |
38 | | */ |
39 | | |
40 | | #include "cairoint.h" |
41 | | |
42 | | #include "cairo-boxes-private.h" |
43 | | #include "cairo-clip-private.h" |
44 | | #include "cairo-composite-rectangles-private.h" |
45 | | #include "cairo-compositor-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" |
52 | | #include "cairo-recording-surface-private.h" |
53 | | #include "cairo-region-private.h" |
54 | | #include "cairo-scaled-font-private.h" |
55 | | #include "cairo-surface-snapshot-inline.h" |
56 | | #include "cairo-surface-snapshot-private.h" |
57 | | #include "cairo-surface-subsurface-private.h" |
58 | | |
59 | | /* Limit on the width / height of an image surface in pixels. This is |
60 | | * mainly determined by coordinates of things sent to pixman at the |
61 | | * moment being in 16.16 format. */ |
62 | 200k | #define MAX_IMAGE_SIZE 32767 |
63 | | |
64 | | /** |
65 | | * SECTION:cairo-image |
66 | | * @Title: Image Surfaces |
67 | | * @Short_Description: Rendering to memory buffers |
68 | | * @See_Also: #cairo_surface_t |
69 | | * |
70 | | * Image surfaces provide the ability to render to memory buffers |
71 | | * either allocated by cairo or by the calling code. The supported |
72 | | * image formats are those defined in #cairo_format_t. |
73 | | **/ |
74 | | |
75 | | /** |
76 | | * CAIRO_HAS_IMAGE_SURFACE: |
77 | | * |
78 | | * Defined if the image surface backend is available. |
79 | | * The image surface backend is always built in. |
80 | | * This macro was added for completeness in cairo 1.8. |
81 | | * |
82 | | * Since: 1.8 |
83 | | **/ |
84 | | |
85 | | static cairo_bool_t |
86 | | _cairo_image_surface_is_size_valid (int width, int height) |
87 | 66.8k | { |
88 | 66.8k | return 0 <= width && width <= MAX_IMAGE_SIZE && |
89 | 66.8k | 0 <= height && height <= MAX_IMAGE_SIZE; |
90 | 66.8k | } |
91 | | |
92 | | cairo_format_t |
93 | | _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) |
94 | 39.2k | { |
95 | 39.2k | switch (pixman_format) { |
96 | 0 | case PIXMAN_rgba_float: |
97 | 0 | return CAIRO_FORMAT_RGBA128F; |
98 | 0 | case PIXMAN_rgb_float: |
99 | 0 | return CAIRO_FORMAT_RGB96F; |
100 | 71 | case PIXMAN_a8r8g8b8: |
101 | 71 | return CAIRO_FORMAT_ARGB32; |
102 | 0 | case PIXMAN_x2r10g10b10: |
103 | 0 | return CAIRO_FORMAT_RGB30; |
104 | 6.45k | case PIXMAN_x8r8g8b8: |
105 | 6.45k | return CAIRO_FORMAT_RGB24; |
106 | 32.6k | case PIXMAN_a8: |
107 | 32.6k | return CAIRO_FORMAT_A8; |
108 | 32 | case PIXMAN_a1: |
109 | 32 | return CAIRO_FORMAT_A1; |
110 | 0 | case PIXMAN_r5g6b5: |
111 | 0 | return CAIRO_FORMAT_RGB16_565; |
112 | 0 | case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: |
113 | 0 | case PIXMAN_a8r8g8b8_sRGB: |
114 | 0 | #if HAS_PIXMAN_r8g8b8_sRGB |
115 | 0 | case PIXMAN_r8g8b8_sRGB: |
116 | 0 | #endif |
117 | 0 | case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: |
118 | 0 | case PIXMAN_b8g8r8: case PIXMAN_b5g6r5: |
119 | 0 | case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5: |
120 | 0 | case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4: |
121 | 0 | case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2: |
122 | 0 | case PIXMAN_b2g3r3: case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2: |
123 | 0 | case PIXMAN_c8: case PIXMAN_g8: case PIXMAN_x4a4: |
124 | 0 | case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1: |
125 | 0 | case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: |
126 | 0 | case PIXMAN_g4: case PIXMAN_g1: |
127 | 0 | case PIXMAN_yuy2: case PIXMAN_yv12: |
128 | 0 | case PIXMAN_b8g8r8x8: |
129 | 0 | case PIXMAN_b8g8r8a8: |
130 | 0 | case PIXMAN_a2b10g10r10: |
131 | 0 | case PIXMAN_x2b10g10r10: |
132 | 0 | case PIXMAN_a2r10g10b10: |
133 | 0 | case PIXMAN_x14r6g6b6: |
134 | 0 | default: |
135 | 0 | return CAIRO_FORMAT_INVALID; |
136 | 39.2k | } |
137 | | |
138 | 0 | return CAIRO_FORMAT_INVALID; |
139 | 39.2k | } |
140 | | |
141 | | cairo_content_t |
142 | | _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) |
143 | 39.2k | { |
144 | 39.2k | cairo_content_t content; |
145 | | |
146 | 39.2k | content = 0; |
147 | 39.2k | if (PIXMAN_FORMAT_RGB (pixman_format)) |
148 | 6.52k | content |= CAIRO_CONTENT_COLOR; |
149 | 39.2k | if (PIXMAN_FORMAT_A (pixman_format)) |
150 | 32.7k | content |= CAIRO_CONTENT_ALPHA; |
151 | | |
152 | 39.2k | return content; |
153 | 39.2k | } |
154 | | |
155 | | void |
156 | | _cairo_image_surface_init (cairo_image_surface_t *surface, |
157 | | pixman_image_t *pixman_image, |
158 | | pixman_format_code_t pixman_format) |
159 | 39.2k | { |
160 | 39.2k | surface->parent = NULL; |
161 | 39.2k | surface->pixman_image = pixman_image; |
162 | | |
163 | 39.2k | surface->pixman_format = pixman_format; |
164 | 39.2k | surface->format = _cairo_format_from_pixman_format (pixman_format); |
165 | 39.2k | surface->data = (uint8_t *) pixman_image_get_data (pixman_image); |
166 | 39.2k | surface->owns_data = FALSE; |
167 | 39.2k | surface->transparency = CAIRO_IMAGE_UNKNOWN; |
168 | 39.2k | surface->color = CAIRO_IMAGE_UNKNOWN_COLOR; |
169 | | |
170 | 39.2k | surface->width = pixman_image_get_width (pixman_image); |
171 | 39.2k | surface->height = pixman_image_get_height (pixman_image); |
172 | 39.2k | surface->stride = pixman_image_get_stride (pixman_image); |
173 | 39.2k | surface->depth = pixman_image_get_depth (pixman_image); |
174 | | |
175 | 39.2k | surface->base.is_clear = surface->width == 0 || surface->height == 0; |
176 | | |
177 | 39.2k | surface->compositor = _cairo_image_spans_compositor_get (); |
178 | 39.2k | } |
179 | | |
180 | | cairo_surface_t * |
181 | | _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, |
182 | | pixman_format_code_t pixman_format) |
183 | 39.2k | { |
184 | 39.2k | cairo_image_surface_t *surface; |
185 | | |
186 | 39.2k | surface = _cairo_calloc (sizeof (cairo_image_surface_t)); |
187 | 39.2k | if (unlikely (surface == NULL)) |
188 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
189 | | |
190 | 39.2k | _cairo_surface_init (&surface->base, |
191 | 39.2k | &_cairo_image_surface_backend, |
192 | 39.2k | NULL, /* device */ |
193 | 39.2k | _cairo_content_from_pixman_format (pixman_format), |
194 | 39.2k | FALSE); /* is_vector */ |
195 | | |
196 | 39.2k | _cairo_image_surface_init (surface, pixman_image, pixman_format); |
197 | | |
198 | 39.2k | return &surface->base; |
199 | 39.2k | } |
200 | | |
201 | | cairo_bool_t |
202 | | _pixman_format_from_masks (cairo_format_masks_t *masks, |
203 | | pixman_format_code_t *format_ret) |
204 | 0 | { |
205 | 0 | pixman_format_code_t format; |
206 | 0 | int format_type; |
207 | 0 | int a, r, g, b; |
208 | 0 | cairo_format_masks_t format_masks; |
209 | |
|
210 | 0 | a = _cairo_popcount (masks->alpha_mask); |
211 | 0 | r = _cairo_popcount (masks->red_mask); |
212 | 0 | g = _cairo_popcount (masks->green_mask); |
213 | 0 | b = _cairo_popcount (masks->blue_mask); |
214 | |
|
215 | 0 | if (masks->red_mask) { |
216 | 0 | if (masks->red_mask > masks->blue_mask) |
217 | 0 | format_type = PIXMAN_TYPE_ARGB; |
218 | 0 | else |
219 | 0 | format_type = PIXMAN_TYPE_ABGR; |
220 | 0 | } else if (masks->alpha_mask) { |
221 | 0 | format_type = PIXMAN_TYPE_A; |
222 | 0 | } else { |
223 | 0 | return FALSE; |
224 | 0 | } |
225 | | |
226 | 0 | format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b); |
227 | |
|
228 | 0 | if (! pixman_format_supported_destination (format)) |
229 | 0 | return FALSE; |
230 | | |
231 | | /* Sanity check that we got out of PIXMAN_FORMAT exactly what we |
232 | | * expected. This avoid any problems from something bizarre like |
233 | | * alpha in the least-significant bits, or insane channel order, |
234 | | * or whatever. */ |
235 | 0 | if (!_pixman_format_to_masks (format, &format_masks) || |
236 | 0 | masks->bpp != format_masks.bpp || |
237 | 0 | masks->red_mask != format_masks.red_mask || |
238 | 0 | masks->green_mask != format_masks.green_mask || |
239 | 0 | masks->blue_mask != format_masks.blue_mask) |
240 | 0 | { |
241 | 0 | return FALSE; |
242 | 0 | } |
243 | | |
244 | 0 | *format_ret = format; |
245 | 0 | return TRUE; |
246 | 0 | } |
247 | | |
248 | | /* Convenience function to convert #cairo_dither_t into #pixman_dither_t */ |
249 | | static pixman_dither_t |
250 | | _cairo_dither_to_pixman_dither (cairo_dither_t dither) |
251 | 65 | { |
252 | 65 | switch (dither) { |
253 | 0 | case CAIRO_DITHER_FAST: |
254 | 0 | return PIXMAN_DITHER_FAST; |
255 | 0 | case CAIRO_DITHER_GOOD: |
256 | 0 | return PIXMAN_DITHER_GOOD; |
257 | 0 | case CAIRO_DITHER_BEST: |
258 | 0 | return PIXMAN_DITHER_BEST; |
259 | 0 | case CAIRO_DITHER_NONE: |
260 | 65 | case CAIRO_DITHER_DEFAULT: |
261 | 65 | default: |
262 | 65 | return PIXMAN_DITHER_NONE; |
263 | 65 | } |
264 | 65 | } |
265 | | |
266 | | /* A mask consisting of N bits set to 1. */ |
267 | 0 | #define MASK(N) ((1UL << (N))-1) |
268 | | |
269 | | cairo_bool_t |
270 | | _pixman_format_to_masks (pixman_format_code_t format, |
271 | | cairo_format_masks_t *masks) |
272 | 0 | { |
273 | 0 | int a, r, g, b; |
274 | |
|
275 | 0 | masks->bpp = PIXMAN_FORMAT_BPP (format); |
276 | | |
277 | | /* Number of bits in each channel */ |
278 | 0 | a = PIXMAN_FORMAT_A (format); |
279 | 0 | r = PIXMAN_FORMAT_R (format); |
280 | 0 | g = PIXMAN_FORMAT_G (format); |
281 | 0 | b = PIXMAN_FORMAT_B (format); |
282 | |
|
283 | 0 | switch (PIXMAN_FORMAT_TYPE (format)) { |
284 | 0 | case PIXMAN_TYPE_ARGB: |
285 | 0 | masks->alpha_mask = MASK (a) << (r + g + b); |
286 | 0 | masks->red_mask = MASK (r) << (g + b); |
287 | 0 | masks->green_mask = MASK (g) << (b); |
288 | 0 | masks->blue_mask = MASK (b); |
289 | 0 | return TRUE; |
290 | 0 | case PIXMAN_TYPE_ABGR: |
291 | 0 | masks->alpha_mask = MASK (a) << (b + g + r); |
292 | 0 | masks->blue_mask = MASK (b) << (g + r); |
293 | 0 | masks->green_mask = MASK (g) << (r); |
294 | 0 | masks->red_mask = MASK (r); |
295 | 0 | return TRUE; |
296 | 0 | #ifdef PIXMAN_TYPE_BGRA |
297 | 0 | case PIXMAN_TYPE_BGRA: |
298 | 0 | masks->blue_mask = MASK (b) << (masks->bpp - b); |
299 | 0 | masks->green_mask = MASK (g) << (masks->bpp - b - g); |
300 | 0 | masks->red_mask = MASK (r) << (masks->bpp - b - g - r); |
301 | 0 | masks->alpha_mask = MASK (a); |
302 | 0 | return TRUE; |
303 | 0 | #endif |
304 | 0 | case PIXMAN_TYPE_A: |
305 | 0 | masks->alpha_mask = MASK (a); |
306 | 0 | masks->red_mask = 0; |
307 | 0 | masks->green_mask = 0; |
308 | 0 | masks->blue_mask = 0; |
309 | 0 | return TRUE; |
310 | 0 | case PIXMAN_TYPE_OTHER: |
311 | 0 | case PIXMAN_TYPE_COLOR: |
312 | 0 | case PIXMAN_TYPE_GRAY: |
313 | 0 | case PIXMAN_TYPE_YUY2: |
314 | 0 | case PIXMAN_TYPE_YV12: |
315 | 0 | default: |
316 | 0 | masks->alpha_mask = 0; |
317 | 0 | masks->red_mask = 0; |
318 | 0 | masks->green_mask = 0; |
319 | 0 | masks->blue_mask = 0; |
320 | 0 | return FALSE; |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | pixman_format_code_t |
325 | | _cairo_format_to_pixman_format_code (cairo_format_t format) |
326 | 33.5k | { |
327 | 33.5k | pixman_format_code_t ret; |
328 | 33.5k | switch (format) { |
329 | 32 | case CAIRO_FORMAT_A1: |
330 | 32 | ret = PIXMAN_a1; |
331 | 32 | break; |
332 | 30.2k | case CAIRO_FORMAT_A8: |
333 | 30.2k | ret = PIXMAN_a8; |
334 | 30.2k | break; |
335 | 3.23k | case CAIRO_FORMAT_RGB24: |
336 | 3.23k | ret = PIXMAN_x8r8g8b8; |
337 | 3.23k | break; |
338 | 0 | case CAIRO_FORMAT_RGB30: |
339 | 0 | ret = PIXMAN_x2r10g10b10; |
340 | 0 | break; |
341 | 0 | case CAIRO_FORMAT_RGB16_565: |
342 | 0 | ret = PIXMAN_r5g6b5; |
343 | 0 | break; |
344 | 0 | case CAIRO_FORMAT_RGB96F: |
345 | 0 | ret = PIXMAN_rgb_float; |
346 | 0 | break; |
347 | 0 | case CAIRO_FORMAT_RGBA128F: |
348 | 0 | ret = PIXMAN_rgba_float; |
349 | 0 | break; |
350 | 58 | case CAIRO_FORMAT_ARGB32: |
351 | 58 | case CAIRO_FORMAT_INVALID: |
352 | 58 | default: |
353 | 58 | ret = PIXMAN_a8r8g8b8; |
354 | 58 | break; |
355 | 33.5k | } |
356 | 33.5k | return ret; |
357 | 33.5k | } |
358 | | |
359 | | cairo_surface_t * |
360 | | _cairo_image_surface_create_with_pixman_format (unsigned char *data, |
361 | | pixman_format_code_t pixman_format, |
362 | | int width, |
363 | | int height, |
364 | | int stride) |
365 | 39.2k | { |
366 | 39.2k | cairo_surface_t *surface; |
367 | 39.2k | pixman_image_t *pixman_image; |
368 | | |
369 | 39.2k | if (! _cairo_image_surface_is_size_valid (width, height)) |
370 | 0 | { |
371 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
372 | 0 | } |
373 | | |
374 | 39.2k | pixman_image = pixman_image_create_bits (pixman_format, width, height, |
375 | 39.2k | (uint32_t *) data, stride); |
376 | | |
377 | 39.2k | if (unlikely (pixman_image == NULL)) |
378 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
379 | | |
380 | 39.2k | surface = _cairo_image_surface_create_for_pixman_image (pixman_image, |
381 | 39.2k | pixman_format); |
382 | 39.2k | if (unlikely (surface->status)) { |
383 | 0 | pixman_image_unref (pixman_image); |
384 | 0 | return surface; |
385 | 0 | } |
386 | | |
387 | | /* we can not make any assumptions about the initial state of user data */ |
388 | 39.2k | surface->is_clear = data == NULL; |
389 | 39.2k | return surface; |
390 | 39.2k | } |
391 | | |
392 | | /** |
393 | | * cairo_image_surface_create: |
394 | | * @format: format of pixels in the surface to create |
395 | | * @width: width of the surface, in pixels |
396 | | * @height: height of the surface, in pixels |
397 | | * |
398 | | * Creates an image surface of the specified format and |
399 | | * dimensions. Initially the surface contents are set to 0. |
400 | | * (Specifically, within each pixel, each color or alpha channel |
401 | | * belonging to format will be 0. The contents of bits within a pixel, |
402 | | * but not belonging to the given format are undefined). |
403 | | * |
404 | | * Return value: a pointer to the newly created surface. The caller |
405 | | * owns the surface and should call cairo_surface_destroy() when done |
406 | | * with it. |
407 | | * |
408 | | * This function always returns a valid pointer, but it will return a |
409 | | * pointer to a "nil" surface if an error such as out of memory |
410 | | * occurs. You can use cairo_surface_status() to check for this. |
411 | | * |
412 | | * Since: 1.0 |
413 | | **/ |
414 | | cairo_surface_t * |
415 | | cairo_image_surface_create (cairo_format_t format, |
416 | | int width, |
417 | | int height) |
418 | 5.87k | { |
419 | 5.87k | pixman_format_code_t pixman_format; |
420 | | |
421 | 5.87k | if (! CAIRO_FORMAT_VALID (format)) |
422 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
423 | | |
424 | 5.87k | pixman_format = _cairo_format_to_pixman_format_code (format); |
425 | | |
426 | 5.87k | return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, |
427 | 5.87k | width, height, -1); |
428 | 5.87k | } |
429 | | |
430 | | cairo_surface_t * |
431 | | _cairo_image_surface_create_with_content (cairo_content_t content, |
432 | | int width, |
433 | | int height) |
434 | 6 | { |
435 | 6 | return cairo_image_surface_create (_cairo_format_from_content (content), |
436 | 6 | width, height); |
437 | 6 | } |
438 | | |
439 | | /** |
440 | | * cairo_format_stride_for_width: |
441 | | * @format: A #cairo_format_t value |
442 | | * @width: The desired width of an image surface to be created. |
443 | | * |
444 | | * This function provides a stride value that will respect all |
445 | | * alignment requirements of the accelerated image-rendering code |
446 | | * within cairo. Typical usage will be of the form: |
447 | | * |
448 | | * <informalexample><programlisting> |
449 | | * int stride; |
450 | | * unsigned char *data; |
451 | | * cairo_surface_t *surface; |
452 | | * |
453 | | * stride = cairo_format_stride_for_width (format, width); |
454 | | * data = malloc (stride * height); |
455 | | * surface = cairo_image_surface_create_for_data (data, format, |
456 | | * width, height, |
457 | | * stride); |
458 | | * </programlisting></informalexample> |
459 | | * |
460 | | * Return value: the appropriate stride to use given the desired |
461 | | * format and width, or -1 if either the format is invalid or the width |
462 | | * too large. |
463 | | * |
464 | | * Since: 1.6 |
465 | | **/ |
466 | | int |
467 | | cairo_format_stride_for_width (cairo_format_t format, |
468 | | int width) |
469 | 27.6k | { |
470 | 27.6k | int bpp; |
471 | | |
472 | 27.6k | if (! CAIRO_FORMAT_VALID (format)) { |
473 | 0 | _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT); |
474 | 0 | return -1; |
475 | 0 | } |
476 | | |
477 | 27.6k | bpp = _cairo_format_bits_per_pixel (format); |
478 | 27.6k | if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp)) |
479 | 0 | return -1; |
480 | | |
481 | 27.6k | return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); |
482 | 27.6k | } |
483 | | |
484 | | /** |
485 | | * cairo_image_surface_create_for_data: |
486 | | * @data: a pointer to a buffer supplied by the application in which |
487 | | * to write contents. This pointer must be suitably aligned for any |
488 | | * kind of variable, (for example, a pointer returned by malloc). |
489 | | * @format: the format of pixels in the buffer |
490 | | * @width: the width of the image to be stored in the buffer |
491 | | * @height: the height of the image to be stored in the buffer |
492 | | * @stride: the number of bytes between the start of rows in the |
493 | | * buffer as allocated. This value should always be computed by |
494 | | * cairo_format_stride_for_width() before allocating the data |
495 | | * buffer. |
496 | | * |
497 | | * Creates an image surface for the provided pixel data. The output |
498 | | * buffer must be kept around until the #cairo_surface_t is destroyed |
499 | | * or cairo_surface_finish() is called on the surface. The initial |
500 | | * contents of @data will be used as the initial image contents; you |
501 | | * must explicitly clear the buffer, using, for example, |
502 | | * cairo_rectangle() and cairo_fill() if you want it cleared. |
503 | | * |
504 | | * Note that the stride may be larger than |
505 | | * width*bytes_per_pixel to provide proper alignment for each pixel |
506 | | * and row. This alignment is required to allow high-performance rendering |
507 | | * within cairo. The correct way to obtain a legal stride value is to |
508 | | * call cairo_format_stride_for_width() with the desired format and |
509 | | * maximum image width value, and then use the resulting stride value |
510 | | * to allocate the data and to create the image surface. See |
511 | | * cairo_format_stride_for_width() for example code. |
512 | | * |
513 | | * Return value: a pointer to the newly created surface. The caller |
514 | | * owns the surface and should call cairo_surface_destroy() when done |
515 | | * with it. |
516 | | * |
517 | | * This function always returns a valid pointer, but it will return a |
518 | | * pointer to a "nil" surface in the case of an error such as out of |
519 | | * memory or an invalid stride value. In case of invalid stride value |
520 | | * the error status of the returned surface will be |
521 | | * %CAIRO_STATUS_INVALID_STRIDE. You can use |
522 | | * cairo_surface_status() to check for this. |
523 | | * |
524 | | * See cairo_surface_set_user_data() for a means of attaching a |
525 | | * destroy-notification fallback to the surface if necessary. |
526 | | * |
527 | | * Since: 1.0 |
528 | | **/ |
529 | | cairo_surface_t * |
530 | | cairo_image_surface_create_for_data (unsigned char *data, |
531 | | cairo_format_t format, |
532 | | int width, |
533 | | int height, |
534 | | int stride) |
535 | 27.6k | { |
536 | 27.6k | pixman_format_code_t pixman_format; |
537 | 27.6k | int minstride; |
538 | | |
539 | 27.6k | if (! CAIRO_FORMAT_VALID (format)) |
540 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
541 | | |
542 | 27.6k | if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) |
543 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
544 | | |
545 | 27.6k | if (! _cairo_image_surface_is_size_valid (width, height)) |
546 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
547 | | |
548 | 27.6k | minstride = cairo_format_stride_for_width (format, width); |
549 | 27.6k | if (stride < 0) { |
550 | 0 | if (stride > -minstride) { |
551 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
552 | 0 | } |
553 | 27.6k | } else { |
554 | 27.6k | if (stride < minstride) { |
555 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
556 | 0 | } |
557 | 27.6k | } |
558 | | |
559 | 27.6k | pixman_format = _cairo_format_to_pixman_format_code (format); |
560 | 27.6k | return _cairo_image_surface_create_with_pixman_format (data, |
561 | 27.6k | pixman_format, |
562 | 27.6k | width, height, |
563 | 27.6k | stride); |
564 | 27.6k | } |
565 | | |
566 | | /** |
567 | | * cairo_image_surface_get_data: |
568 | | * @surface: a #cairo_image_surface_t |
569 | | * |
570 | | * Get a pointer to the data of the image surface, for direct |
571 | | * inspection or modification. |
572 | | * |
573 | | * A call to cairo_surface_flush() is required before accessing the |
574 | | * pixel data to ensure that all pending drawing operations are |
575 | | * finished. A call to cairo_surface_mark_dirty() is required after |
576 | | * the data is modified. |
577 | | * |
578 | | * Return value: a pointer to the image data of this surface or %NULL |
579 | | * if @surface is not an image surface, or if cairo_surface_finish() |
580 | | * has been called. |
581 | | * |
582 | | * Since: 1.2 |
583 | | **/ |
584 | | unsigned char * |
585 | | cairo_image_surface_get_data (cairo_surface_t *surface) |
586 | 5.71k | { |
587 | 5.71k | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
588 | | |
589 | 5.71k | if (! _cairo_surface_is_image (surface)) { |
590 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
591 | 0 | return NULL; |
592 | 0 | } |
593 | | |
594 | 5.71k | return image_surface->data; |
595 | 5.71k | } |
596 | | |
597 | | /** |
598 | | * cairo_image_surface_get_format: |
599 | | * @surface: a #cairo_image_surface_t |
600 | | * |
601 | | * Get the format of the surface. |
602 | | * |
603 | | * Return value: the format of the surface |
604 | | * |
605 | | * Since: 1.2 |
606 | | **/ |
607 | | cairo_format_t |
608 | | cairo_image_surface_get_format (cairo_surface_t *surface) |
609 | 0 | { |
610 | 0 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
611 | |
|
612 | 0 | if (! _cairo_surface_is_image (surface)) { |
613 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
614 | 0 | return CAIRO_FORMAT_INVALID; |
615 | 0 | } |
616 | | |
617 | 0 | return image_surface->format; |
618 | 0 | } |
619 | | |
620 | | /** |
621 | | * cairo_image_surface_get_width: |
622 | | * @surface: a #cairo_image_surface_t |
623 | | * |
624 | | * Get the width of the image surface in pixels. |
625 | | * |
626 | | * Return value: the width of the surface in pixels. |
627 | | * |
628 | | * Since: 1.0 |
629 | | **/ |
630 | | int |
631 | | cairo_image_surface_get_width (cairo_surface_t *surface) |
632 | 1.94k | { |
633 | 1.94k | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
634 | | |
635 | 1.94k | if (! _cairo_surface_is_image (surface)) { |
636 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
637 | 0 | return 0; |
638 | 0 | } |
639 | | |
640 | 1.94k | return image_surface->width; |
641 | 1.94k | } |
642 | | |
643 | | /** |
644 | | * cairo_image_surface_get_height: |
645 | | * @surface: a #cairo_image_surface_t |
646 | | * |
647 | | * Get the height of the image surface in pixels. |
648 | | * |
649 | | * Return value: the height of the surface in pixels. |
650 | | * |
651 | | * Since: 1.0 |
652 | | **/ |
653 | | int |
654 | | cairo_image_surface_get_height (cairo_surface_t *surface) |
655 | 1.94k | { |
656 | 1.94k | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
657 | | |
658 | 1.94k | if (! _cairo_surface_is_image (surface)) { |
659 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
660 | 0 | return 0; |
661 | 0 | } |
662 | | |
663 | 1.94k | return image_surface->height; |
664 | 1.94k | } |
665 | | |
666 | | /** |
667 | | * cairo_image_surface_get_stride: |
668 | | * @surface: a #cairo_image_surface_t |
669 | | * |
670 | | * Get the stride of the image surface in bytes |
671 | | * |
672 | | * Return value: the stride of the image surface in bytes (or 0 if |
673 | | * @surface is not an image surface). The stride is the distance in |
674 | | * bytes from the beginning of one row of the image data to the |
675 | | * beginning of the next row. |
676 | | * |
677 | | * Since: 1.2 |
678 | | **/ |
679 | | int |
680 | | cairo_image_surface_get_stride (cairo_surface_t *surface) |
681 | 5.71k | { |
682 | | |
683 | 5.71k | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
684 | | |
685 | 5.71k | if (! _cairo_surface_is_image (surface)) { |
686 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
687 | 0 | return 0; |
688 | 0 | } |
689 | | |
690 | 5.71k | return image_surface->stride; |
691 | 5.71k | } |
692 | | |
693 | | cairo_format_t |
694 | | _cairo_format_from_content (cairo_content_t content) |
695 | 6 | { |
696 | 6 | switch (content) { |
697 | 0 | case CAIRO_CONTENT_COLOR: |
698 | 0 | return CAIRO_FORMAT_RGB24; |
699 | 6 | case CAIRO_CONTENT_ALPHA: |
700 | 6 | return CAIRO_FORMAT_A8; |
701 | 0 | case CAIRO_CONTENT_COLOR_ALPHA: |
702 | 0 | return CAIRO_FORMAT_ARGB32; |
703 | 6 | } |
704 | | |
705 | 0 | ASSERT_NOT_REACHED; |
706 | 0 | return CAIRO_FORMAT_INVALID; |
707 | 0 | } |
708 | | |
709 | | cairo_content_t |
710 | | _cairo_content_from_format (cairo_format_t format) |
711 | 0 | { |
712 | 0 | switch (format) { |
713 | 0 | case CAIRO_FORMAT_RGBA128F: |
714 | 0 | case CAIRO_FORMAT_ARGB32: |
715 | 0 | return CAIRO_CONTENT_COLOR_ALPHA; |
716 | 0 | case CAIRO_FORMAT_RGB96F: |
717 | 0 | case CAIRO_FORMAT_RGB30: |
718 | 0 | return CAIRO_CONTENT_COLOR; |
719 | 0 | case CAIRO_FORMAT_RGB24: |
720 | 0 | return CAIRO_CONTENT_COLOR; |
721 | 0 | case CAIRO_FORMAT_RGB16_565: |
722 | 0 | return CAIRO_CONTENT_COLOR; |
723 | 0 | case CAIRO_FORMAT_A8: |
724 | 0 | case CAIRO_FORMAT_A1: |
725 | 0 | return CAIRO_CONTENT_ALPHA; |
726 | 0 | case CAIRO_FORMAT_INVALID: |
727 | 0 | break; |
728 | 0 | } |
729 | | |
730 | 0 | ASSERT_NOT_REACHED; |
731 | 0 | return CAIRO_CONTENT_COLOR_ALPHA; |
732 | 0 | } |
733 | | |
734 | | int |
735 | | _cairo_format_bits_per_pixel (cairo_format_t format) |
736 | 27.6k | { |
737 | 27.6k | switch (format) { |
738 | 0 | case CAIRO_FORMAT_RGBA128F: |
739 | 0 | return 128; |
740 | 0 | case CAIRO_FORMAT_RGB96F: |
741 | 0 | return 96; |
742 | 0 | case CAIRO_FORMAT_ARGB32: |
743 | 0 | case CAIRO_FORMAT_RGB30: |
744 | 0 | case CAIRO_FORMAT_RGB24: |
745 | 0 | return 32; |
746 | 0 | case CAIRO_FORMAT_RGB16_565: |
747 | 0 | return 16; |
748 | 27.6k | case CAIRO_FORMAT_A8: |
749 | 27.6k | return 8; |
750 | 0 | case CAIRO_FORMAT_A1: |
751 | 0 | return 1; |
752 | 0 | case CAIRO_FORMAT_INVALID: |
753 | 0 | default: |
754 | 0 | ASSERT_NOT_REACHED; |
755 | 0 | return 0; |
756 | 27.6k | } |
757 | 27.6k | } |
758 | | |
759 | | cairo_surface_t * |
760 | | _cairo_image_surface_create_similar (void *abstract_other, |
761 | | cairo_content_t content, |
762 | | int width, |
763 | | int height) |
764 | 6 | { |
765 | 6 | cairo_image_surface_t *other = abstract_other; |
766 | | |
767 | 6 | TRACE ((stderr, "%s (other=%u)\n", __FUNCTION__, other->base.unique_id)); |
768 | | |
769 | 6 | if (! _cairo_image_surface_is_size_valid (width, height)) |
770 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
771 | | |
772 | 6 | if (content == other->base.content) { |
773 | 0 | return _cairo_image_surface_create_with_pixman_format (NULL, |
774 | 0 | other->pixman_format, |
775 | 0 | width, height, |
776 | 0 | 0); |
777 | 0 | } |
778 | | |
779 | 6 | return _cairo_image_surface_create_with_content (content, |
780 | 6 | width, height); |
781 | 6 | } |
782 | | |
783 | | cairo_surface_t * |
784 | | _cairo_image_surface_snapshot (void *abstract_surface) |
785 | 5.67k | { |
786 | 5.67k | cairo_image_surface_t *image = abstract_surface; |
787 | 5.67k | cairo_image_surface_t *clone; |
788 | | |
789 | | /* If we own the image, we can simply steal the memory for the snapshot */ |
790 | 5.67k | if (image->owns_data && image->base._finishing) { |
791 | 0 | clone = (cairo_image_surface_t *) |
792 | 0 | _cairo_image_surface_create_for_pixman_image (image->pixman_image, |
793 | 0 | image->pixman_format); |
794 | 0 | if (unlikely (clone->base.status)) |
795 | 0 | return &clone->base; |
796 | | |
797 | 0 | image->pixman_image = NULL; |
798 | 0 | image->owns_data = FALSE; |
799 | |
|
800 | 0 | clone->transparency = image->transparency; |
801 | 0 | clone->color = image->color; |
802 | |
|
803 | 0 | clone->owns_data = TRUE; |
804 | 0 | return &clone->base; |
805 | 0 | } |
806 | | |
807 | 5.67k | clone = (cairo_image_surface_t *) |
808 | 5.67k | _cairo_image_surface_create_with_pixman_format (NULL, |
809 | 5.67k | image->pixman_format, |
810 | 5.67k | image->width, |
811 | 5.67k | image->height, |
812 | 5.67k | 0); |
813 | 5.67k | if (unlikely (clone->base.status)) |
814 | 0 | return &clone->base; |
815 | | |
816 | 5.67k | if (clone->stride == image->stride) { |
817 | 5.67k | memcpy (clone->data, image->data, clone->stride * clone->height); |
818 | 5.67k | } else { |
819 | 0 | pixman_image_composite32 (PIXMAN_OP_SRC, |
820 | 0 | image->pixman_image, NULL, clone->pixman_image, |
821 | 0 | 0, 0, |
822 | 0 | 0, 0, |
823 | 0 | 0, 0, |
824 | 0 | image->width, image->height); |
825 | 0 | } |
826 | 5.67k | clone->base.is_clear = FALSE; |
827 | 5.67k | return &clone->base; |
828 | 5.67k | } |
829 | | |
830 | | cairo_image_surface_t * |
831 | | _cairo_image_surface_map_to_image (void *abstract_other, |
832 | | const cairo_rectangle_int_t *extents) |
833 | 0 | { |
834 | 0 | cairo_image_surface_t *other = abstract_other; |
835 | 0 | cairo_surface_t *surface; |
836 | 0 | uint8_t *data; |
837 | |
|
838 | 0 | data = other->data; |
839 | 0 | data += extents->y * other->stride; |
840 | 0 | data += extents->x * PIXMAN_FORMAT_BPP (other->pixman_format)/ 8; |
841 | |
|
842 | 0 | surface = |
843 | 0 | _cairo_image_surface_create_with_pixman_format (data, |
844 | 0 | other->pixman_format, |
845 | 0 | extents->width, |
846 | 0 | extents->height, |
847 | 0 | other->stride); |
848 | |
|
849 | 0 | cairo_surface_set_device_offset (surface, -extents->x, -extents->y); |
850 | 0 | return (cairo_image_surface_t *) surface; |
851 | 0 | } |
852 | | |
853 | | cairo_int_status_t |
854 | | _cairo_image_surface_unmap_image (void *abstract_surface, |
855 | | cairo_image_surface_t *image) |
856 | 0 | { |
857 | 0 | cairo_surface_finish (&image->base); |
858 | 0 | cairo_surface_destroy (&image->base); |
859 | |
|
860 | 0 | return CAIRO_INT_STATUS_SUCCESS; |
861 | 0 | } |
862 | | |
863 | | cairo_status_t |
864 | | _cairo_image_surface_finish (void *abstract_surface) |
865 | 36.3k | { |
866 | 36.3k | cairo_image_surface_t *surface = abstract_surface; |
867 | | |
868 | 36.3k | if (surface->pixman_image) { |
869 | 36.3k | pixman_image_unref (surface->pixman_image); |
870 | 36.3k | surface->pixman_image = NULL; |
871 | 36.3k | } |
872 | | |
873 | 36.3k | if (surface->owns_data) { |
874 | 23.1k | free (surface->data); |
875 | 23.1k | surface->data = NULL; |
876 | 23.1k | } |
877 | | |
878 | 36.3k | if (surface->parent) { |
879 | 0 | cairo_surface_t *parent = surface->parent; |
880 | 0 | surface->parent = NULL; |
881 | 0 | cairo_surface_destroy (parent); |
882 | 0 | } |
883 | | |
884 | 36.3k | return CAIRO_STATUS_SUCCESS; |
885 | 36.3k | } |
886 | | |
887 | | void |
888 | | _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface) |
889 | 25.2k | { |
890 | 25.2k | surface->owns_data = TRUE; |
891 | 25.2k | } |
892 | | |
893 | | cairo_surface_t * |
894 | | _cairo_image_surface_source (void *abstract_surface, |
895 | | cairo_rectangle_int_t *extents) |
896 | 4.90k | { |
897 | 4.90k | cairo_image_surface_t *surface = abstract_surface; |
898 | | |
899 | 4.90k | if (extents) { |
900 | 0 | extents->x = extents->y = 0; |
901 | 0 | extents->width = surface->width; |
902 | 0 | extents->height = surface->height; |
903 | 0 | } |
904 | | |
905 | 4.90k | return &surface->base; |
906 | 4.90k | } |
907 | | |
908 | | cairo_status_t |
909 | | _cairo_image_surface_acquire_source_image (void *abstract_surface, |
910 | | cairo_image_surface_t **image_out, |
911 | | void **image_extra) |
912 | 8.95k | { |
913 | 8.95k | *image_out = abstract_surface; |
914 | 8.95k | *image_extra = NULL; |
915 | | |
916 | 8.95k | return CAIRO_STATUS_SUCCESS; |
917 | 8.95k | } |
918 | | |
919 | | void |
920 | | _cairo_image_surface_release_source_image (void *abstract_surface, |
921 | | cairo_image_surface_t *image, |
922 | | void *image_extra) |
923 | 8.95k | { |
924 | 8.95k | } |
925 | | |
926 | | /* high level image interface */ |
927 | | cairo_bool_t |
928 | | _cairo_image_surface_get_extents (void *abstract_surface, |
929 | | cairo_rectangle_int_t *rectangle) |
930 | 65.9k | { |
931 | 65.9k | cairo_image_surface_t *surface = abstract_surface; |
932 | | |
933 | 65.9k | rectangle->x = 0; |
934 | 65.9k | rectangle->y = 0; |
935 | 65.9k | rectangle->width = surface->width; |
936 | 65.9k | rectangle->height = surface->height; |
937 | | |
938 | 65.9k | return TRUE; |
939 | 65.9k | } |
940 | | |
941 | | cairo_int_status_t |
942 | | _cairo_image_surface_paint (void *abstract_surface, |
943 | | cairo_operator_t op, |
944 | | const cairo_pattern_t *source, |
945 | | const cairo_clip_t *clip) |
946 | 65 | { |
947 | 65 | cairo_image_surface_t *surface = abstract_surface; |
948 | 65 | pixman_dither_t pixman_dither = _cairo_dither_to_pixman_dither (source->dither); |
949 | 65 | pixman_image_set_dither (surface->pixman_image, pixman_dither); |
950 | | |
951 | 65 | TRACE ((stderr, "%s (surface=%d)\n", |
952 | 65 | __FUNCTION__, surface->base.unique_id)); |
953 | | |
954 | 65 | return _cairo_compositor_paint (surface->compositor, |
955 | 65 | &surface->base, op, source, clip); |
956 | 65 | } |
957 | | |
958 | | cairo_int_status_t |
959 | | _cairo_image_surface_mask (void *abstract_surface, |
960 | | cairo_operator_t op, |
961 | | const cairo_pattern_t *source, |
962 | | const cairo_pattern_t *mask, |
963 | | const cairo_clip_t *clip) |
964 | 6 | { |
965 | 6 | cairo_image_surface_t *surface = abstract_surface; |
966 | | |
967 | 6 | TRACE ((stderr, "%s (surface=%d)\n", |
968 | 6 | __FUNCTION__, surface->base.unique_id)); |
969 | | |
970 | 6 | return _cairo_compositor_mask (surface->compositor, |
971 | 6 | &surface->base, op, source, mask, clip); |
972 | 6 | } |
973 | | |
974 | | cairo_int_status_t |
975 | | _cairo_image_surface_stroke (void *abstract_surface, |
976 | | cairo_operator_t op, |
977 | | const cairo_pattern_t *source, |
978 | | const cairo_path_fixed_t *path, |
979 | | const cairo_stroke_style_t *style, |
980 | | const cairo_matrix_t *ctm, |
981 | | const cairo_matrix_t *ctm_inverse, |
982 | | double tolerance, |
983 | | cairo_antialias_t antialias, |
984 | | const cairo_clip_t *clip) |
985 | 0 | { |
986 | 0 | cairo_image_surface_t *surface = abstract_surface; |
987 | |
|
988 | 0 | TRACE ((stderr, "%s (surface=%d)\n", |
989 | 0 | __FUNCTION__, surface->base.unique_id)); |
990 | |
|
991 | 0 | return _cairo_compositor_stroke (surface->compositor, &surface->base, |
992 | 0 | op, source, path, |
993 | 0 | style, ctm, ctm_inverse, |
994 | 0 | tolerance, antialias, clip); |
995 | 0 | } |
996 | | |
997 | | cairo_int_status_t |
998 | | _cairo_image_surface_fill (void *abstract_surface, |
999 | | cairo_operator_t op, |
1000 | | const cairo_pattern_t *source, |
1001 | | const cairo_path_fixed_t *path, |
1002 | | cairo_fill_rule_t fill_rule, |
1003 | | double tolerance, |
1004 | | cairo_antialias_t antialias, |
1005 | | const cairo_clip_t *clip) |
1006 | 20 | { |
1007 | 20 | cairo_image_surface_t *surface = abstract_surface; |
1008 | | |
1009 | 20 | TRACE ((stderr, "%s (surface=%d)\n", |
1010 | 20 | __FUNCTION__, surface->base.unique_id)); |
1011 | | |
1012 | 20 | return _cairo_compositor_fill (surface->compositor, &surface->base, |
1013 | 20 | op, source, path, |
1014 | 20 | fill_rule, tolerance, antialias, |
1015 | 20 | clip); |
1016 | 20 | } |
1017 | | |
1018 | | cairo_int_status_t |
1019 | | _cairo_image_surface_glyphs (void *abstract_surface, |
1020 | | cairo_operator_t op, |
1021 | | const cairo_pattern_t *source, |
1022 | | cairo_glyph_t *glyphs, |
1023 | | int num_glyphs, |
1024 | | cairo_scaled_font_t *scaled_font, |
1025 | | const cairo_clip_t *clip) |
1026 | 0 | { |
1027 | 0 | cairo_image_surface_t *surface = abstract_surface; |
1028 | |
|
1029 | 0 | TRACE ((stderr, "%s (surface=%d)\n", |
1030 | 0 | __FUNCTION__, surface->base.unique_id)); |
1031 | |
|
1032 | 0 | return _cairo_compositor_glyphs (surface->compositor, &surface->base, |
1033 | 0 | op, source, |
1034 | 0 | glyphs, num_glyphs, scaled_font, |
1035 | 0 | clip); |
1036 | 0 | } |
1037 | | |
1038 | | void |
1039 | | _cairo_image_surface_get_font_options (void *abstract_surface, |
1040 | | cairo_font_options_t *options) |
1041 | 0 | { |
1042 | 0 | _cairo_font_options_init_default (options); |
1043 | |
|
1044 | 0 | cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); |
1045 | 0 | _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); |
1046 | 0 | } |
1047 | | |
1048 | | const cairo_surface_backend_t _cairo_image_surface_backend = { |
1049 | | CAIRO_SURFACE_TYPE_IMAGE, |
1050 | | _cairo_image_surface_finish, |
1051 | | |
1052 | | _cairo_default_context_create, |
1053 | | |
1054 | | _cairo_image_surface_create_similar, |
1055 | | NULL, /* create similar image */ |
1056 | | _cairo_image_surface_map_to_image, |
1057 | | _cairo_image_surface_unmap_image, |
1058 | | |
1059 | | _cairo_image_surface_source, |
1060 | | _cairo_image_surface_acquire_source_image, |
1061 | | _cairo_image_surface_release_source_image, |
1062 | | _cairo_image_surface_snapshot, |
1063 | | |
1064 | | NULL, /* copy_page */ |
1065 | | NULL, /* show_page */ |
1066 | | |
1067 | | _cairo_image_surface_get_extents, |
1068 | | _cairo_image_surface_get_font_options, |
1069 | | |
1070 | | NULL, /* flush */ |
1071 | | NULL, |
1072 | | |
1073 | | _cairo_image_surface_paint, |
1074 | | _cairo_image_surface_mask, |
1075 | | _cairo_image_surface_stroke, |
1076 | | _cairo_image_surface_fill, |
1077 | | NULL, /* fill-stroke */ |
1078 | | _cairo_image_surface_glyphs, |
1079 | | }; |
1080 | | |
1081 | | /* A convenience function for when one needs to coerce an image |
1082 | | * surface to an alternate format. */ |
1083 | | cairo_image_surface_t * |
1084 | | _cairo_image_surface_coerce (cairo_image_surface_t *surface) |
1085 | 0 | { |
1086 | 0 | return _cairo_image_surface_coerce_to_format (surface, |
1087 | 0 | _cairo_format_from_content (surface->base.content)); |
1088 | 0 | } |
1089 | | |
1090 | | /* A convenience function for when one needs to coerce an image |
1091 | | * surface to an alternate format. */ |
1092 | | cairo_image_surface_t * |
1093 | | _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, |
1094 | | cairo_format_t format) |
1095 | 32 | { |
1096 | 32 | cairo_image_surface_t *clone; |
1097 | 32 | cairo_status_t status; |
1098 | | |
1099 | 32 | status = surface->base.status; |
1100 | 32 | if (unlikely (status)) |
1101 | 0 | return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); |
1102 | | |
1103 | 32 | if (surface->format == format) |
1104 | 0 | return (cairo_image_surface_t *)cairo_surface_reference(&surface->base); |
1105 | | |
1106 | 32 | clone = (cairo_image_surface_t *) |
1107 | 32 | cairo_image_surface_create (format, surface->width, surface->height); |
1108 | 32 | if (unlikely (clone->base.status)) |
1109 | 0 | return clone; |
1110 | | |
1111 | 32 | pixman_image_composite32 (PIXMAN_OP_SRC, |
1112 | 32 | surface->pixman_image, NULL, clone->pixman_image, |
1113 | 32 | 0, 0, |
1114 | 32 | 0, 0, |
1115 | 32 | 0, 0, |
1116 | 32 | surface->width, surface->height); |
1117 | 32 | clone->base.is_clear = FALSE; |
1118 | | |
1119 | 32 | clone->base.device_transform = |
1120 | 32 | surface->base.device_transform; |
1121 | 32 | clone->base.device_transform_inverse = |
1122 | 32 | surface->base.device_transform_inverse; |
1123 | | |
1124 | 32 | return clone; |
1125 | 32 | } |
1126 | | |
1127 | | cairo_image_surface_t * |
1128 | | _cairo_image_surface_create_from_image (cairo_image_surface_t *other, |
1129 | | pixman_format_code_t format, |
1130 | | int x, int y, |
1131 | | int width, int height, int stride) |
1132 | 0 | { |
1133 | 0 | cairo_image_surface_t *surface; |
1134 | 0 | cairo_status_t status; |
1135 | 0 | pixman_image_t *image; |
1136 | 0 | void *mem = NULL; |
1137 | |
|
1138 | 0 | status = other->base.status; |
1139 | 0 | if (unlikely (status)) |
1140 | 0 | goto cleanup; |
1141 | | |
1142 | 0 | if (stride) { |
1143 | 0 | mem = _cairo_malloc_ab (height, stride); |
1144 | 0 | if (unlikely (mem == NULL)) { |
1145 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1146 | 0 | goto cleanup; |
1147 | 0 | } |
1148 | 0 | } |
1149 | | |
1150 | 0 | image = pixman_image_create_bits (format, width, height, mem, stride); |
1151 | 0 | if (unlikely (image == NULL)) { |
1152 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1153 | 0 | goto cleanup_mem; |
1154 | 0 | } |
1155 | | |
1156 | 0 | surface = (cairo_image_surface_t *) |
1157 | 0 | _cairo_image_surface_create_for_pixman_image (image, format); |
1158 | 0 | if (unlikely (surface->base.status)) { |
1159 | 0 | status = surface->base.status; |
1160 | 0 | goto cleanup_image; |
1161 | 0 | } |
1162 | | |
1163 | 0 | pixman_image_composite32 (PIXMAN_OP_SRC, |
1164 | 0 | other->pixman_image, NULL, image, |
1165 | 0 | x, y, |
1166 | 0 | 0, 0, |
1167 | 0 | 0, 0, |
1168 | 0 | width, height); |
1169 | 0 | surface->base.is_clear = FALSE; |
1170 | 0 | surface->owns_data = mem != NULL; |
1171 | |
|
1172 | 0 | return surface; |
1173 | | |
1174 | 0 | cleanup_image: |
1175 | 0 | pixman_image_unref (image); |
1176 | 0 | cleanup_mem: |
1177 | 0 | free (mem); |
1178 | 0 | cleanup: |
1179 | 0 | return (cairo_image_surface_t *) _cairo_surface_create_in_error (status); |
1180 | 0 | } |
1181 | | |
1182 | | static cairo_image_transparency_t |
1183 | | _cairo_image_compute_transparency (cairo_image_surface_t *image) |
1184 | 13.0k | { |
1185 | 13.0k | int x, y; |
1186 | 13.0k | cairo_image_transparency_t transparency; |
1187 | | |
1188 | 13.0k | if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0) |
1189 | 5.65k | return CAIRO_IMAGE_IS_OPAQUE; |
1190 | | |
1191 | 7.36k | if (image->base.is_clear) |
1192 | 0 | return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
1193 | | |
1194 | 7.36k | if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) { |
1195 | 7.33k | if (image->format == CAIRO_FORMAT_A1) { |
1196 | 0 | return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
1197 | 7.33k | } else if (image->format == CAIRO_FORMAT_A8) { |
1198 | 396k | for (y = 0; y < image->height; y++) { |
1199 | 391k | uint8_t *alpha = (uint8_t *) (image->data + y * image->stride); |
1200 | | |
1201 | 31.3M | for (x = 0; x < image->width; x++, alpha++) { |
1202 | 31.0M | if (*alpha > 0 && *alpha < 255) |
1203 | 2.58k | return CAIRO_IMAGE_HAS_ALPHA; |
1204 | 31.0M | } |
1205 | 391k | } |
1206 | 4.75k | return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
1207 | 7.33k | } else { |
1208 | 0 | return CAIRO_IMAGE_HAS_ALPHA; |
1209 | 0 | } |
1210 | 7.33k | } |
1211 | | |
1212 | 23 | if (image->format == CAIRO_FORMAT_RGB16_565) { |
1213 | 0 | return CAIRO_IMAGE_IS_OPAQUE; |
1214 | 0 | } |
1215 | | |
1216 | 23 | if (image->format != CAIRO_FORMAT_ARGB32) |
1217 | 0 | return CAIRO_IMAGE_HAS_ALPHA; |
1218 | | |
1219 | 23 | transparency = CAIRO_IMAGE_IS_OPAQUE; |
1220 | 1.77k | for (y = 0; y < image->height; y++) { |
1221 | 1.77k | uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); |
1222 | | |
1223 | 985k | for (x = 0; x < image->width; x++, pixel++) { |
1224 | 983k | int a = (*pixel & 0xff000000) >> 24; |
1225 | 983k | if (a > 0 && a < 255) { |
1226 | 20 | return CAIRO_IMAGE_HAS_ALPHA; |
1227 | 983k | } else if (a == 0) { |
1228 | 983k | transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
1229 | 983k | } |
1230 | 983k | } |
1231 | 1.77k | } |
1232 | | |
1233 | 3 | return transparency; |
1234 | 23 | } |
1235 | | |
1236 | | cairo_image_transparency_t |
1237 | | _cairo_image_analyze_transparency (cairo_image_surface_t *image) |
1238 | 13.0k | { |
1239 | 13.0k | if (_cairo_surface_is_snapshot (&image->base)) { |
1240 | 0 | if (image->transparency == CAIRO_IMAGE_UNKNOWN) |
1241 | 0 | image->transparency = _cairo_image_compute_transparency (image); |
1242 | |
|
1243 | 0 | return image->transparency; |
1244 | 0 | } |
1245 | | |
1246 | 13.0k | return _cairo_image_compute_transparency (image); |
1247 | 13.0k | } |
1248 | | |
1249 | | static cairo_image_color_t |
1250 | | _cairo_image_compute_color (cairo_image_surface_t *image) |
1251 | 1.61k | { |
1252 | 1.61k | int x, y; |
1253 | 1.61k | cairo_image_color_t color; |
1254 | | |
1255 | 1.61k | if (image->width == 0 || image->height == 0) |
1256 | 0 | return CAIRO_IMAGE_IS_MONOCHROME; |
1257 | | |
1258 | 1.61k | if (image->format == CAIRO_FORMAT_A1) |
1259 | 0 | return CAIRO_IMAGE_IS_MONOCHROME; |
1260 | | |
1261 | 1.61k | if (image->format == CAIRO_FORMAT_A8) |
1262 | 0 | return CAIRO_IMAGE_IS_GRAYSCALE; |
1263 | | |
1264 | 1.61k | if (image->format == CAIRO_FORMAT_ARGB32) { |
1265 | 7 | color = CAIRO_IMAGE_IS_MONOCHROME; |
1266 | 1.12k | for (y = 0; y < image->height; y++) { |
1267 | 1.12k | uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); |
1268 | | |
1269 | 556k | for (x = 0; x < image->width; x++, pixel++) { |
1270 | 555k | int a = (*pixel & 0xff000000) >> 24; |
1271 | 555k | int r = (*pixel & 0x00ff0000) >> 16; |
1272 | 555k | int g = (*pixel & 0x0000ff00) >> 8; |
1273 | 555k | int b = (*pixel & 0x000000ff); |
1274 | 555k | if (a == 0) { |
1275 | 471k | r = g = b = 0; |
1276 | 471k | } else { |
1277 | 84.5k | r = (r * 255 + a / 2) / a; |
1278 | 84.5k | g = (g * 255 + a / 2) / a; |
1279 | 84.5k | b = (b * 255 + a / 2) / a; |
1280 | 84.5k | } |
1281 | 555k | if (!(r == g && g == b)) |
1282 | 0 | return CAIRO_IMAGE_IS_COLOR; |
1283 | 555k | else if (r > 0 && r < 255) |
1284 | 0 | color = CAIRO_IMAGE_IS_GRAYSCALE; |
1285 | 555k | } |
1286 | 1.12k | } |
1287 | 7 | return color; |
1288 | 7 | } |
1289 | | |
1290 | 1.60k | if (image->format == CAIRO_FORMAT_RGB24) { |
1291 | 1.60k | color = CAIRO_IMAGE_IS_MONOCHROME; |
1292 | 174k | for (y = 0; y < image->height; y++) { |
1293 | 173k | uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); |
1294 | | |
1295 | 30.4M | for (x = 0; x < image->width; x++, pixel++) { |
1296 | 30.2M | int r = (*pixel & 0x00ff0000) >> 16; |
1297 | 30.2M | int g = (*pixel & 0x0000ff00) >> 8; |
1298 | 30.2M | int b = (*pixel & 0x000000ff); |
1299 | 30.2M | if (!(r == g && g == b)) |
1300 | 368 | return CAIRO_IMAGE_IS_COLOR; |
1301 | 30.2M | else if (r > 0 && r < 255) |
1302 | 434k | color = CAIRO_IMAGE_IS_GRAYSCALE; |
1303 | 30.2M | } |
1304 | 173k | } |
1305 | 1.23k | return color; |
1306 | 1.60k | } |
1307 | | |
1308 | 0 | return CAIRO_IMAGE_IS_COLOR; |
1309 | 1.60k | } |
1310 | | |
1311 | | cairo_image_color_t |
1312 | | _cairo_image_analyze_color (cairo_image_surface_t *image) |
1313 | 1.61k | { |
1314 | 1.61k | if (_cairo_surface_is_snapshot (&image->base)) { |
1315 | 0 | if (image->color == CAIRO_IMAGE_UNKNOWN_COLOR) |
1316 | 0 | image->color = _cairo_image_compute_color (image); |
1317 | |
|
1318 | 0 | return image->color; |
1319 | 0 | } |
1320 | | |
1321 | 1.61k | return _cairo_image_compute_color (image); |
1322 | 1.61k | } |
1323 | | |
1324 | | cairo_image_surface_t * |
1325 | | _cairo_image_surface_clone_subimage (cairo_surface_t *surface, |
1326 | | const cairo_rectangle_int_t *extents) |
1327 | 0 | { |
1328 | 0 | cairo_surface_t *image; |
1329 | 0 | cairo_surface_pattern_t pattern; |
1330 | 0 | cairo_status_t status; |
1331 | |
|
1332 | 0 | image = cairo_surface_create_similar_image (surface, |
1333 | 0 | _cairo_format_from_content (surface->content), |
1334 | 0 | extents->width, |
1335 | 0 | extents->height); |
1336 | 0 | if (image->status) |
1337 | 0 | return to_image_surface (image); |
1338 | | |
1339 | | /* TODO: check me with non-identity device_transform. Should we |
1340 | | * clone the scaling, too? */ |
1341 | 0 | cairo_surface_set_device_offset (image, |
1342 | 0 | -extents->x, |
1343 | 0 | -extents->y); |
1344 | |
|
1345 | 0 | _cairo_pattern_init_for_surface (&pattern, surface); |
1346 | 0 | pattern.base.filter = CAIRO_FILTER_NEAREST; |
1347 | |
|
1348 | 0 | status = _cairo_surface_paint (image, |
1349 | 0 | CAIRO_OPERATOR_SOURCE, |
1350 | 0 | &pattern.base, |
1351 | 0 | NULL); |
1352 | |
|
1353 | 0 | _cairo_pattern_fini (&pattern.base); |
1354 | |
|
1355 | 0 | if (unlikely (status)) |
1356 | 0 | goto error; |
1357 | | |
1358 | | /* We use the parent as a flag during map-to-image/umap-image that the |
1359 | | * resultant image came from a fallback rather than as direct call |
1360 | | * to the backend's map_to_image(). Whilst we use it as a simple flag, |
1361 | | * we need to make sure the parent surface obeys the reference counting |
1362 | | * semantics and is consistent for all callers. |
1363 | | */ |
1364 | 0 | _cairo_image_surface_set_parent (to_image_surface (image), |
1365 | 0 | cairo_surface_reference (surface)); |
1366 | |
|
1367 | 0 | return to_image_surface (image); |
1368 | | |
1369 | 0 | error: |
1370 | 0 | cairo_surface_destroy (image); |
1371 | 0 | return to_image_surface (_cairo_surface_create_in_error (status)); |
1372 | 0 | } |