Back to index

lightning-sunbird  0.9+nobinonly
cairo-image-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2003 University of Southern California
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is University of Southern
00031  * California.
00032  *
00033  * Contributor(s):
00034  *     Carl D. Worth <cworth@cworth.org>
00035  */
00036 
00037 #include "cairoint.h"
00038 
00039 static int
00040 _cairo_format_bpp (cairo_format_t format)
00041 {
00042     switch (format) {
00043     case CAIRO_FORMAT_A1:
00044        return 1;
00045     case CAIRO_FORMAT_A8:
00046        return 8;
00047     case CAIRO_FORMAT_RGB24:
00048     case CAIRO_FORMAT_ARGB32:
00049     default:
00050        return 32;
00051     }
00052 }
00053 
00054 static cairo_surface_t *
00055 _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
00056                                          cairo_format_t  format)
00057 {
00058     cairo_image_surface_t *surface;
00059 
00060     surface = malloc (sizeof (cairo_image_surface_t));
00061     if (surface == NULL) {
00062        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00063        return (cairo_surface_t*) &_cairo_surface_nil;
00064     }
00065 
00066     _cairo_surface_init (&surface->base, &cairo_image_surface_backend);
00067 
00068     surface->pixman_image = pixman_image;
00069 
00070     surface->format = format;
00071     surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
00072     surface->owns_data = FALSE;
00073     surface->has_clip = FALSE;
00074 
00075     surface->width = pixman_image_get_width (pixman_image);
00076     surface->height = pixman_image_get_height (pixman_image);
00077     surface->stride = pixman_image_get_stride (pixman_image);
00078     surface->depth = pixman_image_get_depth (pixman_image);
00079 
00080     return &surface->base;
00081 }
00082 
00083 cairo_surface_t *
00084 _cairo_image_surface_create_with_masks (unsigned char          *data,
00085                                    cairo_format_masks_t   *format,
00086                                    int                  width,
00087                                    int                  height,
00088                                    int                  stride)
00089 {
00090     cairo_surface_t *surface;
00091     pixman_format_t *pixman_format;
00092     pixman_image_t *pixman_image;
00093 
00094     pixman_format = pixman_format_create_masks (format->bpp,
00095                                           format->alpha_mask,
00096                                           format->red_mask,
00097                                           format->green_mask,
00098                                           format->blue_mask);
00099 
00100     if (pixman_format == NULL) {
00101        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00102        return (cairo_surface_t*) &_cairo_surface_nil;
00103     }
00104 
00105     pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
00106                                            width, height, format->bpp, stride);
00107 
00108     pixman_format_destroy (pixman_format);
00109 
00110     if (pixman_image == NULL) {
00111        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00112        return (cairo_surface_t*) &_cairo_surface_nil;
00113     }
00114 
00115     surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
00116                                                      (cairo_format_t)-1);
00117 
00118     return surface;
00119 }
00120 
00121 static pixman_format_t *
00122 _create_pixman_format (cairo_format_t format)
00123 {
00124     switch (format) {
00125     case CAIRO_FORMAT_A1:
00126        return pixman_format_create (PIXMAN_FORMAT_NAME_A1);
00127        break;
00128     case CAIRO_FORMAT_A8:
00129        return pixman_format_create (PIXMAN_FORMAT_NAME_A8);
00130        break;
00131     case CAIRO_FORMAT_RGB24:
00132        return pixman_format_create (PIXMAN_FORMAT_NAME_RGB24);
00133        break;
00134     case CAIRO_FORMAT_ARGB32:
00135     default:
00136        return pixman_format_create (PIXMAN_FORMAT_NAME_ARGB32);
00137        break;
00138     }
00139 }
00140 
00160 cairo_surface_t *
00161 cairo_image_surface_create (cairo_format_t       format,
00162                          int                     width,
00163                          int                     height)
00164 {
00165     cairo_surface_t *surface;
00166     pixman_format_t *pixman_format;
00167     pixman_image_t *pixman_image;
00168 
00169     if (! CAIRO_FORMAT_VALID (format))
00170        return (cairo_surface_t*) &_cairo_surface_nil;
00171 
00172     pixman_format = _create_pixman_format (format);
00173     if (pixman_format == NULL) {
00174        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00175        return (cairo_surface_t*) &_cairo_surface_nil;
00176     }
00177 
00178     pixman_image = pixman_image_create (pixman_format, width, height);
00179 
00180     pixman_format_destroy (pixman_format);
00181 
00182     if (pixman_image == NULL) {
00183        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00184        return (cairo_surface_t*) &_cairo_surface_nil;
00185     }
00186 
00187     surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
00188 
00189     return surface;
00190 }
00191 
00219 cairo_surface_t *
00220 cairo_image_surface_create_for_data (unsigned char     *data,
00221                                  cairo_format_t  format,
00222                                  int             width,
00223                                  int             height,
00224                                  int             stride)
00225 {
00226     cairo_surface_t *surface;
00227     pixman_format_t *pixman_format;
00228     pixman_image_t *pixman_image;
00229 
00230     if (! CAIRO_FORMAT_VALID (format))
00231        return (cairo_surface_t*) &_cairo_surface_nil;
00232 
00233     pixman_format = _create_pixman_format (format);
00234     if (pixman_format == NULL) {
00235        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00236        return (cairo_surface_t*) &_cairo_surface_nil;
00237     }
00238     
00239     pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
00240                                            width, height,
00241                                            _cairo_format_bpp (format),
00242                                            stride);
00243 
00244     pixman_format_destroy (pixman_format);
00245 
00246     if (pixman_image == NULL) {
00247        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00248        return (cairo_surface_t*) &_cairo_surface_nil;
00249     }
00250 
00251     surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
00252 
00253     return surface;
00254 }
00255 
00264 int
00265 cairo_image_surface_get_width (cairo_surface_t *surface)
00266 {
00267     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
00268 
00269     if (!_cairo_surface_is_image (surface)) {
00270        _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
00271        return 0;
00272     }
00273 
00274     return image_surface->width;
00275 }
00276 
00285 int
00286 cairo_image_surface_get_height (cairo_surface_t *surface)
00287 {
00288     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
00289 
00290     if (!_cairo_surface_is_image (surface)) {
00291        _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
00292        return 0;
00293     }
00294 
00295     return image_surface->height;
00296 }
00297 
00298 cairo_format_t
00299 _cairo_format_from_content (cairo_content_t content)
00300 {
00301     switch (content) {
00302     case CAIRO_CONTENT_COLOR:
00303        return CAIRO_FORMAT_RGB24;
00304     case CAIRO_CONTENT_ALPHA:
00305        return CAIRO_FORMAT_A8;
00306     case CAIRO_CONTENT_COLOR_ALPHA:
00307        return CAIRO_FORMAT_ARGB32;
00308     }
00309 
00310     ASSERT_NOT_REACHED;
00311     return CAIRO_FORMAT_ARGB32;
00312 }
00313 
00314 cairo_content_t
00315 _cairo_content_from_format (cairo_format_t format)
00316 {
00317     switch (format) {
00318     case CAIRO_FORMAT_ARGB32:
00319        return CAIRO_CONTENT_COLOR_ALPHA;
00320     case CAIRO_FORMAT_RGB24:
00321        return CAIRO_CONTENT_COLOR;
00322     case CAIRO_FORMAT_A8:
00323     case CAIRO_FORMAT_A1:
00324        return CAIRO_CONTENT_ALPHA;
00325     }
00326 
00327     ASSERT_NOT_REACHED;
00328     return CAIRO_CONTENT_COLOR_ALPHA;
00329 }
00330 
00331 static cairo_surface_t *
00332 _cairo_image_surface_create_similar (void        *abstract_src,
00333                                  cairo_content_t content,
00334                                  int             width,
00335                                  int             height)
00336 {
00337     assert (CAIRO_CONTENT_VALID (content));
00338 
00339     return cairo_image_surface_create (_cairo_format_from_content (content),
00340                                    width, height);
00341 }
00342 
00343 static cairo_status_t
00344 _cairo_image_abstract_surface_finish (void *abstract_surface)
00345 {
00346     cairo_image_surface_t *surface = abstract_surface;
00347 
00348     if (surface->pixman_image) {
00349        pixman_image_destroy (surface->pixman_image);
00350        surface->pixman_image = NULL;
00351     }
00352 
00353     if (surface->owns_data) {
00354        free (surface->data);
00355        surface->data = NULL;
00356     }
00357 
00358     return CAIRO_STATUS_SUCCESS;
00359 }
00360 
00361 void
00362 _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
00363 {
00364     surface->owns_data = 1;
00365 }
00366 
00367 static cairo_status_t
00368 _cairo_image_surface_acquire_source_image (void                    *abstract_surface,
00369                                       cairo_image_surface_t  **image_out,
00370                                       void                   **image_extra)
00371 {
00372     *image_out = abstract_surface;
00373     *image_extra = NULL;
00374     
00375     return CAIRO_STATUS_SUCCESS;
00376 }
00377 
00378 static void
00379 _cairo_image_surface_release_source_image (void                   *abstract_surface,
00380                                       cairo_image_surface_t  *image,
00381                                       void                   *image_extra)
00382 {
00383 }
00384 
00385 static cairo_status_t
00386 _cairo_image_surface_acquire_dest_image (void                    *abstract_surface,
00387                                     cairo_rectangle_t       *interest_rect,
00388                                     cairo_image_surface_t  **image_out,
00389                                     cairo_rectangle_t       *image_rect_out,
00390                                     void                   **image_extra)
00391 {
00392     cairo_image_surface_t *surface = abstract_surface;
00393     
00394     image_rect_out->x = 0;
00395     image_rect_out->y = 0;
00396     image_rect_out->width = surface->width;
00397     image_rect_out->height = surface->height;
00398 
00399     *image_out = surface;
00400     *image_extra = NULL;
00401     
00402     return CAIRO_STATUS_SUCCESS;
00403 }
00404 
00405 static void
00406 _cairo_image_surface_release_dest_image (void                   *abstract_surface,
00407                                     cairo_rectangle_t      *interest_rect,
00408                                     cairo_image_surface_t  *image,
00409                                     cairo_rectangle_t      *image_rect,
00410                                     void                   *image_extra)
00411 {
00412 }
00413 
00414 static cairo_status_t
00415 _cairo_image_surface_clone_similar (void         *abstract_surface,
00416                                 cairo_surface_t  *src,
00417                                 cairo_surface_t    **clone_out)
00418 {
00419     cairo_image_surface_t *surface = abstract_surface;
00420 
00421     if (src->backend == surface->base.backend) {
00422        *clone_out = cairo_surface_reference (src);
00423 
00424        return CAIRO_STATUS_SUCCESS;
00425     }  
00426     
00427     return CAIRO_INT_STATUS_UNSUPPORTED;
00428 }
00429 
00430 static cairo_status_t
00431 _cairo_image_surface_set_matrix (cairo_image_surface_t  *surface,
00432                              const cairo_matrix_t       *matrix)
00433 {
00434     pixman_transform_t pixman_transform;
00435 
00436     pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
00437     pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
00438     pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
00439 
00440     pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
00441     pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
00442     pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
00443 
00444     pixman_transform.matrix[2][0] = 0;
00445     pixman_transform.matrix[2][1] = 0;
00446     pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1);
00447 
00448     pixman_image_set_transform (surface->pixman_image, &pixman_transform);
00449 
00450     return CAIRO_STATUS_SUCCESS;
00451 }
00452 
00453 static cairo_status_t
00454 _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
00455 {
00456     pixman_filter_t pixman_filter;
00457 
00458     switch (filter) {
00459     case CAIRO_FILTER_FAST:
00460        pixman_filter = PIXMAN_FILTER_FAST;
00461        break;
00462     case CAIRO_FILTER_GOOD:
00463        pixman_filter = PIXMAN_FILTER_GOOD;
00464        break;
00465     case CAIRO_FILTER_BEST:
00466        pixman_filter = PIXMAN_FILTER_BEST;
00467        break;
00468     case CAIRO_FILTER_NEAREST:
00469        pixman_filter = PIXMAN_FILTER_NEAREST;
00470        break;
00471     case CAIRO_FILTER_BILINEAR:
00472        pixman_filter = PIXMAN_FILTER_BILINEAR;
00473        break;
00474     default:
00475        pixman_filter = PIXMAN_FILTER_BEST;
00476     }
00477 
00478     pixman_image_set_filter (surface->pixman_image, pixman_filter);
00479 
00480     return CAIRO_STATUS_SUCCESS;
00481 }
00482 
00483 static cairo_status_t
00484 _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
00485 {
00486     pixman_image_set_repeat (surface->pixman_image, repeat);
00487 
00488     return CAIRO_STATUS_SUCCESS;
00489 }
00490 
00491 static cairo_int_status_t
00492 _cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
00493                                  cairo_surface_attributes_t *attributes)
00494 {
00495     cairo_int_status_t status;
00496     
00497     status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
00498     if (status)
00499        return status;
00500 
00501     switch (attributes->extend) {
00502     case CAIRO_EXTEND_NONE:
00503        _cairo_image_surface_set_repeat (surface, 0);
00504        break;
00505     case CAIRO_EXTEND_REPEAT:
00506        _cairo_image_surface_set_repeat (surface, 1);
00507        break;
00508     case CAIRO_EXTEND_REFLECT:
00509        /* XXX: Obviously wrong. */
00510        _cairo_image_surface_set_repeat (surface, 1);
00511        break;
00512     }
00513     
00514     status = _cairo_image_surface_set_filter (surface, attributes->filter);
00515     
00516     return status;
00517 }
00518 
00519 /* XXX: I think we should fix pixman to match the names/order of the
00520  * cairo operators, but that will likely be better done at the same
00521  * time the X server is ported to pixman, (which will change a lot of
00522  * things in pixman I think).
00523  */
00524 static pixman_operator_t
00525 _pixman_operator (cairo_operator_t operator)
00526 {
00527     switch (operator) {
00528     case CAIRO_OPERATOR_CLEAR:
00529        return PIXMAN_OPERATOR_CLEAR;
00530 
00531     case CAIRO_OPERATOR_SOURCE:
00532        return PIXMAN_OPERATOR_SRC;
00533     case CAIRO_OPERATOR_OVER:
00534        return PIXMAN_OPERATOR_OVER;
00535     case CAIRO_OPERATOR_IN:
00536        return PIXMAN_OPERATOR_IN;
00537     case CAIRO_OPERATOR_OUT:
00538        return PIXMAN_OPERATOR_OUT;
00539     case CAIRO_OPERATOR_ATOP:
00540        return PIXMAN_OPERATOR_ATOP;
00541 
00542     case CAIRO_OPERATOR_DEST:
00543        return PIXMAN_OPERATOR_DST;
00544     case CAIRO_OPERATOR_DEST_OVER:
00545        return PIXMAN_OPERATOR_OVER_REVERSE;
00546     case CAIRO_OPERATOR_DEST_IN:
00547        return PIXMAN_OPERATOR_IN_REVERSE;
00548     case CAIRO_OPERATOR_DEST_OUT:
00549        return PIXMAN_OPERATOR_OUT_REVERSE;
00550     case CAIRO_OPERATOR_DEST_ATOP:
00551        return PIXMAN_OPERATOR_ATOP_REVERSE;
00552 
00553     case CAIRO_OPERATOR_XOR:
00554        return PIXMAN_OPERATOR_XOR;
00555     case CAIRO_OPERATOR_ADD:
00556        return PIXMAN_OPERATOR_ADD;
00557     case CAIRO_OPERATOR_SATURATE:
00558        return PIXMAN_OPERATOR_SATURATE;
00559     default:
00560        return PIXMAN_OPERATOR_OVER;
00561     }
00562 }
00563 
00564 static cairo_int_status_t
00565 _cairo_image_surface_composite (cairo_operator_t operator,
00566                             cairo_pattern_t             *src_pattern,
00567                             cairo_pattern_t             *mask_pattern,
00568                             void                 *abstract_dst,
00569                             int                  src_x,
00570                             int                  src_y,
00571                             int                  mask_x,
00572                             int                  mask_y,
00573                             int                  dst_x,
00574                             int                  dst_y,
00575                             unsigned int         width,
00576                             unsigned int         height)
00577 {
00578     cairo_surface_attributes_t     src_attr, mask_attr;
00579     cairo_image_surface_t   *dst = abstract_dst;
00580     cairo_image_surface_t   *src;
00581     cairo_image_surface_t   *mask;
00582     cairo_int_status_t             status;
00583 
00584     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
00585                                          &dst->base,
00586                                          src_x, src_y,
00587                                          mask_x, mask_y,
00588                                          width, height,
00589                                          (cairo_surface_t **) &src,
00590                                          (cairo_surface_t **) &mask,
00591                                          &src_attr, &mask_attr);
00592     if (status)
00593        return status;
00594     
00595     status = _cairo_image_surface_set_attributes (src, &src_attr);
00596     if (status)
00597       goto CLEANUP_SURFACES;
00598 
00599     if (mask)
00600     {
00601        status = _cairo_image_surface_set_attributes (mask, &mask_attr);
00602        if (status)
00603            goto CLEANUP_SURFACES;
00604        
00605        pixman_composite (_pixman_operator (operator),
00606                        src->pixman_image,
00607                        mask->pixman_image,
00608                        dst->pixman_image,
00609                        src_x + src_attr.x_offset,
00610                        src_y + src_attr.y_offset,
00611                        mask_x + mask_attr.x_offset,
00612                        mask_y + mask_attr.y_offset,
00613                        dst_x, dst_y,
00614                        width, height);
00615     }
00616     else
00617     {
00618        pixman_composite (_pixman_operator (operator),
00619                        src->pixman_image,
00620                        NULL,
00621                        dst->pixman_image,
00622                        src_x + src_attr.x_offset,
00623                        src_y + src_attr.y_offset,
00624                        0, 0,
00625                        dst_x, dst_y,
00626                        width, height);
00627     }
00628     
00629     if (!_cairo_operator_bounded (operator) ||
00630        operator == CAIRO_OPERATOR_SOURCE ||
00631        operator == CAIRO_OPERATOR_CLEAR)
00632        status = _cairo_surface_composite_fixup_unbounded (&dst->base,
00633                                                     &src_attr, src->width, src->height,
00634                                                     mask ? &mask_attr : NULL,
00635                                                     mask ? mask->width : 0,
00636                                                     mask ? mask->height : 0,
00637                                                     src_x, src_y,
00638                                                     mask_x, mask_y,
00639                                                     dst_x, dst_y, width, height);
00640 
00641  CLEANUP_SURFACES:
00642     if (mask)
00643        _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
00644     
00645     _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
00646     
00647     return status;
00648 }
00649 
00650 static cairo_int_status_t
00651 _cairo_image_surface_fill_rectangles (void                     *abstract_surface,
00652                                   cairo_operator_t             operator,
00653                                   const cairo_color_t   *color,
00654                                   cairo_rectangle_t            *rects,
00655                                   int                   num_rects)
00656 {
00657     cairo_image_surface_t *surface = abstract_surface;
00658 
00659     pixman_color_t pixman_color;
00660 
00661     pixman_color.red   = color->red_short;
00662     pixman_color.green = color->green_short;
00663     pixman_color.blue  = color->blue_short;
00664     pixman_color.alpha = color->alpha_short;
00665 
00666     /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */
00667     pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image,
00668                          &pixman_color, (pixman_rectangle_t *) rects, num_rects);
00669 
00670     return CAIRO_STATUS_SUCCESS;
00671 }
00672 
00673 static cairo_bool_t
00674 _cairo_image_surface_is_alpha_only (cairo_image_surface_t *surface)
00675 {
00676     int bpp, alpha, red, green, blue;
00677     
00678     if (surface->format != (cairo_format_t) -1)
00679        return surface->format == CAIRO_FORMAT_A1 || surface->format == CAIRO_FORMAT_A8;
00680 
00681     pixman_format_get_masks (pixman_image_get_format (surface->pixman_image),
00682                           &bpp, &alpha, &red, &green, &blue);
00683 
00684     return red == 0 && blue == 0 && green == 0;
00685 }
00686 
00687 static cairo_int_status_t
00688 _cairo_image_surface_composite_trapezoids (cairo_operator_t    operator,
00689                                       cairo_pattern_t   *pattern,
00690                                       void                     *abstract_dst,
00691                                       cairo_antialias_t antialias,
00692                                       int               src_x,
00693                                       int               src_y,
00694                                       int               dst_x,
00695                                       int               dst_y,
00696                                       unsigned int             width,
00697                                       unsigned int             height,
00698                                       cairo_trapezoid_t *traps,
00699                                       int               num_traps)
00700 {
00701     cairo_surface_attributes_t     attributes;
00702     cairo_image_surface_t   *dst = abstract_dst;
00703     cairo_image_surface_t   *src;
00704     cairo_int_status_t             status;
00705     pixman_image_t          *mask;
00706     pixman_format_t         *format;
00707     pixman_bits_t           *mask_data;
00708     int                            mask_stride;
00709     int                            mask_bpp;
00710 
00711     /* Special case adding trapezoids onto a mask surface; we want to avoid
00712      * creating an intermediate temporary mask unecessarily.
00713      *
00714      * We make the assumption here that the portion of the trapezoids
00715      * contained within the surface is bounded by [dst_x,dst_y,width,height];
00716      * the Cairo core code passes bounds based on the trapezoid extents.
00717      *
00718      * Currently the check surface->has_clip is needed for correct
00719      * functioning, since pixman_add_trapezoids() doesn't obey the
00720      * surface clip, which is a libpixman bug , but there's no harm in
00721      * falling through to the general case when the surface is clipped
00722      * since libpixman would have to generate an intermediate mask anyways.
00723      */
00724     if (operator == CAIRO_OPERATOR_ADD &&
00725        _cairo_pattern_is_opaque_solid (pattern) &&
00726        _cairo_image_surface_is_alpha_only (dst) &&
00727        !dst->has_clip &&
00728        antialias != CAIRO_ANTIALIAS_NONE)
00729     {
00730        pixman_add_trapezoids (dst->pixman_image, 0, 0,
00731                             (pixman_trapezoid_t *) traps, num_traps);
00732        return CAIRO_STATUS_SUCCESS;
00733     }
00734 
00735     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
00736                                         src_x, src_y, width, height,
00737                                         (cairo_surface_t **) &src,
00738                                         &attributes);
00739     if (status)
00740        return status;
00741 
00742     status = _cairo_image_surface_set_attributes (src, &attributes);
00743     if (status)
00744        goto CLEANUP_SOURCE;
00745 
00746     switch (antialias) {
00747     case CAIRO_ANTIALIAS_NONE:
00748        format = pixman_format_create (PIXMAN_FORMAT_NAME_A1);
00749        mask_stride = (width + 31)/8;
00750        mask_bpp = 1;
00751        break;
00752     default:
00753        format = pixman_format_create (PIXMAN_FORMAT_NAME_A8);
00754        mask_stride = (width + 3) & ~3;
00755        mask_bpp = 8;
00756        break;
00757     }
00758     if (!format) {
00759        status = CAIRO_STATUS_NO_MEMORY;
00760        goto CLEANUP_SOURCE;
00761     }
00762 
00763     /* The image must be initially transparent */
00764     mask_data = calloc (1, mask_stride * height);
00765     if (!mask_data) {
00766        status = CAIRO_STATUS_NO_MEMORY;
00767        pixman_format_destroy (format);
00768        goto CLEANUP_SOURCE;
00769     }
00770 
00771     mask = pixman_image_create_for_data (mask_data, format, width, height,
00772                                     mask_bpp, mask_stride);
00773     pixman_format_destroy (format);
00774     if (!mask) {
00775        status = CAIRO_STATUS_NO_MEMORY;
00776        goto CLEANUP_IMAGE_DATA;
00777     }
00778 
00779     /* XXX: The pixman_trapezoid_t cast is evil and needs to go away
00780      * somehow. */
00781     pixman_add_trapezoids (mask, - dst_x, - dst_y,
00782                         (pixman_trapezoid_t *) traps, num_traps);
00783 
00784     pixman_composite (_pixman_operator (operator),
00785                     src->pixman_image,
00786                     mask,
00787                     dst->pixman_image,
00788                     src_x + attributes.x_offset,
00789                     src_y + attributes.y_offset,
00790                     0, 0,
00791                     dst_x, dst_y,
00792                     width, height);
00793 
00794     if (!_cairo_operator_bounded (operator))
00795        status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
00796                                                          &attributes, src->width, src->height,
00797                                                          width, height,
00798                                                          src_x, src_y,
00799                                                          0, 0,
00800                                                          dst_x, dst_y, width, height);
00801     pixman_image_destroy (mask);
00802 
00803  CLEANUP_IMAGE_DATA:
00804     free (mask_data);
00805 
00806  CLEANUP_SOURCE:
00807     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
00808 
00809     return status;
00810 }
00811 
00812 static cairo_int_status_t
00813 _cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
00814                                           pixman_region16_t *region)
00815 {
00816     cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
00817 
00818     return _cairo_image_surface_set_clip_region (surface, region);
00819 }
00820 
00821 cairo_int_status_t
00822 _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
00823                                   pixman_region16_t *region)
00824 {
00825     pixman_image_set_clip_region (surface->pixman_image, region);
00826 
00827     surface->has_clip = region != NULL;
00828 
00829     return CAIRO_STATUS_SUCCESS;
00830 }
00831 
00832 static cairo_int_status_t
00833 _cairo_image_surface_get_extents (cairo_image_surface_t *surface,
00834                               cairo_rectangle_t  *rectangle)
00835 {
00836     rectangle->x = 0;
00837     rectangle->y = 0;
00838     rectangle->width  = surface->width;
00839     rectangle->height = surface->height;
00840 
00841     return CAIRO_STATUS_SUCCESS;
00842 }
00843 
00844 static cairo_int_status_t
00845 _cairo_image_abstract_surface_get_extents (void              *abstract_surface,
00846                                       cairo_rectangle_t *rectangle)
00847 {
00848     cairo_image_surface_t *surface = abstract_surface;
00849 
00850     return _cairo_image_surface_get_extents (surface, rectangle);
00851 }
00852 
00861 cairo_bool_t
00862 _cairo_surface_is_image (cairo_surface_t *surface)
00863 {
00864     return surface->backend == &cairo_image_surface_backend;
00865 }
00866 
00867 const cairo_surface_backend_t cairo_image_surface_backend = {
00868     _cairo_image_surface_create_similar,
00869     _cairo_image_abstract_surface_finish,
00870     _cairo_image_surface_acquire_source_image,
00871     _cairo_image_surface_release_source_image,
00872     _cairo_image_surface_acquire_dest_image,
00873     _cairo_image_surface_release_dest_image,
00874     _cairo_image_surface_clone_similar,
00875     _cairo_image_surface_composite,
00876     _cairo_image_surface_fill_rectangles,
00877     _cairo_image_surface_composite_trapezoids,
00878     NULL, /* copy_page */
00879     NULL, /* show_page */
00880     _cairo_image_abstract_surface_set_clip_region,
00881     NULL, /* intersect_clip_path */
00882     _cairo_image_abstract_surface_get_extents,
00883     NULL /* show_glyphs */
00884 };