Back to index

lightning-sunbird  0.9+nobinonly
cairo-gstate.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 
00042 #include "cairo-clip-private.h"
00043 #include "cairo-gstate-private.h"
00044 
00045 static cairo_status_t
00046 _cairo_gstate_init (cairo_gstate_t  *gstate,
00047                   cairo_surface_t *target);
00048 
00049 static cairo_status_t
00050 _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
00051 
00052 static void
00053 _cairo_gstate_fini (cairo_gstate_t *gstate);
00054 
00055 static cairo_status_t
00056 _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
00057                                         cairo_traps_t  *traps);
00058 
00059 static cairo_status_t
00060 _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
00061 
00062 static cairo_status_t
00063 _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
00064 
00065 static void
00066 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
00067 
00068 cairo_gstate_t *
00069 _cairo_gstate_create (cairo_surface_t *target)
00070 {
00071     cairo_status_t status;
00072     cairo_gstate_t *gstate;
00073 
00074     gstate = malloc (sizeof (cairo_gstate_t));
00075 
00076     if (gstate)
00077     {
00078        status = _cairo_gstate_init (gstate, target);
00079        if (status) {
00080            free (gstate);
00081            return NULL;            
00082        }
00083     }
00084 
00085     return gstate;
00086 }
00087 
00088 static cairo_status_t
00089 _cairo_gstate_init (cairo_gstate_t  *gstate,
00090                   cairo_surface_t *target)
00091 {
00092     gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
00093 
00094     gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
00095     gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
00096 
00097     gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
00098     gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
00099     gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
00100     gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
00101 
00102     gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
00103 
00104     gstate->dash = NULL;
00105     gstate->num_dashes = 0;
00106     gstate->dash_offset = 0.0;
00107 
00108     gstate->font_face = NULL;
00109     gstate->scaled_font = NULL;
00110 
00111     cairo_matrix_init_scale (&gstate->font_matrix,
00112                           CAIRO_GSTATE_DEFAULT_FONT_SIZE, 
00113                           CAIRO_GSTATE_DEFAULT_FONT_SIZE);
00114 
00115     _cairo_font_options_init_default (&gstate->font_options);
00116     
00117     _cairo_clip_init (&gstate->clip, target);
00118 
00119     gstate->target = cairo_surface_reference (target);
00120 
00121     _cairo_gstate_identity_matrix (gstate);
00122     gstate->source_ctm_inverse = gstate->ctm_inverse;
00123 
00124     _cairo_pen_init_empty (&gstate->pen_regular);
00125 
00126     gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
00127     if (gstate->source->status)
00128        return CAIRO_STATUS_NO_MEMORY;
00129 
00130     gstate->next = NULL;
00131 
00132     return CAIRO_STATUS_SUCCESS;
00133 }
00134 
00135 static cairo_status_t
00136 _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
00137 {
00138     cairo_status_t status;
00139     cairo_gstate_t *next;
00140     
00141     /* Copy all members, but don't smash the next pointer */
00142     next = gstate->next;
00143     *gstate = *other;
00144     gstate->next = next;
00145 
00146     /* Now fix up pointer data that needs to be cloned/referenced */
00147     if (other->dash) {
00148        gstate->dash = malloc (other->num_dashes * sizeof (double));
00149        if (gstate->dash == NULL)
00150            return CAIRO_STATUS_NO_MEMORY;
00151        memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
00152     }
00153 
00154     _cairo_clip_init_copy (&gstate->clip, &other->clip);
00155 
00156     if (gstate->font_face)
00157        cairo_font_face_reference (gstate->font_face);
00158 
00159     if (gstate->scaled_font)
00160        cairo_scaled_font_reference (gstate->scaled_font);
00161     
00162     cairo_surface_reference (gstate->target);
00163 
00164     cairo_pattern_reference (gstate->source);
00165     
00166     status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
00167     if (status)
00168        goto CLEANUP_FONT;
00169 
00170     return status;
00171 
00172   CLEANUP_FONT:
00173     cairo_scaled_font_destroy (gstate->scaled_font);
00174     gstate->scaled_font = NULL;
00175     
00176     free (gstate->dash);
00177     gstate->dash = NULL;
00178 
00179     return CAIRO_STATUS_NO_MEMORY;
00180 }
00181 
00182 static void
00183 _cairo_gstate_fini (cairo_gstate_t *gstate)
00184 {
00185     if (gstate->font_face)
00186        cairo_font_face_destroy (gstate->font_face);
00187 
00188     if (gstate->scaled_font)
00189        cairo_scaled_font_destroy (gstate->scaled_font);
00190 
00191     if (gstate->target) {
00192        cairo_surface_destroy (gstate->target);
00193        gstate->target = NULL;
00194     }
00195 
00196     _cairo_clip_fini (&gstate->clip);
00197 
00198     cairo_pattern_destroy (gstate->source);
00199 
00200     _cairo_pen_fini (&gstate->pen_regular);
00201 
00202     if (gstate->dash) {
00203        free (gstate->dash);
00204        gstate->dash = NULL;
00205     }
00206 }
00207 
00208 void
00209 _cairo_gstate_destroy (cairo_gstate_t *gstate)
00210 {
00211     _cairo_gstate_fini (gstate);
00212     free (gstate);
00213 }
00214 
00215 cairo_gstate_t*
00216 _cairo_gstate_clone (cairo_gstate_t *gstate)
00217 {
00218     cairo_status_t status;
00219     cairo_gstate_t *clone;
00220 
00221     clone = malloc (sizeof (cairo_gstate_t));
00222     if (clone) {
00223        status = _cairo_gstate_init_copy (clone, gstate);
00224        if (status) {
00225            free (clone);
00226            return NULL;
00227        }
00228        clone->next = NULL;
00229     }
00230 
00231     return clone;
00232 }
00233 
00234 /* Push rendering off to an off-screen group. */
00235 /* XXX: Rethinking this API
00236 cairo_status_t
00237 _cairo_gstate_begin_group (cairo_gstate_t *gstate)
00238 {
00239     Pixmap pix;
00240     unsigned int width, height;
00241 
00242     gstate->parent_surface = gstate->target;
00243 
00244     width = _cairo_surface_get_width (gstate->target);
00245     height = _cairo_surface_get_height (gstate->target);
00246 
00247     pix = XCreatePixmap (gstate->dpy,
00248                       _cairo_surface_get_drawable (gstate->target),
00249                       width, height,
00250                       _cairo_surface_get_depth (gstate->target));
00251     if (pix == 0)
00252        return CAIRO_STATUS_NO_MEMORY;
00253 
00254     gstate->target = cairo_surface_create (gstate->dpy);
00255     if (gstate->target->status)
00256        return gstate->target->status;
00257 
00258     _cairo_surface_set_drawableWH (gstate->target, pix, width, height);
00259 
00260     status = _cairo_surface_fill_rectangle (gstate->target,
00261                                    CAIRO_OPERATOR_CLEAR,
00262                                CAIRO_COLOR_TRANSPARENT,
00263                                0, 0,
00264                                 _cairo_surface_get_width (gstate->target),
00265                                _cairo_surface_get_height (gstate->target));
00266     if (status)                            
00267         return status;
00268 
00269     return CAIRO_STATUS_SUCCESS;
00270 }
00271 */
00272 
00273 /* Complete the current offscreen group, composing its contents onto the parent surface. */
00274 /* XXX: Rethinking this API
00275 cairo_status_t
00276 _cairo_gstate_end_group (cairo_gstate_t *gstate)
00277 {
00278     Pixmap pix;
00279     cairo_color_t mask_color;
00280     cairo_surface_t mask;
00281 
00282     if (gstate->parent_surface == NULL)
00283        return CAIRO_STATUS_INVALID_POP_GROUP;
00284 
00285     _cairo_surface_init (&mask, gstate->dpy);
00286     _cairo_color_init (&mask_color);
00287 
00288     _cairo_surface_set_solid_color (&mask, &mask_color);
00289 
00290     * XXX: This could be made much more efficient by using
00291        _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept
00292        track of such informaton. *
00293     _cairo_surface_composite (gstate->operator,
00294                            gstate->target,
00295                            mask,
00296                            gstate->parent_surface,
00297                            0, 0,
00298                            0, 0,
00299                            0, 0,
00300                            _cairo_surface_get_width (gstate->target),
00301                            _cairo_surface_get_height (gstate->target));
00302 
00303     _cairo_surface_fini (&mask);
00304 
00305     pix = _cairo_surface_get_drawable (gstate->target);
00306     XFreePixmap (gstate->dpy, pix);
00307 
00308     cairo_surface_destroy (gstate->target);
00309     gstate->target = gstate->parent_surface;
00310     gstate->parent_surface = NULL;
00311 
00312     return CAIRO_STATUS_SUCCESS;
00313 }
00314 */
00315 
00316 cairo_surface_t *
00317 _cairo_gstate_get_target (cairo_gstate_t *gstate)
00318 {
00319     return gstate->target;
00320 }
00321 
00322 cairo_status_t
00323 _cairo_gstate_set_source (cairo_gstate_t  *gstate,
00324                        cairo_pattern_t *source)
00325 {
00326     if (source->status)
00327        return source->status;
00328 
00329     cairo_pattern_reference (source);
00330     cairo_pattern_destroy (gstate->source);
00331     gstate->source = source;
00332     gstate->source_ctm_inverse = gstate->ctm_inverse;
00333     
00334     return CAIRO_STATUS_SUCCESS;
00335 }
00336 
00337 cairo_pattern_t *
00338 _cairo_gstate_get_source (cairo_gstate_t *gstate)
00339 {
00340     if (gstate == NULL)
00341        return NULL;
00342 
00343     return gstate->source;
00344 }
00345 
00346 cairo_status_t
00347 _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
00348 {
00349     gstate->operator = operator;
00350 
00351     return CAIRO_STATUS_SUCCESS;
00352 }
00353 
00354 cairo_operator_t
00355 _cairo_gstate_get_operator (cairo_gstate_t *gstate)
00356 {
00357     return gstate->operator;
00358 }
00359 
00360 cairo_status_t
00361 _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
00362 {
00363     gstate->tolerance = tolerance;
00364 
00365     return CAIRO_STATUS_SUCCESS;
00366 }
00367 
00368 double
00369 _cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
00370 {
00371     return gstate->tolerance;
00372 }
00373 
00374 cairo_status_t
00375 _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
00376 {
00377     gstate->fill_rule = fill_rule;
00378 
00379     return CAIRO_STATUS_SUCCESS;
00380 }
00381 
00382 cairo_fill_rule_t
00383 _cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
00384 {
00385     return gstate->fill_rule;
00386 }
00387 
00388 cairo_status_t
00389 _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
00390 {
00391     gstate->line_width = width;
00392 
00393     return CAIRO_STATUS_SUCCESS;
00394 }
00395 
00396 double
00397 _cairo_gstate_get_line_width (cairo_gstate_t *gstate)
00398 {
00399     return gstate->line_width;
00400 }
00401 
00402 cairo_status_t
00403 _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
00404 {
00405     gstate->line_cap = line_cap;
00406 
00407     return CAIRO_STATUS_SUCCESS;
00408 }
00409 
00410 cairo_line_cap_t
00411 _cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
00412 {
00413     return gstate->line_cap;
00414 }
00415 
00416 cairo_status_t
00417 _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
00418 {
00419     gstate->line_join = line_join;
00420 
00421     return CAIRO_STATUS_SUCCESS;
00422 }
00423 
00424 cairo_line_join_t
00425 _cairo_gstate_get_line_join (cairo_gstate_t *gstate)
00426 {
00427     return gstate->line_join;
00428 }
00429 
00430 cairo_status_t
00431 _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset)
00432 {
00433     int i;
00434     double dash_total;
00435 
00436     if (gstate->dash)
00437        free (gstate->dash);
00438     
00439     gstate->num_dashes = num_dashes;
00440 
00441     if (gstate->num_dashes == 0) {
00442        gstate->dash = NULL;
00443        gstate->dash_offset = 0.0;
00444        return CAIRO_STATUS_SUCCESS;
00445     }
00446 
00447     gstate->dash = malloc (gstate->num_dashes * sizeof (double));
00448     if (gstate->dash == NULL) {
00449        gstate->num_dashes = 0;
00450        return CAIRO_STATUS_NO_MEMORY;
00451     }
00452 
00453     memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
00454     
00455     dash_total = 0.0;
00456     for (i = 0; i < gstate->num_dashes; i++) {
00457        if (gstate->dash[i] < 0)
00458            return CAIRO_STATUS_INVALID_DASH;
00459        dash_total += gstate->dash[i];
00460     }
00461 
00462     if (dash_total == 0.0)
00463        return CAIRO_STATUS_INVALID_DASH;
00464 
00465     /* A single dash value indicate symmetric repeating, so the total
00466      * is twice as long. */
00467     if (gstate->num_dashes == 1)
00468        dash_total *= 2;
00469 
00470     /* The dashing code doesn't like a negative offset, so we compute
00471      * the equivalent positive offset. */
00472     if (offset < 0)
00473        offset += ceil (-offset / dash_total + 0.5) * dash_total;
00474 
00475     gstate->dash_offset = offset;
00476 
00477     return CAIRO_STATUS_SUCCESS;
00478 }
00479 
00480 cairo_status_t
00481 _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
00482 {
00483     gstate->miter_limit = limit;
00484 
00485     return CAIRO_STATUS_SUCCESS;
00486 }
00487 
00488 double
00489 _cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
00490 {
00491     return gstate->miter_limit;
00492 }
00493 
00494 static void
00495 _cairo_gstate_apply_device_transform (cairo_gstate_t    *gstate,
00496                                   cairo_matrix_t *matrix)
00497 {
00498     if (gstate->target->device_x_scale != 1.0 ||
00499        gstate->target->device_y_scale != 1.0)
00500     {
00501        cairo_matrix_scale (matrix,
00502                          gstate->target->device_x_scale,
00503                          gstate->target->device_y_scale);
00504     }
00505 }
00506 
00507 static void
00508 _cairo_gstate_apply_device_inverse_transform (cairo_gstate_t    *gstate,
00509                                          cairo_matrix_t *matrix)
00510 {
00511     if (gstate->target->device_x_scale != 1.0 ||
00512        gstate->target->device_y_scale != 1.0)
00513     {
00514        cairo_matrix_scale (matrix,
00515                          1/gstate->target->device_x_scale,
00516                          1/gstate->target->device_y_scale);
00517     }
00518 }
00519 
00520 void
00521 _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
00522 {
00523     *matrix = gstate->ctm;
00524     _cairo_gstate_apply_device_inverse_transform (gstate, matrix);
00525 }
00526 
00527 cairo_status_t
00528 _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
00529 {
00530     cairo_matrix_t tmp;
00531 
00532     _cairo_gstate_unset_scaled_font (gstate);
00533     
00534     cairo_matrix_init_translate (&tmp, tx, ty);
00535     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
00536 
00537     cairo_matrix_init_translate (&tmp, -tx, -ty);
00538     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
00539 
00540     return CAIRO_STATUS_SUCCESS;
00541 }
00542 
00543 cairo_status_t
00544 _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
00545 {
00546     cairo_matrix_t tmp;
00547 
00548     if (sx == 0 || sy == 0)
00549        return CAIRO_STATUS_INVALID_MATRIX;
00550 
00551     _cairo_gstate_unset_scaled_font (gstate);
00552     
00553     cairo_matrix_init_scale (&tmp, sx, sy);
00554     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
00555 
00556     cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
00557     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
00558 
00559     return CAIRO_STATUS_SUCCESS;
00560 }
00561 
00562 cairo_status_t
00563 _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
00564 {
00565     cairo_matrix_t tmp;
00566 
00567     _cairo_gstate_unset_scaled_font (gstate);
00568     
00569     cairo_matrix_init_rotate (&tmp, angle);
00570     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
00571 
00572     cairo_matrix_init_rotate (&tmp, -angle);
00573     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
00574 
00575     return CAIRO_STATUS_SUCCESS;
00576 }
00577 
00578 cairo_status_t
00579 _cairo_gstate_transform (cairo_gstate_t         *gstate,
00580                       const cairo_matrix_t *matrix)
00581 {
00582     cairo_matrix_t tmp;
00583 
00584     _cairo_gstate_unset_scaled_font (gstate);
00585     
00586     tmp = *matrix;
00587     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
00588 
00589     cairo_matrix_invert (&tmp);
00590     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
00591 
00592     return CAIRO_STATUS_SUCCESS;
00593 }
00594 
00595 cairo_status_t
00596 _cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
00597                        const cairo_matrix_t *matrix)
00598 {
00599     cairo_status_t status;
00600 
00601     _cairo_gstate_unset_scaled_font (gstate);
00602     
00603     gstate->ctm = *matrix;
00604 
00605     gstate->ctm_inverse = *matrix;
00606     status = cairo_matrix_invert (&gstate->ctm_inverse);
00607     if (status)
00608        return status;
00609 
00610     _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
00611     _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
00612 
00613     return CAIRO_STATUS_SUCCESS;
00614 }
00615 
00616 cairo_status_t
00617 _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
00618 {
00619     _cairo_gstate_unset_scaled_font (gstate);
00620     
00621     cairo_matrix_init_identity (&gstate->ctm);
00622     cairo_matrix_init_identity (&gstate->ctm_inverse);
00623 
00624     _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
00625     _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
00626 
00627     return CAIRO_STATUS_SUCCESS;
00628 }
00629 
00630 cairo_status_t
00631 _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
00632 {
00633     cairo_matrix_transform_point (&gstate->ctm, x, y);
00634 
00635     return CAIRO_STATUS_SUCCESS;
00636 }
00637 
00638 cairo_status_t
00639 _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
00640                                    double *dx, double *dy)
00641 {
00642     cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
00643 
00644     return CAIRO_STATUS_SUCCESS;
00645 }
00646 
00647 cairo_status_t
00648 _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
00649 {
00650     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
00651 
00652     return CAIRO_STATUS_SUCCESS;
00653 }
00654 
00655 cairo_status_t
00656 _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
00657                                    double *dx, double *dy)
00658 {
00659     cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
00660 
00661     return CAIRO_STATUS_SUCCESS;
00662 }
00663 
00664 void
00665 _cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
00666 {
00667     cairo_matrix_transform_point (&gstate->ctm, x, y);
00668     *x += gstate->target->device_x_offset;
00669     *y += gstate->target->device_y_offset;
00670 }
00671 
00672 void
00673 _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
00674 {
00675     *x -= gstate->target->device_x_offset;
00676     *y -= gstate->target->device_y_offset;
00677     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
00678 }
00679 
00680 /* XXX: NYI 
00681 cairo_status_t
00682 _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
00683 {
00684     cairo_status_t status;
00685 
00686     _cairo_pen_init (&gstate);
00687     return CAIRO_STATUS_SUCCESS;
00688 }
00689 */
00690 
00691 static void
00692 _cairo_gstate_copy_transformed_pattern (cairo_gstate_t  *gstate,
00693                                    cairo_pattern_t *pattern,
00694                                    cairo_pattern_t *original,
00695                                    cairo_matrix_t  *ctm_inverse)
00696 {
00697     cairo_matrix_t tmp_matrix = *ctm_inverse;
00698   
00699     _cairo_pattern_init_copy (pattern, original);
00700 
00701     if (gstate->target)
00702        cairo_matrix_translate (&tmp_matrix,
00703                             - gstate->target->device_x_offset,
00704                             - gstate->target->device_y_offset);
00705 
00706     _cairo_pattern_transform (pattern, &tmp_matrix);
00707 }
00708 
00709 static void
00710 _cairo_gstate_copy_transformed_source (cairo_gstate_t  *gstate,
00711                                    cairo_pattern_t *pattern)
00712 {
00713     _cairo_gstate_copy_transformed_pattern (gstate, pattern,
00714                                        gstate->source,
00715                                        &gstate->source_ctm_inverse);
00716 }
00717 
00718 static void
00719 _cairo_gstate_copy_transformed_mask (cairo_gstate_t  *gstate,
00720                                  cairo_pattern_t *pattern,
00721                                  cairo_pattern_t *mask)
00722 {
00723     _cairo_gstate_copy_transformed_pattern (gstate, pattern,
00724                                        mask,
00725                                        &gstate->ctm_inverse);
00726 }
00727 
00728 cairo_status_t
00729 _cairo_gstate_paint (cairo_gstate_t *gstate)
00730 {
00731     cairo_rectangle_t rectangle;
00732     cairo_status_t status;
00733     cairo_box_t box;
00734     cairo_traps_t traps;
00735 
00736     if (gstate->source->status)
00737        return gstate->source->status;
00738 
00739     status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
00740     if (status)
00741        return status;
00742 
00743     status = _cairo_surface_get_extents (gstate->target, &rectangle);
00744     if (status)
00745        return status;
00746     status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &rectangle);
00747     if (status)
00748        return status;
00749 
00750     box.p1.x = _cairo_fixed_from_int (rectangle.x);
00751     box.p1.y = _cairo_fixed_from_int (rectangle.y);
00752     box.p2.x = _cairo_fixed_from_int (rectangle.x + rectangle.width);
00753     box.p2.y = _cairo_fixed_from_int (rectangle.y + rectangle.height);
00754     status = _cairo_traps_init_box (&traps, &box);
00755     if (status)
00756        return status;
00757     
00758     _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
00759 
00760     _cairo_traps_fini (&traps);
00761 
00762     return CAIRO_STATUS_SUCCESS;
00763 }
00764 
00778 cairo_bool_t
00779 _cairo_operator_bounded (cairo_operator_t operator)
00780 {
00781     switch (operator) {
00782     case CAIRO_OPERATOR_CLEAR:
00783     case CAIRO_OPERATOR_SOURCE:
00784     case CAIRO_OPERATOR_OVER:
00785     case CAIRO_OPERATOR_ATOP:
00786     case CAIRO_OPERATOR_DEST:
00787     case CAIRO_OPERATOR_DEST_OVER:
00788     case CAIRO_OPERATOR_DEST_OUT:
00789     case CAIRO_OPERATOR_XOR:
00790     case CAIRO_OPERATOR_ADD:
00791     case CAIRO_OPERATOR_SATURATE:
00792        return TRUE;
00793     case CAIRO_OPERATOR_OUT:
00794     case CAIRO_OPERATOR_IN:
00795     case CAIRO_OPERATOR_DEST_IN:
00796     case CAIRO_OPERATOR_DEST_ATOP:
00797        return FALSE;
00798     }
00799     
00800     ASSERT_NOT_REACHED;
00801     return FALSE;
00802 }
00803 
00804 typedef cairo_status_t (*cairo_draw_func_t) (void                    *closure,
00805                                         cairo_operator_t         operator,
00806                                         cairo_pattern_t         *src,
00807                                         cairo_surface_t         *dst,
00808                                         int                      dst_x,
00809                                         int                      dst_y,
00810                                         const cairo_rectangle_t *extents);
00811 
00812 static cairo_status_t
00813 _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
00814                             cairo_clip_t            *clip,
00815                             cairo_draw_func_t        draw_func,
00816                             void                    *draw_closure,
00817                             cairo_surface_t         *dst,
00818                             const cairo_rectangle_t *extents)
00819 {
00820     cairo_surface_t *mask;
00821     cairo_status_t status;
00822     
00823     mask = cairo_surface_create_similar (dst,
00824                                     CAIRO_CONTENT_ALPHA,
00825                                     extents->width,
00826                                     extents->height);
00827     if (mask->status)
00828        return CAIRO_STATUS_NO_MEMORY;
00829     
00830     status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
00831                         NULL, mask,
00832                         extents->x, extents->y,
00833                         extents);
00834     if (status)
00835        goto CLEANUP_SURFACE;
00836 
00837     if (clip->surface)
00838        status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
00839                                            mask,
00840                                            extents->x, extents->y,
00841                                            extents);
00842     if (status)
00843        goto CLEANUP_SURFACE;
00844     
00845     _cairo_pattern_init_for_surface (mask_pattern, mask);
00846 
00847  CLEANUP_SURFACE:
00848     cairo_surface_destroy (mask);
00849 
00850     return status;
00851 }
00852 
00853 /* Handles compositing with a clip surface when the operator allows
00854  * us to combine the clip with the mask
00855  */
00856 static cairo_status_t
00857 _cairo_gstate_clip_and_composite_with_mask (cairo_clip_t            *clip,
00858                                        cairo_operator_t         operator,
00859                                        cairo_pattern_t         *src,
00860                                        cairo_draw_func_t        draw_func,
00861                                        void                    *draw_closure,
00862                                        cairo_surface_t         *dst,
00863                                        const cairo_rectangle_t *extents)
00864 {
00865     cairo_surface_pattern_t mask_pattern;
00866     cairo_status_t status;
00867 
00868     status = _create_composite_mask_pattern (&mask_pattern,
00869                                         clip,
00870                                         draw_func, draw_closure,
00871                                         dst, extents);
00872     if (status)
00873        return status;
00874        
00875     status = _cairo_surface_composite (operator,
00876                                    src, &mask_pattern.base, dst,
00877                                    extents->x,     extents->y,
00878                                    0,              0,
00879                                    extents->x,     extents->y,
00880                                    extents->width, extents->height);
00881 
00882     _cairo_pattern_fini (&mask_pattern.base);
00883 
00884     return status;
00885 }
00886 
00887 /* Handles compositing with a clip surface when we have to do the operation
00888  * in two pieces and combine them together.
00889  */
00890 static cairo_status_t
00891 _cairo_gstate_clip_and_composite_combine (cairo_clip_t            *clip,
00892                                      cairo_operator_t         operator,
00893                                      cairo_pattern_t         *src,
00894                                      cairo_draw_func_t        draw_func,
00895                                      void                    *draw_closure,
00896                                      cairo_surface_t         *dst,
00897                                      const cairo_rectangle_t *extents)
00898 {
00899     cairo_surface_t *intermediate;
00900     cairo_surface_pattern_t dst_pattern;
00901     cairo_surface_pattern_t intermediate_pattern;
00902     cairo_status_t status;
00903 
00904     /* We'd be better off here creating a surface identical in format
00905      * to dst, but we have no way of getting that information.
00906      * A CAIRO_CONTENT_CLONE or something might be useful.
00907      * cairo_surface_create_similar() also unnecessarily clears the surface.
00908      */
00909     intermediate = cairo_surface_create_similar (dst,
00910                                            CAIRO_CONTENT_COLOR_ALPHA,
00911                                            extents->width,
00912                                            extents->height);
00913     if (intermediate->status)
00914        return CAIRO_STATUS_NO_MEMORY;
00915 
00916     /* Initialize the intermediate surface from the destination surface
00917      */
00918     _cairo_pattern_init_for_surface (&dst_pattern, dst);
00919 
00920     status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
00921                                    &dst_pattern.base, NULL, intermediate,
00922                                    extents->x,     extents->y,
00923                                    0,              0,
00924                                    0,              0,
00925                                    extents->width, extents->height);
00926 
00927     _cairo_pattern_fini (&dst_pattern.base);
00928 
00929     if (status)
00930        goto CLEANUP_SURFACE;
00931 
00932     status = (*draw_func) (draw_closure, operator,
00933                         src, intermediate,
00934                         extents->x, extents->y,
00935                         extents);
00936     if (status)
00937        goto CLEANUP_SURFACE;
00938 
00939     /* Combine that with the clip
00940      */
00941     status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
00942                                         intermediate,
00943                                         extents->x, extents->y,                                        
00944                                         extents);
00945     if (status)
00946        goto CLEANUP_SURFACE;
00947 
00948     /* Punch the clip out of the destination
00949      */
00950     status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
00951                                         dst,
00952                                         0, 0,
00953                                         extents);
00954     if (status)
00955        goto CLEANUP_SURFACE;
00956 
00957     /* Now add the two results together
00958      */
00959     _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
00960     
00961     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
00962                                    &intermediate_pattern.base, NULL, dst,
00963                                    0,              0,
00964                                    0,              0,
00965                                    extents->x,     extents->y,
00966                                    extents->width, extents->height);
00967 
00968     _cairo_pattern_fini (&intermediate_pattern.base);
00969     
00970  CLEANUP_SURFACE:
00971     cairo_surface_destroy (intermediate);
00972 
00973     return status;
00974 }
00975 
00976 /* Handles compositing for CAIRO_OPERATOR_SOURCE, which is special; it's
00977  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
00978  */
00979 static cairo_status_t
00980 _cairo_gstate_clip_and_composite_source (cairo_clip_t            *clip,
00981                                     cairo_pattern_t         *src,
00982                                     cairo_draw_func_t        draw_func,
00983                                     void                    *draw_closure,
00984                                     cairo_surface_t         *dst,
00985                                     const cairo_rectangle_t *extents)
00986 {
00987     cairo_surface_pattern_t mask_pattern;
00988     cairo_status_t status;
00989 
00990     /* Create a surface that is mask IN clip
00991      */
00992     status = _create_composite_mask_pattern (&mask_pattern,
00993                                         clip,
00994                                         draw_func, draw_closure,
00995                                         dst, extents);
00996     if (status)
00997        return status;
00998     
00999     /* Compute dest' = dest OUT (mask IN clip)
01000      */
01001     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
01002                                    &mask_pattern.base, NULL, dst,
01003                                    0,              0,
01004                                    0,              0,
01005                                    extents->x,     extents->y,
01006                                    extents->width, extents->height);
01007 
01008     if (status)
01009        goto CLEANUP_MASK_PATTERN;
01010 
01011     /* Now compute (src IN (mask IN clip)) ADD dest'
01012      */
01013     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
01014                                    src, &mask_pattern.base, dst,
01015                                    extents->x,     extents->y,
01016                                    0,              0,
01017                                    extents->x,     extents->y,
01018                                    extents->width, extents->height);
01019 
01020  CLEANUP_MASK_PATTERN:
01021     _cairo_pattern_fini (&mask_pattern.base);
01022     return status;
01023 }
01024 
01025 static int
01026 _cairo_rectangle_empty (const cairo_rectangle_t *rect)
01027 {
01028     return rect->width == 0 || rect->height == 0;
01029 }
01030 
01052 static cairo_status_t
01053 _cairo_gstate_clip_and_composite (cairo_clip_t            *clip,
01054                               cairo_operator_t         operator,
01055                               cairo_pattern_t         *src,
01056                               cairo_draw_func_t        draw_func,
01057                               void                    *draw_closure,
01058                               cairo_surface_t         *dst,
01059                               const cairo_rectangle_t *extents)
01060 {
01061     cairo_pattern_union_t solid_pattern;
01062     cairo_status_t status;
01063 
01064     if (_cairo_rectangle_empty (extents))
01065        /* Nothing to do */
01066        return CAIRO_STATUS_SUCCESS;
01067 
01068     if (operator == CAIRO_OPERATOR_CLEAR) {
01069        _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
01070        src = &solid_pattern.base;
01071        operator = CAIRO_OPERATOR_DEST_OUT;
01072     }
01073 
01074     if (clip->surface || operator == CAIRO_OPERATOR_SOURCE)
01075     {
01076        if (operator == CAIRO_OPERATOR_SOURCE)
01077            status = _cairo_gstate_clip_and_composite_source (clip,
01078                                                        src,
01079                                                        draw_func, draw_closure,
01080                                                        dst, extents);
01081        else if (_cairo_operator_bounded (operator))
01082            status = _cairo_gstate_clip_and_composite_with_mask (clip, operator,
01083                                                          src,
01084                                                          draw_func, draw_closure,
01085                                                          dst, extents);
01086        else
01087            status = _cairo_gstate_clip_and_composite_combine (clip, operator,
01088                                                         src,
01089                                                         draw_func, draw_closure,
01090                                                         dst, extents);
01091     }
01092     else
01093     {
01094        status = (*draw_func) (draw_closure, operator,
01095                             src, dst,
01096                             0, 0,
01097                             extents);
01098     }
01099 
01100     if (src == &solid_pattern.base)
01101        _cairo_pattern_fini (&solid_pattern.base);
01102 
01103     return status;
01104 }
01105                             
01106 
01107 static cairo_status_t
01108 _get_mask_extents (cairo_gstate_t    *gstate,
01109                  cairo_pattern_t   *mask,
01110                  cairo_rectangle_t *extents)
01111 {
01112     cairo_status_t status;
01113 
01114     /*
01115      * XXX should take mask extents into account, but
01116      * that involves checking the transform and
01117      * _cairo_operator_bounded (operator)...  For now,
01118      * be lazy and just use the destination extents
01119      */
01120     status = _cairo_surface_get_extents (gstate->target, extents);
01121     if (status)
01122        return status;
01123 
01124     return _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
01125 }
01126 
01127 static cairo_status_t
01128 _cairo_gstate_mask_draw_func (void                    *closure,
01129                            cairo_operator_t         operator,
01130                            cairo_pattern_t         *src,
01131                            cairo_surface_t         *dst,
01132                            int                      dst_x,
01133                            int                      dst_y,
01134                            const cairo_rectangle_t *extents)
01135 {
01136     cairo_pattern_t *mask = closure;
01137 
01138     if (src)
01139        return _cairo_surface_composite (operator,
01140                                     src, mask, dst,
01141                                     extents->x,         extents->y,
01142                                     extents->x,         extents->y,
01143                                     extents->x - dst_x, extents->y - dst_y,
01144                                     extents->width,     extents->height);
01145     else
01146        return _cairo_surface_composite (operator,
01147                                     mask, NULL, dst,
01148                                     extents->x,         extents->y,
01149                                     0,                  0, /* unused */
01150                                     extents->x - dst_x, extents->y - dst_y,
01151                                     extents->width,     extents->height);
01152 }
01153 
01154 cairo_status_t
01155 _cairo_gstate_mask (cairo_gstate_t  *gstate,
01156                   cairo_pattern_t *mask)
01157 {
01158     cairo_rectangle_t extents;
01159     cairo_pattern_union_t source_pattern, mask_pattern;
01160     cairo_status_t status;
01161 
01162     if (mask->status)
01163        return mask->status;
01164 
01165     if (gstate->source->status)
01166        return gstate->source->status;
01167 
01168     status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
01169     if (status)
01170        return status;
01171 
01172     _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
01173     _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
01174     
01175     _get_mask_extents (gstate, &mask_pattern.base, &extents);
01176     
01177     status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
01178                                           &source_pattern.base, 
01179                                           _cairo_gstate_mask_draw_func, &mask_pattern.base,
01180                                           gstate->target,
01181                                           &extents);
01182 
01183     _cairo_pattern_fini (&source_pattern.base);
01184     _cairo_pattern_fini (&mask_pattern.base);
01185 
01186     return status;
01187 }
01188 
01189 cairo_status_t
01190 _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
01191 {
01192     cairo_status_t status;
01193     cairo_traps_t traps;
01194 
01195     if (gstate->source->status)
01196        return gstate->source->status;
01197 
01198     if (gstate->line_width <= 0.0)
01199        return CAIRO_STATUS_SUCCESS;
01200 
01201     status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
01202     if (status)
01203        return status;
01204 
01205     _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
01206 
01207     _cairo_traps_init (&traps);
01208 
01209     status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
01210     if (status) {
01211        _cairo_traps_fini (&traps);
01212        return status;
01213     }
01214 
01215     _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
01216 
01217     _cairo_traps_fini (&traps);
01218 
01219     return CAIRO_STATUS_SUCCESS;
01220 }
01221 
01222 cairo_status_t
01223 _cairo_gstate_in_stroke (cairo_gstate_t       *gstate,
01224                       cairo_path_fixed_t *path,
01225                       double                   x,
01226                       double                   y,
01227                       cairo_bool_t     *inside_ret)
01228 {
01229     cairo_status_t status = CAIRO_STATUS_SUCCESS;
01230     cairo_traps_t traps;
01231 
01232     _cairo_gstate_user_to_backend (gstate, &x, &y);
01233 
01234     _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
01235 
01236     _cairo_traps_init (&traps);
01237 
01238     status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
01239     if (status)
01240        goto BAIL;
01241 
01242     *inside_ret = _cairo_traps_contain (&traps, x, y);
01243 
01244 BAIL:
01245     _cairo_traps_fini (&traps);
01246 
01247     return status;
01248 }
01249 
01250 /* XXX We currently have a confusing mix of boxes and rectangles as
01251  * exemplified by this function.  A cairo_box_t is a rectangular area
01252  * represented by the coordinates of the upper left and lower right
01253  * corners, expressed in fixed point numbers.  A cairo_rectangle_t is
01254  * also a rectangular area, but represented by the upper left corner
01255  * and the width and the height, as integer numbers.
01256  *
01257  * This function converts a cairo_box_t to a cairo_rectangle_t by
01258  * increasing the area to the nearest integer coordinates.  We should
01259  * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and
01260  * this function could be renamed to the more reasonable
01261  * _cairo_rectangle_fixed_round.
01262  */
01263 
01264 void
01265 _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
01266 {
01267     rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
01268     rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
01269     rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
01270     rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
01271 }
01272 
01273 void
01274 _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
01275 {
01276     int x1, y1, x2, y2;
01277 
01278     x1 = MAX (dest->x, src->x);
01279     y1 = MAX (dest->y, src->y);
01280     x2 = MIN (dest->x + dest->width, src->x + src->width);
01281     y2 = MIN (dest->y + dest->height, src->y + src->height);
01282 
01283     if (x1 >= x2 || y1 >= y2) {
01284        dest->x = 0;
01285        dest->y = 0;
01286        dest->width = 0;
01287        dest->height = 0;
01288     } else {
01289        dest->x = x1;
01290        dest->y = y1;
01291        dest->width = x2 - x1;
01292        dest->height = y2 - y1;
01293     }  
01294 }
01295 
01296 /* Composites a region representing a set of trapezoids.
01297  */
01298 static cairo_status_t
01299 _composite_trap_region (cairo_clip_t      *clip,
01300                      cairo_pattern_t   *src,
01301                      cairo_operator_t   operator,
01302                      cairo_surface_t   *dst,
01303                      pixman_region16_t *trap_region,
01304                      cairo_rectangle_t *extents)
01305 {
01306     cairo_status_t status;
01307     cairo_pattern_union_t solid_pattern;
01308     cairo_pattern_union_t mask;
01309     int num_rects = pixman_region_num_rects (trap_region);
01310     unsigned int clip_serial;
01311 
01312     if (clip->surface && operator == CAIRO_OPERATOR_CLEAR) {
01313        _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE);
01314        src = &solid_pattern.base;
01315        operator = CAIRO_OPERATOR_DEST_OUT;
01316     }
01317 
01318     if (num_rects == 0)
01319        return CAIRO_STATUS_SUCCESS;
01320     
01321     if (num_rects > 1) {
01322        if (clip->mode != CAIRO_CLIP_MODE_REGION)
01323            return CAIRO_INT_STATUS_UNSUPPORTED;
01324        
01325        clip_serial = _cairo_surface_allocate_clip_serial (dst);
01326        status = _cairo_surface_set_clip_region (dst,
01327                                            trap_region,
01328                                            clip_serial);
01329        if (status)
01330            return status;
01331     }
01332     
01333     if (clip->surface)
01334        _cairo_pattern_init_for_surface (&mask.surface, clip->surface);
01335        
01336     status = _cairo_surface_composite (operator,
01337                                    src,
01338                                    clip->surface ? &mask.base : NULL,
01339                                    dst,
01340                                    extents->x, extents->y,
01341                                    extents->x - (clip->surface ? clip->surface_rect.x : 0),
01342                                    extents->y - (clip->surface ? clip->surface_rect.y : 0),
01343                                    extents->x, extents->y,
01344                                    extents->width, extents->height);
01345 
01346     if (clip->surface)
01347       _cairo_pattern_fini (&mask.base);
01348 
01349     if (src == &solid_pattern.base)
01350        _cairo_pattern_fini (&solid_pattern.base);
01351 
01352     return status;
01353 }
01354 
01355 typedef struct {
01356     cairo_traps_t *traps;
01357     cairo_antialias_t antialias;
01358 } cairo_composite_traps_info_t;
01359 
01360 static cairo_status_t
01361 _composite_traps_draw_func (void                    *closure,
01362                          cairo_operator_t         operator,
01363                          cairo_pattern_t         *src,
01364                          cairo_surface_t         *dst,
01365                          int                      dst_x,
01366                          int                      dst_y,
01367                          const cairo_rectangle_t *extents)
01368 {
01369     cairo_composite_traps_info_t *info = closure;
01370     cairo_pattern_union_t pattern;
01371     cairo_status_t status;
01372     
01373     if (dst_x != 0 || dst_y != 0)
01374        _cairo_traps_translate (info->traps, - dst_x, - dst_y);
01375 
01376     _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
01377     if (!src)
01378        src = &pattern.base;
01379     
01380     status = _cairo_surface_composite_trapezoids (operator,
01381                                             src, dst, info->antialias,
01382                                             extents->x,         extents->y,
01383                                             extents->x - dst_x, extents->y - dst_y,
01384                                             extents->width,     extents->height,
01385                                             info->traps->traps,
01386                                             info->traps->num_traps);
01387     _cairo_pattern_fini (&pattern.base);
01388 
01389     return status;
01390 }
01391 
01392 /* Warning: This call modifies the coordinates of traps */
01393 cairo_status_t
01394 _cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src,
01395                                          cairo_operator_t operator,
01396                                          cairo_surface_t *dst,
01397                                          cairo_traps_t *traps,
01398                                          cairo_clip_t *clip,
01399                                          cairo_antialias_t antialias)
01400 {
01401     cairo_status_t status;
01402     pixman_region16_t *trap_region;
01403     pixman_region16_t *clear_region = NULL;
01404     cairo_rectangle_t extents;
01405     cairo_composite_traps_info_t traps_info;
01406     
01407     if (traps->num_traps == 0)
01408        return CAIRO_STATUS_SUCCESS;
01409 
01410     status = _cairo_traps_extract_region (traps, &trap_region);
01411     if (status)
01412        return status;
01413 
01414     if (_cairo_operator_bounded (operator))
01415     {
01416        if (trap_region) {
01417            status = _cairo_clip_intersect_to_region (clip, trap_region);
01418            _cairo_region_extents_rectangle (trap_region, &extents);
01419        } else {
01420            cairo_box_t trap_extents;
01421            _cairo_traps_extents (traps, &trap_extents);
01422            _cairo_box_round_to_rectangle (&trap_extents, &extents);
01423            status = _cairo_clip_intersect_to_rectangle (clip, &extents);
01424        }
01425     }
01426     else
01427     {
01428        status = _cairo_surface_get_extents (dst, &extents);
01429        if (status)
01430            return status;
01431        
01432        if (trap_region && !clip->surface) {
01433            /* If we optimize drawing with an unbounded operator to
01434             * _cairo_surface_fill_rectangles() or to drawing with a
01435             * clip region, then we have an additional region to clear.
01436             */
01437            status = _cairo_surface_get_extents (dst, &extents);
01438            if (status)
01439               return status;
01440            
01441            clear_region = _cairo_region_create_from_rectangle (&extents);
01442            status = _cairo_clip_intersect_to_region (clip, clear_region);
01443            if (status)
01444               return status;
01445            
01446            _cairo_region_extents_rectangle (clear_region,  &extents);
01447            
01448            if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
01449               return CAIRO_STATUS_NO_MEMORY;
01450            
01451            if (!pixman_region_not_empty (clear_region)) {
01452               pixman_region_destroy (clear_region);
01453               clear_region = NULL;
01454            }
01455        } else {
01456            status = _cairo_clip_intersect_to_rectangle (clip, &extents);
01457            if (status)
01458               return status;
01459        }
01460     }
01461        
01462     if (status)
01463        goto out;
01464     
01465     if (trap_region)
01466     {
01467        if ((src->type == CAIRO_PATTERN_SOLID || operator == CAIRO_OPERATOR_CLEAR) &&
01468            !clip->surface)
01469        {
01470            const cairo_color_t *color;
01471 
01472            if (operator == CAIRO_OPERATOR_CLEAR)
01473               color = CAIRO_COLOR_TRANSPARENT;
01474            else
01475               color = &((cairo_solid_pattern_t *)src)->color;
01476          
01477            /* Solid rectangles special case */
01478            status = _cairo_surface_fill_region (dst, operator, color, trap_region);
01479            if (!status && clear_region)
01480               status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
01481                                                CAIRO_COLOR_TRANSPARENT,
01482                                                clear_region);
01483 
01484            goto out;
01485        }
01486 
01487        if ((_cairo_operator_bounded (operator) && operator != CAIRO_OPERATOR_SOURCE) ||
01488            !clip->surface)
01489        {
01490            /* For a simple rectangle, we can just use composite(), for more
01491             * rectangles, we have to set a clip region. The cost of rasterizing
01492             * trapezoids is pretty high for most backends currently, so it's
01493             * worthwhile even if a region is needed.
01494             *
01495             * If we have a clip surface, we set it as the mask; this only works
01496             * for bounded operators other than SOURCE; for unbounded operators,
01497             * clip and mask cannot be interchanged. For SOURCE, the operator
01498             * as implemented by the backends is different in it's handling
01499             * of the mask then what we want.
01500             *
01501             * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
01502             * more than rectangle and the destination doesn't support clip
01503             * regions. In that case, we fall through.
01504             */
01505            status = _composite_trap_region (clip, src, operator, dst,
01506                                         trap_region, &extents);
01507            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
01508            {
01509               if (!status && clear_region)
01510                   status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
01511                                                   CAIRO_COLOR_TRANSPARENT,
01512                                                   clear_region);
01513               goto out;
01514            }
01515        }
01516     }
01517 
01518     traps_info.traps = traps;
01519     traps_info.antialias = antialias;
01520 
01521     status = _cairo_gstate_clip_and_composite (clip, operator, src,
01522                                           _composite_traps_draw_func, &traps_info,
01523                                           dst, &extents);
01524 
01525  out:
01526     if (trap_region)
01527        pixman_region_destroy (trap_region);
01528     if (clear_region)
01529        pixman_region_destroy (clear_region);
01530     
01531     return status;
01532 }
01533 
01534 /* Warning: This call modifies the coordinates of traps */
01535 static cairo_status_t
01536 _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
01537                                         cairo_traps_t  *traps)
01538 {
01539   cairo_pattern_union_t pattern;
01540   cairo_status_t status;
01541   
01542   _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
01543   
01544   status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base,
01545                                                   gstate->operator,
01546                                                   gstate->target,
01547                                                   traps,
01548                                                   &gstate->clip,
01549                                                   gstate->antialias);
01550 
01551   _cairo_pattern_fini (&pattern.base);
01552 
01553   return status;
01554 }
01555 
01556 cairo_status_t
01557 _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
01558 {
01559     cairo_status_t status;
01560     cairo_traps_t traps;
01561 
01562     if (gstate->source->status)
01563        return gstate->source->status;
01564     
01565     status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
01566     if (status)
01567        return status;
01568 
01569     status = _cairo_surface_fill_path (gstate->operator,
01570                                    gstate->source,
01571                                    gstate->target,
01572                                    path,
01573                                    gstate->fill_rule,
01574                                    gstate->tolerance);
01575     
01576     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
01577        return status;
01578 
01579     _cairo_traps_init (&traps);
01580 
01581     status = _cairo_path_fixed_fill_to_traps (path,
01582                                          gstate->fill_rule,
01583                                          gstate->tolerance,
01584                                          &traps);
01585     if (status) {
01586        _cairo_traps_fini (&traps);
01587        return status;
01588     }
01589 
01590     _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
01591 
01592     _cairo_traps_fini (&traps);
01593 
01594     return CAIRO_STATUS_SUCCESS;
01595 }
01596 
01597 cairo_status_t
01598 _cairo_gstate_in_fill (cairo_gstate_t       *gstate,
01599                      cairo_path_fixed_t *path,
01600                      double           x,
01601                      double           y,
01602                      cairo_bool_t    *inside_ret)
01603 {
01604     cairo_status_t status = CAIRO_STATUS_SUCCESS;
01605     cairo_traps_t traps;
01606 
01607     _cairo_gstate_user_to_backend (gstate, &x, &y);
01608 
01609     _cairo_traps_init (&traps);
01610 
01611     status = _cairo_path_fixed_fill_to_traps (path,
01612                                          gstate->fill_rule,
01613                                          gstate->tolerance,
01614                                          &traps);
01615     if (status)
01616        goto BAIL;
01617 
01618     *inside_ret = _cairo_traps_contain (&traps, x, y);
01619     
01620 BAIL:
01621     _cairo_traps_fini (&traps);
01622 
01623     return status;
01624 }
01625 
01626 cairo_status_t
01627 _cairo_gstate_copy_page (cairo_gstate_t *gstate)
01628 {
01629     return _cairo_surface_copy_page (gstate->target);
01630 }
01631 
01632 cairo_status_t
01633 _cairo_gstate_show_page (cairo_gstate_t *gstate)
01634 {
01635     return _cairo_surface_show_page (gstate->target);
01636 }
01637 
01638 cairo_status_t
01639 _cairo_gstate_stroke_extents (cairo_gstate_t      *gstate,
01640                            cairo_path_fixed_t *path,
01641                               double *x1, double *y1,
01642                            double *x2, double *y2)
01643 {
01644     cairo_status_t status;
01645     cairo_traps_t traps;
01646     cairo_box_t extents;
01647   
01648     _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
01649 
01650     _cairo_traps_init (&traps);
01651   
01652     status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
01653     if (status)
01654        goto BAIL;
01655 
01656     _cairo_traps_extents (&traps, &extents);
01657 
01658     *x1 = _cairo_fixed_to_double (extents.p1.x);
01659     *y1 = _cairo_fixed_to_double (extents.p1.y);
01660     *x2 = _cairo_fixed_to_double (extents.p2.x);
01661     *y2 = _cairo_fixed_to_double (extents.p2.y);
01662 
01663     _cairo_gstate_backend_to_user (gstate, x1, y1);
01664     _cairo_gstate_backend_to_user (gstate, x2, y2);
01665   
01666 BAIL:
01667     _cairo_traps_fini (&traps);
01668   
01669     return status;
01670 }
01671 
01672 cairo_status_t
01673 _cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
01674                          cairo_path_fixed_t *path,
01675                             double *x1, double *y1,
01676                          double *x2, double *y2)
01677 {
01678     cairo_status_t status;
01679     cairo_traps_t traps;
01680     cairo_box_t extents;
01681   
01682     _cairo_traps_init (&traps);
01683   
01684     status = _cairo_path_fixed_fill_to_traps (path,
01685                                          gstate->fill_rule,
01686                                          gstate->tolerance,
01687                                          &traps);
01688     if (status)
01689        goto BAIL;
01690   
01691     _cairo_traps_extents (&traps, &extents);
01692 
01693     *x1 = _cairo_fixed_to_double (extents.p1.x);
01694     *y1 = _cairo_fixed_to_double (extents.p1.y);
01695     *x2 = _cairo_fixed_to_double (extents.p2.x);
01696     *y2 = _cairo_fixed_to_double (extents.p2.y);
01697 
01698     _cairo_gstate_backend_to_user (gstate, x1, y1);
01699     _cairo_gstate_backend_to_user (gstate, x2, y2);
01700   
01701 BAIL:
01702     _cairo_traps_fini (&traps);
01703   
01704     return status;
01705 }
01706 
01707 cairo_status_t
01708 _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
01709 {
01710     return _cairo_clip_reset (&gstate->clip);
01711 }
01712 
01713 cairo_status_t
01714 _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
01715 {
01716     return _cairo_clip_clip (&gstate->clip,
01717                           path, gstate->fill_rule, gstate->tolerance,
01718                           gstate->antialias, gstate->target);
01719 }
01720 
01721 static void
01722 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
01723 {
01724     if (gstate->scaled_font) {
01725        cairo_scaled_font_destroy (gstate->scaled_font);
01726        gstate->scaled_font = NULL;
01727     }
01728 }
01729 
01730 cairo_status_t
01731 _cairo_gstate_select_font_face (cairo_gstate_t       *gstate, 
01732                             const char           *family, 
01733                             cairo_font_slant_t    slant, 
01734                             cairo_font_weight_t   weight)
01735 {
01736     cairo_font_face_t *font_face;
01737 
01738     font_face = _cairo_toy_font_face_create (family, slant, weight);
01739     if (font_face->status)
01740        return font_face->status;
01741 
01742     _cairo_gstate_set_font_face (gstate, font_face);
01743     cairo_font_face_destroy (font_face);
01744 
01745     return CAIRO_STATUS_SUCCESS;
01746 }
01747 
01748 cairo_status_t
01749 _cairo_gstate_set_font_size (cairo_gstate_t *gstate, 
01750                           double          size)
01751 {
01752     _cairo_gstate_unset_scaled_font (gstate);
01753 
01754     cairo_matrix_init_scale (&gstate->font_matrix, size, size);
01755 
01756     return CAIRO_STATUS_SUCCESS;
01757 }
01758 
01759 cairo_status_t
01760 _cairo_gstate_set_font_matrix (cairo_gstate_t        *gstate, 
01761                             const cairo_matrix_t *matrix)
01762 {
01763     _cairo_gstate_unset_scaled_font (gstate);
01764 
01765     gstate->font_matrix = *matrix;
01766 
01767     return CAIRO_STATUS_SUCCESS;
01768 }
01769 
01770 void
01771 _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
01772                             cairo_matrix_t *matrix)
01773 {
01774     *matrix = gstate->font_matrix;
01775 }
01776 
01777 cairo_status_t
01778 _cairo_gstate_set_font_options (cairo_gstate_t             *gstate,
01779                             const cairo_font_options_t *options)
01780 {
01781     _cairo_gstate_unset_scaled_font (gstate);
01782 
01783     gstate->font_options = *options;
01784 
01785     return CAIRO_STATUS_SUCCESS;
01786 }
01787 
01788 void
01789 _cairo_gstate_get_font_options (cairo_gstate_t       *gstate,
01790                             cairo_font_options_t *options)
01791 {
01792     *options = gstate->font_options;
01793 }
01794 
01795 cairo_status_t
01796 _cairo_gstate_get_font_face (cairo_gstate_t     *gstate,
01797                           cairo_font_face_t **font_face)
01798 {
01799     cairo_status_t status;
01800 
01801     status = _cairo_gstate_ensure_font_face (gstate);
01802     if (status)
01803        return status;
01804     
01805     *font_face = gstate->font_face;
01806 
01807     return CAIRO_STATUS_SUCCESS;
01808 }
01809 
01810 /* 
01811  * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
01812  * it is easy to get confused about what's going on.
01813  *
01814  * The user's view
01815  * ---------------
01816  *
01817  * Users ask for things in user space. When cairo starts, a user space unit
01818  * is about 1/96 inch, which is similar to (but importantly different from)
01819  * the normal "point" units most users think in terms of. When a user
01820  * selects a font, its scale is set to "one user unit". The user can then
01821  * independently scale the user coordinate system *or* the font matrix, in
01822  * order to adjust the rendered size of the font.
01823  *
01824  * Metrics are returned in user space, whether they are obtained from
01825  * the currently selected font in a  #cairo_t or from a #cairo_scaled_font_t
01826  * which is aa font specialized to a particular scale matrix, CTM, and target
01827  * surface. 
01828  *
01829  * The font's view
01830  * ---------------
01831  *
01832  * Fonts are designed and stored (in say .ttf files) in "font space", which
01833  * describes an "EM Square" (a design tile) and has some abstract number
01834  * such as 1000, 1024, or 2048 units per "EM". This is basically an
01835  * uninteresting space for us, but we need to remember that it exists.
01836  *
01837  * Font resources (from libraries or operating systems) render themselves
01838  * to a particular device. Since they do not want to make most programmers
01839  * worry about the font design space, the scaling API is simplified to
01840  * involve just telling the font the required pixel size of the EM square
01841  * (that is, in device space).
01842  *
01843  *
01844  * Cairo's gstate view
01845  * -------------------
01846  *
01847  * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
01848  * called the "font matrix" which describes the user's most recent
01849  * font-scaling or font-transforming request. This is kept in terms of an
01850  * abstract scale factor, composed with the CTM and used to set the font's
01851  * pixel size. So if the user asks to "scale the font by 12", the matrix
01852  * is:
01853  *
01854  *   [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
01855  *
01856  * It is an affine matrix, like all cairo matrices, but its tx and ty
01857  * components are always set to zero; we don't permit "nudging" fonts
01858  * around.
01859  *
01860  * In order to perform any action on a font, we must build an object
01861  * called a cairo_font_scale_t; this contains the central 2x2 matrix 
01862  * resulting from "font matrix * CTM".
01863  *  
01864  * We pass this to the font when making requests of it, which causes it to
01865  * reply for a particular [user request, device] combination, under the CTM
01866  * (to accomodate the "zoom in" == "bigger fonts" issue above).
01867  *
01868  * The other terms in our communication with the font are therefore in
01869  * device space. When we ask it to perform text->glyph conversion, it will
01870  * produce a glyph string in device space. Glyph vectors we pass to it for
01871  * measuring or rendering should be in device space. The metrics which we
01872  * get back from the font will be in device space. The contents of the
01873  * global glyph image cache will be in device space.
01874  *
01875  *
01876  * Cairo's public view
01877  * -------------------
01878  *
01879  * Since the values entering and leaving via public API calls are in user
01880  * space, the gstate functions typically need to multiply argumens by the
01881  * CTM (for user-input glyph vectors), and return values by the CTM inverse
01882  * (for font responses such as metrics or glyph vectors).
01883  *
01884  */
01885 
01886 static cairo_status_t
01887 _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
01888 {
01889     if (!gstate->font_face) {
01890        cairo_font_face_t *font_face;
01891 
01892        font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
01893                                            CAIRO_FONT_SLANT_DEFAULT,
01894                                            CAIRO_FONT_WEIGHT_DEFAULT);
01895        if (font_face->status)
01896            return font_face->status;
01897        else
01898            gstate->font_face = font_face;
01899     }
01900     
01901     return CAIRO_STATUS_SUCCESS;
01902 }
01903     
01904 static cairo_status_t
01905 _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
01906 {
01907     cairo_status_t status;
01908     cairo_font_options_t options;
01909     
01910     if (gstate->scaled_font)
01911        return CAIRO_STATUS_SUCCESS;
01912     
01913     status = _cairo_gstate_ensure_font_face (gstate);
01914     if (status)
01915        return status;
01916 
01917     cairo_surface_get_font_options (gstate->target, &options);
01918     cairo_font_options_merge (&options, &gstate->font_options);
01919     
01920     gstate->scaled_font = cairo_scaled_font_create (gstate->font_face,
01921                                               &gstate->font_matrix,
01922                                               &gstate->ctm,
01923                                               &options);
01924     
01925     if (!gstate->scaled_font)
01926        return CAIRO_STATUS_NO_MEMORY;
01927 
01928     return CAIRO_STATUS_SUCCESS;
01929 }
01930 
01931 cairo_status_t
01932 _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, 
01933                             cairo_font_extents_t *extents)
01934 {
01935     cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
01936     if (status)
01937        return status;
01938 
01939     cairo_scaled_font_extents (gstate->scaled_font, extents);
01940 
01941     return CAIRO_STATUS_SUCCESS;
01942 }
01943 
01944 cairo_status_t
01945 _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, 
01946                            const char     *utf8,
01947                            double        x,
01948                            double        y,
01949                            cairo_glyph_t **glyphs,
01950                            int          *num_glyphs)
01951 {
01952     cairo_status_t status;
01953     int i;
01954 
01955     status = _cairo_gstate_ensure_scaled_font (gstate);
01956     if (status)
01957        return status;
01958     
01959     status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, 
01960                                           utf8, glyphs, num_glyphs);
01961 
01962     if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs))
01963        return status;
01964 
01965     /* The font responded in glyph space, starting from (0,0).  Convert to
01966        user space by applying the font transform, then add any current point
01967        offset. */
01968 
01969     for (i = 0; i < *num_glyphs; ++i) {
01970        cairo_matrix_transform_point (&gstate->font_matrix, 
01971                                   &((*glyphs)[i].x),
01972                                   &((*glyphs)[i].y));
01973        (*glyphs)[i].x += x;
01974        (*glyphs)[i].y += y;
01975     }
01976     
01977     return CAIRO_STATUS_SUCCESS;
01978 }
01979 
01980 cairo_status_t
01981 _cairo_gstate_set_font_face (cairo_gstate_t    *gstate, 
01982                           cairo_font_face_t *font_face)
01983 {
01984     if (font_face && font_face->status)
01985        return font_face->status;
01986     
01987     if (font_face != gstate->font_face) {
01988        cairo_font_face_destroy (gstate->font_face);
01989        gstate->font_face = cairo_font_face_reference (font_face);
01990     }
01991 
01992     _cairo_gstate_unset_scaled_font (gstate);
01993     
01994     return CAIRO_STATUS_SUCCESS;
01995 }
01996 
01997 cairo_status_t
01998 _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
01999                           cairo_glyph_t *glyphs, 
02000                           int num_glyphs,
02001                           cairo_text_extents_t *extents)
02002 {
02003     cairo_status_t status;
02004 
02005     status = _cairo_gstate_ensure_scaled_font (gstate);
02006     if (status)
02007        return status;
02008 
02009     cairo_scaled_font_glyph_extents (gstate->scaled_font,
02010                                  glyphs, num_glyphs,
02011                                  extents);
02012 
02013     return CAIRO_STATUS_SUCCESS;
02014 }
02015 
02016 typedef struct {
02017     cairo_scaled_font_t *font;
02018     cairo_glyph_t *glyphs;
02019     int num_glyphs;
02020 } cairo_show_glyphs_info_t;
02021 
02022 static cairo_status_t
02023 _cairo_gstate_show_glyphs_draw_func (void                    *closure,
02024                                  cairo_operator_t         operator,
02025                                  cairo_pattern_t         *src,
02026                                  cairo_surface_t         *dst,
02027                                  int                      dst_x,
02028                                  int                      dst_y,
02029                                  const cairo_rectangle_t *extents)
02030 {
02031     cairo_show_glyphs_info_t *glyph_info = closure;
02032     cairo_pattern_union_t pattern;
02033     cairo_status_t status;
02034 
02035     /* Modifying the glyph array is fine because we know that this function
02036      * will be called only once, and we've already made a copy of the
02037      * glyphs in the wrapper.
02038      */
02039     if (dst_x != 0 || dst_y != 0) {
02040        int i;
02041        
02042        for (i = 0; i < glyph_info->num_glyphs; ++i)
02043        {
02044            glyph_info->glyphs[i].x -= dst_x;
02045            glyph_info->glyphs[i].y -= dst_y;
02046        }
02047     }
02048 
02049     _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
02050     if (!src)
02051        src = &pattern.base;
02052     
02053     status = _cairo_scaled_font_show_glyphs (glyph_info->font, 
02054                                         operator, 
02055                                         src, dst,
02056                                         extents->x,         extents->y,
02057                                         extents->x - dst_x, extents->y - dst_y,
02058                                         extents->width,     extents->height,
02059                                         glyph_info->glyphs,
02060                                         glyph_info->num_glyphs);
02061 
02062     if (src == &pattern.base)
02063        _cairo_pattern_fini (&pattern.base);
02064 
02065     return status;
02066 }
02067 
02068 cairo_status_t
02069 _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, 
02070                         cairo_glyph_t *glyphs, 
02071                         int num_glyphs)
02072 {
02073     cairo_status_t status;
02074     int i;
02075     cairo_glyph_t *transformed_glyphs = NULL;
02076     cairo_pattern_union_t pattern;
02077     cairo_box_t bbox;
02078     cairo_rectangle_t extents;
02079     cairo_show_glyphs_info_t glyph_info;
02080 
02081     if (gstate->source->status)
02082        return gstate->source->status;
02083 
02084     status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
02085     if (status)
02086        return status;
02087 
02088     status = _cairo_gstate_ensure_scaled_font (gstate);
02089     if (status)
02090        return status;
02091     
02092     transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
02093     if (transformed_glyphs == NULL)
02094        return CAIRO_STATUS_NO_MEMORY;
02095     
02096     for (i = 0; i < num_glyphs; ++i)
02097     {
02098        transformed_glyphs[i] = glyphs[i];
02099        _cairo_gstate_user_to_backend (gstate,
02100                                    &transformed_glyphs[i].x, 
02101                                    &transformed_glyphs[i].y);
02102     }
02103 
02104     if (_cairo_operator_bounded (gstate->operator))
02105     {
02106        status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
02107                                           transformed_glyphs, num_glyphs, 
02108                                           &bbox);
02109        if (status)
02110            goto CLEANUP_GLYPHS;
02111        
02112        _cairo_box_round_to_rectangle (&bbox, &extents);
02113     }
02114     else
02115     {
02116        status = _cairo_surface_get_extents (gstate->target, &extents);
02117        if (status)
02118            goto CLEANUP_GLYPHS;
02119     }
02120     
02121     status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
02122     if (status)
02123        goto CLEANUP_GLYPHS;
02124     
02125     _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
02126 
02127     glyph_info.font = gstate->scaled_font;
02128     glyph_info.glyphs = transformed_glyphs;
02129     glyph_info.num_glyphs = num_glyphs;
02130     
02131     status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
02132                                           &pattern.base,
02133                                           _cairo_gstate_show_glyphs_draw_func, &glyph_info,
02134                                           gstate->target,
02135                                           &extents);
02136 
02137     _cairo_pattern_fini (&pattern.base);
02138     
02139  CLEANUP_GLYPHS:
02140     free (transformed_glyphs);
02141     
02142     return status;
02143 }
02144 
02145 cairo_status_t
02146 _cairo_gstate_glyph_path (cairo_gstate_t     *gstate,
02147                        cairo_glyph_t           *glyphs, 
02148                        int               num_glyphs,
02149                        cairo_path_fixed_t *path)
02150 {
02151     cairo_status_t status;
02152     int i;
02153     cairo_glyph_t *transformed_glyphs = NULL;
02154 
02155     status = _cairo_gstate_ensure_scaled_font (gstate);
02156     if (status)
02157        return status;
02158     
02159     transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
02160     if (transformed_glyphs == NULL)
02161        return CAIRO_STATUS_NO_MEMORY;
02162     
02163     for (i = 0; i < num_glyphs; ++i)
02164     {
02165        transformed_glyphs[i] = glyphs[i];
02166        _cairo_gstate_user_to_backend (gstate,
02167                                    &(transformed_glyphs[i].x), 
02168                                    &(transformed_glyphs[i].y));
02169     }
02170 
02171     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
02172                                        transformed_glyphs, num_glyphs,
02173                                        path);
02174 
02175     free (transformed_glyphs);
02176     return status;
02177 }
02178 
02179 cairo_private cairo_status_t
02180 _cairo_gstate_set_antialias (cairo_gstate_t *gstate,
02181                           cairo_antialias_t antialias)
02182 {
02183     gstate->antialias = antialias;
02184 
02185     return CAIRO_STATUS_SUCCESS;
02186 }
02187 
02188 cairo_private cairo_antialias_t
02189 _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
02190 {
02191     return gstate->antialias;
02192 }
02193