Back to index

lightning-sunbird  0.9+nobinonly
cairo-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2002 University of Southern California
00004  * Copyright © 2005 Red Hat, Inc.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it either under the terms of the GNU Lesser General Public
00008  * License version 2.1 as published by the Free Software Foundation
00009  * (the "LGPL") or, at your option, under the terms of the Mozilla
00010  * Public License Version 1.1 (the "MPL"). If you do not alter this
00011  * notice, a recipient may use your version of this file under either
00012  * the MPL or the LGPL.
00013  *
00014  * You should have received a copy of the LGPL along with this library
00015  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017  * You should have received a copy of the MPL along with this library
00018  * in the file COPYING-MPL-1.1
00019  *
00020  * The contents of this file are subject to the Mozilla Public License
00021  * Version 1.1 (the "License"); you may not use this file except in
00022  * compliance with the License. You may obtain a copy of the License at
00023  * http://www.mozilla.org/MPL/
00024  *
00025  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00026  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00027  * the specific language governing rights and limitations.
00028  *
00029  * The Original Code is the cairo graphics library.
00030  *
00031  * The Initial Developer of the Original Code is University of Southern
00032  * California.
00033  *
00034  * Contributor(s):
00035  *     Carl D. Worth <cworth@cworth.org>
00036  */
00037 
00038 #include <stdlib.h>
00039 
00040 #include "cairoint.h"
00041 #include "cairo-gstate-private.h"
00042 
00043 const cairo_surface_t _cairo_surface_nil = {
00044     &cairo_image_surface_backend,  /* backend */
00045     -1,                                   /* ref_count */
00046     CAIRO_STATUS_NO_MEMORY,        /* status */
00047     FALSE,                         /* finished */
00048     { 0,      /* size */
00049       0,      /* num_elements */
00050       0,      /* element_size */
00051       NULL,   /* elements */
00052     },                             /* user_data */
00053     0.0,                           /* device_x_offset */
00054     0.0,                           /* device_y_offset */
00055     0,                             /* next_clip_serial */
00056     0                              /* current_clip_serial */
00057 };
00058 
00059 const cairo_surface_t _cairo_surface_nil_file_not_found = {
00060     &cairo_image_surface_backend,  /* backend */
00061     -1,                                   /* ref_count */
00062     CAIRO_STATUS_FILE_NOT_FOUND,   /* status */
00063     FALSE,                         /* finished */
00064     { 0,      /* size */
00065       0,      /* num_elements */
00066       0,      /* element_size */
00067       NULL,   /* elements */
00068     },                             /* user_data */
00069     0.0,                           /* device_x_offset */
00070     0.0,                           /* device_y_offset */
00071     0,                             /* next_clip_serial */
00072     0                              /* current_clip_serial */
00073 };
00074 
00075 const cairo_surface_t _cairo_surface_nil_read_error = {
00076     &cairo_image_surface_backend,  /* backend */
00077     -1,                                   /* ref_count */
00078     CAIRO_STATUS_READ_ERROR,              /* status */
00079     FALSE,                         /* finished */
00080     { 0,      /* size */
00081       0,      /* num_elements */
00082       0,      /* element_size */
00083       NULL,   /* elements */
00084     },                             /* user_data */
00085     0.0,                           /* device_x_offset */
00086     0.0,                           /* device_y_offset */
00087     0,                             /* next_clip_serial */
00088     0                              /* current_clip_serial */
00089 };
00090 
00107 static void
00108 _cairo_surface_set_error (cairo_surface_t *surface,
00109                        cairo_status_t status)
00110 {
00111     /* Don't overwrite an existing error. This preserves the first
00112      * error, which is the most significant. It also avoids attempting
00113      * to write to read-only data (eg. from a nil surface). */
00114     if (surface->status == CAIRO_STATUS_SUCCESS)
00115        surface->status = status;
00116 
00117     _cairo_error (status);
00118 }
00119 
00132 cairo_status_t
00133 cairo_surface_status (cairo_surface_t *surface)
00134 {
00135     return surface->status;
00136 }
00137 
00138 void
00139 _cairo_surface_init (cairo_surface_t                    *surface,
00140                    const cairo_surface_backend_t *backend)
00141 {
00142     surface->backend = backend;
00143 
00144     surface->ref_count = 1;
00145     surface->status = CAIRO_STATUS_SUCCESS;
00146     surface->finished = FALSE;
00147 
00148     _cairo_user_data_array_init (&surface->user_data);
00149 
00150     surface->device_x_offset = 0.0;
00151     surface->device_y_offset = 0.0;
00152     surface->device_x_scale = 1.0;
00153     surface->device_y_scale = 1.0;
00154 
00155     surface->next_clip_serial = 0;
00156     surface->current_clip_serial = 0;
00157 }
00158 
00159 cairo_surface_t *
00160 _cairo_surface_create_similar_scratch (cairo_surface_t *other,
00161                                    cairo_content_t      content,
00162                                    int           width,
00163                                    int           height)
00164 {
00165     cairo_format_t format = _cairo_format_from_content (content);
00166 
00167     if (other->status)
00168        return (cairo_surface_t*) &_cairo_surface_nil;
00169 
00170     if (other->backend->create_similar)
00171        return other->backend->create_similar (other, content, width, height);
00172     else
00173        return cairo_image_surface_create (format, width, height);
00174 }
00175 
00195 cairo_surface_t *
00196 cairo_surface_create_similar (cairo_surface_t  *other,
00197                            cairo_content_t       content,
00198                            int            width,
00199                            int            height)
00200 {
00201     if (other->status)
00202        return (cairo_surface_t*) &_cairo_surface_nil;
00203 
00204     if (! CAIRO_CONTENT_VALID (content)) {
00205        _cairo_error (CAIRO_STATUS_INVALID_CONTENT);
00206        return (cairo_surface_t*) &_cairo_surface_nil;
00207     }
00208 
00209     return _cairo_surface_create_similar_solid (other, content,
00210                                           width, height,
00211                                           CAIRO_COLOR_TRANSPARENT);
00212 }
00213 
00214 cairo_surface_t *
00215 _cairo_surface_create_similar_solid (cairo_surface_t     *other,
00216                                  cairo_content_t   content,
00217                                  int               width,
00218                                  int               height,
00219                                  const cairo_color_t *color)
00220 {
00221     cairo_status_t status;
00222     cairo_surface_t *surface;
00223 
00224     surface = _cairo_surface_create_similar_scratch (other, content,
00225                                                width, height);
00226     if (surface->status) {
00227        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00228        return (cairo_surface_t*) &_cairo_surface_nil;
00229     }
00230     
00231     status = _cairo_surface_fill_rectangle (surface,
00232                                        CAIRO_OPERATOR_SOURCE, color,
00233                                        0, 0, width, height);
00234     if (status) {
00235        cairo_surface_destroy (surface);
00236        _cairo_error (status);
00237        return (cairo_surface_t*) &_cairo_surface_nil;
00238     }
00239 
00240     return surface;
00241 }
00242 
00243 cairo_clip_mode_t
00244 _cairo_surface_get_clip_mode (cairo_surface_t *surface)
00245 {
00246     if (surface->backend->intersect_clip_path != NULL)
00247        return CAIRO_CLIP_MODE_PATH;
00248     else if (surface->backend->set_clip_region != NULL)
00249        return CAIRO_CLIP_MODE_REGION;
00250     else
00251        return CAIRO_CLIP_MODE_MASK;
00252 }
00253 
00264 cairo_surface_t *
00265 cairo_surface_reference (cairo_surface_t *surface)
00266 {
00267     if (surface == NULL)
00268        return NULL;
00269 
00270     if (surface->ref_count == (unsigned int)-1)
00271        return surface;
00272 
00273     assert (surface->ref_count > 0);
00274 
00275     surface->ref_count++;
00276 
00277     return surface;
00278 }
00279 
00288 void
00289 cairo_surface_destroy (cairo_surface_t *surface)
00290 {
00291     if (surface == NULL)
00292        return;
00293 
00294     if (surface->ref_count == (unsigned int)-1)
00295        return;
00296 
00297     assert (surface->ref_count > 0);
00298 
00299     surface->ref_count--;
00300     if (surface->ref_count)
00301        return;
00302 
00303     cairo_surface_finish (surface);
00304 
00305     _cairo_user_data_array_fini (&surface->user_data);
00306 
00307     free (surface);
00308 }
00309 slim_hidden_def(cairo_surface_destroy);
00310 
00329 void
00330 cairo_surface_finish (cairo_surface_t *surface)
00331 {
00332     cairo_status_t status;
00333 
00334     if (surface->finished) {
00335        _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
00336        return;
00337     }
00338 
00339     if (surface->backend->finish == NULL) {
00340        surface->finished = TRUE;
00341        return;
00342     }
00343 
00344     if (!surface->status && surface->backend->flush) {
00345        status = surface->backend->flush (surface);
00346        if (status) {
00347            _cairo_surface_set_error (surface, status);
00348            return;
00349        }
00350     }
00351 
00352     status = surface->backend->finish (surface);
00353     if (status) {
00354        _cairo_surface_set_error (surface, status);
00355        return;
00356     }
00357 
00358     surface->finished = TRUE;
00359 }
00360 
00373 void *
00374 cairo_surface_get_user_data (cairo_surface_t             *surface,
00375                           const cairo_user_data_key_t *key)
00376 {
00377     return _cairo_user_data_array_get_data (&surface->user_data,
00378                                        key);
00379 }
00380 
00397 cairo_status_t
00398 cairo_surface_set_user_data (cairo_surface_t             *surface,
00399                           const cairo_user_data_key_t *key,
00400                           void                    *user_data,
00401                           cairo_destroy_func_t    destroy)
00402 {
00403     if (surface->ref_count == -1)
00404        return CAIRO_STATUS_NO_MEMORY;
00405     
00406     return _cairo_user_data_array_set_data (&surface->user_data,
00407                                        key, user_data, destroy);
00408 }
00409 
00422 void
00423 cairo_surface_get_font_options (cairo_surface_t       *surface,
00424                             cairo_font_options_t  *options)
00425 {
00426     if (!surface->finished && surface->backend->get_font_options) {
00427        surface->backend->get_font_options (surface, options);
00428     } else {
00429        _cairo_font_options_init_default (options);
00430     }
00431 }
00432 
00444 void
00445 cairo_surface_flush (cairo_surface_t *surface)
00446 {
00447     if (surface->status)
00448        return;
00449 
00450     if (surface->finished) {
00451        _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
00452        return;
00453     }
00454 
00455     if (surface->backend->flush) {
00456        cairo_status_t status;
00457 
00458        status = surface->backend->flush (surface);
00459        
00460        if (status)
00461            _cairo_surface_set_error (surface, status);
00462     }
00463 }
00464 
00473 void
00474 cairo_surface_mark_dirty (cairo_surface_t *surface)
00475 {
00476     cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1);
00477 }
00478 
00491 void
00492 cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
00493                                 int              x,
00494                                 int              y,
00495                                 int              width,
00496                                 int              height)
00497 {
00498     if (surface->status)
00499        return;
00500 
00501     if (surface->finished) {
00502        _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
00503        return;
00504     }
00505 
00506     if (surface->backend->mark_dirty_rectangle) {
00507        cairo_status_t status;
00508        
00509        status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height);
00510        
00511        if (status)
00512            _cairo_surface_set_error (surface, status);
00513     }
00514 }
00515 
00534 void
00535 cairo_surface_set_device_offset (cairo_surface_t *surface,
00536                              double           x_offset,
00537                              double           y_offset)
00538 {
00539     if (surface->status)
00540        return;
00541 
00542     if (surface->finished) {
00543        _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
00544        return;
00545     }
00546 
00547     surface->device_x_offset = x_offset * surface->device_x_scale;
00548     surface->device_y_offset = y_offset * surface->device_y_scale;
00549 }
00550 
00568 cairo_status_t
00569 _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
00570                                  cairo_image_surface_t  **image_out,
00571                                  void                   **image_extra)
00572 {
00573     assert (!surface->finished);
00574 
00575     return surface->backend->acquire_source_image (surface,  image_out, image_extra);
00576 }
00577 
00585 void
00586 _cairo_surface_release_source_image (cairo_surface_t        *surface,
00587                                  cairo_image_surface_t  *image,
00588                                  void                   *image_extra)
00589 {
00590     assert (!surface->finished);
00591 
00592     if (surface->backend->release_source_image)
00593        surface->backend->release_source_image (surface, image, image_extra);
00594 }
00595 
00626 cairo_status_t
00627 _cairo_surface_acquire_dest_image (cairo_surface_t         *surface,
00628                                cairo_rectangle_t       *interest_rect,
00629                                cairo_image_surface_t  **image_out,
00630                                cairo_rectangle_t       *image_rect,
00631                                void                   **image_extra)
00632 {
00633     assert (!surface->finished);
00634 
00635     return surface->backend->acquire_dest_image (surface, interest_rect,
00636                                            image_out, image_rect, image_extra);
00637 }
00638 
00651 void
00652 _cairo_surface_release_dest_image (cairo_surface_t        *surface,
00653                                cairo_rectangle_t      *interest_rect,
00654                                cairo_image_surface_t  *image,
00655                                cairo_rectangle_t      *image_rect,
00656                                void                   *image_extra)
00657 {
00658     assert (!surface->finished);
00659 
00660     if (surface->backend->release_dest_image)
00661        surface->backend->release_dest_image (surface, interest_rect,
00662                                          image, image_rect, image_extra);
00663 }
00664 
00681 cairo_status_t
00682 _cairo_surface_clone_similar (cairo_surface_t  *surface,
00683                            cairo_surface_t  *src,
00684                            cairo_surface_t **clone_out)
00685 {
00686     cairo_status_t status;
00687     cairo_image_surface_t *image;
00688     void *image_extra;
00689     
00690     if (surface->finished)
00691        return CAIRO_STATUS_SURFACE_FINISHED;
00692 
00693     if (surface->backend->clone_similar == NULL)
00694        return CAIRO_INT_STATUS_UNSUPPORTED;
00695       
00696     status = surface->backend->clone_similar (surface, src, clone_out);
00697     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
00698        return status;
00699 
00700     status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
00701     if (status != CAIRO_STATUS_SUCCESS)
00702        return status;
00703     
00704     status = surface->backend->clone_similar (surface, &image->base, clone_out);
00705 
00706     /* If the above failed point, we could implement a full fallback
00707      * using acquire_dest_image, but that's going to be very
00708      * inefficient compared to a backend-specific implementation of
00709      * clone_similar() with an image source. So we don't bother
00710      */
00711     
00712     _cairo_surface_release_source_image (src, image, image_extra);
00713     return status;
00714 }
00715 
00716 typedef struct {
00717     cairo_surface_t *dst;
00718     cairo_rectangle_t extents;
00719     cairo_image_surface_t *image;
00720     cairo_rectangle_t image_rect;
00721     void *image_extra;
00722 } fallback_state_t;
00723 
00734 static cairo_int_status_t
00735 _fallback_init (fallback_state_t *state,
00736               cairo_surface_t  *dst,
00737               int               x,
00738               int               y,
00739               int               width,
00740               int               height)
00741 {
00742     cairo_status_t status;
00743 
00744     state->extents.x = x;
00745     state->extents.y = y;
00746     state->extents.width = width;
00747     state->extents.height = height;
00748     
00749     state->dst = dst;
00750 
00751     status = _cairo_surface_acquire_dest_image (dst, &state->extents,
00752                                           &state->image, &state->image_rect,
00753                                           &state->image_extra);
00754     if (status)
00755        return status;
00756 
00757     /* XXX: This NULL value tucked away in state->image is a rather
00758      * ugly interface. Cleaner would be to push the
00759      * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
00760      * _cairo_surface_acquire_dest_image and its backend
00761      * counterparts. */
00762     if (state->image == NULL)
00763        return CAIRO_INT_STATUS_NOTHING_TO_DO;
00764 
00765     return CAIRO_STATUS_SUCCESS;
00766 }
00767 
00768 static void
00769 _fallback_fini (fallback_state_t *state)
00770 {
00771     _cairo_surface_release_dest_image (state->dst, &state->extents,
00772                                    state->image, &state->image_rect,
00773                                    state->image_extra);
00774 }
00775 
00776 static cairo_status_t
00777 _fallback_composite (cairo_operator_t     operator,
00778                    cairo_pattern_t *src,
00779                    cairo_pattern_t *mask,
00780                    cairo_surface_t *dst,
00781                    int             src_x,
00782                    int             src_y,
00783                    int             mask_x,
00784                    int             mask_y,
00785                    int             dst_x,
00786                    int             dst_y,
00787                    unsigned int    width,
00788                    unsigned int    height)
00789 {
00790     fallback_state_t state;
00791     cairo_status_t status;
00792 
00793     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
00794     if (status) {
00795        if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
00796            return CAIRO_STATUS_SUCCESS;
00797        return status;
00798     }
00799 
00800     status = state.image->base.backend->composite (operator, src, mask,
00801                                              &state.image->base,
00802                                              src_x, src_y, mask_x, mask_y,
00803                                              dst_x - state.image_rect.x,
00804                                              dst_y - state.image_rect.y,
00805                                              width, height);
00806     _fallback_fini (&state);
00807 
00808     return status;
00809 }
00810 
00811 cairo_status_t
00812 _cairo_surface_composite (cairo_operator_t       operator,
00813                        cairo_pattern_t    *src,
00814                        cairo_pattern_t    *mask,
00815                        cairo_surface_t    *dst,
00816                        int                src_x,
00817                        int                src_y,
00818                        int                mask_x,
00819                        int                mask_y,
00820                        int                dst_x,
00821                        int                dst_y,
00822                        unsigned int              width,
00823                        unsigned int              height)
00824 {
00825     cairo_int_status_t status;
00826 
00827     if (mask) {
00828        /* These operators aren't interpreted the same way by the backends;
00829         * they are implemented in terms of other operators in cairo-gstate.c
00830         */
00831        assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR);
00832     }
00833 
00834     if (dst->status)
00835        return dst->status;
00836        
00837     if (dst->finished)
00838        return CAIRO_STATUS_SURFACE_FINISHED;
00839 
00840     if (dst->backend->composite) {
00841        status = dst->backend->composite (operator,
00842                                      src, mask, dst,
00843                                      src_x, src_y,
00844                                      mask_x, mask_y,
00845                                      dst_x, dst_y,
00846                                      width, height);
00847        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
00848            return status;
00849     }
00850 
00851     return _fallback_composite (operator,
00852                             src, mask, dst,
00853                             src_x, src_y,
00854                             mask_x, mask_y,
00855                             dst_x, dst_y,
00856                             width, height);
00857 }
00858 
00874 cairo_status_t
00875 _cairo_surface_fill_rectangle (cairo_surface_t      *surface,
00876                             cairo_operator_t         operator,
00877                             const cairo_color_t *color,
00878                             int               x,
00879                             int               y,
00880                             int               width,
00881                             int               height)
00882 {
00883     cairo_rectangle_t rect;
00884 
00885     if (surface->status)
00886        return surface->status;
00887 
00888     if (surface->finished)
00889        return CAIRO_STATUS_SURFACE_FINISHED;
00890 
00891     rect.x = x;
00892     rect.y = y;
00893     rect.width = width;
00894     rect.height = height;
00895 
00896     return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1);
00897 }
00898 
00912 cairo_status_t
00913 _cairo_surface_fill_region (cairo_surface_t         *surface,
00914                          cairo_operator_t     operator,
00915                          const cairo_color_t    *color,
00916                          pixman_region16_t      *region)
00917 {
00918     int num_rects = pixman_region_num_rects (region);
00919     pixman_box16_t *boxes = pixman_region_rects (region);
00920     cairo_rectangle_t *rects;
00921     cairo_status_t status;
00922     int i;
00923 
00924     if (!num_rects)
00925        return CAIRO_STATUS_SUCCESS;
00926     
00927     rects = malloc (sizeof (pixman_rectangle_t) * num_rects);
00928     if (!rects)
00929        return CAIRO_STATUS_NO_MEMORY;
00930 
00931     for (i = 0; i < num_rects; i++) {
00932        rects[i].x = boxes[i].x1;
00933        rects[i].y = boxes[i].y1;
00934        rects[i].width = boxes[i].x2 - boxes[i].x1;
00935        rects[i].height = boxes[i].y2 - boxes[i].y1;
00936     }
00937 
00938     status =  _cairo_surface_fill_rectangles (surface, operator,
00939                                          color, rects, num_rects);
00940     
00941     free (rects);
00942 
00943     return status;
00944 }
00945 
00946 static cairo_status_t
00947 _fallback_fill_rectangles (cairo_surface_t       *surface,
00948                         cairo_operator_t  operator,
00949                         const cairo_color_t      *color,
00950                         cairo_rectangle_t *rects,
00951                         int               num_rects)
00952 {
00953     fallback_state_t state;
00954     cairo_rectangle_t *offset_rects = NULL;
00955     cairo_status_t status;
00956     int x1, y1, x2, y2;
00957     int i;
00958 
00959     if (num_rects <= 0)
00960        return CAIRO_STATUS_SUCCESS;
00961 
00962     /* Compute the bounds of the rectangles, so that we know what area of the
00963      * destination surface to fetch
00964      */
00965     x1 = rects[0].x;
00966     y1 = rects[0].y;
00967     x2 = rects[0].x + rects[0].width;
00968     y2 = rects[0].y + rects[0].height;
00969     
00970     for (i = 1; i < num_rects; i++) {
00971        if (rects[i].x < x1)
00972            x1 = rects[i].x;
00973        if (rects[i].y < y1)
00974            y1 = rects[i].y;
00975 
00976        if (rects[i].x + rects[i].width > x2)
00977            x2 = rects[i].x + rects[i].width;
00978        if (rects[i].y + rects[i].height > y2)
00979            y2 = rects[i].y + rects[i].height;
00980     }
00981 
00982     status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
00983     if (status) {
00984        if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
00985            return CAIRO_STATUS_SUCCESS;
00986        return status;
00987     }
00988 
00989     /* If the fetched image isn't at 0,0, we need to offset the rectangles */
00990     
00991     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
00992        offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
00993        if (offset_rects == NULL) {
00994            status = CAIRO_STATUS_NO_MEMORY;
00995            goto DONE;
00996        }
00997 
00998        for (i = 0; i < num_rects; i++) {
00999            offset_rects[i].x = rects[i].x - state.image_rect.x;
01000            offset_rects[i].y = rects[i].y - state.image_rect.y;
01001            offset_rects[i].width = rects[i].width;
01002            offset_rects[i].height = rects[i].height;
01003        }
01004 
01005        rects = offset_rects;
01006     }
01007 
01008     status = state.image->base.backend->fill_rectangles (&state.image->base,
01009                                                   operator, color,
01010                                                   rects, num_rects);
01011 
01012     free (offset_rects);
01013 
01014  DONE:
01015     _fallback_fini (&state);
01016 
01017     return status;
01018 }
01019 
01036 cairo_status_t
01037 _cairo_surface_fill_rectangles (cairo_surface_t         *surface,
01038                             cairo_operator_t     operator,
01039                             const cairo_color_t  *color,
01040                             cairo_rectangle_t    *rects,
01041                             int                  num_rects)
01042 {
01043     cairo_int_status_t status;
01044 
01045     if (surface->status)
01046        return surface->status;
01047 
01048     if (surface->finished)
01049        return CAIRO_STATUS_SURFACE_FINISHED;
01050 
01051     if (num_rects == 0)
01052        return CAIRO_STATUS_SUCCESS;
01053 
01054     if (surface->backend->fill_rectangles) {
01055        status = surface->backend->fill_rectangles (surface,
01056                                               operator,
01057                                               color,
01058                                               rects, num_rects);
01059        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
01060            return status;
01061     }
01062 
01063     return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
01064 }
01065 
01066 cairo_int_status_t
01067 _cairo_surface_fill_path (cairo_operator_t       operator,
01068                        cairo_pattern_t    *pattern,
01069                        cairo_surface_t    *dst,
01070                        cairo_path_fixed_t *path,
01071                        cairo_fill_rule_t  fill_rule,
01072                        double             tolerance)
01073 {
01074     if (dst->backend->fill_path)
01075        return dst->backend->fill_path (operator, pattern, dst, path,
01076                                    fill_rule, tolerance);
01077     else
01078        return CAIRO_INT_STATUS_UNSUPPORTED;
01079 }
01080 
01081   
01082 static cairo_status_t
01083 _fallback_composite_trapezoids (cairo_operator_t operator,
01084                             cairo_pattern_t             *pattern,
01085                             cairo_surface_t             *dst,
01086                             cairo_antialias_t    antialias,
01087                             int                  src_x,
01088                             int                  src_y,
01089                             int                  dst_x,
01090                             int                  dst_y,
01091                             unsigned int         width,
01092                             unsigned int         height,
01093                             cairo_trapezoid_t    *traps,
01094                             int                  num_traps)
01095 {
01096     fallback_state_t state;
01097     cairo_trapezoid_t *offset_traps = NULL;
01098     cairo_status_t status;
01099     int i;
01100 
01101     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
01102     if (status) {
01103        if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
01104            return CAIRO_STATUS_SUCCESS;
01105        return status;
01106     }
01107 
01108     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
01109     
01110     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
01111 
01112        cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
01113        cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
01114        
01115        offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
01116        if (!offset_traps) {
01117            status = CAIRO_STATUS_NO_MEMORY;
01118            goto DONE;
01119        }
01120 
01121        for (i = 0; i < num_traps; i++) {
01122            offset_traps[i].top = traps[i].top - yoff;
01123            offset_traps[i].bottom = traps[i].bottom - yoff;
01124            offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
01125            offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
01126            offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
01127            offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
01128            offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
01129            offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
01130            offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
01131            offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
01132        }
01133 
01134        traps = offset_traps;
01135     }
01136 
01137     state.image->base.backend->composite_trapezoids (operator, pattern,
01138                                                &state.image->base,
01139                                                antialias,
01140                                                src_x, src_y,
01141                                                dst_x - state.image_rect.x,
01142                                                dst_y - state.image_rect.y,
01143                                                width, height, traps, num_traps);
01144     if (offset_traps)
01145        free (offset_traps);
01146 
01147  DONE:
01148     _fallback_fini (&state);
01149     
01150     return status;
01151 }
01152 
01153 cairo_status_t
01154 _cairo_surface_composite_trapezoids (cairo_operator_t          operator,
01155                                  cairo_pattern_t        *pattern,
01156                                  cairo_surface_t        *dst,
01157                                  cairo_antialias_t             antialias,
01158                                  int                    src_x,
01159                                  int                    src_y,
01160                                  int                    dst_x,
01161                                  int                    dst_y,
01162                                  unsigned int           width,
01163                                  unsigned int           height,
01164                                  cairo_trapezoid_t             *traps,
01165                                  int                    num_traps)
01166 {
01167     cairo_int_status_t status;
01168 
01169     /* These operators aren't interpreted the same way by the backends;
01170      * they are implemented in terms of other operators in cairo-gstate.c
01171      */
01172     assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR);
01173 
01174     if (dst->status)
01175        return dst->status;
01176 
01177     if (dst->finished)
01178        return CAIRO_STATUS_SURFACE_FINISHED;
01179 
01180     if (dst->backend->composite_trapezoids) {
01181        status = dst->backend->composite_trapezoids (operator,
01182                                                pattern, dst,
01183                                                antialias,
01184                                                src_x, src_y,
01185                                                dst_x, dst_y,
01186                                                width, height,
01187                                                traps, num_traps);
01188        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
01189            return status;
01190     }
01191 
01192     return  _fallback_composite_trapezoids (operator, pattern, dst,
01193                                        antialias,
01194                                        src_x, src_y,
01195                                        dst_x, dst_y,
01196                                        width, height,
01197                                        traps, num_traps);
01198 }
01199 
01200 cairo_status_t
01201 _cairo_surface_copy_page (cairo_surface_t *surface)
01202 {
01203     if (surface->status)
01204        return surface->status;
01205 
01206     if (surface->finished)
01207        return CAIRO_STATUS_SURFACE_FINISHED;
01208 
01209     /* It's fine if some backends just don't support this. */
01210     if (surface->backend->copy_page == NULL)
01211        return CAIRO_STATUS_SUCCESS;
01212 
01213     return surface->backend->copy_page (surface);
01214 }
01215 
01216 cairo_status_t
01217 _cairo_surface_show_page (cairo_surface_t *surface)
01218 {
01219     if (surface->status)
01220        return surface->status;
01221 
01222     if (surface->finished)
01223        return CAIRO_STATUS_SURFACE_FINISHED;
01224 
01225     /* It's fine if some backends just don't support this. */
01226     if (surface->backend->show_page == NULL)
01227        return CAIRO_STATUS_SUCCESS;
01228 
01229     return surface->backend->show_page (surface);
01230 }
01231 
01241 unsigned int
01242 _cairo_surface_get_current_clip_serial (cairo_surface_t *surface)
01243 {
01244     return surface->current_clip_serial;
01245 }
01246 
01257 unsigned int
01258 _cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
01259 {
01260     unsigned int    serial;
01261     
01262     if (surface->status)
01263        return 0;
01264 
01265     if ((serial = ++(surface->next_clip_serial)) == 0)
01266        serial = ++(surface->next_clip_serial);
01267     return serial;
01268 }
01269 
01279 cairo_status_t
01280 _cairo_surface_reset_clip (cairo_surface_t *surface)
01281 {
01282     cairo_status_t  status;
01283 
01284     if (surface->status)
01285        return surface->status;
01286 
01287     if (surface->finished)
01288        return CAIRO_STATUS_SURFACE_FINISHED;
01289     
01290     surface->current_clip_serial = 0;
01291 
01292     if (surface->backend->intersect_clip_path) {
01293        status = surface->backend->intersect_clip_path (surface,
01294                                                  NULL,
01295                                                  CAIRO_FILL_RULE_WINDING,
01296                                                  0,
01297                                                  CAIRO_ANTIALIAS_DEFAULT);
01298        if (status)
01299            return status;
01300     }
01301 
01302     if (surface->backend->set_clip_region != NULL) {
01303        status = surface->backend->set_clip_region (surface, NULL);
01304        if (status)
01305            return status;
01306     }
01307 
01308     return CAIRO_STATUS_SUCCESS;
01309 }
01310 
01321 cairo_status_t
01322 _cairo_surface_set_clip_region (cairo_surface_t      *surface,
01323                             pixman_region16_t   *region,
01324                             unsigned int      serial)
01325 {
01326     if (surface->status)
01327        return surface->status;
01328 
01329     if (surface->finished)
01330        return CAIRO_STATUS_SURFACE_FINISHED;
01331     
01332     assert (surface->backend->set_clip_region != NULL);
01333     
01334     surface->current_clip_serial = serial;
01335 
01336     return surface->backend->set_clip_region (surface, region);
01337 }
01338 
01339 cairo_int_status_t
01340 _cairo_surface_intersect_clip_path (cairo_surface_t    *surface,
01341                                 cairo_path_fixed_t *path,
01342                                 cairo_fill_rule_t   fill_rule,
01343                                 double           tolerance,
01344                                 cairo_antialias_t       antialias)
01345 {
01346     if (surface->status)
01347        return surface->status;
01348 
01349     if (surface->finished)
01350        return CAIRO_STATUS_SURFACE_FINISHED;
01351     
01352     assert (surface->backend->intersect_clip_path != NULL);
01353 
01354     return surface->backend->intersect_clip_path (surface,
01355                                             path,
01356                                             fill_rule,
01357                                             tolerance,
01358                                             antialias);
01359 }
01360 
01361 static cairo_status_t
01362 _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
01363                                    cairo_clip_path_t *clip_path)
01364 {
01365     cairo_status_t status;
01366 
01367     if (clip_path == NULL)
01368        return CAIRO_STATUS_SUCCESS;
01369 
01370     status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev);
01371     if (status)
01372        return status;
01373 
01374     return surface->backend->intersect_clip_path (surface,
01375                                             &clip_path->path,
01376                                             clip_path->fill_rule,
01377                                             clip_path->tolerance,
01378                                             clip_path->antialias);
01379 }
01380 
01390 static cairo_status_t
01391 _cairo_surface_set_clip_path (cairo_surface_t    *surface,
01392                            cairo_clip_path_t     *clip_path,
01393                            unsigned int   serial)
01394 {
01395     cairo_status_t status;
01396 
01397     if (surface->status)
01398        return surface->status;
01399 
01400     if (surface->finished)
01401        return CAIRO_STATUS_SURFACE_FINISHED;
01402 
01403     assert (surface->backend->intersect_clip_path != NULL);
01404 
01405     status = surface->backend->intersect_clip_path (surface,
01406                                               NULL,
01407                                               CAIRO_FILL_RULE_WINDING,
01408                                               0,
01409                                               CAIRO_ANTIALIAS_DEFAULT);
01410     if (status)
01411        return status;
01412 
01413     status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
01414     if (status)
01415        return status;
01416 
01417     surface->current_clip_serial = serial;
01418 
01419     return CAIRO_STATUS_SUCCESS;
01420 }
01421 
01422 cairo_status_t
01423 _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
01424 {
01425     if (!surface)
01426        return CAIRO_STATUS_NULL_POINTER;
01427     if (clip->serial == _cairo_surface_get_current_clip_serial (surface))
01428        return CAIRO_STATUS_SUCCESS;
01429     
01430     if (clip->path)
01431        return _cairo_surface_set_clip_path (surface,
01432                                         clip->path,
01433                                         clip->serial);
01434     
01435     if (clip->region)
01436        return _cairo_surface_set_clip_region (surface, 
01437                                           clip->region,
01438                                           clip->serial);
01439     
01440     return _cairo_surface_reset_clip (surface);
01441 }
01442 
01458 cairo_status_t
01459 _cairo_surface_get_extents (cairo_surface_t   *surface,
01460                          cairo_rectangle_t *rectangle)
01461 {
01462     if (surface->status)
01463        return surface->status;
01464 
01465     if (surface->finished)
01466        return CAIRO_STATUS_SURFACE_FINISHED;
01467 
01468     return surface->backend->get_extents (surface, rectangle);
01469 }
01470 
01471 cairo_status_t
01472 _cairo_surface_show_glyphs (cairo_scaled_font_t          *scaled_font,
01473                          cairo_operator_t        operator,
01474                          cairo_pattern_t         *pattern,
01475                          cairo_surface_t         *dst,
01476                          int                            source_x,
01477                          int                            source_y,
01478                          int                            dest_x,
01479                          int                            dest_y,
01480                          unsigned int            width,
01481                          unsigned int            height,
01482                          const cairo_glyph_t            *glyphs,
01483                          int                            num_glyphs)
01484 {
01485     cairo_status_t status;
01486 
01487     if (dst->status)
01488        return dst->status;
01489 
01490     if (dst->finished)
01491        return CAIRO_STATUS_SURFACE_FINISHED;
01492 
01493     if (dst->backend->show_glyphs)
01494        status = dst->backend->show_glyphs (scaled_font, operator, pattern, dst,
01495                                        source_x, source_y,
01496                                        dest_x, dest_y,
01497                                        width, height,
01498                                        glyphs, num_glyphs);
01499     else
01500        status = CAIRO_INT_STATUS_UNSUPPORTED;
01501 
01502     return status;
01503 }
01504 
01505 static cairo_status_t
01506 _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t            *dst,
01507                                              cairo_rectangle_t          *src_rectangle,
01508                                              cairo_rectangle_t          *mask_rectangle,
01509                                              int                      dst_x,
01510                                              int                      dst_y,
01511                                              unsigned int                    width,
01512                                              unsigned int                    height)
01513 {
01514     cairo_rectangle_t dst_rectangle;
01515     cairo_rectangle_t drawn_rectangle;
01516     pixman_region16_t *drawn_region;
01517     pixman_region16_t *clear_region;
01518     cairo_status_t status = CAIRO_STATUS_SUCCESS;
01519 
01520     /* The area that was drawn is the area in the destination rectangle but not within
01521      * the source or the mask.
01522      */
01523     dst_rectangle.x = dst_x;
01524     dst_rectangle.y = dst_y;
01525     dst_rectangle.width = width;
01526     dst_rectangle.height = height;
01527 
01528     drawn_rectangle = dst_rectangle;
01529 
01530     if (src_rectangle)
01531        _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle);
01532 
01533     if (mask_rectangle)
01534        _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle);
01535 
01536     /* Now compute the area that is in dst_rectangle but not in drawn_rectangle
01537      */
01538     drawn_region = _cairo_region_create_from_rectangle (&drawn_rectangle);
01539     clear_region = _cairo_region_create_from_rectangle (&dst_rectangle);
01540     if (!drawn_region || !clear_region) {
01541        status = CAIRO_STATUS_NO_MEMORY;
01542        goto CLEANUP_REGIONS;
01543     }
01544 
01545     if (pixman_region_subtract (clear_region, clear_region, drawn_region) != PIXMAN_REGION_STATUS_SUCCESS) {
01546        status = CAIRO_STATUS_NO_MEMORY;
01547        goto CLEANUP_REGIONS;
01548     }
01549 
01550     status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
01551                                     CAIRO_COLOR_TRANSPARENT,
01552                                     clear_region);
01553 
01554  CLEANUP_REGIONS:
01555     if (drawn_region)
01556        pixman_region_destroy (drawn_region);
01557     if (clear_region)
01558        pixman_region_destroy (clear_region);
01559 
01560     return status;
01561 }
01562 
01587 cairo_status_t
01588 _cairo_surface_composite_fixup_unbounded (cairo_surface_t            *dst,
01589                                      cairo_surface_attributes_t *src_attr,
01590                                      int                         src_width,
01591                                      int                         src_height,
01592                                      cairo_surface_attributes_t *mask_attr,
01593                                      int                         mask_width,
01594                                      int                         mask_height,
01595                                      int                      src_x,
01596                                      int                      src_y,
01597                                      int                      mask_x,
01598                                      int                      mask_y,
01599                                      int                      dst_x,
01600                                      int                      dst_y,
01601                                      unsigned int                    width,
01602                                      unsigned int                    height)
01603 {
01604     cairo_rectangle_t src_tmp, mask_tmp;
01605     cairo_rectangle_t *src_rectangle = NULL;
01606     cairo_rectangle_t *mask_rectangle = NULL;
01607   
01608     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
01609      * non-repeating sources and masks. Other sources and masks can be ignored.
01610      */
01611     if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
01612        src_attr->extend == CAIRO_EXTEND_NONE)
01613     {
01614        src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
01615        src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
01616        src_tmp.width = src_width;
01617        src_tmp.height = src_height;
01618 
01619        src_rectangle = &src_tmp;
01620     }
01621 
01622     if (mask_attr &&
01623        _cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) &&
01624        mask_attr->extend == CAIRO_EXTEND_NONE)
01625     {
01626        mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset));
01627        mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset));
01628        mask_tmp.width = mask_width;
01629        mask_tmp.height = mask_height;
01630 
01631        mask_rectangle = &mask_tmp;
01632     }
01633 
01634     return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
01635                                                        dst_x, dst_y, width, height);
01636 }
01637 
01661 cairo_status_t
01662 _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t            *dst,
01663                                           cairo_surface_attributes_t *src_attr,
01664                                           int                         src_width,
01665                                           int                         src_height,
01666                                           int                         mask_width,
01667                                           int                         mask_height,
01668                                           int                      src_x,
01669                                           int                      src_y,
01670                                           int                      mask_x,
01671                                           int                      mask_y,
01672                                           int                      dst_x,
01673                                           int                      dst_y,
01674                                           unsigned int             width,
01675                                           unsigned int             height)
01676 {
01677     cairo_rectangle_t src_tmp, mask_tmp;
01678     cairo_rectangle_t *src_rectangle = NULL;
01679     cairo_rectangle_t *mask_rectangle = NULL;
01680   
01681     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
01682      * non-repeating sources and masks. Other sources and masks can be ignored.
01683      */
01684     if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
01685        src_attr->extend == CAIRO_EXTEND_NONE)
01686     {
01687        src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
01688        src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
01689        src_tmp.width = src_width;
01690        src_tmp.height = src_height;
01691 
01692        src_rectangle = &src_tmp;
01693     }
01694 
01695     mask_tmp.x = dst_x - mask_x;
01696     mask_tmp.y = dst_y - mask_y;
01697     mask_tmp.width = mask_width;
01698     mask_tmp.height = mask_height;
01699     
01700     mask_rectangle = &mask_tmp;
01701 
01702     return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
01703                                                        dst_x, dst_y, width, height);
01704 }