Back to index

lightning-sunbird  0.9+nobinonly
cairo-meta-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2005 Red Hat, Inc
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 Red Hat, Inc.
00031  *
00032  * Contributor(s):
00033  *     Kristian Høgsberg <krh@redhat.com>
00034  */
00035 
00036 #include "cairoint.h"
00037 #include "cairo-meta-surface-private.h"
00038 #include "cairo-gstate-private.h"
00039 
00040 static const cairo_surface_backend_t cairo_meta_surface_backend;
00041 
00042 cairo_surface_t *
00043 _cairo_meta_surface_create (double width, double height)
00044 {
00045     cairo_meta_surface_t *meta;
00046 
00047     meta = malloc (sizeof (cairo_meta_surface_t));
00048     if (meta == NULL) {
00049        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00050        return (cairo_surface_t*) &_cairo_surface_nil;
00051     }
00052 
00053     meta->width = width;
00054     meta->height = height;
00055     _cairo_surface_init (&meta->base, &cairo_meta_surface_backend);
00056     _cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
00057 
00058     return &meta->base;
00059 }
00060 
00061 static cairo_surface_t *
00062 _cairo_meta_surface_create_similar (void         *abstract_surface,
00063                                 cairo_content_t  content,
00064                                 int                     width,
00065                                 int                     height)
00066 {
00067     return _cairo_meta_surface_create (width, height);
00068 }
00069 
00070 static cairo_status_t
00071 _cairo_meta_surface_finish (void *abstract_surface)
00072 {
00073     cairo_meta_surface_t *meta = abstract_surface;
00074     cairo_command_t *command;
00075     cairo_command_t **elements;
00076     int i, num_elements;
00077 
00078     num_elements = meta->commands.num_elements;
00079     elements = (cairo_command_t **) meta->commands.elements;
00080     for (i = 0; i < num_elements; i++) {
00081        command = elements[i];
00082        switch (command->type) {
00083        case CAIRO_COMMAND_COMPOSITE:
00084            _cairo_pattern_fini (&command->composite.src_pattern.base);
00085            if (command->composite.mask_pattern_pointer)
00086               _cairo_pattern_fini (command->composite.mask_pattern_pointer);
00087            free (command);
00088            break;
00089 
00090        case CAIRO_COMMAND_FILL_RECTANGLES:
00091            free (command->fill_rectangles.rects);
00092            free (command);
00093            break;
00094 
00095        case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS:
00096            _cairo_pattern_fini (&command->composite_trapezoids.pattern.base);
00097            free (command->composite_trapezoids.traps);
00098            free (command);
00099            break;
00100 
00101        case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
00102            if (command->intersect_clip_path.path_pointer)
00103               _cairo_path_fixed_fini (&command->intersect_clip_path.path);
00104            free (command);
00105            break;
00106 
00107        case CAIRO_COMMAND_SHOW_GLYPHS:
00108            cairo_scaled_font_destroy (command->show_glyphs.scaled_font);
00109            _cairo_pattern_fini (&command->show_glyphs.pattern.base);
00110            free (command->show_glyphs.glyphs);
00111            free (command);
00112            break;
00113 
00114        case CAIRO_COMMAND_FILL_PATH:
00115            _cairo_pattern_fini (&command->fill_path.pattern.base);
00116            _cairo_path_fixed_fini (&command->fill_path.path);
00117            free (command);
00118            break;
00119 
00120        default:
00121            ASSERT_NOT_REACHED;
00122        }
00123     }
00124 
00125     _cairo_array_fini (&meta->commands);
00126 
00127     return CAIRO_STATUS_SUCCESS;
00128 }
00129 
00130 static cairo_int_status_t
00131 _cairo_meta_surface_composite (cairo_operator_t  operator,
00132                             cairo_pattern_t      *src_pattern,
00133                             cairo_pattern_t      *mask_pattern,
00134                             void          *abstract_surface,
00135                             int           src_x,
00136                             int           src_y,
00137                             int           mask_x,
00138                             int           mask_y,
00139                             int           dst_x,
00140                             int           dst_y,
00141                             unsigned int  width,
00142                             unsigned int  height)
00143 {
00144     cairo_meta_surface_t *meta = abstract_surface;
00145     cairo_command_composite_t *command;
00146 
00147     command = malloc (sizeof (cairo_command_composite_t));
00148     if (command == NULL)
00149        return CAIRO_STATUS_NO_MEMORY;
00150 
00151     command->type = CAIRO_COMMAND_COMPOSITE;
00152     command->operator = operator;
00153     _cairo_pattern_init_copy (&command->src_pattern.base, src_pattern);
00154     if (mask_pattern) {
00155        _cairo_pattern_init_copy (&command->mask_pattern.base, mask_pattern);
00156        command->mask_pattern_pointer = &command->mask_pattern.base;
00157     } else {
00158        command->mask_pattern_pointer = NULL;
00159     }
00160        
00161     command->src_x = src_x;
00162     command->src_y = src_y;
00163     command->mask_x = mask_x;
00164     command->mask_y = mask_y;
00165     command->dst_x = dst_x;
00166     command->dst_y = dst_y;
00167     command->width = width;
00168     command->height = height;
00169 
00170     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00171        _cairo_pattern_fini (&command->src_pattern.base);
00172        _cairo_pattern_fini (command->mask_pattern_pointer);
00173        free (command);
00174        return CAIRO_STATUS_NO_MEMORY;
00175     }
00176 
00177     return CAIRO_STATUS_SUCCESS;
00178 }
00179 
00180 static cairo_int_status_t
00181 _cairo_meta_surface_fill_rectangles (void               *abstract_surface,
00182                                  cairo_operator_t              operator,
00183                                  const cairo_color_t    *color,
00184                                  cairo_rectangle_t             *rects,
00185                                  int                    num_rects)
00186 {
00187     cairo_meta_surface_t *meta = abstract_surface;
00188     cairo_command_fill_rectangles_t *command;
00189 
00190     command = malloc (sizeof (cairo_command_fill_rectangles_t));
00191     if (command == NULL)
00192        return CAIRO_STATUS_NO_MEMORY;
00193 
00194     command->type = CAIRO_COMMAND_FILL_RECTANGLES;
00195     command->operator = operator;
00196     command->color = *color;
00197 
00198     command->rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
00199     if (command->rects == NULL) {
00200        free (command);
00201         return CAIRO_STATUS_NO_MEMORY;
00202     }
00203     memcpy (command->rects, rects, sizeof (cairo_rectangle_t) * num_rects);
00204 
00205     command->num_rects = num_rects;
00206 
00207     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00208        free (command->rects);
00209        free (command);
00210        return CAIRO_STATUS_NO_MEMORY;
00211     }
00212 
00213     return CAIRO_STATUS_SUCCESS;
00214 }
00215 
00216 static cairo_int_status_t
00217 _cairo_meta_surface_composite_trapezoids (cairo_operator_t     operator,
00218                                      cairo_pattern_t    *pattern,
00219                                      void               *abstract_surface,
00220                                      cairo_antialias_t  antialias,
00221                                      int                x_src,
00222                                      int                y_src,
00223                                      int                x_dst,
00224                                      int                y_dst,
00225                                      unsigned int              width,
00226                                      unsigned int              height,
00227                                      cairo_trapezoid_t  *traps,
00228                                      int                num_traps)
00229 {
00230     cairo_meta_surface_t *meta = abstract_surface;
00231     cairo_command_composite_trapezoids_t *command;
00232 
00233     command = malloc (sizeof (cairo_command_composite_trapezoids_t));
00234     if (command == NULL)
00235        return CAIRO_STATUS_NO_MEMORY;
00236 
00237     command->type = CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS;
00238     command->operator = operator;
00239     _cairo_pattern_init_copy (&command->pattern.base, pattern);
00240     command->antialias = antialias;
00241     command->x_src = x_src;
00242     command->y_src = y_src;
00243     command->x_dst = x_dst;
00244     command->y_dst = y_dst;
00245     command->width = width;
00246     command->height = height;
00247 
00248     command->traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
00249     if (command->traps == NULL) {
00250        _cairo_pattern_fini (&command->pattern.base);
00251        free (command);
00252         return CAIRO_STATUS_NO_MEMORY;
00253     }
00254     memcpy (command->traps, traps, sizeof (cairo_trapezoid_t) * num_traps);
00255 
00256     command->num_traps = num_traps;
00257 
00258     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00259        _cairo_pattern_fini (&command->pattern.base);
00260        free (command->traps);
00261        free (command);
00262        return CAIRO_STATUS_NO_MEMORY;
00263     }
00264 
00265     return CAIRO_STATUS_SUCCESS;
00266 }
00267 
00268 static cairo_int_status_t
00269 _cairo_meta_surface_intersect_clip_path (void               *dst,
00270                                     cairo_path_fixed_t *path,
00271                                     cairo_fill_rule_t   fill_rule,
00272                                     double                   tolerance,
00273                                     cairo_antialias_t   antialias)
00274 {
00275     cairo_meta_surface_t *meta = dst;
00276     cairo_command_intersect_clip_path_t *command;
00277     cairo_status_t status;
00278 
00279     command = malloc (sizeof (cairo_command_intersect_clip_path_t));
00280     if (command == NULL)
00281        return CAIRO_STATUS_NO_MEMORY;
00282 
00283     command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
00284 
00285     if (path) {
00286        status = _cairo_path_fixed_init_copy (&command->path, path);
00287        if (status) {
00288            free (command);
00289            return status;
00290        }
00291        command->path_pointer = &command->path;
00292     } else {
00293        command->path_pointer = NULL;
00294     }
00295     command->fill_rule = fill_rule;
00296     command->tolerance = tolerance;
00297     command->antialias = antialias;
00298 
00299     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00300        if (path)
00301            _cairo_path_fixed_fini (&command->path);
00302        free (command);
00303        return CAIRO_STATUS_NO_MEMORY;
00304     }
00305 
00306     return CAIRO_STATUS_SUCCESS;
00307 }
00308 
00309 static cairo_int_status_t
00310 _cairo_meta_surface_get_extents (void               *abstract_surface,
00311                              cairo_rectangle_t *rectangle)
00312 {
00313     cairo_meta_surface_t *meta = abstract_surface;
00314 
00315     /* Currently this is used for getting the extents of the surface
00316      * before calling cairo_paint().  This is the only this that
00317      * requires the meta surface to have an explicit size.  If paint
00318      * was just a backend function, this would not be necessary. */
00319 
00320     rectangle->x = 0;
00321     rectangle->y = 0;
00322     rectangle->width = meta->width;
00323     rectangle->height = meta->height;
00324     
00325     return CAIRO_STATUS_SUCCESS;
00326 }
00327 
00328 static cairo_int_status_t
00329 _cairo_meta_surface_show_glyphs (cairo_scaled_font_t    *scaled_font,
00330                              cairo_operator_t    operator,
00331                              cairo_pattern_t     *pattern,
00332                              void                *abstract_surface,
00333                              int                 source_x,
00334                              int                 source_y,
00335                              int                 dest_x,
00336                              int                 dest_y,
00337                              unsigned int        width,
00338                              unsigned int        height,
00339                              const cairo_glyph_t *glyphs,
00340                              int                 num_glyphs)
00341 {
00342     cairo_meta_surface_t *meta = abstract_surface;
00343     cairo_command_show_glyphs_t *command;
00344 
00345     command = malloc (sizeof (cairo_command_show_glyphs_t));
00346     if (command == NULL)
00347        return CAIRO_STATUS_NO_MEMORY;
00348 
00349     command->type = CAIRO_COMMAND_SHOW_GLYPHS;
00350     command->scaled_font = cairo_scaled_font_reference (scaled_font);
00351     command->operator = operator;
00352     _cairo_pattern_init_copy (&command->pattern.base, pattern);
00353     command->source_x = source_x;
00354     command->source_y = source_y;
00355     command->dest_x = dest_x;
00356     command->dest_y = dest_y;
00357     command->width = width;
00358     command->height = height;
00359 
00360     command->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs);
00361     if (command->glyphs == NULL) {
00362        _cairo_pattern_fini (&command->pattern.base);
00363        free (command);
00364         return CAIRO_STATUS_NO_MEMORY;
00365     }
00366     memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
00367 
00368     command->num_glyphs = num_glyphs;
00369 
00370     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00371        _cairo_pattern_fini (&command->pattern.base);
00372        free (command->glyphs);
00373        free (command);
00374        return CAIRO_STATUS_NO_MEMORY;
00375     }
00376 
00377     return CAIRO_STATUS_SUCCESS;
00378 }
00379 
00380 static cairo_int_status_t
00381 _cairo_meta_surface_fill_path (cairo_operator_t     operator,
00382                             cairo_pattern_t        *pattern,
00383                             void            *abstract_surface,
00384                             cairo_path_fixed_t *path,
00385                             cairo_fill_rule_t   fill_rule,
00386                             double           tolerance)
00387 {
00388     cairo_meta_surface_t *meta = abstract_surface;
00389     cairo_command_fill_path_t *command;
00390     cairo_status_t status;
00391 
00392     command = malloc (sizeof (cairo_command_fill_path_t));
00393     if (command == NULL)
00394        return CAIRO_STATUS_NO_MEMORY;
00395 
00396     command->type = CAIRO_COMMAND_FILL_PATH;
00397     command->operator = operator;
00398     _cairo_pattern_init_copy (&command->pattern.base, pattern);
00399     status = _cairo_path_fixed_init_copy (&command->path, path);
00400     if (status) {
00401        _cairo_pattern_fini (&command->pattern.base);
00402        free (command);
00403        return CAIRO_STATUS_NO_MEMORY;
00404     }  
00405     command->fill_rule = fill_rule;
00406     command->tolerance = tolerance;
00407 
00408     if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
00409        _cairo_path_fixed_fini (&command->path);
00410        _cairo_pattern_fini (&command->pattern.base);
00411        free (command);
00412        return CAIRO_STATUS_NO_MEMORY;
00413     }
00414 
00415     return CAIRO_STATUS_SUCCESS;
00416 }
00417 
00418 static const cairo_surface_backend_t cairo_meta_surface_backend = {
00419     _cairo_meta_surface_create_similar,
00420     _cairo_meta_surface_finish,
00421     NULL, /* acquire_source_image */
00422     NULL, /* release_source_image */
00423     NULL, /* acquire_dest_image */
00424     NULL, /* release_dest_image */
00425     NULL, /* clone_similar */
00426     _cairo_meta_surface_composite,
00427     _cairo_meta_surface_fill_rectangles,
00428     _cairo_meta_surface_composite_trapezoids,
00429     NULL, /* copy_page */
00430     NULL, /* show_page */
00431     NULL, /* set_clip_region */
00432     _cairo_meta_surface_intersect_clip_path,
00433     _cairo_meta_surface_get_extents,
00434     _cairo_meta_surface_show_glyphs,
00435     _cairo_meta_surface_fill_path,
00436 };
00437 
00438 cairo_int_status_t
00439 _cairo_meta_surface_replay (cairo_surface_t *surface,
00440                          cairo_surface_t *target)
00441 {
00442     cairo_meta_surface_t *meta;
00443     cairo_command_t *command, **elements;
00444     int i, num_elements;
00445     cairo_int_status_t status;
00446     cairo_traps_t traps;
00447     cairo_clip_t clip;
00448 
00449     meta = (cairo_meta_surface_t *) surface;
00450     status = CAIRO_STATUS_SUCCESS;
00451 
00452     _cairo_clip_init (&clip, target);    
00453 
00454     num_elements = meta->commands.num_elements;
00455     elements = (cairo_command_t **) meta->commands.elements;
00456     for (i = 0; i < num_elements; i++) {
00457        command = elements[i];
00458        switch (command->type) {
00459        case CAIRO_COMMAND_COMPOSITE:
00460            status = _cairo_surface_set_clip (target, &clip);
00461            if (status)
00462               break;
00463 
00464            status = _cairo_surface_composite
00465               (command->composite.operator,
00466                &command->composite.src_pattern.base,
00467                command->composite.mask_pattern_pointer,
00468                target,
00469                command->composite.src_x,
00470                command->composite.src_y,
00471                command->composite.mask_x,
00472                command->composite.mask_y,
00473                command->composite.dst_x,
00474                command->composite.dst_y,
00475                command->composite.width,
00476                command->composite.height);
00477            break;
00478 
00479        case CAIRO_COMMAND_FILL_RECTANGLES:
00480            status = _cairo_surface_set_clip (target, &clip);
00481            if (status)
00482               break;
00483 
00484            status = _cairo_surface_fill_rectangles
00485               (target,
00486                command->fill_rectangles.operator,
00487                &command->fill_rectangles.color,
00488                command->fill_rectangles.rects,
00489                command->fill_rectangles.num_rects);
00490            break;
00491 
00492        case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS:
00493            status = _cairo_surface_set_clip (target, &clip);
00494            if (status)
00495               break;
00496 
00497            status = _cairo_surface_composite_trapezoids
00498               (command->composite_trapezoids.operator,
00499                &command->composite_trapezoids.pattern.base,
00500                target,
00501                command->composite_trapezoids.antialias,
00502                command->composite_trapezoids.x_src,
00503                command->composite_trapezoids.y_src,
00504                command->composite_trapezoids.x_dst,
00505                command->composite_trapezoids.y_dst,
00506                command->composite_trapezoids.width,
00507                command->composite_trapezoids.height,
00508                command->composite_trapezoids.traps,
00509                command->composite_trapezoids.num_traps);
00510            break;
00511 
00512        case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
00513            /* XXX Meta surface clipping is broken and requires some
00514             * cairo-gstate.c rewriting.  Work around it for now. */
00515            if (command->intersect_clip_path.path_pointer == NULL)
00516               status = _cairo_clip_reset (&clip);
00517            else
00518               status = _cairo_clip_clip (&clip,
00519                                       command->intersect_clip_path.path_pointer,
00520                                       command->intersect_clip_path.fill_rule,
00521                                       command->intersect_clip_path.tolerance,
00522                                       command->intersect_clip_path.antialias,
00523                                       target);
00524            break;
00525 
00526        case CAIRO_COMMAND_SHOW_GLYPHS:
00527            status = _cairo_surface_set_clip (target, &clip);
00528            if (status)
00529               break;
00530 
00531            status = _cairo_surface_show_glyphs
00532               (command->show_glyphs.scaled_font,
00533                command->show_glyphs.operator,
00534                &command->show_glyphs.pattern.base,
00535                target,
00536                command->show_glyphs.source_x,
00537                command->show_glyphs.source_y,
00538                command->show_glyphs.dest_x,
00539                command->show_glyphs.dest_y,
00540                command->show_glyphs.width,
00541                command->show_glyphs.height,
00542                command->show_glyphs.glyphs,
00543                command->show_glyphs.num_glyphs);
00544            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
00545               break;
00546            
00547            status = (*command->show_glyphs.scaled_font->backend->
00548                     show_glyphs) (command->show_glyphs.scaled_font,
00549                                 command->show_glyphs.operator,
00550                                 &command->show_glyphs.pattern.base,
00551                                 target,
00552                                 command->show_glyphs.source_x,
00553                                 command->show_glyphs.source_y,
00554                                 command->show_glyphs.dest_x,
00555                                 command->show_glyphs.dest_y,
00556                                 command->show_glyphs.width,
00557                                 command->show_glyphs.height,
00558                                 command->show_glyphs.glyphs,
00559                                 command->show_glyphs.num_glyphs);
00560 
00561            break;
00562 
00563        case CAIRO_COMMAND_FILL_PATH:
00564            status = _cairo_surface_set_clip (target, &clip);
00565            if (status)
00566               break;
00567 
00568            status = _cairo_surface_fill_path (command->fill_path.operator,
00569                                           &command->fill_path.pattern.base,
00570                                           target,
00571                                           &command->fill_path.path,
00572                                           command->fill_path.fill_rule,
00573                                           command->fill_path.tolerance);
00574            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
00575               break;
00576 
00577            _cairo_traps_init (&traps);
00578 
00579            status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path,
00580                                                 command->fill_path.fill_rule,
00581                                                 command->fill_path.tolerance,
00582                                                 &traps);
00583            if (status) {
00584               _cairo_traps_fini (&traps);
00585               break;
00586            }
00587 
00588            status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base,
00589                                                            command->fill_path.operator,
00590                                                            target,
00591                                                            &traps,
00592                                                            &clip,
00593                                                            command->fill_path.antialias);
00594 
00595            _cairo_traps_fini (&traps);
00596            break;
00597 
00598        default:
00599            ASSERT_NOT_REACHED;
00600        }
00601 
00602        if (status)
00603            break;
00604     }
00605 
00606     _cairo_clip_fini (&clip);
00607 
00608     return status;
00609 }