Coverage Report

Created: 2025-11-16 09:57

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