LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-gstate.c (source / functions) Found Hit Coverage
Test: app.info Lines: 948 151 15.9 %
Date: 2012-06-02 Functions: 88 16 18.2 %

       1                 : /* cairo - a vector graphics library with display and print output
       2                 :  *
       3                 :  * Copyright © 2002 University of Southern California
       4                 :  * Copyright © 2005 Red Hat, Inc.
       5                 :  *
       6                 :  * This library is free software; you can redistribute it and/or
       7                 :  * modify it either under the terms of the GNU Lesser General Public
       8                 :  * License version 2.1 as published by the Free Software Foundation
       9                 :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      10                 :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      11                 :  * notice, a recipient may use your version of this file under either
      12                 :  * the MPL or the LGPL.
      13                 :  *
      14                 :  * You should have received a copy of the LGPL along with this library
      15                 :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      16                 :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      17                 :  * You should have received a copy of the MPL along with this library
      18                 :  * in the file COPYING-MPL-1.1
      19                 :  *
      20                 :  * The contents of this file are subject to the Mozilla Public License
      21                 :  * Version 1.1 (the "License"); you may not use this file except in
      22                 :  * compliance with the License. You may obtain a copy of the License at
      23                 :  * http://www.mozilla.org/MPL/
      24                 :  *
      25                 :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      26                 :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      27                 :  * the specific language governing rights and limitations.
      28                 :  *
      29                 :  * The Original Code is the cairo graphics library.
      30                 :  *
      31                 :  * The Initial Developer of the Original Code is University of Southern
      32                 :  * California.
      33                 :  *
      34                 :  * Contributor(s):
      35                 :  *      Carl D. Worth <cworth@cworth.org>
      36                 :  */
      37                 : 
      38                 : #include "cairoint.h"
      39                 : 
      40                 : #include "cairo-clip-private.h"
      41                 : #include "cairo-error-private.h"
      42                 : #include "cairo-gstate-private.h"
      43                 : 
      44                 : #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
      45                 : #define ISFINITE(x) isfinite (x)
      46                 : #else
      47                 : #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
      48                 : #endif
      49                 : 
      50                 : static cairo_status_t
      51                 : _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
      52                 : 
      53                 : static cairo_status_t
      54                 : _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
      55                 : 
      56                 : static cairo_status_t
      57                 : _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
      58                 : 
      59                 : static void
      60                 : _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
      61                 : 
      62                 : static cairo_status_t
      63                 : _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
      64                 :                                            const cairo_glyph_t *glyphs,
      65                 :                                            int                  num_glyphs,
      66                 :                                            const cairo_text_cluster_t   *clusters,
      67                 :                                            int                   num_clusters,
      68                 :                                            cairo_text_cluster_flags_t cluster_flags,
      69                 :                                            cairo_glyph_t       *transformed_glyphs,
      70                 :                                            int                  *num_transformed_glyphs,
      71                 :                                            cairo_text_cluster_t *transformed_clusters);
      72                 : 
      73                 : static void
      74               0 : _cairo_gstate_update_device_transform (cairo_observer_t *observer,
      75                 :                                        void *arg)
      76                 : {
      77               0 :     cairo_gstate_t *gstate = cairo_container_of (observer,
      78                 :                                                  cairo_gstate_t,
      79                 :                                                  device_transform_observer);
      80                 : 
      81               0 :     gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
      82               0 :                            _cairo_matrix_is_identity (&gstate->target->device_transform));
      83               0 : }
      84                 : 
      85                 : cairo_status_t
      86              64 : _cairo_gstate_init (cairo_gstate_t  *gstate,
      87                 :                     cairo_surface_t *target)
      88                 : {
      89                 :     cairo_status_t status;
      90                 : 
      91                 :     VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
      92                 : 
      93              64 :     gstate->next = NULL;
      94                 : 
      95              64 :     gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
      96                 : 
      97              64 :     gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
      98              64 :     gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
      99                 : 
     100              64 :     _cairo_stroke_style_init (&gstate->stroke_style);
     101                 : 
     102              64 :     gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
     103                 : 
     104              64 :     gstate->font_face = NULL;
     105              64 :     gstate->scaled_font = NULL;
     106              64 :     gstate->previous_scaled_font = NULL;
     107                 : 
     108              64 :     cairo_matrix_init_scale (&gstate->font_matrix,
     109                 :                              CAIRO_GSTATE_DEFAULT_FONT_SIZE,
     110                 :                              CAIRO_GSTATE_DEFAULT_FONT_SIZE);
     111                 : 
     112              64 :     _cairo_font_options_init_default (&gstate->font_options);
     113                 : 
     114              64 :     _cairo_clip_init (&gstate->clip);
     115                 : 
     116              64 :     gstate->target = cairo_surface_reference (target);
     117              64 :     gstate->parent_target = NULL;
     118              64 :     gstate->original_target = cairo_surface_reference (target);
     119                 : 
     120              64 :     gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
     121              64 :     cairo_list_add (&gstate->device_transform_observer.link,
     122              64 :                     &gstate->target->device_transform_observers);
     123                 : 
     124              64 :     gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
     125              64 :     cairo_matrix_init_identity (&gstate->ctm);
     126              64 :     gstate->ctm_inverse = gstate->ctm;
     127              64 :     gstate->source_ctm_inverse = gstate->ctm;
     128                 : 
     129              64 :     gstate->source = (cairo_pattern_t *) &_cairo_pattern_black.base;
     130                 : 
     131                 :     /* Now that the gstate is fully initialized and ready for the eventual
     132                 :      * _cairo_gstate_fini(), we can check for errors (and not worry about
     133                 :      * the resource deallocation). */
     134              64 :     status = target->status;
     135              64 :     if (unlikely (status))
     136               0 :         return status;
     137                 : 
     138              64 :     status = gstate->source->status;
     139              64 :     if (unlikely (status))
     140               0 :         return status;
     141                 : 
     142              64 :     return CAIRO_STATUS_SUCCESS;
     143                 : }
     144                 : 
     145                 : /**
     146                 :  * _cairo_gstate_init_copy:
     147                 :  *
     148                 :  * Initialize @gstate by performing a deep copy of state fields from
     149                 :  * @other. Note that gstate->next is not copied but is set to %NULL by
     150                 :  * this function.
     151                 :  **/
     152                 : static cairo_status_t
     153               0 : _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
     154                 : {
     155                 :     cairo_status_t status;
     156                 : 
     157                 :     VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
     158                 : 
     159               0 :     gstate->op = other->op;
     160                 : 
     161               0 :     gstate->tolerance = other->tolerance;
     162               0 :     gstate->antialias = other->antialias;
     163                 : 
     164               0 :     status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
     165               0 :                                             &other->stroke_style);
     166               0 :     if (unlikely (status))
     167               0 :         return status;
     168                 : 
     169               0 :     gstate->fill_rule = other->fill_rule;
     170                 : 
     171               0 :     gstate->font_face = cairo_font_face_reference (other->font_face);
     172               0 :     gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font);
     173               0 :     gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font);
     174                 : 
     175               0 :     gstate->font_matrix = other->font_matrix;
     176                 : 
     177               0 :     _cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
     178                 : 
     179               0 :     _cairo_clip_init_copy (&gstate->clip, &other->clip);
     180                 : 
     181               0 :     gstate->target = cairo_surface_reference (other->target);
     182                 :     /* parent_target is always set to NULL; it's only ever set by redirect_target */
     183               0 :     gstate->parent_target = NULL;
     184               0 :     gstate->original_target = cairo_surface_reference (other->original_target);
     185                 : 
     186               0 :     gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
     187               0 :     cairo_list_add (&gstate->device_transform_observer.link,
     188               0 :                     &gstate->target->device_transform_observers);
     189                 : 
     190               0 :     gstate->is_identity = other->is_identity;
     191               0 :     gstate->ctm = other->ctm;
     192               0 :     gstate->ctm_inverse = other->ctm_inverse;
     193               0 :     gstate->source_ctm_inverse = other->source_ctm_inverse;
     194                 : 
     195               0 :     gstate->source = cairo_pattern_reference (other->source);
     196                 : 
     197               0 :     gstate->next = NULL;
     198                 : 
     199               0 :     return CAIRO_STATUS_SUCCESS;
     200                 : }
     201                 : 
     202                 : void
     203              64 : _cairo_gstate_fini (cairo_gstate_t *gstate)
     204                 : {
     205              64 :     _cairo_stroke_style_fini (&gstate->stroke_style);
     206                 : 
     207              64 :     cairo_font_face_destroy (gstate->font_face);
     208              64 :     gstate->font_face = NULL;
     209                 : 
     210              64 :     cairo_scaled_font_destroy (gstate->previous_scaled_font);
     211              64 :     gstate->previous_scaled_font = NULL;
     212                 : 
     213              64 :     cairo_scaled_font_destroy (gstate->scaled_font);
     214              64 :     gstate->scaled_font = NULL;
     215                 : 
     216              64 :     _cairo_clip_reset (&gstate->clip);
     217                 : 
     218              64 :     cairo_list_del (&gstate->device_transform_observer.link);
     219                 : 
     220              64 :     cairo_surface_destroy (gstate->target);
     221              64 :     gstate->target = NULL;
     222                 : 
     223              64 :     cairo_surface_destroy (gstate->parent_target);
     224              64 :     gstate->parent_target = NULL;
     225                 : 
     226              64 :     cairo_surface_destroy (gstate->original_target);
     227              64 :     gstate->original_target = NULL;
     228                 : 
     229              64 :     cairo_pattern_destroy (gstate->source);
     230              64 :     gstate->source = NULL;
     231                 : 
     232                 :     VG (VALGRIND_MAKE_MEM_NOACCESS (gstate, sizeof (cairo_gstate_t)));
     233              64 : }
     234                 : 
     235                 : /**
     236                 :  * _cairo_gstate_save:
     237                 :  * @gstate: input/output gstate pointer
     238                 :  *
     239                 :  * Makes a copy of the current state of @gstate and saves it
     240                 :  * to @gstate->next, then put the address of the newly allcated
     241                 :  * copy into @gstate.  _cairo_gstate_restore() reverses this.
     242                 :  **/
     243                 : cairo_status_t
     244               0 : _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
     245                 : {
     246                 :     cairo_gstate_t *top;
     247                 :     cairo_status_t status;
     248                 : 
     249                 :     if (CAIRO_INJECT_FAULT ())
     250                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     251                 : 
     252               0 :     top = *freelist;
     253               0 :     if (top == NULL) {
     254               0 :         top = malloc (sizeof (cairo_gstate_t));
     255               0 :         if (unlikely (top == NULL))
     256               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     257                 :     } else
     258               0 :         *freelist = top->next;
     259                 : 
     260               0 :     status = _cairo_gstate_init_copy (top, *gstate);
     261               0 :     if (unlikely (status)) {
     262               0 :         top->next = *freelist;
     263               0 :         *freelist = top;
     264               0 :         return status;
     265                 :     }
     266                 : 
     267               0 :     top->next = *gstate;
     268               0 :     *gstate = top;
     269                 : 
     270               0 :     return CAIRO_STATUS_SUCCESS;
     271                 : }
     272                 : 
     273                 : /**
     274                 :  * _cairo_gstate_restore:
     275                 :  * @gstate: input/output gstate pointer
     276                 :  *
     277                 :  * Reverses the effects of one _cairo_gstate_save() call.
     278                 :  **/
     279                 : cairo_status_t
     280               0 : _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
     281                 : {
     282                 :     cairo_gstate_t *top;
     283                 : 
     284               0 :     top = *gstate;
     285               0 :     if (top->next == NULL)
     286               0 :         return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
     287                 : 
     288               0 :     *gstate = top->next;
     289                 : 
     290               0 :     _cairo_gstate_fini (top);
     291                 :     VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *)));
     292               0 :     top->next = *freelist;
     293               0 :     *freelist = top;
     294                 : 
     295               0 :     return CAIRO_STATUS_SUCCESS;
     296                 : }
     297                 : 
     298                 : /**
     299                 :  * _cairo_gstate_redirect_target:
     300                 :  * @gstate: a #cairo_gstate_t
     301                 :  * @child: the new child target
     302                 :  *
     303                 :  * Redirect @gstate rendering to a "child" target. The original
     304                 :  * "parent" target with which the gstate was created will not be
     305                 :  * affected. See _cairo_gstate_get_target().
     306                 :  *
     307                 :  * Unless the redirected target has the same device offsets as the
     308                 :  * original #cairo_t target, the clip will be INVALID after this call,
     309                 :  * and the caller should either recreate or reset the clip.
     310                 :  **/
     311                 : cairo_status_t
     312               0 : _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
     313                 : {
     314                 :     cairo_matrix_t matrix;
     315                 : 
     316                 :     /* If this gstate is already redirected, this is an error; we need a
     317                 :      * new gstate to be able to redirect */
     318               0 :     assert (gstate->parent_target == NULL);
     319                 : 
     320                 :     /* Set up our new parent_target based on our current target;
     321                 :      * gstate->parent_target will take the ref that is held by gstate->target
     322                 :      */
     323               0 :     cairo_surface_destroy (gstate->parent_target);
     324               0 :     gstate->parent_target = gstate->target;
     325                 : 
     326                 :     /* Now set up our new target; we overwrite gstate->target directly,
     327                 :      * since its ref is now owned by gstate->parent_target */
     328               0 :     gstate->target = cairo_surface_reference (child);
     329               0 :     gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
     330               0 :     cairo_list_move (&gstate->device_transform_observer.link,
     331               0 :                      &gstate->target->device_transform_observers);
     332                 : 
     333                 :     /* The clip is in surface backend coordinates for the previous target;
     334                 :      * translate it into the child's backend coordinates. */
     335               0 :     cairo_matrix_init_translate (&matrix,
     336               0 :                                  child->device_transform.x0 - gstate->parent_target->device_transform.x0,
     337               0 :                                  child->device_transform.y0 - gstate->parent_target->device_transform.y0);
     338               0 :     _cairo_clip_reset (&gstate->clip);
     339               0 :     return _cairo_clip_init_copy_transformed (&gstate->clip,
     340               0 :                                               &gstate->next->clip,
     341                 :                                               &matrix);
     342                 : }
     343                 : 
     344                 : /**
     345                 :  * _cairo_gstate_is_redirected
     346                 :  * @gstate: a #cairo_gstate_t
     347                 :  *
     348                 :  * This space left intentionally blank.
     349                 :  *
     350                 :  * Return value: %TRUE if the gstate is redirected to a target
     351                 :  * different than the original, %FALSE otherwise.
     352                 :  **/
     353                 : cairo_bool_t
     354               0 : _cairo_gstate_is_redirected (cairo_gstate_t *gstate)
     355                 : {
     356               0 :     return (gstate->target != gstate->original_target);
     357                 : }
     358                 : 
     359                 : /**
     360                 :  * _cairo_gstate_get_target:
     361                 :  * @gstate: a #cairo_gstate_t
     362                 :  *
     363                 :  * Return the current drawing target; if drawing is not redirected,
     364                 :  * this will be the same as _cairo_gstate_get_original_target().
     365                 :  *
     366                 :  * Return value: the current target surface
     367                 :  **/
     368                 : cairo_surface_t *
     369               0 : _cairo_gstate_get_target (cairo_gstate_t *gstate)
     370                 : {
     371               0 :     return gstate->target;
     372                 : }
     373                 : 
     374                 : /**
     375                 :  * _cairo_gstate_get_parent_target:
     376                 :  * @gstate: a #cairo_gstate_t
     377                 :  *
     378                 :  * Return the parent surface of the current drawing target surface;
     379                 :  * if this particular gstate isn't a redirect gstate, this will return %NULL.
     380                 :  **/
     381                 : cairo_surface_t *
     382               0 : _cairo_gstate_get_parent_target (cairo_gstate_t *gstate)
     383                 : {
     384               0 :     return gstate->parent_target;
     385                 : }
     386                 : 
     387                 : /**
     388                 :  * _cairo_gstate_get_original_target:
     389                 :  * @gstate: a #cairo_gstate_t
     390                 :  *
     391                 :  * Return the original target with which @gstate was created. This
     392                 :  * function always returns the original target independent of any
     393                 :  * child target that may have been set with
     394                 :  * _cairo_gstate_redirect_target.
     395                 :  *
     396                 :  * Return value: the original target surface
     397                 :  **/
     398                 : cairo_surface_t *
     399              64 : _cairo_gstate_get_original_target (cairo_gstate_t *gstate)
     400                 : {
     401              64 :     return gstate->original_target;
     402                 : }
     403                 : 
     404                 : /**
     405                 :  * _cairo_gstate_get_clip:
     406                 :  * @gstate: a #cairo_gstate_t
     407                 :  *
     408                 :  * This space left intentionally blank.
     409                 :  *
     410                 :  * Return value: a pointer to the gstate's #cairo_clip_t structure.
     411                 :  */
     412                 : cairo_clip_t *
     413               0 : _cairo_gstate_get_clip (cairo_gstate_t *gstate)
     414                 : {
     415               0 :     return &gstate->clip;
     416                 : }
     417                 : 
     418                 : cairo_status_t
     419              75 : _cairo_gstate_set_source (cairo_gstate_t  *gstate,
     420                 :                           cairo_pattern_t *source)
     421                 : {
     422              75 :     if (source->status)
     423               0 :         return source->status;
     424                 : 
     425              75 :     source = cairo_pattern_reference (source);
     426              75 :     cairo_pattern_destroy (gstate->source);
     427              75 :     gstate->source = source;
     428              75 :     gstate->source_ctm_inverse = gstate->ctm_inverse;
     429                 : 
     430              75 :     return CAIRO_STATUS_SUCCESS;
     431                 : }
     432                 : 
     433                 : cairo_pattern_t *
     434               0 : _cairo_gstate_get_source (cairo_gstate_t *gstate)
     435                 : {
     436               0 :     if (gstate->source == &_cairo_pattern_black.base) {
     437                 :         /* do not expose the static object to the user */
     438               0 :         gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
     439                 :     }
     440                 : 
     441               0 :     return gstate->source;
     442                 : }
     443                 : 
     444                 : cairo_status_t
     445              64 : _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op)
     446                 : {
     447              64 :     gstate->op = op;
     448                 : 
     449              64 :     return CAIRO_STATUS_SUCCESS;
     450                 : }
     451                 : 
     452                 : cairo_operator_t
     453               0 : _cairo_gstate_get_operator (cairo_gstate_t *gstate)
     454                 : {
     455               0 :     return gstate->op;
     456                 : }
     457                 : 
     458                 : cairo_status_t
     459               0 : _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
     460                 : {
     461               0 :     gstate->tolerance = tolerance;
     462                 : 
     463               0 :     return CAIRO_STATUS_SUCCESS;
     464                 : }
     465                 : 
     466                 : double
     467               0 : _cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
     468                 : {
     469               0 :     return gstate->tolerance;
     470                 : }
     471                 : 
     472                 : cairo_status_t
     473               0 : _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
     474                 : {
     475               0 :     gstate->fill_rule = fill_rule;
     476                 : 
     477               0 :     return CAIRO_STATUS_SUCCESS;
     478                 : }
     479                 : 
     480                 : cairo_fill_rule_t
     481               0 : _cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
     482                 : {
     483               0 :     return gstate->fill_rule;
     484                 : }
     485                 : 
     486                 : cairo_status_t
     487               0 : _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
     488                 : {
     489               0 :     gstate->stroke_style.line_width = width;
     490                 : 
     491               0 :     return CAIRO_STATUS_SUCCESS;
     492                 : }
     493                 : 
     494                 : double
     495               0 : _cairo_gstate_get_line_width (cairo_gstate_t *gstate)
     496                 : {
     497               0 :     return gstate->stroke_style.line_width;
     498                 : }
     499                 : 
     500                 : cairo_status_t
     501               0 : _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
     502                 : {
     503               0 :     gstate->stroke_style.line_cap = line_cap;
     504                 : 
     505               0 :     return CAIRO_STATUS_SUCCESS;
     506                 : }
     507                 : 
     508                 : cairo_line_cap_t
     509               0 : _cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
     510                 : {
     511               0 :     return gstate->stroke_style.line_cap;
     512                 : }
     513                 : 
     514                 : cairo_status_t
     515               0 : _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
     516                 : {
     517               0 :     gstate->stroke_style.line_join = line_join;
     518                 : 
     519               0 :     return CAIRO_STATUS_SUCCESS;
     520                 : }
     521                 : 
     522                 : cairo_line_join_t
     523               0 : _cairo_gstate_get_line_join (cairo_gstate_t *gstate)
     524                 : {
     525               0 :     return gstate->stroke_style.line_join;
     526                 : }
     527                 : 
     528                 : cairo_status_t
     529               0 : _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset)
     530                 : {
     531                 :     unsigned int i;
     532                 :     double dash_total;
     533                 : 
     534               0 :     if (gstate->stroke_style.dash)
     535               0 :         free (gstate->stroke_style.dash);
     536                 : 
     537               0 :     gstate->stroke_style.num_dashes = num_dashes;
     538                 : 
     539               0 :     if (gstate->stroke_style.num_dashes == 0) {
     540               0 :         gstate->stroke_style.dash = NULL;
     541               0 :         gstate->stroke_style.dash_offset = 0.0;
     542               0 :         return CAIRO_STATUS_SUCCESS;
     543                 :     }
     544                 : 
     545               0 :     gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
     546               0 :     if (unlikely (gstate->stroke_style.dash == NULL)) {
     547               0 :         gstate->stroke_style.num_dashes = 0;
     548               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     549                 :     }
     550                 : 
     551               0 :     memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double));
     552                 : 
     553               0 :     dash_total = 0.0;
     554               0 :     for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
     555               0 :         if (gstate->stroke_style.dash[i] < 0)
     556               0 :             return _cairo_error (CAIRO_STATUS_INVALID_DASH);
     557                 : 
     558               0 :         dash_total += gstate->stroke_style.dash[i];
     559                 :     }
     560                 : 
     561               0 :     if (dash_total == 0.0)
     562               0 :         return _cairo_error (CAIRO_STATUS_INVALID_DASH);
     563                 : 
     564                 :     /* An odd dash value indicate symmetric repeating, so the total
     565                 :      * is twice as long. */
     566               0 :     if (gstate->stroke_style.num_dashes & 1)
     567               0 :         dash_total *= 2;
     568                 : 
     569                 :     /* The dashing code doesn't like a negative offset or a big positive
     570                 :      * offset, so we compute an equivalent offset which is guaranteed to be
     571                 :      * positive and less than twice the pattern length. */
     572               0 :     offset = fmod (offset, dash_total);
     573               0 :     if (offset < 0.0)
     574               0 :         offset += dash_total;
     575               0 :     if (offset <= 0.0)               /* Take care of -0 */
     576               0 :         offset = 0.0;
     577               0 :     gstate->stroke_style.dash_offset = offset;
     578                 : 
     579               0 :     return CAIRO_STATUS_SUCCESS;
     580                 : }
     581                 : 
     582                 : void
     583               0 : _cairo_gstate_get_dash (cairo_gstate_t *gstate,
     584                 :                         double         *dashes,
     585                 :                         int            *num_dashes,
     586                 :                         double         *offset)
     587                 : {
     588               0 :     if (dashes) {
     589               0 :         memcpy (dashes,
     590               0 :                 gstate->stroke_style.dash,
     591               0 :                 sizeof (double) * gstate->stroke_style.num_dashes);
     592                 :     }
     593                 : 
     594               0 :     if (num_dashes)
     595               0 :         *num_dashes = gstate->stroke_style.num_dashes;
     596                 : 
     597               0 :     if (offset)
     598               0 :         *offset = gstate->stroke_style.dash_offset;
     599               0 : }
     600                 : 
     601                 : cairo_status_t
     602               0 : _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
     603                 : {
     604               0 :     gstate->stroke_style.miter_limit = limit;
     605                 : 
     606               0 :     return CAIRO_STATUS_SUCCESS;
     607                 : }
     608                 : 
     609                 : double
     610               0 : _cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
     611                 : {
     612               0 :     return gstate->stroke_style.miter_limit;
     613                 : }
     614                 : 
     615                 : void
     616               0 : _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
     617                 : {
     618               0 :     *matrix = gstate->ctm;
     619               0 : }
     620                 : 
     621                 : cairo_status_t
     622              19 : _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
     623                 : {
     624                 :     cairo_matrix_t tmp;
     625                 : 
     626              19 :     if (! ISFINITE (tx) || ! ISFINITE (ty))
     627               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     628                 : 
     629              19 :     _cairo_gstate_unset_scaled_font (gstate);
     630                 : 
     631              19 :     cairo_matrix_init_translate (&tmp, tx, ty);
     632              19 :     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
     633              19 :     gstate->is_identity = FALSE;
     634                 : 
     635                 :     /* paranoid check against gradual numerical instability */
     636              19 :     if (! _cairo_matrix_is_invertible (&gstate->ctm))
     637               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     638                 : 
     639              19 :     cairo_matrix_init_translate (&tmp, -tx, -ty);
     640              19 :     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
     641                 : 
     642              19 :     return CAIRO_STATUS_SUCCESS;
     643                 : }
     644                 : 
     645                 : cairo_status_t
     646              12 : _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
     647                 : {
     648                 :     cairo_matrix_t tmp;
     649                 : 
     650              12 :     if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
     651               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     652              12 :     if (! ISFINITE (sx) || ! ISFINITE (sy))
     653               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     654                 : 
     655              12 :     _cairo_gstate_unset_scaled_font (gstate);
     656                 : 
     657              12 :     cairo_matrix_init_scale (&tmp, sx, sy);
     658              12 :     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
     659              12 :     gstate->is_identity = FALSE;
     660                 : 
     661                 :     /* paranoid check against gradual numerical instability */
     662              12 :     if (! _cairo_matrix_is_invertible (&gstate->ctm))
     663               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     664                 : 
     665              12 :     cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
     666              12 :     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
     667                 : 
     668              12 :     return CAIRO_STATUS_SUCCESS;
     669                 : }
     670                 : 
     671                 : cairo_status_t
     672               0 : _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
     673                 : {
     674                 :     cairo_matrix_t tmp;
     675                 : 
     676               0 :     if (angle == 0.)
     677               0 :         return CAIRO_STATUS_SUCCESS;
     678                 : 
     679               0 :     if (! ISFINITE (angle))
     680               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     681                 : 
     682               0 :     _cairo_gstate_unset_scaled_font (gstate);
     683                 : 
     684               0 :     cairo_matrix_init_rotate (&tmp, angle);
     685               0 :     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
     686               0 :     gstate->is_identity = FALSE;
     687                 : 
     688                 :     /* paranoid check against gradual numerical instability */
     689               0 :     if (! _cairo_matrix_is_invertible (&gstate->ctm))
     690               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     691                 : 
     692               0 :     cairo_matrix_init_rotate (&tmp, -angle);
     693               0 :     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
     694                 : 
     695               0 :     return CAIRO_STATUS_SUCCESS;
     696                 : }
     697                 : 
     698                 : cairo_status_t
     699               0 : _cairo_gstate_transform (cairo_gstate_t       *gstate,
     700                 :                          const cairo_matrix_t *matrix)
     701                 : {
     702                 :     cairo_matrix_t tmp;
     703                 :     cairo_status_t status;
     704                 : 
     705               0 :     if (! _cairo_matrix_is_invertible (matrix))
     706               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     707                 : 
     708               0 :     if (_cairo_matrix_is_identity (matrix))
     709               0 :         return CAIRO_STATUS_SUCCESS;
     710                 : 
     711               0 :     tmp = *matrix;
     712               0 :     status = cairo_matrix_invert (&tmp);
     713               0 :     if (unlikely (status))
     714               0 :         return status;
     715                 : 
     716               0 :     _cairo_gstate_unset_scaled_font (gstate);
     717                 : 
     718               0 :     cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
     719               0 :     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
     720               0 :     gstate->is_identity = FALSE;
     721                 : 
     722                 :     /* paranoid check against gradual numerical instability */
     723               0 :     if (! _cairo_matrix_is_invertible (&gstate->ctm))
     724               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     725                 : 
     726               0 :     return CAIRO_STATUS_SUCCESS;
     727                 : }
     728                 : 
     729                 : cairo_status_t
     730               0 : _cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
     731                 :                           const cairo_matrix_t *matrix)
     732                 : {
     733                 :     cairo_status_t status;
     734                 : 
     735               0 :     if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0)
     736               0 :         return CAIRO_STATUS_SUCCESS;
     737                 : 
     738               0 :     if (! _cairo_matrix_is_invertible (matrix))
     739               0 :         return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
     740                 : 
     741               0 :     if (_cairo_matrix_is_identity (matrix)) {
     742               0 :         _cairo_gstate_identity_matrix (gstate);
     743               0 :         return CAIRO_STATUS_SUCCESS;
     744                 :     }
     745                 : 
     746               0 :     _cairo_gstate_unset_scaled_font (gstate);
     747                 : 
     748               0 :     gstate->ctm = *matrix;
     749               0 :     gstate->ctm_inverse = *matrix;
     750               0 :     status = cairo_matrix_invert (&gstate->ctm_inverse);
     751               0 :     assert (status == CAIRO_STATUS_SUCCESS);
     752               0 :     gstate->is_identity = FALSE;
     753                 : 
     754               0 :     return CAIRO_STATUS_SUCCESS;
     755                 : }
     756                 : 
     757                 : void
     758               0 : _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
     759                 : {
     760               0 :     if (_cairo_matrix_is_identity (&gstate->ctm))
     761               0 :         return;
     762                 : 
     763               0 :     _cairo_gstate_unset_scaled_font (gstate);
     764                 : 
     765               0 :     cairo_matrix_init_identity (&gstate->ctm);
     766               0 :     cairo_matrix_init_identity (&gstate->ctm_inverse);
     767               0 :     gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
     768                 : }
     769                 : 
     770                 : void
     771               0 : _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
     772                 : {
     773               0 :     cairo_matrix_transform_point (&gstate->ctm, x, y);
     774               0 : }
     775                 : 
     776                 : void
     777              63 : _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
     778                 :                                        double *dx, double *dy)
     779                 : {
     780              63 :     cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
     781              63 : }
     782                 : 
     783                 : void
     784               0 : _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
     785                 : {
     786               0 :     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
     787               0 : }
     788                 : 
     789                 : void
     790               0 : _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
     791                 :                                        double *dx, double *dy)
     792                 : {
     793               0 :     cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
     794               0 : }
     795                 : 
     796                 : void
     797               0 : _do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
     798                 : {
     799               0 :     cairo_matrix_transform_point (&gstate->ctm, x, y);
     800               0 :     cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
     801               0 : }
     802                 : 
     803                 : void
     804               0 : _do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
     805                 : {
     806               0 :     cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
     807               0 :     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
     808               0 : }
     809                 : 
     810                 : void
     811               0 : _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
     812                 :                                          double *x1, double *y1,
     813                 :                                          double *x2, double *y2,
     814                 :                                          cairo_bool_t *is_tight)
     815                 : {
     816                 :     cairo_matrix_t matrix_inverse;
     817                 : 
     818               0 :     cairo_matrix_multiply (&matrix_inverse,
     819               0 :                            &gstate->target->device_transform_inverse,
     820               0 :                            &gstate->ctm_inverse);
     821               0 :     _cairo_matrix_transform_bounding_box (&matrix_inverse,
     822                 :                                           x1, y1, x2, y2, is_tight);
     823               0 : }
     824                 : 
     825                 : /* XXX: NYI
     826                 : cairo_status_t
     827                 : _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
     828                 : {
     829                 :     cairo_status_t status;
     830                 : 
     831                 :     _cairo_pen_init (&gstate);
     832                 :     return CAIRO_STATUS_SUCCESS;
     833                 : }
     834                 : */
     835                 : 
     836                 : void
     837               0 : _cairo_gstate_path_extents (cairo_gstate_t     *gstate,
     838                 :                             cairo_path_fixed_t *path,
     839                 :                             double *x1, double *y1,
     840                 :                             double *x2, double *y2)
     841                 : {
     842                 :     cairo_box_t box;
     843                 :     double px1, py1, px2, py2;
     844                 : 
     845               0 :     if (_cairo_path_fixed_extents (path, &box)) {
     846               0 :         px1 = _cairo_fixed_to_double (box.p1.x);
     847               0 :         py1 = _cairo_fixed_to_double (box.p1.y);
     848               0 :         px2 = _cairo_fixed_to_double (box.p2.x);
     849               0 :         py2 = _cairo_fixed_to_double (box.p2.y);
     850                 : 
     851               0 :         _cairo_gstate_backend_to_user_rectangle (gstate,
     852                 :                                                  &px1, &py1, &px2, &py2,
     853                 :                                                  NULL);
     854                 :     } else {
     855               0 :         px1 = 0.0;
     856               0 :         py1 = 0.0;
     857               0 :         px2 = 0.0;
     858               0 :         py2 = 0.0;
     859                 :     }
     860                 : 
     861               0 :     if (x1)
     862               0 :         *x1 = px1;
     863               0 :     if (y1)
     864               0 :         *y1 = py1;
     865               0 :     if (x2)
     866               0 :         *x2 = px2;
     867               0 :     if (y2)
     868               0 :         *y2 = py2;
     869               0 : }
     870                 : 
     871                 : static void
     872              47 : _cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
     873                 :                             const cairo_pattern_t *original)
     874                 : {
     875                 :     /* First check if the we can replace the original with a much simpler
     876                 :      * pattern. For example, gradients that are uniform or just have a single
     877                 :      * stop can sometimes be replaced with a solid.
     878                 :      */
     879                 : 
     880              47 :     if (_cairo_pattern_is_clear (original)) {
     881               0 :         _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
     882                 :                                    CAIRO_COLOR_TRANSPARENT);
     883               0 :         return;
     884                 :     }
     885                 : 
     886              94 :     if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
     887              47 :         original->type == CAIRO_PATTERN_TYPE_RADIAL)
     888                 :     {
     889                 :         cairo_color_t color;
     890               0 :         if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
     891                 :                                               NULL,
     892                 :                                               &color))
     893                 :         {
     894               0 :             _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
     895                 :                                        &color);
     896               0 :             return;
     897                 :         }
     898                 :     }
     899                 : 
     900              47 :     _cairo_pattern_init_static_copy (pattern, original);
     901                 : }
     902                 : 
     903                 : static void
     904              47 : _cairo_gstate_copy_transformed_pattern (cairo_gstate_t  *gstate,
     905                 :                                         cairo_pattern_t *pattern,
     906                 :                                         const cairo_pattern_t *original,
     907                 :                                         const cairo_matrix_t  *ctm_inverse)
     908                 : {
     909              47 :     _cairo_gstate_copy_pattern (pattern, original);
     910                 : 
     911                 :     /* apply device_transform first so that it is transformed by ctm_inverse */
     912              47 :     if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
     913                 :         cairo_surface_pattern_t *surface_pattern;
     914                 :         cairo_surface_t *surface;
     915                 : 
     916              47 :         surface_pattern = (cairo_surface_pattern_t *) original;
     917              47 :         surface = surface_pattern->surface;
     918                 : 
     919              47 :         if (_cairo_surface_has_device_transform (surface))
     920               0 :             _cairo_pattern_transform (pattern, &surface->device_transform);
     921                 :     }
     922                 : 
     923              47 :     if (! _cairo_matrix_is_identity (ctm_inverse))
     924              10 :         _cairo_pattern_transform (pattern, ctm_inverse);
     925                 : 
     926              47 :     if (_cairo_surface_has_device_transform (gstate->target)) {
     927               0 :         _cairo_pattern_transform (pattern,
     928               0 :                                   &gstate->target->device_transform_inverse);
     929                 :     }
     930              47 : }
     931                 : 
     932                 : static void
     933              47 : _cairo_gstate_copy_transformed_source (cairo_gstate_t   *gstate,
     934                 :                                        cairo_pattern_t  *pattern)
     935                 : {
     936              47 :     _cairo_gstate_copy_transformed_pattern (gstate, pattern,
     937              47 :                                             gstate->source,
     938              47 :                                             &gstate->source_ctm_inverse);
     939              47 : }
     940                 : 
     941                 : static void
     942               0 : _cairo_gstate_copy_transformed_mask (cairo_gstate_t   *gstate,
     943                 :                                      cairo_pattern_t  *pattern,
     944                 :                                      cairo_pattern_t  *mask)
     945                 : {
     946               0 :     _cairo_gstate_copy_transformed_pattern (gstate, pattern,
     947                 :                                             mask,
     948               0 :                                             &gstate->ctm_inverse);
     949               0 : }
     950                 : 
     951                 : /* We need to take a copy of the clip so that the lower layers may modify it
     952                 :  * by, perhaps, intersecting it with the operation extents and other paths.
     953                 :  */
     954                 : #define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
     955                 : 
     956                 : static cairo_bool_t
     957              64 : _clipped (cairo_gstate_t *gstate)
     958                 : {
     959                 :     cairo_rectangle_int_t extents;
     960                 : 
     961              64 :     if (gstate->clip.all_clipped)
     962               0 :         return TRUE;
     963                 : 
     964                 :     /* XXX consider applying a surface clip? */
     965                 : 
     966              64 :     if (gstate->clip.path == NULL)
     967              64 :         return FALSE;
     968                 : 
     969               0 :     if (_cairo_surface_get_extents (gstate->target, &extents)) {
     970               0 :         if (extents.width == 0 || extents.height == 0)
     971               0 :             return TRUE;
     972                 : 
     973               0 :         if (! _cairo_rectangle_intersect (&extents,
     974               0 :                                           &gstate->clip.path->extents))
     975                 :         {
     976               0 :             return TRUE;
     977                 :         }
     978                 :     }
     979                 : 
     980                 :     /* perform a simple query to exclude trivial all-clipped cases */
     981               0 :     return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
     982                 : }
     983                 : 
     984                 : static cairo_operator_t
     985              64 : _reduce_op (cairo_gstate_t *gstate)
     986                 : {
     987                 :     cairo_operator_t op;
     988                 :     const cairo_pattern_t *pattern;
     989                 : 
     990              64 :     op = gstate->op;
     991              64 :     if (op != CAIRO_OPERATOR_SOURCE)
     992              17 :         return op;
     993                 : 
     994              47 :     pattern = gstate->source;
     995              47 :     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
     996               0 :         const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
     997               0 :         if (solid->color.alpha_short <= 0x00ff) {
     998               0 :             op = CAIRO_OPERATOR_CLEAR;
     999               0 :         } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
    1000               0 :             if ((solid->color.red_short |
    1001               0 :                  solid->color.green_short |
    1002               0 :                  solid->color.blue_short) <= 0x00ff)
    1003                 :             {
    1004               0 :                 op = CAIRO_OPERATOR_CLEAR;
    1005                 :             }
    1006                 :         }
    1007              47 :     } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
    1008              47 :         const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
    1009              47 :         if (surface->surface->is_clear &&
    1010               0 :             surface->surface->content & CAIRO_CONTENT_ALPHA)
    1011                 :         {
    1012               0 :             op = CAIRO_OPERATOR_CLEAR;
    1013                 :         }
    1014                 :     } else {
    1015               0 :         const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
    1016               0 :         if (gradient->n_stops == 0)
    1017               0 :             op = CAIRO_OPERATOR_CLEAR;
    1018                 :     }
    1019                 : 
    1020              47 :     return op;
    1021                 : }
    1022                 : 
    1023                 : cairo_status_t
    1024              43 : _cairo_gstate_paint (cairo_gstate_t *gstate)
    1025                 : {
    1026                 :     cairo_pattern_union_t source_pattern;
    1027                 :     const cairo_pattern_t *pattern;
    1028                 :     cairo_clip_t clip;
    1029                 :     cairo_status_t status;
    1030                 :     cairo_operator_t op;
    1031                 : 
    1032              43 :     if (unlikely (gstate->source->status))
    1033               0 :         return gstate->source->status;
    1034                 : 
    1035              43 :     if (gstate->op == CAIRO_OPERATOR_DEST)
    1036               0 :         return CAIRO_STATUS_SUCCESS;
    1037                 : 
    1038              43 :     if (_clipped (gstate))
    1039               0 :         return CAIRO_STATUS_SUCCESS;
    1040                 : 
    1041              43 :     op = _reduce_op (gstate);
    1042              43 :     if (op == CAIRO_OPERATOR_CLEAR) {
    1043              17 :         pattern = &_cairo_pattern_clear.base;
    1044                 :     } else {
    1045              26 :         _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
    1046              26 :         pattern = &source_pattern.base;
    1047                 :     }
    1048                 : 
    1049              43 :     status = _cairo_surface_paint (gstate->target,
    1050                 :                                    op, pattern,
    1051                 :                                    _gstate_get_clip (gstate, &clip));
    1052              43 :     _cairo_clip_fini (&clip);
    1053                 : 
    1054              43 :     return status;
    1055                 : }
    1056                 : 
    1057                 : cairo_status_t
    1058               0 : _cairo_gstate_mask (cairo_gstate_t  *gstate,
    1059                 :                     cairo_pattern_t *mask)
    1060                 : {
    1061                 :     cairo_pattern_union_t source_pattern, mask_pattern;
    1062                 :     const cairo_pattern_t *source;
    1063                 :     cairo_operator_t op;
    1064                 :     cairo_clip_t clip;
    1065                 :     cairo_status_t status;
    1066                 : 
    1067               0 :     if (unlikely (mask->status))
    1068               0 :         return mask->status;
    1069                 : 
    1070               0 :     if (unlikely (gstate->source->status))
    1071               0 :         return gstate->source->status;
    1072                 : 
    1073               0 :     if (gstate->op == CAIRO_OPERATOR_DEST)
    1074               0 :         return CAIRO_STATUS_SUCCESS;
    1075                 : 
    1076               0 :     if (_clipped (gstate))
    1077               0 :         return CAIRO_STATUS_SUCCESS;
    1078                 : 
    1079               0 :     if (_cairo_pattern_is_opaque (mask, NULL))
    1080               0 :         return _cairo_gstate_paint (gstate);
    1081                 : 
    1082               0 :     if (_cairo_pattern_is_clear (mask) &&
    1083               0 :         _cairo_operator_bounded_by_mask (gstate->op))
    1084                 :     {
    1085               0 :         return CAIRO_STATUS_SUCCESS;
    1086                 :     }
    1087                 : 
    1088               0 :     op = _reduce_op (gstate);
    1089               0 :     if (op == CAIRO_OPERATOR_CLEAR) {
    1090               0 :         source = &_cairo_pattern_clear.base;
    1091                 :     } else {
    1092               0 :         _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
    1093               0 :         source = &source_pattern.base;
    1094                 :     }
    1095               0 :     _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
    1096                 : 
    1097               0 :     if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
    1098               0 :         mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
    1099               0 :         _cairo_operator_bounded_by_source (op))
    1100               0 :     {
    1101               0 :         const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
    1102                 :         cairo_color_t combined;
    1103                 : 
    1104               0 :         if (mask_pattern.base.has_component_alpha) {
    1105                 : #define M(R, A, B, c) R.c = A.c * B.c
    1106               0 :             M(combined, solid->color, mask_pattern.solid.color, red);
    1107               0 :             M(combined, solid->color, mask_pattern.solid.color, green);
    1108               0 :             M(combined, solid->color, mask_pattern.solid.color, blue);
    1109               0 :             M(combined, solid->color, mask_pattern.solid.color, alpha);
    1110                 : #undef M
    1111                 :         } else {
    1112               0 :             combined = solid->color;
    1113               0 :             _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
    1114                 :         }
    1115                 : 
    1116               0 :         _cairo_pattern_init_solid (&source_pattern.solid, &combined);
    1117                 : 
    1118               0 :         status = _cairo_surface_paint (gstate->target, op,
    1119                 :                                        &source_pattern.base,
    1120                 :                                        _gstate_get_clip (gstate, &clip));
    1121                 :     }
    1122                 :     else
    1123                 :     {
    1124               0 :         status = _cairo_surface_mask (gstate->target, op,
    1125                 :                                       source,
    1126                 :                                       &mask_pattern.base,
    1127                 :                                       _gstate_get_clip (gstate, &clip));
    1128                 :     }
    1129               0 :     _cairo_clip_fini (&clip);
    1130                 : 
    1131               0 :     return status;
    1132                 : }
    1133                 : 
    1134                 : cairo_status_t
    1135               0 : _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
    1136                 : {
    1137                 :     cairo_pattern_union_t source_pattern;
    1138                 :     cairo_stroke_style_t style;
    1139                 :     double dash[2];
    1140                 :     cairo_clip_t clip;
    1141                 :     cairo_status_t status;
    1142                 : 
    1143               0 :     if (unlikely (gstate->source->status))
    1144               0 :         return gstate->source->status;
    1145                 : 
    1146               0 :     if (gstate->op == CAIRO_OPERATOR_DEST)
    1147               0 :         return CAIRO_STATUS_SUCCESS;
    1148                 : 
    1149               0 :     if (gstate->stroke_style.line_width <= 0.0)
    1150               0 :         return CAIRO_STATUS_SUCCESS;
    1151                 : 
    1152               0 :     if (_clipped (gstate))
    1153               0 :         return CAIRO_STATUS_SUCCESS;
    1154                 : 
    1155               0 :     memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
    1156               0 :     if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
    1157               0 :         style.dash = dash;
    1158               0 :         _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
    1159                 :                                               &style.dash_offset,
    1160                 :                                               style.dash,
    1161                 :                                               &style.num_dashes);
    1162                 :     }
    1163                 : 
    1164               0 :     _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
    1165                 : 
    1166               0 :     status = _cairo_surface_stroke (gstate->target,
    1167                 :                                     gstate->op,
    1168                 :                                     &source_pattern.base,
    1169                 :                                     path,
    1170                 :                                     &style,
    1171               0 :                                     &gstate->ctm,
    1172               0 :                                     &gstate->ctm_inverse,
    1173                 :                                     gstate->tolerance,
    1174                 :                                     gstate->antialias,
    1175                 :                                     _gstate_get_clip (gstate, &clip));
    1176               0 :     _cairo_clip_fini (&clip);
    1177                 : 
    1178               0 :     return status;
    1179                 : }
    1180                 : 
    1181                 : cairo_status_t
    1182               0 : _cairo_gstate_in_stroke (cairo_gstate_t     *gstate,
    1183                 :                          cairo_path_fixed_t *path,
    1184                 :                          double              x,
    1185                 :                          double              y,
    1186                 :                          cairo_bool_t       *inside_ret)
    1187                 : {
    1188                 :     cairo_status_t status;
    1189                 :     cairo_rectangle_int_t extents;
    1190                 :     cairo_box_t limit;
    1191                 :     cairo_traps_t traps;
    1192                 : 
    1193               0 :     if (gstate->stroke_style.line_width <= 0.0) {
    1194               0 :         *inside_ret = FALSE;
    1195               0 :         return CAIRO_STATUS_SUCCESS;
    1196                 :     }
    1197                 : 
    1198               0 :     _cairo_gstate_user_to_backend (gstate, &x, &y);
    1199                 : 
    1200                 :     /* Before we perform the expensive stroke analysis,
    1201                 :      * check whether the point is within the extents of the path.
    1202                 :      */
    1203               0 :     _cairo_path_fixed_approximate_stroke_extents (path,
    1204               0 :                                                   &gstate->stroke_style,
    1205               0 :                                                   &gstate->ctm,
    1206                 :                                                   &extents);
    1207               0 :     if (x < extents.x || x > extents.x + extents.width ||
    1208               0 :         y < extents.y || y > extents.y + extents.height)
    1209                 :     {
    1210               0 :         *inside_ret = FALSE;
    1211               0 :         return CAIRO_STATUS_SUCCESS;
    1212                 :     }
    1213                 : 
    1214               0 :     limit.p1.x = _cairo_fixed_from_double (x) - 5;
    1215               0 :     limit.p1.y = _cairo_fixed_from_double (y) - 5;
    1216               0 :     limit.p2.x = limit.p1.x + 5;
    1217               0 :     limit.p2.y = limit.p1.y + 5;
    1218                 : 
    1219               0 :     _cairo_traps_init (&traps);
    1220               0 :     _cairo_traps_limit (&traps, &limit, 1);
    1221                 : 
    1222               0 :     status = _cairo_path_fixed_stroke_to_traps (path,
    1223               0 :                                                 &gstate->stroke_style,
    1224               0 :                                                 &gstate->ctm,
    1225               0 :                                                 &gstate->ctm_inverse,
    1226                 :                                                 gstate->tolerance,
    1227                 :                                                 &traps);
    1228               0 :     if (unlikely (status))
    1229               0 :         goto BAIL;
    1230                 : 
    1231               0 :     *inside_ret = _cairo_traps_contain (&traps, x, y);
    1232                 : 
    1233                 : BAIL:
    1234               0 :     _cairo_traps_fini (&traps);
    1235                 : 
    1236               0 :     return status;
    1237                 : }
    1238                 : 
    1239                 : cairo_status_t
    1240              21 : _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
    1241                 : {
    1242                 :     cairo_clip_t clip;
    1243                 :     cairo_status_t status;
    1244                 : 
    1245              21 :     if (unlikely (gstate->source->status))
    1246               0 :         return gstate->source->status;
    1247                 : 
    1248              21 :     if (gstate->op == CAIRO_OPERATOR_DEST)
    1249               0 :         return CAIRO_STATUS_SUCCESS;
    1250                 : 
    1251              21 :     if (_clipped (gstate))
    1252               0 :         return CAIRO_STATUS_SUCCESS;
    1253                 : 
    1254              21 :     if (_cairo_path_fixed_fill_is_empty (path)) {
    1255               0 :         if (_cairo_operator_bounded_by_mask (gstate->op))
    1256               0 :             return CAIRO_STATUS_SUCCESS;
    1257                 : 
    1258               0 :         status = _cairo_surface_paint (gstate->target,
    1259                 :                                        CAIRO_OPERATOR_CLEAR,
    1260                 :                                        &_cairo_pattern_clear.base,
    1261                 :                                        _gstate_get_clip (gstate, &clip));
    1262                 :     } else {
    1263                 :         cairo_pattern_union_t source_pattern;
    1264                 :         const cairo_pattern_t *pattern;
    1265                 :         cairo_operator_t op;
    1266                 :         cairo_rectangle_int_t extents;
    1267                 :         cairo_box_t box;
    1268                 : 
    1269              21 :         op = _reduce_op (gstate);
    1270              21 :         if (op == CAIRO_OPERATOR_CLEAR) {
    1271               0 :             pattern = &_cairo_pattern_clear.base;
    1272                 :         } else {
    1273              21 :             _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
    1274              21 :             pattern = &source_pattern.base;
    1275                 :         }
    1276                 : 
    1277                 :         /* Toolkits often paint the entire background with a fill */
    1278              42 :         if (_cairo_surface_get_extents (gstate->target, &extents) &&
    1279              42 :             _cairo_path_fixed_is_box (path, &box) &&
    1280              42 :             box.p1.x <= _cairo_fixed_from_int (extents.x) &&
    1281              42 :             box.p1.y <= _cairo_fixed_from_int (extents.y) &&
    1282              42 :             box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
    1283              21 :             box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
    1284                 :         {
    1285              21 :             status = _cairo_surface_paint (gstate->target, op, pattern,
    1286                 :                                            _gstate_get_clip (gstate, &clip));
    1287                 :         }
    1288                 :         else
    1289                 :         {
    1290               0 :             status = _cairo_surface_fill (gstate->target, op, pattern,
    1291                 :                                           path,
    1292                 :                                           gstate->fill_rule,
    1293                 :                                           gstate->tolerance,
    1294                 :                                           gstate->antialias,
    1295                 :                                           _gstate_get_clip (gstate, &clip));
    1296                 :         }
    1297                 :     }
    1298                 : 
    1299              21 :     _cairo_clip_fini (&clip);
    1300                 : 
    1301              21 :     return status;
    1302                 : }
    1303                 : 
    1304                 : cairo_bool_t
    1305               0 : _cairo_gstate_in_fill (cairo_gstate_t     *gstate,
    1306                 :                        cairo_path_fixed_t *path,
    1307                 :                        double              x,
    1308                 :                        double              y)
    1309                 : {
    1310               0 :     _cairo_gstate_user_to_backend (gstate, &x, &y);
    1311                 : 
    1312               0 :     return _cairo_path_fixed_in_fill (path,
    1313                 :                                       gstate->fill_rule,
    1314                 :                                       gstate->tolerance,
    1315                 :                                       x, y);
    1316                 : }
    1317                 : 
    1318                 : cairo_bool_t
    1319               0 : _cairo_gstate_in_clip (cairo_gstate_t     *gstate,
    1320                 :                        double              x,
    1321                 :                        double              y)
    1322                 : {
    1323                 :     cairo_clip_path_t *clip_path;
    1324                 : 
    1325               0 :     if (gstate->clip.all_clipped)
    1326               0 :         return FALSE;
    1327                 : 
    1328               0 :     clip_path = gstate->clip.path;
    1329               0 :     if (clip_path == NULL)
    1330               0 :         return TRUE;
    1331                 : 
    1332               0 :     _cairo_gstate_user_to_backend (gstate, &x, &y);
    1333                 : 
    1334               0 :     if (x <  clip_path->extents.x ||
    1335               0 :         x >= clip_path->extents.x + clip_path->extents.width ||
    1336               0 :         y <  clip_path->extents.y ||
    1337               0 :         y >= clip_path->extents.y + clip_path->extents.height)
    1338                 :     {
    1339               0 :         return FALSE;
    1340                 :     }
    1341                 : 
    1342                 :     do {
    1343               0 :         if (! _cairo_path_fixed_in_fill (&clip_path->path,
    1344                 :                                          clip_path->fill_rule,
    1345                 :                                          clip_path->tolerance,
    1346                 :                                          x, y))
    1347               0 :             return FALSE;
    1348               0 :     } while ((clip_path = clip_path->prev) != NULL);
    1349                 : 
    1350               0 :     return TRUE;
    1351                 : }
    1352                 : 
    1353                 : cairo_status_t
    1354               0 : _cairo_gstate_copy_page (cairo_gstate_t *gstate)
    1355                 : {
    1356               0 :     cairo_surface_copy_page (gstate->target);
    1357               0 :     return cairo_surface_status (gstate->target);
    1358                 : }
    1359                 : 
    1360                 : cairo_status_t
    1361               0 : _cairo_gstate_show_page (cairo_gstate_t *gstate)
    1362                 : {
    1363               0 :     cairo_surface_show_page (gstate->target);
    1364               0 :     return cairo_surface_status (gstate->target);
    1365                 : }
    1366                 : 
    1367                 : static void
    1368               0 : _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t     *gstate,
    1369                 :                                                cairo_traps_t      *traps,
    1370                 :                                                double *x1, double *y1,
    1371                 :                                                double *x2, double *y2)
    1372                 : {
    1373                 :     cairo_box_t extents;
    1374                 : 
    1375               0 :     if (traps->num_traps == 0) {
    1376                 :         /* no traps, so we actually won't draw anything */
    1377               0 :         if (x1)
    1378               0 :             *x1 = 0.0;
    1379               0 :         if (y1)
    1380               0 :             *y1 = 0.0;
    1381               0 :         if (x2)
    1382               0 :             *x2 = 0.0;
    1383               0 :         if (y2)
    1384               0 :             *y2 = 0.0;
    1385                 :     } else {
    1386                 :         double px1, py1, px2, py2;
    1387                 : 
    1388               0 :         _cairo_traps_extents (traps, &extents);
    1389                 : 
    1390               0 :         px1 = _cairo_fixed_to_double (extents.p1.x);
    1391               0 :         py1 = _cairo_fixed_to_double (extents.p1.y);
    1392               0 :         px2 = _cairo_fixed_to_double (extents.p2.x);
    1393               0 :         py2 = _cairo_fixed_to_double (extents.p2.y);
    1394                 : 
    1395               0 :         _cairo_gstate_backend_to_user_rectangle (gstate,
    1396                 :                                                  &px1, &py1, &px2, &py2,
    1397                 :                                                  NULL);
    1398               0 :         if (x1)
    1399               0 :             *x1 = px1;
    1400               0 :         if (y1)
    1401               0 :             *y1 = py1;
    1402               0 :         if (x2)
    1403               0 :             *x2 = px2;
    1404               0 :         if (y2)
    1405               0 :             *y2 = py2;
    1406                 :     }
    1407               0 : }
    1408                 : 
    1409                 : cairo_status_t
    1410               0 : _cairo_gstate_stroke_extents (cairo_gstate_t     *gstate,
    1411                 :                               cairo_path_fixed_t *path,
    1412                 :                               double *x1, double *y1,
    1413                 :                               double *x2, double *y2)
    1414                 : {
    1415                 :     cairo_status_t status;
    1416                 :     cairo_traps_t traps;
    1417                 : 
    1418               0 :     if (gstate->stroke_style.line_width <= 0.0) {
    1419               0 :         if (x1)
    1420               0 :             *x1 = 0.0;
    1421               0 :         if (y1)
    1422               0 :             *y1 = 0.0;
    1423               0 :         if (x2)
    1424               0 :             *x2 = 0.0;
    1425               0 :         if (y2)
    1426               0 :             *y2 = 0.0;
    1427               0 :         return CAIRO_STATUS_SUCCESS;
    1428                 :     }
    1429                 : 
    1430               0 :     _cairo_traps_init (&traps);
    1431                 : 
    1432               0 :     status = _cairo_path_fixed_stroke_to_traps (path,
    1433               0 :                                                 &gstate->stroke_style,
    1434               0 :                                                 &gstate->ctm,
    1435               0 :                                                 &gstate->ctm_inverse,
    1436                 :                                                 gstate->tolerance,
    1437                 :                                                 &traps);
    1438               0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
    1439               0 :         _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
    1440                 :                                                        x1, y1, x2, y2);
    1441                 :     }
    1442                 : 
    1443               0 :     _cairo_traps_fini (&traps);
    1444                 : 
    1445               0 :     return status;
    1446                 : }
    1447                 : 
    1448                 : cairo_status_t
    1449               0 : _cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
    1450                 :                             cairo_path_fixed_t *path,
    1451                 :                             double *x1, double *y1,
    1452                 :                             double *x2, double *y2)
    1453                 : {
    1454                 :     cairo_status_t status;
    1455                 :     cairo_traps_t traps;
    1456                 : 
    1457               0 :     if (path->is_empty_fill) {
    1458               0 :         if (x1)
    1459               0 :             *x1 = 0.0;
    1460               0 :         if (y1)
    1461               0 :             *y1 = 0.0;
    1462               0 :         if (x2)
    1463               0 :             *x2 = 0.0;
    1464               0 :         if (y2)
    1465               0 :             *y2 = 0.0;
    1466               0 :         return CAIRO_STATUS_SUCCESS;
    1467                 :     }
    1468                 : 
    1469               0 :     _cairo_traps_init (&traps);
    1470                 : 
    1471               0 :     status = _cairo_path_fixed_fill_to_traps (path,
    1472                 :                                               gstate->fill_rule,
    1473                 :                                               gstate->tolerance,
    1474                 :                                               &traps);
    1475               0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
    1476               0 :         _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
    1477                 :                                                        x1, y1, x2, y2);
    1478                 :     }
    1479                 : 
    1480               0 :     _cairo_traps_fini (&traps);
    1481                 : 
    1482               0 :     return status;
    1483                 : }
    1484                 : 
    1485                 : cairo_status_t
    1486               0 : _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
    1487                 : {
    1488               0 :     _cairo_clip_reset (&gstate->clip);
    1489                 : 
    1490               0 :     return CAIRO_STATUS_SUCCESS;
    1491                 : }
    1492                 : 
    1493                 : cairo_status_t
    1494               0 : _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
    1495                 : {
    1496               0 :     return _cairo_clip_clip (&gstate->clip,
    1497                 :                              path, gstate->fill_rule,
    1498                 :                              gstate->tolerance, gstate->antialias);
    1499                 : }
    1500                 : 
    1501                 : static cairo_bool_t
    1502               0 : _cairo_gstate_int_clip_extents (cairo_gstate_t        *gstate,
    1503                 :                                 cairo_rectangle_int_t *extents)
    1504                 : {
    1505                 :     const cairo_rectangle_int_t *clip_extents;
    1506                 :     cairo_bool_t is_bounded;
    1507                 : 
    1508               0 :     is_bounded = _cairo_surface_get_extents (gstate->target, extents);
    1509                 : 
    1510               0 :     clip_extents = _cairo_clip_get_extents (&gstate->clip);
    1511               0 :     if (clip_extents != NULL) {
    1512                 :         cairo_bool_t is_empty;
    1513                 : 
    1514               0 :         is_empty = _cairo_rectangle_intersect (extents, clip_extents);
    1515               0 :         is_bounded = TRUE;
    1516                 :     }
    1517                 : 
    1518               0 :     return is_bounded;
    1519                 : }
    1520                 : 
    1521                 : cairo_bool_t
    1522               0 : _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
    1523                 :                             double         *x1,
    1524                 :                             double         *y1,
    1525                 :                             double         *x2,
    1526                 :                             double         *y2)
    1527                 : {
    1528                 :     cairo_rectangle_int_t extents;
    1529                 :     double px1, py1, px2, py2;
    1530                 : 
    1531               0 :     if (! _cairo_gstate_int_clip_extents (gstate, &extents))
    1532               0 :         return FALSE;
    1533                 : 
    1534               0 :     px1 = extents.x;
    1535               0 :     py1 = extents.y;
    1536               0 :     px2 = extents.x + (int) extents.width;
    1537               0 :     py2 = extents.y + (int) extents.height;
    1538                 : 
    1539               0 :     _cairo_gstate_backend_to_user_rectangle (gstate,
    1540                 :                                              &px1, &py1, &px2, &py2,
    1541                 :                                              NULL);
    1542                 : 
    1543               0 :     if (x1)
    1544               0 :         *x1 = px1;
    1545               0 :     if (y1)
    1546               0 :         *y1 = py1;
    1547               0 :     if (x2)
    1548               0 :         *x2 = px2;
    1549               0 :     if (y2)
    1550               0 :         *y2 = py2;
    1551                 : 
    1552               0 :     return TRUE;
    1553                 : }
    1554                 : 
    1555                 : cairo_rectangle_list_t*
    1556               0 : _cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
    1557                 : {
    1558                 :     cairo_clip_t clip;
    1559                 :     cairo_rectangle_int_t extents;
    1560                 :     cairo_rectangle_list_t *list;
    1561                 : 
    1562               0 :     _cairo_clip_init_copy (&clip, &gstate->clip);
    1563                 : 
    1564               0 :     if (_cairo_surface_get_extents (gstate->target, &extents))
    1565               0 :         _cairo_clip_rectangle (&clip, &extents);
    1566                 : 
    1567               0 :     list = _cairo_clip_copy_rectangle_list (&clip, gstate);
    1568               0 :     _cairo_clip_fini (&clip);
    1569                 : 
    1570               0 :     return list;
    1571                 : }
    1572                 : 
    1573                 : static void
    1574              31 : _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
    1575                 : {
    1576              31 :     if (gstate->scaled_font == NULL)
    1577              31 :         return;
    1578                 : 
    1579               0 :     if (gstate->previous_scaled_font != NULL)
    1580               0 :         cairo_scaled_font_destroy (gstate->previous_scaled_font);
    1581                 : 
    1582               0 :     gstate->previous_scaled_font = gstate->scaled_font;
    1583               0 :     gstate->scaled_font = NULL;
    1584                 : }
    1585                 : 
    1586                 : cairo_status_t
    1587               0 : _cairo_gstate_select_font_face (cairo_gstate_t       *gstate,
    1588                 :                                 const char           *family,
    1589                 :                                 cairo_font_slant_t    slant,
    1590                 :                                 cairo_font_weight_t   weight)
    1591                 : {
    1592                 :     cairo_font_face_t *font_face;
    1593                 :     cairo_status_t status;
    1594                 : 
    1595               0 :     font_face = cairo_toy_font_face_create (family, slant, weight);
    1596               0 :     if (font_face->status)
    1597               0 :         return font_face->status;
    1598                 : 
    1599               0 :     status = _cairo_gstate_set_font_face (gstate, font_face);
    1600               0 :     cairo_font_face_destroy (font_face);
    1601                 : 
    1602               0 :     return status;
    1603                 : }
    1604                 : 
    1605                 : cairo_status_t
    1606               0 : _cairo_gstate_set_font_size (cairo_gstate_t *gstate,
    1607                 :                              double          size)
    1608                 : {
    1609               0 :     _cairo_gstate_unset_scaled_font (gstate);
    1610                 : 
    1611               0 :     cairo_matrix_init_scale (&gstate->font_matrix, size, size);
    1612                 : 
    1613               0 :     return CAIRO_STATUS_SUCCESS;
    1614                 : }
    1615                 : 
    1616                 : cairo_status_t
    1617               0 : _cairo_gstate_set_font_matrix (cairo_gstate_t       *gstate,
    1618                 :                                const cairo_matrix_t *matrix)
    1619                 : {
    1620               0 :     if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0)
    1621               0 :         return CAIRO_STATUS_SUCCESS;
    1622                 : 
    1623               0 :     if (! _cairo_matrix_is_invertible (matrix)) {
    1624                 :         /* rank 0 matrices are ok even though they are not invertible */
    1625               0 :         if (!(matrix->xx == 0. && matrix->xy == 0. &&
    1626               0 :               matrix->yx == 0. && matrix->yy == 0.)) {
    1627               0 :             return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
    1628                 :         }
    1629                 :     }
    1630                 : 
    1631               0 :     _cairo_gstate_unset_scaled_font (gstate);
    1632                 : 
    1633               0 :     gstate->font_matrix = *matrix;
    1634                 : 
    1635               0 :     return CAIRO_STATUS_SUCCESS;
    1636                 : }
    1637                 : 
    1638                 : void
    1639               0 : _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
    1640                 :                                cairo_matrix_t *matrix)
    1641                 : {
    1642               0 :     *matrix = gstate->font_matrix;
    1643               0 : }
    1644                 : 
    1645                 : void
    1646               0 : _cairo_gstate_set_font_options (cairo_gstate_t             *gstate,
    1647                 :                                 const cairo_font_options_t *options)
    1648                 : {
    1649               0 :     if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
    1650               0 :         return;
    1651                 : 
    1652               0 :     _cairo_gstate_unset_scaled_font (gstate);
    1653                 : 
    1654               0 :     _cairo_font_options_init_copy (&gstate->font_options, options);
    1655                 : }
    1656                 : 
    1657                 : void
    1658               0 : _cairo_gstate_get_font_options (cairo_gstate_t       *gstate,
    1659                 :                                 cairo_font_options_t *options)
    1660                 : {
    1661               0 :     *options = gstate->font_options;
    1662               0 : }
    1663                 : 
    1664                 : cairo_status_t
    1665               0 : _cairo_gstate_get_font_face (cairo_gstate_t     *gstate,
    1666                 :                              cairo_font_face_t **font_face)
    1667                 : {
    1668                 :     cairo_status_t status;
    1669                 : 
    1670               0 :     status = _cairo_gstate_ensure_font_face (gstate);
    1671               0 :     if (unlikely (status))
    1672               0 :         return status;
    1673                 : 
    1674               0 :     *font_face = gstate->font_face;
    1675                 : 
    1676               0 :     return CAIRO_STATUS_SUCCESS;
    1677                 : }
    1678                 : 
    1679                 : cairo_status_t
    1680               0 : _cairo_gstate_get_scaled_font (cairo_gstate_t       *gstate,
    1681                 :                                cairo_scaled_font_t **scaled_font)
    1682                 : {
    1683                 :     cairo_status_t status;
    1684                 : 
    1685               0 :     status = _cairo_gstate_ensure_scaled_font (gstate);
    1686               0 :     if (unlikely (status))
    1687               0 :         return status;
    1688                 : 
    1689               0 :     *scaled_font = gstate->scaled_font;
    1690                 : 
    1691               0 :     return CAIRO_STATUS_SUCCESS;
    1692                 : }
    1693                 : 
    1694                 : /*
    1695                 :  * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
    1696                 :  * it is easy to get confused about what's going on.
    1697                 :  *
    1698                 :  * The user's view
    1699                 :  * ---------------
    1700                 :  *
    1701                 :  * Users ask for things in user space. When cairo starts, a user space unit
    1702                 :  * is about 1/96 inch, which is similar to (but importantly different from)
    1703                 :  * the normal "point" units most users think in terms of. When a user
    1704                 :  * selects a font, its scale is set to "one user unit". The user can then
    1705                 :  * independently scale the user coordinate system *or* the font matrix, in
    1706                 :  * order to adjust the rendered size of the font.
    1707                 :  *
    1708                 :  * Metrics are returned in user space, whether they are obtained from
    1709                 :  * the currently selected font in a  #cairo_t or from a #cairo_scaled_font_t
    1710                 :  * which is a font specialized to a particular scale matrix, CTM, and target
    1711                 :  * surface.
    1712                 :  *
    1713                 :  * The font's view
    1714                 :  * ---------------
    1715                 :  *
    1716                 :  * Fonts are designed and stored (in say .ttf files) in "font space", which
    1717                 :  * describes an "EM Square" (a design tile) and has some abstract number
    1718                 :  * such as 1000, 1024, or 2048 units per "EM". This is basically an
    1719                 :  * uninteresting space for us, but we need to remember that it exists.
    1720                 :  *
    1721                 :  * Font resources (from libraries or operating systems) render themselves
    1722                 :  * to a particular device. Since they do not want to make most programmers
    1723                 :  * worry about the font design space, the scaling API is simplified to
    1724                 :  * involve just telling the font the required pixel size of the EM square
    1725                 :  * (that is, in device space).
    1726                 :  *
    1727                 :  *
    1728                 :  * Cairo's gstate view
    1729                 :  * -------------------
    1730                 :  *
    1731                 :  * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
    1732                 :  * called the "font matrix" which describes the user's most recent
    1733                 :  * font-scaling or font-transforming request. This is kept in terms of an
    1734                 :  * abstract scale factor, composed with the CTM and used to set the font's
    1735                 :  * pixel size. So if the user asks to "scale the font by 12", the matrix
    1736                 :  * is:
    1737                 :  *
    1738                 :  *   [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
    1739                 :  *
    1740                 :  * It is an affine matrix, like all cairo matrices, where its tx and ty
    1741                 :  * components are used to "nudging" fonts around and are handled in gstate
    1742                 :  * and then ignored by the "scaled-font" layer.
    1743                 :  *
    1744                 :  * In order to perform any action on a font, we must build an object
    1745                 :  * called a #cairo_font_scale_t; this contains the central 2x2 matrix
    1746                 :  * resulting from "font matrix * CTM" (sans the font matrix translation
    1747                 :  * components as stated in the previous paragraph).
    1748                 :  *
    1749                 :  * We pass this to the font when making requests of it, which causes it to
    1750                 :  * reply for a particular [user request, device] combination, under the CTM
    1751                 :  * (to accommodate the "zoom in" == "bigger fonts" issue above).
    1752                 :  *
    1753                 :  * The other terms in our communication with the font are therefore in
    1754                 :  * device space. When we ask it to perform text->glyph conversion, it will
    1755                 :  * produce a glyph string in device space. Glyph vectors we pass to it for
    1756                 :  * measuring or rendering should be in device space. The metrics which we
    1757                 :  * get back from the font will be in device space. The contents of the
    1758                 :  * global glyph image cache will be in device space.
    1759                 :  *
    1760                 :  *
    1761                 :  * Cairo's public view
    1762                 :  * -------------------
    1763                 :  *
    1764                 :  * Since the values entering and leaving via public API calls are in user
    1765                 :  * space, the gstate functions typically need to multiply arguments by the
    1766                 :  * CTM (for user-input glyph vectors), and return values by the CTM inverse
    1767                 :  * (for font responses such as metrics or glyph vectors).
    1768                 :  *
    1769                 :  */
    1770                 : 
    1771                 : static cairo_status_t
    1772               0 : _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
    1773                 : {
    1774                 :     cairo_font_face_t *font_face;
    1775                 : 
    1776               0 :     if (gstate->font_face != NULL)
    1777               0 :         return gstate->font_face->status;
    1778                 : 
    1779                 : 
    1780               0 :     font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
    1781                 :                                             CAIRO_FONT_SLANT_DEFAULT,
    1782                 :                                             CAIRO_FONT_WEIGHT_DEFAULT);
    1783               0 :     if (font_face->status)
    1784               0 :         return font_face->status;
    1785                 : 
    1786               0 :     gstate->font_face = font_face;
    1787                 : 
    1788               0 :     return CAIRO_STATUS_SUCCESS;
    1789                 : }
    1790                 : 
    1791                 : static cairo_status_t
    1792               0 : _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
    1793                 : {
    1794                 :     cairo_status_t status;
    1795                 :     cairo_font_options_t options;
    1796                 :     cairo_scaled_font_t *scaled_font;
    1797                 : 
    1798               0 :     if (gstate->scaled_font != NULL)
    1799               0 :         return gstate->scaled_font->status;
    1800                 : 
    1801               0 :     status = _cairo_gstate_ensure_font_face (gstate);
    1802               0 :     if (unlikely (status))
    1803               0 :         return status;
    1804                 : 
    1805               0 :     cairo_surface_get_font_options (gstate->target, &options);
    1806               0 :     cairo_font_options_merge (&options, &gstate->font_options);
    1807                 : 
    1808               0 :     scaled_font = cairo_scaled_font_create (gstate->font_face,
    1809               0 :                                             &gstate->font_matrix,
    1810               0 :                                             &gstate->ctm,
    1811                 :                                             &options);
    1812                 : 
    1813               0 :     status = cairo_scaled_font_status (scaled_font);
    1814               0 :     if (unlikely (status))
    1815               0 :         return status;
    1816                 : 
    1817               0 :     gstate->scaled_font = scaled_font;
    1818                 : 
    1819               0 :     return CAIRO_STATUS_SUCCESS;
    1820                 : }
    1821                 : 
    1822                 : cairo_status_t
    1823               0 : _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
    1824                 :                                 cairo_font_extents_t *extents)
    1825                 : {
    1826               0 :     cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
    1827               0 :     if (unlikely (status))
    1828               0 :         return status;
    1829                 : 
    1830               0 :     cairo_scaled_font_extents (gstate->scaled_font, extents);
    1831                 : 
    1832               0 :     return cairo_scaled_font_status (gstate->scaled_font);
    1833                 : }
    1834                 : 
    1835                 : cairo_status_t
    1836               0 : _cairo_gstate_text_to_glyphs (cairo_gstate_t             *gstate,
    1837                 :                               double                      x,
    1838                 :                               double                      y,
    1839                 :                               const char                 *utf8,
    1840                 :                               int                         utf8_len,
    1841                 :                               cairo_glyph_t             **glyphs,
    1842                 :                               int                        *num_glyphs,
    1843                 :                               cairo_text_cluster_t      **clusters,
    1844                 :                               int                        *num_clusters,
    1845                 :                               cairo_text_cluster_flags_t *cluster_flags)
    1846                 : {
    1847                 :     cairo_status_t status;
    1848                 : 
    1849               0 :     status = _cairo_gstate_ensure_scaled_font (gstate);
    1850               0 :     if (unlikely (status))
    1851               0 :         return status;
    1852                 : 
    1853               0 :     return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
    1854                 :                                              utf8, utf8_len,
    1855                 :                                              glyphs, num_glyphs,
    1856                 :                                              clusters, num_clusters,
    1857                 :                                              cluster_flags);
    1858                 : }
    1859                 : 
    1860                 : cairo_status_t
    1861               0 : _cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
    1862                 :                              cairo_font_face_t *font_face)
    1863                 : {
    1864               0 :     if (font_face && font_face->status)
    1865               0 :         return _cairo_error (font_face->status);
    1866                 : 
    1867               0 :     if (font_face == gstate->font_face)
    1868               0 :         return CAIRO_STATUS_SUCCESS;
    1869                 : 
    1870               0 :     cairo_font_face_destroy (gstate->font_face);
    1871               0 :     gstate->font_face = cairo_font_face_reference (font_face);
    1872                 : 
    1873               0 :     _cairo_gstate_unset_scaled_font (gstate);
    1874                 : 
    1875               0 :     return CAIRO_STATUS_SUCCESS;
    1876                 : }
    1877                 : 
    1878                 : cairo_status_t
    1879               0 : _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
    1880                 :                              const cairo_glyph_t *glyphs,
    1881                 :                              int num_glyphs,
    1882                 :                              cairo_text_extents_t *extents)
    1883                 : {
    1884                 :     cairo_status_t status;
    1885                 : 
    1886               0 :     status = _cairo_gstate_ensure_scaled_font (gstate);
    1887               0 :     if (unlikely (status))
    1888               0 :         return status;
    1889                 : 
    1890               0 :     cairo_scaled_font_glyph_extents (gstate->scaled_font,
    1891                 :                                      glyphs, num_glyphs,
    1892                 :                                      extents);
    1893                 : 
    1894               0 :     return cairo_scaled_font_status (gstate->scaled_font);
    1895                 : }
    1896                 : 
    1897                 : cairo_status_t
    1898               0 : _cairo_gstate_show_text_glyphs (cairo_gstate_t             *gstate,
    1899                 :                                 const char                 *utf8,
    1900                 :                                 int                         utf8_len,
    1901                 :                                 const cairo_glyph_t        *glyphs,
    1902                 :                                 int                         num_glyphs,
    1903                 :                                 const cairo_text_cluster_t *clusters,
    1904                 :                                 int                         num_clusters,
    1905                 :                                 cairo_text_cluster_flags_t  cluster_flags)
    1906                 : {
    1907                 :     cairo_pattern_union_t source_pattern;
    1908                 :     const cairo_pattern_t *pattern;
    1909                 :     cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
    1910                 :     cairo_glyph_t *transformed_glyphs;
    1911                 :     cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
    1912                 :     cairo_text_cluster_t *transformed_clusters;
    1913                 :     cairo_operator_t op;
    1914                 :     cairo_status_t status;
    1915                 :     cairo_clip_t clip;
    1916                 : 
    1917               0 :     if (unlikely (gstate->source->status))
    1918               0 :         return gstate->source->status;
    1919                 : 
    1920               0 :     if (gstate->op == CAIRO_OPERATOR_DEST)
    1921               0 :         return CAIRO_STATUS_SUCCESS;
    1922                 : 
    1923               0 :     if (_clipped (gstate))
    1924               0 :         return CAIRO_STATUS_SUCCESS;
    1925                 : 
    1926               0 :     status = _cairo_gstate_ensure_scaled_font (gstate);
    1927               0 :     if (unlikely (status))
    1928               0 :         return status;
    1929                 : 
    1930               0 :     transformed_glyphs = stack_transformed_glyphs;
    1931               0 :     transformed_clusters = stack_transformed_clusters;
    1932                 : 
    1933               0 :     if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
    1934               0 :         transformed_glyphs = cairo_glyph_allocate (num_glyphs);
    1935               0 :         if (unlikely (transformed_glyphs == NULL)) {
    1936               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1937               0 :             goto CLEANUP_GLYPHS;
    1938                 :         }
    1939                 :     }
    1940                 : 
    1941                 :     /* Just in case */
    1942               0 :     if (!clusters)
    1943               0 :         num_clusters = 0;
    1944                 : 
    1945               0 :     if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
    1946               0 :         transformed_clusters = cairo_text_cluster_allocate (num_clusters);
    1947               0 :         if (unlikely (transformed_clusters == NULL)) {
    1948               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1949               0 :             goto CLEANUP_GLYPHS;
    1950                 :         }
    1951                 :     }
    1952                 : 
    1953               0 :     status = _cairo_gstate_transform_glyphs_to_backend (gstate,
    1954                 :                                                         glyphs, num_glyphs,
    1955                 :                                                         clusters,
    1956                 :                                                         num_clusters,
    1957                 :                                                         cluster_flags,
    1958                 :                                                         transformed_glyphs,
    1959                 :                                                         &num_glyphs,
    1960                 :                                                         transformed_clusters);
    1961                 : 
    1962               0 :     if (status || num_glyphs == 0)
    1963                 :         goto CLEANUP_GLYPHS;
    1964                 : 
    1965               0 :     op = _reduce_op (gstate);
    1966               0 :     if (op == CAIRO_OPERATOR_CLEAR) {
    1967               0 :         pattern = &_cairo_pattern_clear.base;
    1968                 :     } else {
    1969               0 :         _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
    1970               0 :         pattern = &source_pattern.base;
    1971                 :     }
    1972               0 :     _cairo_clip_init(&clip);
    1973                 : 
    1974                 :     /* For really huge font sizes, we can just do path;fill instead of
    1975                 :      * show_glyphs, as show_glyphs would put excess pressure on the cache,
    1976                 :      * not all components below us correctly handle huge font sizes, and
    1977                 :      * path filling can be cheaper since parts of glyphs are likely to be
    1978                 :      * clipped out.  256 seems like a good limit.  But alas, seems like cairo's
    1979                 :      * rasterizer is something like ten times slower than freetype's for huge
    1980                 :      * sizes.  So, no win just yet when we're using cairo's rasterizer.
    1981                 :      * For now, if we're using cairo's rasterizer, use path filling only
    1982                 :      * for insanely-huge sizes, just to make sure we don't make anyone
    1983                 :      * unhappy.  When we get a really fast rasterizer in cairo, we may
    1984                 :      * want to readjust this.  The threshold calculation is
    1985                 :      * encapsulated in _cairo_surface_get_text_path_fill_threshold.
    1986                 :      *
    1987                 :      * Needless to say, do this only if show_text_glyphs is not available. */
    1988               0 :     if (cairo_surface_has_show_text_glyphs (gstate->target) ||
    1989               0 :         _cairo_scaled_font_get_max_scale (gstate->scaled_font) <=
    1990               0 :         _cairo_surface_get_text_path_fill_threshold (gstate->target))
    1991                 :     {
    1992               0 :         status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
    1993                 :                                                   utf8, utf8_len,
    1994                 :                                                   transformed_glyphs, num_glyphs,
    1995                 :                                                   transformed_clusters, num_clusters,
    1996                 :                                                   cluster_flags,
    1997                 :                                                   gstate->scaled_font,
    1998                 :                                                   _gstate_get_clip (gstate, &clip));
    1999                 :     }
    2000                 :     else
    2001                 :     {
    2002                 :         cairo_path_fixed_t path;
    2003                 : 
    2004               0 :         _cairo_path_fixed_init (&path);
    2005                 : 
    2006               0 :         status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
    2007                 :                                                 transformed_glyphs, num_glyphs,
    2008                 :                                                 &path);
    2009                 : 
    2010               0 :         if (status == CAIRO_STATUS_SUCCESS) {
    2011               0 :             status = _cairo_surface_fill (gstate->target, op, pattern,
    2012                 :                                           &path,
    2013                 :                                           CAIRO_FILL_RULE_WINDING,
    2014                 :                                           gstate->tolerance,
    2015               0 :                                           gstate->scaled_font->options.antialias,
    2016                 :                                           _gstate_get_clip (gstate, &clip));
    2017                 :         }
    2018                 : 
    2019               0 :         _cairo_path_fixed_fini (&path);
    2020                 :     }
    2021                 : 
    2022               0 :     _cairo_clip_fini (&clip);
    2023                 : 
    2024                 : CLEANUP_GLYPHS:
    2025               0 :     if (transformed_glyphs != stack_transformed_glyphs)
    2026               0 :       cairo_glyph_free (transformed_glyphs);
    2027               0 :     if (transformed_clusters != stack_transformed_clusters)
    2028               0 :       cairo_text_cluster_free (transformed_clusters);
    2029                 : 
    2030               0 :     return status;
    2031                 : }
    2032                 : 
    2033                 : cairo_status_t
    2034               0 : _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
    2035                 :                           const cairo_glyph_t *glyphs,
    2036                 :                           int                  num_glyphs,
    2037                 :                           cairo_path_fixed_t  *path)
    2038                 : {
    2039                 :     cairo_status_t status;
    2040                 :     cairo_glyph_t *transformed_glyphs;
    2041                 :     cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
    2042                 : 
    2043               0 :     status = _cairo_gstate_ensure_scaled_font (gstate);
    2044               0 :     if (unlikely (status))
    2045               0 :         return status;
    2046                 : 
    2047               0 :     if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
    2048               0 :       transformed_glyphs = stack_transformed_glyphs;
    2049                 :     } else {
    2050               0 :         transformed_glyphs = cairo_glyph_allocate (num_glyphs);
    2051               0 :         if (unlikely (transformed_glyphs == NULL))
    2052               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2053                 :     }
    2054                 : 
    2055               0 :     status = _cairo_gstate_transform_glyphs_to_backend (gstate,
    2056                 :                                                         glyphs, num_glyphs,
    2057                 :                                                         NULL, 0, 0,
    2058                 :                                                         transformed_glyphs,
    2059                 :                                                         NULL, NULL);
    2060               0 :     if (unlikely (status))
    2061               0 :         goto CLEANUP_GLYPHS;
    2062                 : 
    2063               0 :     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
    2064                 :                                             transformed_glyphs, num_glyphs,
    2065                 :                                             path);
    2066                 : 
    2067                 :   CLEANUP_GLYPHS:
    2068               0 :     if (transformed_glyphs != stack_transformed_glyphs)
    2069               0 :       cairo_glyph_free (transformed_glyphs);
    2070                 : 
    2071               0 :     return status;
    2072                 : }
    2073                 : 
    2074                 : cairo_status_t
    2075               0 : _cairo_gstate_set_antialias (cairo_gstate_t *gstate,
    2076                 :                              cairo_antialias_t antialias)
    2077                 : {
    2078               0 :     gstate->antialias = antialias;
    2079                 : 
    2080               0 :     return CAIRO_STATUS_SUCCESS;
    2081                 : }
    2082                 : 
    2083                 : cairo_antialias_t
    2084               0 : _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
    2085                 : {
    2086               0 :     return gstate->antialias;
    2087                 : }
    2088                 : 
    2089                 : /**
    2090                 :  * _cairo_gstate_transform_glyphs_to_backend:
    2091                 :  * @gstate: a #cairo_gstate_t
    2092                 :  * @glyphs: the array of #cairo_glyph_t objects to be transformed
    2093                 :  * @num_glyphs: the number of elements in @glyphs
    2094                 :  * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
    2095                 :  * #cairo_glyph_t objects
    2096                 :  * @num_transformed_glyphs: the number of elements in @transformed_glyphs
    2097                 :  * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
    2098                 :  * dropped
    2099                 :  *
    2100                 :  * Transform an array of glyphs to backend space by first adding the offset
    2101                 :  * of the font matrix, then transforming from user space to backend space.
    2102                 :  * The result of the transformation is placed in @transformed_glyphs.
    2103                 :  *
    2104                 :  * This also uses information from the scaled font and the surface to
    2105                 :  * cull/drop glyphs that will not be visible.
    2106                 :  **/
    2107                 : static cairo_status_t
    2108               0 : _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t       *gstate,
    2109                 :                                            const cairo_glyph_t  *glyphs,
    2110                 :                                            int                   num_glyphs,
    2111                 :                                            const cairo_text_cluster_t   *clusters,
    2112                 :                                            int                   num_clusters,
    2113                 :                                            cairo_text_cluster_flags_t cluster_flags,
    2114                 :                                            cairo_glyph_t        *transformed_glyphs,
    2115                 :                                            int                  *num_transformed_glyphs,
    2116                 :                                            cairo_text_cluster_t *transformed_clusters)
    2117                 : {
    2118                 :     int i, j, k;
    2119               0 :     cairo_matrix_t *ctm = &gstate->ctm;
    2120               0 :     cairo_matrix_t *font_matrix = &gstate->font_matrix;
    2121               0 :     cairo_matrix_t *device_transform = &gstate->target->device_transform;
    2122               0 :     cairo_bool_t drop = FALSE;
    2123               0 :     double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
    2124                 : 
    2125               0 :     if (num_transformed_glyphs != NULL) {
    2126                 :         cairo_rectangle_int_t surface_extents;
    2127                 : 
    2128               0 :         drop = TRUE;
    2129               0 :         if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
    2130               0 :             drop = FALSE; /* unbounded surface */
    2131                 :         } else {
    2132               0 :             double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
    2133               0 :             if (surface_extents.width == 0 || surface_extents.height == 0) {
    2134                 :               /* No visible area.  Don't draw anything */
    2135               0 :               *num_transformed_glyphs = 0;
    2136               0 :               return CAIRO_STATUS_SUCCESS;
    2137                 :             }
    2138                 :             /* XXX We currently drop any glyphs that has its position outside
    2139                 :              * of the surface boundaries by a safety margin depending on the
    2140                 :              * font scale.  This however can fail in extreme cases where the
    2141                 :              * font has really long swashes for example...  We can correctly
    2142                 :              * handle that by looking the glyph up and using its device bbox
    2143                 :              * to device if it's going to be visible, but I'm not inclined to
    2144                 :              * do that now.
    2145                 :              */
    2146               0 :             x1 = surface_extents.x - scale10;
    2147               0 :             y1 = surface_extents.y - scale10;
    2148               0 :             x2 = surface_extents.x + (int) surface_extents.width  + scale10;
    2149               0 :             y2 = surface_extents.y + (int) surface_extents.height + scale10;
    2150                 :         }
    2151                 : 
    2152               0 :         if (!drop)
    2153               0 :             *num_transformed_glyphs = num_glyphs;
    2154                 :     } else
    2155               0 :         num_transformed_glyphs = &j;
    2156                 : 
    2157                 : #define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
    2158                 : 
    2159               0 :     j = 0;
    2160               0 :     if (_cairo_matrix_is_identity (ctm) &&
    2161               0 :         _cairo_matrix_is_identity (device_transform) &&
    2162               0 :         font_matrix->x0 == 0 && font_matrix->y0 == 0)
    2163                 :     {
    2164               0 :         if (! drop) {
    2165               0 :             memcpy (transformed_glyphs, glyphs,
    2166                 :                     num_glyphs * sizeof (cairo_glyph_t));
    2167               0 :             j = num_glyphs;
    2168               0 :         } else if (num_clusters == 0) {
    2169               0 :             for (i = 0; i < num_glyphs; i++) {
    2170               0 :                 transformed_glyphs[j].index = glyphs[i].index;
    2171               0 :                 transformed_glyphs[j].x = glyphs[i].x;
    2172               0 :                 transformed_glyphs[j].y = glyphs[i].y;
    2173               0 :                 if (KEEP_GLYPH (transformed_glyphs[j]))
    2174               0 :                     j++;
    2175                 :             }
    2176                 :         } else {
    2177                 :             const cairo_glyph_t *cur_glyph;
    2178                 : 
    2179               0 :             if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2180               0 :                 cur_glyph = glyphs + num_glyphs - 1;
    2181                 :             else
    2182               0 :                 cur_glyph = glyphs;
    2183                 : 
    2184               0 :             for (i = 0; i < num_clusters; i++) {
    2185               0 :                 cairo_bool_t cluster_visible = FALSE;
    2186                 : 
    2187               0 :                 for (k = 0; k < clusters[i].num_glyphs; k++) {
    2188               0 :                     transformed_glyphs[j+k].index = cur_glyph->index;
    2189               0 :                     transformed_glyphs[j+k].x = cur_glyph->x;
    2190               0 :                     transformed_glyphs[j+k].y = cur_glyph->y;
    2191               0 :                     if (KEEP_GLYPH (transformed_glyphs[j+k]))
    2192               0 :                         cluster_visible = TRUE;
    2193                 : 
    2194               0 :                     if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2195               0 :                         cur_glyph--;
    2196                 :                     else
    2197               0 :                         cur_glyph++;
    2198                 :                 }
    2199                 : 
    2200               0 :                 transformed_clusters[i] = clusters[i];
    2201               0 :                 if (cluster_visible)
    2202               0 :                     j += k;
    2203                 :                 else
    2204               0 :                     transformed_clusters[i].num_glyphs = 0;
    2205                 :             }
    2206                 :         }
    2207                 :     }
    2208               0 :     else if (_cairo_matrix_is_translation (ctm) &&
    2209               0 :              _cairo_matrix_is_translation (device_transform))
    2210               0 :     {
    2211               0 :         double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
    2212               0 :         double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
    2213                 : 
    2214               0 :         if (! drop || num_clusters == 0) {
    2215               0 :             for (i = 0; i < num_glyphs; i++) {
    2216               0 :                 transformed_glyphs[j].index = glyphs[i].index;
    2217               0 :                 transformed_glyphs[j].x = glyphs[i].x + tx;
    2218               0 :                 transformed_glyphs[j].y = glyphs[i].y + ty;
    2219               0 :                 if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
    2220               0 :                     j++;
    2221                 :             }
    2222                 :         } else {
    2223                 :             const cairo_glyph_t *cur_glyph;
    2224                 : 
    2225               0 :             if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2226               0 :                 cur_glyph = glyphs + num_glyphs - 1;
    2227                 :             else
    2228               0 :                 cur_glyph = glyphs;
    2229                 : 
    2230               0 :             for (i = 0; i < num_clusters; i++) {
    2231               0 :                 cairo_bool_t cluster_visible = FALSE;
    2232                 : 
    2233               0 :                 for (k = 0; k < clusters[i].num_glyphs; k++) {
    2234               0 :                     transformed_glyphs[j+k].index = cur_glyph->index;
    2235               0 :                     transformed_glyphs[j+k].x = cur_glyph->x + tx;
    2236               0 :                     transformed_glyphs[j+k].y = cur_glyph->y + ty;
    2237               0 :                     if (KEEP_GLYPH (transformed_glyphs[j+k]))
    2238               0 :                         cluster_visible = TRUE;
    2239                 : 
    2240               0 :                     if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2241               0 :                         cur_glyph--;
    2242                 :                     else
    2243               0 :                         cur_glyph++;
    2244                 :                 }
    2245                 : 
    2246               0 :                 transformed_clusters[i] = clusters[i];
    2247               0 :                 if (cluster_visible)
    2248               0 :                     j += k;
    2249                 :                 else
    2250               0 :                     transformed_clusters[i].num_glyphs = 0;
    2251                 :             }
    2252                 :         }
    2253                 :     }
    2254                 :     else
    2255                 :     {
    2256                 :         cairo_matrix_t aggregate_transform;
    2257                 : 
    2258               0 :         cairo_matrix_init_translate (&aggregate_transform,
    2259                 :                                      gstate->font_matrix.x0,
    2260                 :                                      gstate->font_matrix.y0);
    2261               0 :         cairo_matrix_multiply (&aggregate_transform,
    2262                 :                                &aggregate_transform, ctm);
    2263               0 :         cairo_matrix_multiply (&aggregate_transform,
    2264                 :                                &aggregate_transform, device_transform);
    2265                 : 
    2266               0 :         if (! drop || num_clusters == 0) {
    2267               0 :             for (i = 0; i < num_glyphs; i++) {
    2268               0 :                 transformed_glyphs[j] = glyphs[i];
    2269               0 :                 cairo_matrix_transform_point (&aggregate_transform,
    2270               0 :                                               &transformed_glyphs[j].x,
    2271               0 :                                               &transformed_glyphs[j].y);
    2272               0 :                 if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
    2273               0 :                     j++;
    2274                 :             }
    2275                 :         } else {
    2276                 :             const cairo_glyph_t *cur_glyph;
    2277                 : 
    2278               0 :             if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2279               0 :                 cur_glyph = glyphs + num_glyphs - 1;
    2280                 :             else
    2281               0 :                 cur_glyph = glyphs;
    2282                 : 
    2283               0 :             for (i = 0; i < num_clusters; i++) {
    2284               0 :                 cairo_bool_t cluster_visible = FALSE;
    2285               0 :                 for (k = 0; k < clusters[i].num_glyphs; k++) {
    2286               0 :                     transformed_glyphs[j+k] = *cur_glyph;
    2287               0 :                     cairo_matrix_transform_point (&aggregate_transform,
    2288               0 :                                                   &transformed_glyphs[j+k].x,
    2289               0 :                                                   &transformed_glyphs[j+k].y);
    2290               0 :                     if (KEEP_GLYPH (transformed_glyphs[j+k]))
    2291               0 :                         cluster_visible = TRUE;
    2292                 : 
    2293               0 :                     if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
    2294               0 :                         cur_glyph--;
    2295                 :                     else
    2296               0 :                         cur_glyph++;
    2297                 :                 }
    2298                 : 
    2299               0 :                 transformed_clusters[i] = clusters[i];
    2300               0 :                 if (cluster_visible)
    2301               0 :                     j += k;
    2302                 :                 else
    2303               0 :                     transformed_clusters[i].num_glyphs = 0;
    2304                 :             }
    2305                 :         }
    2306                 :     }
    2307               0 :     *num_transformed_glyphs = j;
    2308                 : 
    2309               0 :     if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
    2310               0 :         for (i = 0; i < --j; i++) {
    2311                 :             cairo_glyph_t tmp;
    2312                 : 
    2313               0 :             tmp = transformed_glyphs[i];
    2314               0 :             transformed_glyphs[i] = transformed_glyphs[j];
    2315               0 :             transformed_glyphs[j] = tmp;
    2316                 :         }
    2317                 :     }
    2318                 : 
    2319               0 :     return CAIRO_STATUS_SUCCESS;
    2320                 : }

Generated by: LCOV version 1.7