Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 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 |
||
3959 | Serge | 5 | * Copyright © 2009,2010,2011 Intel Corporation |
1892 | serge | 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 |
||
37 | * Chris Wilson |
||
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" |
||
3959 | Serge | 45 | #include "cairo-compositor-private.h" |
46 | #include "cairo-default-context-private.h" |
||
1892 | serge | 47 | #include "cairo-error-private.h" |
3959 | Serge | 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" |
||
1892 | serge | 53 | #include "cairo-region-private.h" |
54 | #include "cairo-scaled-font-private.h" |
||
55 | #include "cairo-surface-snapshot-private.h" |
||
56 | #include "cairo-surface-subsurface-private.h" |
||
57 | |||
58 | /* Limit on the width / height of an image surface in pixels. This is |
||
59 | * mainly determined by coordinates of things sent to pixman at the |
||
60 | * moment being in 16.16 format. */ |
||
61 | #define MAX_IMAGE_SIZE 32767 |
||
62 | |||
63 | /** |
||
64 | * SECTION:cairo-image |
||
65 | * @Title: Image Surfaces |
||
66 | * @Short_Description: Rendering to memory buffers |
||
67 | * @See_Also: #cairo_surface_t |
||
68 | * |
||
69 | * Image surfaces provide the ability to render to memory buffers |
||
70 | * either allocated by cairo or by the calling code. The supported |
||
71 | * image formats are those defined in #cairo_format_t. |
||
3959 | Serge | 72 | **/ |
1892 | serge | 73 | |
74 | /** |
||
75 | * CAIRO_HAS_IMAGE_SURFACE: |
||
76 | * |
||
77 | * Defined if the image surface backend is available. |
||
78 | * The image surface backend is always built in. |
||
79 | * This macro was added for completeness in cairo 1.8. |
||
80 | * |
||
3959 | Serge | 81 | * Since: 1.8 |
82 | **/ |
||
1892 | serge | 83 | |
84 | static cairo_bool_t |
||
85 | _cairo_image_surface_is_size_valid (int width, int height) |
||
86 | { |
||
87 | return 0 <= width && width <= MAX_IMAGE_SIZE && |
||
88 | |||
89 | } |
||
90 | |||
91 | cairo_format_t |
||
92 | _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) |
||
93 | { |
||
94 | switch (pixman_format) { |
||
95 | case PIXMAN_a8r8g8b8: |
||
96 | return CAIRO_FORMAT_ARGB32; |
||
3959 | Serge | 97 | case PIXMAN_x2r10g10b10: |
98 | return CAIRO_FORMAT_RGB30; |
||
1892 | serge | 99 | case PIXMAN_x8r8g8b8: |
100 | return CAIRO_FORMAT_RGB24; |
||
101 | case PIXMAN_a8: |
||
102 | return CAIRO_FORMAT_A8; |
||
103 | case PIXMAN_a1: |
||
104 | return CAIRO_FORMAT_A1; |
||
105 | case PIXMAN_r5g6b5: |
||
106 | return CAIRO_FORMAT_RGB16_565; |
||
3959 | Serge | 107 | #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) |
108 | case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: |
||
109 | #endif |
||
1892 | serge | 110 | case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: |
111 | case PIXMAN_b8g8r8: case PIXMAN_b5g6r5: |
||
112 | case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5: |
||
113 | case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4: |
||
114 | case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2: |
||
115 | case PIXMAN_b2g3r3: case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2: |
||
116 | case PIXMAN_c8: case PIXMAN_g8: case PIXMAN_x4a4: |
||
117 | case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1: |
||
118 | case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: |
||
119 | case PIXMAN_g4: case PIXMAN_g1: |
||
120 | case PIXMAN_yuy2: case PIXMAN_yv12: |
||
121 | case PIXMAN_b8g8r8x8: |
||
122 | case PIXMAN_b8g8r8a8: |
||
3959 | Serge | 123 | case PIXMAN_a2b10g10r10: |
1892 | serge | 124 | case PIXMAN_x2b10g10r10: |
125 | case PIXMAN_a2r10g10b10: |
||
3959 | Serge | 126 | #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) |
127 | case PIXMAN_x14r6g6b6: |
||
128 | #endif |
||
1892 | serge | 129 | default: |
130 | return CAIRO_FORMAT_INVALID; |
||
131 | } |
||
132 | |||
133 | return CAIRO_FORMAT_INVALID; |
||
134 | } |
||
135 | |||
136 | cairo_content_t |
||
137 | _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) |
||
138 | { |
||
139 | cairo_content_t content; |
||
140 | |||
141 | content = 0; |
||
142 | if (PIXMAN_FORMAT_RGB (pixman_format)) |
||
143 | content |= CAIRO_CONTENT_COLOR; |
||
144 | if (PIXMAN_FORMAT_A (pixman_format)) |
||
145 | content |= CAIRO_CONTENT_ALPHA; |
||
146 | |||
147 | return content; |
||
148 | } |
||
149 | |||
3959 | Serge | 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 (); |
||
173 | } |
||
174 | |||
1892 | serge | 175 | cairo_surface_t * |
176 | _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, |
||
177 | pixman_format_code_t pixman_format) |
||
178 | { |
||
179 | cairo_image_surface_t *surface; |
||
180 | |||
181 | surface = malloc (sizeof (cairo_image_surface_t)); |
||
182 | if (unlikely (surface == NULL)) |
||
183 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
184 | |||
185 | _cairo_surface_init (&surface->base, |
||
186 | &_cairo_image_surface_backend, |
||
187 | NULL, /* device */ |
||
188 | _cairo_content_from_pixman_format (pixman_format)); |
||
189 | |||
3959 | Serge | 190 | _cairo_image_surface_init (surface, pixman_image, pixman_format); |
1892 | serge | 191 | |
192 | return &surface->base; |
||
193 | } |
||
194 | |||
195 | cairo_bool_t |
||
196 | _pixman_format_from_masks (cairo_format_masks_t *masks, |
||
197 | pixman_format_code_t *format_ret) |
||
198 | { |
||
199 | pixman_format_code_t format; |
||
200 | int format_type; |
||
201 | int a, r, g, b; |
||
202 | cairo_format_masks_t format_masks; |
||
203 | |||
204 | a = _cairo_popcount (masks->alpha_mask); |
||
205 | r = _cairo_popcount (masks->red_mask); |
||
206 | g = _cairo_popcount (masks->green_mask); |
||
207 | b = _cairo_popcount (masks->blue_mask); |
||
208 | |||
209 | if (masks->red_mask) { |
||
210 | if (masks->red_mask > masks->blue_mask) |
||
211 | format_type = PIXMAN_TYPE_ARGB; |
||
212 | else |
||
213 | format_type = PIXMAN_TYPE_ABGR; |
||
214 | } else if (masks->alpha_mask) { |
||
215 | format_type = PIXMAN_TYPE_A; |
||
216 | } else { |
||
217 | return FALSE; |
||
218 | } |
||
219 | |||
220 | format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b); |
||
221 | |||
222 | if (! pixman_format_supported_destination (format)) |
||
223 | return FALSE; |
||
224 | |||
225 | /* Sanity check that we got out of PIXMAN_FORMAT exactly what we |
||
226 | * expected. This avoid any problems from something bizarre like |
||
227 | * alpha in the least-significant bits, or insane channel order, |
||
228 | * or whatever. */ |
||
229 | if (!_pixman_format_to_masks (format, &format_masks) || |
||
230 | masks->bpp != format_masks.bpp || |
||
231 | masks->red_mask != format_masks.red_mask || |
||
232 | masks->green_mask != format_masks.green_mask || |
||
233 | masks->blue_mask != format_masks.blue_mask) |
||
234 | { |
||
235 | return FALSE; |
||
236 | } |
||
237 | |||
238 | *format_ret = format; |
||
239 | return TRUE; |
||
240 | } |
||
241 | |||
242 | /* A mask consisting of N bits set to 1. */ |
||
243 | #define MASK(N) ((1UL << (N))-1) |
||
244 | |||
245 | cairo_bool_t |
||
246 | _pixman_format_to_masks (pixman_format_code_t format, |
||
247 | cairo_format_masks_t *masks) |
||
248 | { |
||
249 | int a, r, g, b; |
||
250 | |||
251 | masks->bpp = PIXMAN_FORMAT_BPP (format); |
||
252 | |||
253 | /* Number of bits in each channel */ |
||
254 | a = PIXMAN_FORMAT_A (format); |
||
255 | r = PIXMAN_FORMAT_R (format); |
||
256 | g = PIXMAN_FORMAT_G (format); |
||
257 | b = PIXMAN_FORMAT_B (format); |
||
258 | |||
259 | switch (PIXMAN_FORMAT_TYPE (format)) { |
||
260 | case PIXMAN_TYPE_ARGB: |
||
261 | masks->alpha_mask = MASK (a) << (r + g + b); |
||
262 | masks->red_mask = MASK (r) << (g + b); |
||
263 | masks->green_mask = MASK (g) << (b); |
||
264 | masks->blue_mask = MASK (b); |
||
265 | return TRUE; |
||
266 | case PIXMAN_TYPE_ABGR: |
||
267 | masks->alpha_mask = MASK (a) << (b + g + r); |
||
268 | masks->blue_mask = MASK (b) << (g + r); |
||
269 | masks->green_mask = MASK (g) << (r); |
||
270 | masks->red_mask = MASK (r); |
||
271 | return TRUE; |
||
272 | #ifdef PIXMAN_TYPE_BGRA |
||
273 | case PIXMAN_TYPE_BGRA: |
||
274 | masks->blue_mask = MASK (b) << (masks->bpp - b); |
||
275 | masks->green_mask = MASK (g) << (masks->bpp - b - g); |
||
276 | masks->red_mask = MASK (r) << (masks->bpp - b - g - r); |
||
277 | masks->alpha_mask = MASK (a); |
||
278 | return TRUE; |
||
279 | #endif |
||
280 | case PIXMAN_TYPE_A: |
||
281 | masks->alpha_mask = MASK (a); |
||
282 | masks->red_mask = 0; |
||
283 | masks->green_mask = 0; |
||
284 | masks->blue_mask = 0; |
||
285 | return TRUE; |
||
286 | case PIXMAN_TYPE_OTHER: |
||
287 | case PIXMAN_TYPE_COLOR: |
||
288 | case PIXMAN_TYPE_GRAY: |
||
289 | case PIXMAN_TYPE_YUY2: |
||
290 | case PIXMAN_TYPE_YV12: |
||
291 | default: |
||
292 | masks->alpha_mask = 0; |
||
293 | masks->red_mask = 0; |
||
294 | masks->green_mask = 0; |
||
295 | masks->blue_mask = 0; |
||
296 | return FALSE; |
||
297 | } |
||
298 | } |
||
299 | |||
300 | pixman_format_code_t |
||
301 | _cairo_format_to_pixman_format_code (cairo_format_t format) |
||
302 | { |
||
303 | pixman_format_code_t ret; |
||
304 | switch (format) { |
||
305 | case CAIRO_FORMAT_A1: |
||
306 | ret = PIXMAN_a1; |
||
307 | break; |
||
308 | case CAIRO_FORMAT_A8: |
||
309 | ret = PIXMAN_a8; |
||
310 | break; |
||
311 | case CAIRO_FORMAT_RGB24: |
||
312 | ret = PIXMAN_x8r8g8b8; |
||
313 | break; |
||
3959 | Serge | 314 | case CAIRO_FORMAT_RGB30: |
315 | ret = PIXMAN_x2r10g10b10; |
||
316 | break; |
||
1892 | serge | 317 | case CAIRO_FORMAT_RGB16_565: |
318 | ret = PIXMAN_r5g6b5; |
||
319 | break; |
||
320 | case CAIRO_FORMAT_ARGB32: |
||
321 | case CAIRO_FORMAT_INVALID: |
||
322 | default: |
||
323 | ret = PIXMAN_a8r8g8b8; |
||
324 | break; |
||
325 | } |
||
326 | return ret; |
||
327 | } |
||
328 | |||
329 | cairo_surface_t * |
||
330 | _cairo_image_surface_create_with_pixman_format (unsigned char *data, |
||
331 | pixman_format_code_t pixman_format, |
||
332 | int width, |
||
333 | int height, |
||
334 | int stride) |
||
335 | { |
||
336 | cairo_surface_t *surface; |
||
337 | pixman_image_t *pixman_image; |
||
338 | |||
339 | if (! _cairo_image_surface_is_size_valid (width, height)) |
||
340 | { |
||
341 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
342 | } |
||
343 | |||
344 | pixman_image = pixman_image_create_bits (pixman_format, width, height, |
||
345 | (uint32_t *) data, stride); |
||
346 | |||
347 | if (unlikely (pixman_image == NULL)) |
||
348 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
349 | |||
350 | surface = _cairo_image_surface_create_for_pixman_image (pixman_image, |
||
351 | pixman_format); |
||
352 | if (unlikely (surface->status)) { |
||
353 | pixman_image_unref (pixman_image); |
||
354 | return surface; |
||
355 | } |
||
356 | |||
357 | /* we can not make any assumptions about the initial state of user data */ |
||
358 | surface->is_clear = data == NULL; |
||
359 | return surface; |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * cairo_image_surface_create: |
||
364 | * @format: format of pixels in the surface to create |
||
365 | * @width: width of the surface, in pixels |
||
366 | * @height: height of the surface, in pixels |
||
367 | * |
||
368 | * Creates an image surface of the specified format and |
||
369 | * dimensions. Initially the surface contents are all |
||
370 | * 0. (Specifically, within each pixel, each color or alpha channel |
||
371 | * belonging to format will be 0. The contents of bits within a pixel, |
||
372 | * but not belonging to the given format are undefined). |
||
373 | * |
||
374 | * Return value: a pointer to the newly created surface. The caller |
||
375 | * owns the surface and should call cairo_surface_destroy() when done |
||
376 | * with it. |
||
377 | * |
||
378 | * This function always returns a valid pointer, but it will return a |
||
379 | * pointer to a "nil" surface if an error such as out of memory |
||
380 | * occurs. You can use cairo_surface_status() to check for this. |
||
3959 | Serge | 381 | * |
382 | * Since: 1.0 |
||
1892 | serge | 383 | **/ |
384 | cairo_surface_t * |
||
385 | cairo_image_surface_create (cairo_format_t format, |
||
386 | int width, |
||
387 | int height) |
||
388 | { |
||
389 | pixman_format_code_t pixman_format; |
||
390 | |||
391 | if (! CAIRO_FORMAT_VALID (format)) |
||
392 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
||
393 | |||
394 | pixman_format = _cairo_format_to_pixman_format_code (format); |
||
395 | |||
396 | return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, |
||
397 | width, height, -1); |
||
398 | } |
||
399 | slim_hidden_def (cairo_image_surface_create); |
||
400 | |||
3959 | Serge | 401 | cairo_surface_t * |
1892 | serge | 402 | _cairo_image_surface_create_with_content (cairo_content_t content, |
403 | int width, |
||
404 | int height) |
||
405 | { |
||
406 | return cairo_image_surface_create (_cairo_format_from_content (content), |
||
407 | width, height); |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * cairo_format_stride_for_width: |
||
412 | * @format: A #cairo_format_t value |
||
413 | * @width: The desired width of an image surface to be created. |
||
414 | * |
||
415 | * This function provides a stride value that will respect all |
||
416 | * alignment requirements of the accelerated image-rendering code |
||
417 | * within cairo. Typical usage will be of the form: |
||
418 | * |
||
419 | * |
||
420 | * int stride; |
||
421 | * unsigned char *data; |
||
422 | * #cairo_surface_t *surface; |
||
423 | * |
||
424 | * stride = cairo_format_stride_for_width (format, width); |
||
425 | * data = malloc (stride * height); |
||
426 | * surface = cairo_image_surface_create_for_data (data, format, |
||
427 | * width, height, |
||
428 | * stride); |
||
429 | * |
||
430 | * |
||
431 | * Return value: the appropriate stride to use given the desired |
||
432 | * format and width, or -1 if either the format is invalid or the width |
||
433 | * too large. |
||
434 | * |
||
435 | * Since: 1.6 |
||
436 | **/ |
||
3959 | Serge | 437 | int |
1892 | serge | 438 | cairo_format_stride_for_width (cairo_format_t format, |
439 | int width) |
||
440 | { |
||
441 | int bpp; |
||
442 | |||
443 | if (! CAIRO_FORMAT_VALID (format)) { |
||
444 | _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT); |
||
445 | return -1; |
||
446 | } |
||
447 | |||
448 | bpp = _cairo_format_bits_per_pixel (format); |
||
449 | if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp)) |
||
450 | return -1; |
||
451 | |||
452 | return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); |
||
453 | } |
||
454 | slim_hidden_def (cairo_format_stride_for_width); |
||
455 | |||
456 | /** |
||
457 | * cairo_image_surface_create_for_data: |
||
458 | * @data: a pointer to a buffer supplied by the application in which |
||
459 | * to write contents. This pointer must be suitably aligned for any |
||
460 | * kind of variable, (for example, a pointer returned by malloc). |
||
461 | * @format: the format of pixels in the buffer |
||
462 | * @width: the width of the image to be stored in the buffer |
||
463 | * @height: the height of the image to be stored in the buffer |
||
464 | * @stride: the number of bytes between the start of rows in the |
||
465 | * buffer as allocated. This value should always be computed by |
||
466 | * cairo_format_stride_for_width() before allocating the data |
||
467 | * buffer. |
||
468 | * |
||
469 | * Creates an image surface for the provided pixel data. The output |
||
470 | * buffer must be kept around until the #cairo_surface_t is destroyed |
||
471 | * or cairo_surface_finish() is called on the surface. The initial |
||
472 | * contents of @data will be used as the initial image contents; you |
||
473 | * must explicitly clear the buffer, using, for example, |
||
474 | * cairo_rectangle() and cairo_fill() if you want it cleared. |
||
475 | * |
||
476 | * Note that the stride may be larger than |
||
477 | * width*bytes_per_pixel to provide proper alignment for each pixel |
||
478 | * and row. This alignment is required to allow high-performance rendering |
||
479 | * within cairo. The correct way to obtain a legal stride value is to |
||
480 | * call cairo_format_stride_for_width() with the desired format and |
||
481 | * maximum image width value, and then use the resulting stride value |
||
482 | * to allocate the data and to create the image surface. See |
||
483 | * cairo_format_stride_for_width() for example code. |
||
484 | * |
||
485 | * Return value: a pointer to the newly created surface. The caller |
||
486 | * owns the surface and should call cairo_surface_destroy() when done |
||
487 | * with it. |
||
488 | * |
||
489 | * This function always returns a valid pointer, but it will return a |
||
490 | * pointer to a "nil" surface in the case of an error such as out of |
||
491 | * memory or an invalid stride value. In case of invalid stride value |
||
492 | * the error status of the returned surface will be |
||
493 | * %CAIRO_STATUS_INVALID_STRIDE. You can use |
||
494 | * cairo_surface_status() to check for this. |
||
495 | * |
||
496 | * See cairo_surface_set_user_data() for a means of attaching a |
||
497 | * destroy-notification fallback to the surface if necessary. |
||
3959 | Serge | 498 | * |
499 | * Since: 1.0 |
||
1892 | serge | 500 | **/ |
3959 | Serge | 501 | cairo_surface_t * |
1892 | serge | 502 | cairo_image_surface_create_for_data (unsigned char *data, |
503 | cairo_format_t format, |
||
504 | int width, |
||
505 | int height, |
||
506 | int stride) |
||
507 | { |
||
508 | pixman_format_code_t pixman_format; |
||
509 | int minstride; |
||
510 | |||
511 | if (! CAIRO_FORMAT_VALID (format)) |
||
512 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
||
513 | |||
514 | if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) |
||
515 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
||
516 | |||
517 | if (! _cairo_image_surface_is_size_valid (width, height)) |
||
518 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
519 | |||
520 | minstride = cairo_format_stride_for_width (format, width); |
||
521 | if (stride < 0) { |
||
522 | if (stride > -minstride) { |
||
523 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
||
524 | } |
||
525 | } else { |
||
526 | if (stride < minstride) { |
||
527 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); |
||
528 | } |
||
529 | } |
||
530 | |||
531 | pixman_format = _cairo_format_to_pixman_format_code (format); |
||
532 | return _cairo_image_surface_create_with_pixman_format (data, |
||
533 | pixman_format, |
||
534 | width, height, |
||
535 | stride); |
||
536 | } |
||
537 | slim_hidden_def (cairo_image_surface_create_for_data); |
||
538 | |||
539 | /** |
||
540 | * cairo_image_surface_get_data: |
||
541 | * @surface: a #cairo_image_surface_t |
||
542 | * |
||
543 | * Get a pointer to the data of the image surface, for direct |
||
544 | * inspection or modification. |
||
545 | * |
||
3959 | Serge | 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 | * |
||
1892 | serge | 551 | * Return value: a pointer to the image data of this surface or %NULL |
552 | * if @surface is not an image surface, or if cairo_surface_finish() |
||
553 | * has been called. |
||
554 | * |
||
555 | * Since: 1.2 |
||
556 | **/ |
||
557 | unsigned char * |
||
558 | cairo_image_surface_get_data (cairo_surface_t *surface) |
||
559 | { |
||
560 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
||
561 | |||
562 | if (! _cairo_surface_is_image (surface)) { |
||
563 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
||
564 | return NULL; |
||
565 | } |
||
566 | |||
567 | return image_surface->data; |
||
568 | } |
||
569 | slim_hidden_def (cairo_image_surface_get_data); |
||
570 | |||
571 | /** |
||
572 | * cairo_image_surface_get_format: |
||
573 | * @surface: a #cairo_image_surface_t |
||
574 | * |
||
575 | * Get the format of the surface. |
||
576 | * |
||
577 | * Return value: the format of the surface |
||
578 | * |
||
579 | * Since: 1.2 |
||
580 | **/ |
||
581 | cairo_format_t |
||
582 | cairo_image_surface_get_format (cairo_surface_t *surface) |
||
583 | { |
||
584 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
||
585 | |||
586 | if (! _cairo_surface_is_image (surface)) { |
||
587 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
||
588 | return CAIRO_FORMAT_INVALID; |
||
589 | } |
||
590 | |||
591 | return image_surface->format; |
||
592 | } |
||
593 | slim_hidden_def (cairo_image_surface_get_format); |
||
594 | |||
595 | /** |
||
596 | * cairo_image_surface_get_width: |
||
597 | * @surface: a #cairo_image_surface_t |
||
598 | * |
||
599 | * Get the width of the image surface in pixels. |
||
600 | * |
||
601 | * Return value: the width of the surface in pixels. |
||
3959 | Serge | 602 | * |
603 | * Since: 1.0 |
||
1892 | serge | 604 | **/ |
605 | int |
||
606 | cairo_image_surface_get_width (cairo_surface_t *surface) |
||
607 | { |
||
608 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
||
609 | |||
610 | if (! _cairo_surface_is_image (surface)) { |
||
611 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
||
612 | return 0; |
||
613 | } |
||
614 | |||
615 | return image_surface->width; |
||
616 | } |
||
617 | slim_hidden_def (cairo_image_surface_get_width); |
||
618 | |||
619 | /** |
||
620 | * cairo_image_surface_get_height: |
||
621 | * @surface: a #cairo_image_surface_t |
||
622 | * |
||
623 | * Get the height of the image surface in pixels. |
||
624 | * |
||
625 | * Return value: the height of the surface in pixels. |
||
3959 | Serge | 626 | * |
627 | * Since: 1.0 |
||
1892 | serge | 628 | **/ |
629 | int |
||
630 | cairo_image_surface_get_height (cairo_surface_t *surface) |
||
631 | { |
||
632 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
||
633 | |||
634 | if (! _cairo_surface_is_image (surface)) { |
||
635 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
||
636 | return 0; |
||
637 | } |
||
638 | |||
639 | return image_surface->height; |
||
640 | } |
||
641 | slim_hidden_def (cairo_image_surface_get_height); |
||
642 | |||
643 | /** |
||
644 | * cairo_image_surface_get_stride: |
||
645 | * @surface: a #cairo_image_surface_t |
||
646 | * |
||
647 | * Get the stride of the image surface in bytes |
||
648 | * |
||
649 | * Return value: the stride of the image surface in bytes (or 0 if |
||
650 | * @surface is not an image surface). The stride is the distance in |
||
651 | * bytes from the beginning of one row of the image data to the |
||
652 | * beginning of the next row. |
||
653 | * |
||
654 | * Since: 1.2 |
||
655 | **/ |
||
656 | int |
||
657 | cairo_image_surface_get_stride (cairo_surface_t *surface) |
||
658 | { |
||
659 | |||
660 | cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; |
||
661 | |||
662 | if (! _cairo_surface_is_image (surface)) { |
||
663 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
||
664 | return 0; |
||
665 | } |
||
666 | |||
667 | return image_surface->stride; |
||
668 | } |
||
669 | slim_hidden_def (cairo_image_surface_get_stride); |
||
670 | |||
3959 | Serge | 671 | cairo_format_t |
1892 | serge | 672 | _cairo_format_from_content (cairo_content_t content) |
673 | { |
||
674 | switch (content) { |
||
675 | case CAIRO_CONTENT_COLOR: |
||
676 | return CAIRO_FORMAT_RGB24; |
||
677 | case CAIRO_CONTENT_ALPHA: |
||
678 | return CAIRO_FORMAT_A8; |
||
679 | case CAIRO_CONTENT_COLOR_ALPHA: |
||
680 | return CAIRO_FORMAT_ARGB32; |
||
681 | } |
||
682 | |||
683 | ASSERT_NOT_REACHED; |
||
684 | return CAIRO_FORMAT_INVALID; |
||
685 | } |
||
686 | |||
3959 | Serge | 687 | cairo_content_t |
1892 | serge | 688 | _cairo_content_from_format (cairo_format_t format) |
689 | { |
||
690 | switch (format) { |
||
691 | case CAIRO_FORMAT_ARGB32: |
||
692 | return CAIRO_CONTENT_COLOR_ALPHA; |
||
3959 | Serge | 693 | case CAIRO_FORMAT_RGB30: |
694 | return CAIRO_CONTENT_COLOR; |
||
1892 | serge | 695 | case CAIRO_FORMAT_RGB24: |
696 | return CAIRO_CONTENT_COLOR; |
||
697 | case CAIRO_FORMAT_RGB16_565: |
||
698 | return CAIRO_CONTENT_COLOR; |
||
699 | case CAIRO_FORMAT_A8: |
||
700 | case CAIRO_FORMAT_A1: |
||
701 | return CAIRO_CONTENT_ALPHA; |
||
702 | case CAIRO_FORMAT_INVALID: |
||
703 | break; |
||
704 | } |
||
705 | |||
706 | ASSERT_NOT_REACHED; |
||
707 | return CAIRO_CONTENT_COLOR_ALPHA; |
||
708 | } |
||
709 | |||
3959 | Serge | 710 | int |
1892 | serge | 711 | _cairo_format_bits_per_pixel (cairo_format_t format) |
712 | { |
||
713 | switch (format) { |
||
714 | case CAIRO_FORMAT_ARGB32: |
||
3959 | Serge | 715 | case CAIRO_FORMAT_RGB30: |
1892 | serge | 716 | case CAIRO_FORMAT_RGB24: |
717 | return 32; |
||
718 | case CAIRO_FORMAT_RGB16_565: |
||
719 | return 16; |
||
720 | case CAIRO_FORMAT_A8: |
||
721 | return 8; |
||
722 | case CAIRO_FORMAT_A1: |
||
723 | return 1; |
||
724 | case CAIRO_FORMAT_INVALID: |
||
725 | default: |
||
726 | ASSERT_NOT_REACHED; |
||
727 | return 0; |
||
728 | } |
||
729 | } |
||
730 | |||
3959 | Serge | 731 | cairo_surface_t * |
1892 | serge | 732 | _cairo_image_surface_create_similar (void *abstract_other, |
733 | cairo_content_t content, |
||
734 | int width, |
||
735 | int height) |
||
736 | { |
||
737 | cairo_image_surface_t *other = abstract_other; |
||
738 | |||
3959 | Serge | 739 | TRACE ((stderr, "%s (other=%u)\n", __FUNCTION__, other->base.unique_id)); |
740 | |||
1892 | serge | 741 | if (! _cairo_image_surface_is_size_valid (width, height)) |
742 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
743 | |||
744 | if (content == other->base.content) { |
||
745 | return _cairo_image_surface_create_with_pixman_format (NULL, |
||
746 | other->pixman_format, |
||
747 | width, height, |
||
748 | 0); |
||
749 | } |
||
750 | |||
751 | return _cairo_image_surface_create_with_content (content, |
||
752 | width, height); |
||
753 | } |
||
754 | |||
3959 | Serge | 755 | cairo_surface_t * |
756 | _cairo_image_surface_snapshot (void *abstract_surface) |
||
1892 | serge | 757 | { |
3959 | Serge | 758 | cairo_image_surface_t *image = abstract_surface; |
759 | cairo_image_surface_t *clone; |
||
1892 | serge | 760 | |
3959 | Serge | 761 | /* If we own the image, we can simply steal the memory for the snapshot */ |
762 | if (image->owns_data && image->base._finishing) { |
||
763 | clone = (cairo_image_surface_t *) |
||
764 | _cairo_image_surface_create_for_pixman_image (image->pixman_image, |
||
765 | image->pixman_format); |
||
766 | if (unlikely (clone->base.status)) |
||
767 | return &clone->base; |
||
1892 | serge | 768 | |
3959 | Serge | 769 | image->pixman_image = NULL; |
770 | image->owns_data = FALSE; |
||
1892 | serge | 771 | |
3959 | Serge | 772 | clone->transparency = image->transparency; |
773 | clone->color = image->color; |
||
1892 | serge | 774 | |
3959 | Serge | 775 | clone->owns_data = TRUE; |
776 | return &clone->base; |
||
1892 | serge | 777 | } |
778 | |||
3959 | Serge | 779 | clone = (cairo_image_surface_t *) |
780 | _cairo_image_surface_create_with_pixman_format (NULL, |
||
781 | image->pixman_format, |
||
782 | image->width, |
||
783 | image->height, |
||
784 | 0); |
||
785 | if (unlikely (clone->base.status)) |
||
786 | return &clone->base; |
||
1892 | serge | 787 | |
3959 | Serge | 788 | if (clone->stride == image->stride) { |
789 | memcpy (clone->data, image->data, clone->stride * clone->height); |
||
1892 | serge | 790 | } else { |
3959 | Serge | 791 | pixman_image_composite32 (PIXMAN_OP_SRC, |
792 | image->pixman_image, NULL, clone->pixman_image, |
||
793 | 0, 0, |
||
794 | 0, 0, |
||
795 | 0, 0, |
||
796 | image->width, image->height); |
||
1892 | serge | 797 | } |
3959 | Serge | 798 | clone->base.is_clear = FALSE; |
799 | return &clone->base; |
||
1892 | serge | 800 | } |
801 | |||
3959 | Serge | 802 | cairo_image_surface_t * |
803 | _cairo_image_surface_map_to_image (void *abstract_other, |
||
804 | const cairo_rectangle_int_t *extents) |
||
1892 | serge | 805 | { |
3959 | Serge | 806 | cairo_image_surface_t *other = abstract_other; |
1892 | serge | 807 | cairo_surface_t *surface; |
3959 | Serge | 808 | uint8_t *data; |
1892 | serge | 809 | |
3959 | Serge | 810 | data = other->data; |
811 | data += extents->y * other->stride; |
||
812 | data += extents->x * PIXMAN_FORMAT_BPP (other->pixman_format)/ 8; |
||
1892 | serge | 813 | |
3959 | Serge | 814 | surface = |
815 | _cairo_image_surface_create_with_pixman_format (data, |
||
816 | other->pixman_format, |
||
817 | extents->width, |
||
818 | extents->height, |
||
819 | other->stride); |
||
1892 | serge | 820 | |
3959 | Serge | 821 | cairo_surface_set_device_offset (surface, -extents->x, -extents->y); |
822 | return (cairo_image_surface_t *) surface; |
||
1892 | serge | 823 | } |
824 | |||
3959 | Serge | 825 | cairo_int_status_t |
826 | _cairo_image_surface_unmap_image (void *abstract_surface, |
||
827 | cairo_image_surface_t *image) |
||
1892 | serge | 828 | { |
3959 | Serge | 829 | cairo_surface_finish (&image->base); |
830 | cairo_surface_destroy (&image->base); |
||
1892 | serge | 831 | |
3959 | Serge | 832 | return CAIRO_INT_STATUS_SUCCESS; |
1892 | serge | 833 | } |
834 | |||
3959 | Serge | 835 | cairo_status_t |
836 | _cairo_image_surface_finish (void *abstract_surface) |
||
1892 | serge | 837 | { |
3959 | Serge | 838 | cairo_image_surface_t *surface = abstract_surface; |
1892 | serge | 839 | |
3959 | Serge | 840 | if (surface->pixman_image) { |
841 | pixman_image_unref (surface->pixman_image); |
||
842 | surface->pixman_image = NULL; |
||
1892 | serge | 843 | } |
844 | |||
3959 | Serge | 845 | if (surface->owns_data) { |
846 | free (surface->data); |
||
847 | surface->data = NULL; |
||
1892 | serge | 848 | } |
849 | |||
3959 | Serge | 850 | if (surface->parent) { |
851 | cairo_surface_t *parent = surface->parent; |
||
852 | surface->parent = NULL; |
||
853 | cairo_surface_destroy (parent); |
||
1892 | serge | 854 | } |
855 | |||
856 | return CAIRO_STATUS_SUCCESS; |
||
857 | } |
||
858 | |||
3959 | Serge | 859 | void |
860 | _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface) |
||
1892 | serge | 861 | { |
3959 | Serge | 862 | surface->owns_data = TRUE; |
1892 | serge | 863 | } |
864 | |||
3959 | Serge | 865 | cairo_surface_t * |
866 | _cairo_image_surface_source (void *abstract_surface, |
||
867 | cairo_rectangle_int_t *extents) |
||
1892 | serge | 868 | { |
3959 | Serge | 869 | cairo_image_surface_t *surface = abstract_surface; |
1892 | serge | 870 | |
3959 | Serge | 871 | if (extents) { |
872 | extents->x = extents->y = 0; |
||
873 | extents->width = surface->width; |
||
874 | extents->height = surface->height; |
||
1892 | serge | 875 | } |
876 | |||
3959 | Serge | 877 | return &surface->base; |
1892 | serge | 878 | } |
879 | |||
3959 | Serge | 880 | cairo_status_t |
881 | _cairo_image_surface_acquire_source_image (void *abstract_surface, |
||
882 | cairo_image_surface_t **image_out, |
||
883 | void **image_extra) |
||
1892 | serge | 884 | { |
3959 | Serge | 885 | *image_out = abstract_surface; |
886 | *image_extra = NULL; |
||
1892 | serge | 887 | |
888 | return CAIRO_STATUS_SUCCESS; |
||
889 | } |
||
890 | |||
3959 | Serge | 891 | void |
892 | _cairo_image_surface_release_source_image (void *abstract_surface, |
||
893 | cairo_image_surface_t *image, |
||
894 | void *image_extra) |
||
1892 | serge | 895 | { |
896 | } |
||
897 | |||
3959 | Serge | 898 | /* high level image interface */ |
899 | cairo_bool_t |
||
900 | _cairo_image_surface_get_extents (void *abstract_surface, |
||
901 | cairo_rectangle_int_t *rectangle) |
||
1892 | serge | 902 | { |
3959 | Serge | 903 | cairo_image_surface_t *surface = abstract_surface; |
1892 | serge | 904 | |
3959 | Serge | 905 | rectangle->x = 0; |
906 | rectangle->y = 0; |
||
907 | rectangle->width = surface->width; |
||
908 | rectangle->height = surface->height; |
||
1892 | serge | 909 | |
910 | return TRUE; |
||
911 | } |
||
912 | |||
3959 | Serge | 913 | cairo_int_status_t |
1892 | serge | 914 | _cairo_image_surface_paint (void *abstract_surface, |
915 | cairo_operator_t op, |
||
916 | const cairo_pattern_t *source, |
||
3959 | Serge | 917 | const cairo_clip_t *clip) |
1892 | serge | 918 | { |
919 | cairo_image_surface_t *surface = abstract_surface; |
||
920 | |||
3959 | Serge | 921 | TRACE ((stderr, "%s (surface=%d)\n", |
922 | __FUNCTION__, surface->base.unique_id)); |
||
1892 | serge | 923 | |
3959 | Serge | 924 | return _cairo_compositor_paint (surface->compositor, |
925 | &surface->base, op, source, clip); |
||
1892 | serge | 926 | } |
927 | |||
3959 | Serge | 928 | cairo_int_status_t |
1892 | serge | 929 | _cairo_image_surface_mask (void *abstract_surface, |
930 | cairo_operator_t op, |
||
931 | const cairo_pattern_t *source, |
||
932 | const cairo_pattern_t *mask, |
||
3959 | Serge | 933 | const cairo_clip_t *clip) |
1892 | serge | 934 | { |
935 | cairo_image_surface_t *surface = abstract_surface; |
||
936 | |||
3959 | Serge | 937 | TRACE ((stderr, "%s (surface=%d)\n", |
938 | __FUNCTION__, surface->base.unique_id)); |
||
1892 | serge | 939 | |
3959 | Serge | 940 | return _cairo_compositor_mask (surface->compositor, |
941 | &surface->base, op, source, mask, clip); |
||
1892 | serge | 942 | } |
943 | |||
3959 | Serge | 944 | cairo_int_status_t |
1892 | serge | 945 | _cairo_image_surface_stroke (void *abstract_surface, |
946 | cairo_operator_t op, |
||
947 | const cairo_pattern_t *source, |
||
3959 | Serge | 948 | const cairo_path_fixed_t *path, |
1892 | serge | 949 | const cairo_stroke_style_t *style, |
950 | const cairo_matrix_t *ctm, |
||
951 | const cairo_matrix_t *ctm_inverse, |
||
952 | double tolerance, |
||
953 | cairo_antialias_t antialias, |
||
3959 | Serge | 954 | const cairo_clip_t *clip) |
1892 | serge | 955 | { |
956 | cairo_image_surface_t *surface = abstract_surface; |
||
957 | |||
3959 | Serge | 958 | TRACE ((stderr, "%s (surface=%d)\n", |
959 | __FUNCTION__, surface->base.unique_id)); |
||
1892 | serge | 960 | |
3959 | Serge | 961 | return _cairo_compositor_stroke (surface->compositor, &surface->base, |
962 | op, source, path, |
||
963 | style, ctm, ctm_inverse, |
||
964 | tolerance, antialias, clip); |
||
1892 | serge | 965 | } |
966 | |||
3959 | Serge | 967 | cairo_int_status_t |
1892 | serge | 968 | _cairo_image_surface_fill (void *abstract_surface, |
969 | cairo_operator_t op, |
||
970 | const cairo_pattern_t *source, |
||
3959 | Serge | 971 | const cairo_path_fixed_t *path, |
1892 | serge | 972 | cairo_fill_rule_t fill_rule, |
973 | double tolerance, |
||
974 | cairo_antialias_t antialias, |
||
3959 | Serge | 975 | const cairo_clip_t *clip) |
1892 | serge | 976 | { |
977 | cairo_image_surface_t *surface = abstract_surface; |
||
978 | |||
3959 | Serge | 979 | TRACE ((stderr, "%s (surface=%d)\n", |
980 | __FUNCTION__, surface->base.unique_id)); |
||
1892 | serge | 981 | |
3959 | Serge | 982 | return _cairo_compositor_fill (surface->compositor, &surface->base, |
983 | op, source, path, |
||
984 | fill_rule, tolerance, antialias, |
||
985 | clip); |
||
1892 | serge | 986 | } |
987 | |||
3959 | Serge | 988 | cairo_int_status_t |
1892 | serge | 989 | _cairo_image_surface_glyphs (void *abstract_surface, |
990 | cairo_operator_t op, |
||
991 | const cairo_pattern_t *source, |
||
992 | cairo_glyph_t *glyphs, |
||
993 | int num_glyphs, |
||
994 | cairo_scaled_font_t *scaled_font, |
||
3959 | Serge | 995 | const cairo_clip_t *clip) |
1892 | serge | 996 | { |
997 | cairo_image_surface_t *surface = abstract_surface; |
||
998 | |||
3959 | Serge | 999 | TRACE ((stderr, "%s (surface=%d)\n", |
1000 | __FUNCTION__, surface->base.unique_id)); |
||
1892 | serge | 1001 | |
3959 | Serge | 1002 | return _cairo_compositor_glyphs (surface->compositor, &surface->base, |
1003 | op, source, |
||
1004 | glyphs, num_glyphs, scaled_font, |
||
1005 | clip); |
||
1892 | serge | 1006 | } |
1007 | |||
3959 | Serge | 1008 | void |
1892 | serge | 1009 | _cairo_image_surface_get_font_options (void *abstract_surface, |
1010 | cairo_font_options_t *options) |
||
1011 | { |
||
1012 | _cairo_font_options_init_default (options); |
||
1013 | |||
1014 | cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); |
||
3959 | Serge | 1015 | _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); |
1892 | serge | 1016 | } |
1017 | |||
3959 | Serge | 1018 | const cairo_surface_backend_t _cairo_image_surface_backend = { |
1019 | CAIRO_SURFACE_TYPE_IMAGE, |
||
1020 | _cairo_image_surface_finish, |
||
1892 | serge | 1021 | |
3959 | Serge | 1022 | _cairo_default_context_create, |
1892 | serge | 1023 | |
3959 | Serge | 1024 | _cairo_image_surface_create_similar, |
1025 | NULL, /* create similar image */ |
||
1026 | _cairo_image_surface_map_to_image, |
||
1027 | _cairo_image_surface_unmap_image, |
||
1892 | serge | 1028 | |
3959 | Serge | 1029 | _cairo_image_surface_source, |
1892 | serge | 1030 | _cairo_image_surface_acquire_source_image, |
1031 | _cairo_image_surface_release_source_image, |
||
3959 | Serge | 1032 | _cairo_image_surface_snapshot, |
1892 | serge | 1033 | |
1034 | NULL, /* copy_page */ |
||
1035 | NULL, /* show_page */ |
||
3959 | Serge | 1036 | |
1892 | serge | 1037 | _cairo_image_surface_get_extents, |
1038 | _cairo_image_surface_get_font_options, |
||
3959 | Serge | 1039 | |
1892 | serge | 1040 | NULL, /* flush */ |
3959 | Serge | 1041 | NULL, |
1892 | serge | 1042 | |
1043 | _cairo_image_surface_paint, |
||
1044 | _cairo_image_surface_mask, |
||
1045 | _cairo_image_surface_stroke, |
||
1046 | _cairo_image_surface_fill, |
||
3959 | Serge | 1047 | NULL, /* fill-stroke */ |
1892 | serge | 1048 | _cairo_image_surface_glyphs, |
1049 | }; |
||
1050 | |||
1051 | /* A convenience function for when one needs to coerce an image |
||
1052 | * surface to an alternate format. */ |
||
1053 | cairo_image_surface_t * |
||
1054 | _cairo_image_surface_coerce (cairo_image_surface_t *surface) |
||
1055 | { |
||
1056 | return _cairo_image_surface_coerce_to_format (surface, |
||
1057 | _cairo_format_from_content (surface->base.content)); |
||
1058 | } |
||
1059 | |||
1060 | /* A convenience function for when one needs to coerce an image |
||
1061 | * surface to an alternate format. */ |
||
1062 | cairo_image_surface_t * |
||
1063 | _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, |
||
1064 | cairo_format_t format) |
||
1065 | { |
||
1066 | cairo_image_surface_t *clone; |
||
1067 | cairo_status_t status; |
||
1068 | |||
1069 | status = surface->base.status; |
||
1070 | if (unlikely (status)) |
||
1071 | return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); |
||
1072 | |||
1073 | if (surface->format == format) |
||
1074 | return (cairo_image_surface_t *)cairo_surface_reference(&surface->base); |
||
1075 | |||
1076 | clone = (cairo_image_surface_t *) |
||
1077 | cairo_image_surface_create (format, surface->width, surface->height); |
||
1078 | if (unlikely (clone->base.status)) |
||
1079 | return clone; |
||
1080 | |||
1081 | pixman_image_composite32 (PIXMAN_OP_SRC, |
||
1082 | surface->pixman_image, NULL, clone->pixman_image, |
||
1083 | 0, 0, |
||
1084 | 0, 0, |
||
1085 | 0, 0, |
||
1086 | surface->width, surface->height); |
||
1087 | clone->base.is_clear = FALSE; |
||
1088 | |||
1089 | clone->base.device_transform = |
||
1090 | surface->base.device_transform; |
||
1091 | clone->base.device_transform_inverse = |
||
1092 | surface->base.device_transform_inverse; |
||
1093 | |||
1094 | return clone; |
||
1095 | } |
||
1096 | |||
3959 | Serge | 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); |
||
1150 | } |
||
1151 | |||
1892 | serge | 1152 | cairo_image_transparency_t |
3959 | Serge | 1153 | _cairo_image_analyze_transparency (cairo_image_surface_t *image) |
1892 | serge | 1154 | { |
1155 | int x, y; |
||
1156 | |||
1157 | if (image->transparency != CAIRO_IMAGE_UNKNOWN) |
||
1158 | return image->transparency; |
||
1159 | |||
1160 | if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0) |
||
1161 | return image->transparency = CAIRO_IMAGE_IS_OPAQUE; |
||
1162 | |||
3959 | Serge | 1163 | if (image->base.is_clear) |
1164 | return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
||
1165 | |||
1892 | serge | 1166 | if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) { |
3959 | Serge | 1167 | if (image->format == CAIRO_FORMAT_A1) { |
1892 | serge | 1168 | return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
3959 | Serge | 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 | } |
||
1177 | } |
||
1178 | return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
||
1179 | } else { |
||
1892 | serge | 1180 | return image->transparency = CAIRO_IMAGE_HAS_ALPHA; |
3959 | Serge | 1181 | } |
1892 | serge | 1182 | } |
1183 | |||
1184 | if (image->format == CAIRO_FORMAT_RGB16_565) { |
||
1185 | image->transparency = CAIRO_IMAGE_IS_OPAQUE; |
||
1186 | return CAIRO_IMAGE_IS_OPAQUE; |
||
1187 | } |
||
1188 | |||
1189 | if (image->format != CAIRO_FORMAT_ARGB32) |
||
1190 | return image->transparency = CAIRO_IMAGE_HAS_ALPHA; |
||
1191 | |||
1192 | image->transparency = CAIRO_IMAGE_IS_OPAQUE; |
||
1193 | for (y = 0; y < image->height; y++) { |
||
1194 | uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); |
||
1195 | |||
1196 | for (x = 0; x < image->width; x++, pixel++) { |
||
1197 | int a = (*pixel & 0xff000000) >> 24; |
||
1198 | if (a > 0 && a < 255) { |
||
1199 | return image->transparency = CAIRO_IMAGE_HAS_ALPHA; |
||
1200 | } else if (a == 0) { |
||
1201 | image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; |
||
1202 | } |
||
1203 | } |
||
1204 | } |
||
1205 | |||
1206 | return image->transparency; |
||
1207 | } |
||
3959 | Serge | 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)); |
||
1318 | }>>>>>>>>>>>>>>><>><>><>><>><>><>><>><>><>><>=>=>=>=> |