LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-path-stroke.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 912 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 39 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
       2             : /* cairo - a vector graphics library with display and print output
       3             :  *
       4             :  * Copyright © 2002 University of Southern California
       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             :  *      Chris Wilson <chris@chris-wilson.co.uk>
      37             :  */
      38             : 
      39             : #define _BSD_SOURCE /* for hypot() */
      40             : #include "cairoint.h"
      41             : 
      42             : #include "cairo-boxes-private.h"
      43             : #include "cairo-error-private.h"
      44             : #include "cairo-path-fixed-private.h"
      45             : #include "cairo-slope-private.h"
      46             : 
      47             : typedef struct _cairo_stroker_dash {
      48             :     cairo_bool_t dashed;
      49             :     unsigned int dash_index;
      50             :     cairo_bool_t dash_on;
      51             :     cairo_bool_t dash_starts_on;
      52             :     double dash_remain;
      53             : 
      54             :     double dash_offset;
      55             :     const double *dashes;
      56             :     unsigned int num_dashes;
      57             : } cairo_stroker_dash_t;
      58             : 
      59             : typedef struct cairo_stroker {
      60             :     cairo_stroke_style_t style;
      61             : 
      62             :     const cairo_matrix_t *ctm;
      63             :     const cairo_matrix_t *ctm_inverse;
      64             :     double tolerance;
      65             :     double ctm_determinant;
      66             :     cairo_bool_t ctm_det_positive;
      67             : 
      68             :     void *closure;
      69             :     cairo_status_t (*add_external_edge) (void *closure,
      70             :                                          const cairo_point_t *p1,
      71             :                                          const cairo_point_t *p2);
      72             :     cairo_status_t (*add_triangle) (void *closure,
      73             :                                     const cairo_point_t triangle[3]);
      74             :     cairo_status_t (*add_triangle_fan) (void *closure,
      75             :                                         const cairo_point_t *midpt,
      76             :                                         const cairo_point_t *points,
      77             :                                         int npoints);
      78             :     cairo_status_t (*add_convex_quad) (void *closure,
      79             :                                        const cairo_point_t quad[4]);
      80             : 
      81             :     cairo_pen_t   pen;
      82             : 
      83             :     cairo_point_t current_point;
      84             :     cairo_point_t first_point;
      85             : 
      86             :     cairo_bool_t has_initial_sub_path;
      87             : 
      88             :     cairo_bool_t has_current_face;
      89             :     cairo_stroke_face_t current_face;
      90             : 
      91             :     cairo_bool_t has_first_face;
      92             :     cairo_stroke_face_t first_face;
      93             : 
      94             :     cairo_stroker_dash_t dash;
      95             : 
      96             :     cairo_bool_t has_bounds;
      97             :     cairo_box_t bounds;
      98             : } cairo_stroker_t;
      99             : 
     100             : static void
     101           0 : _cairo_stroker_dash_start (cairo_stroker_dash_t *dash)
     102             : {
     103             :     double offset;
     104           0 :     cairo_bool_t on = TRUE;
     105           0 :     unsigned int i = 0;
     106             : 
     107           0 :     if (! dash->dashed)
     108           0 :         return;
     109             : 
     110           0 :     offset = dash->dash_offset;
     111             : 
     112             :     /* We stop searching for a starting point as soon as the
     113             :        offset reaches zero.  Otherwise when an initial dash
     114             :        segment shrinks to zero it will be skipped over. */
     115           0 :     while (offset > 0.0 && offset >= dash->dashes[i]) {
     116           0 :         offset -= dash->dashes[i];
     117           0 :         on = !on;
     118           0 :         if (++i == dash->num_dashes)
     119           0 :             i = 0;
     120             :     }
     121             : 
     122           0 :     dash->dash_index = i;
     123           0 :     dash->dash_on = dash->dash_starts_on = on;
     124           0 :     dash->dash_remain = dash->dashes[i] - offset;
     125             : }
     126             : 
     127             : static void
     128           0 : _cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step)
     129             : {
     130           0 :     dash->dash_remain -= step;
     131           0 :     if (dash->dash_remain <= 0.) {
     132           0 :         if (++dash->dash_index == dash->num_dashes)
     133           0 :             dash->dash_index = 0;
     134             : 
     135           0 :         dash->dash_on = ! dash->dash_on;
     136           0 :         dash->dash_remain = dash->dashes[dash->dash_index];
     137             :     }
     138           0 : }
     139             : 
     140             : static void
     141           0 : _cairo_stroker_dash_init (cairo_stroker_dash_t *dash,
     142             :                           const cairo_stroke_style_t *style)
     143             : {
     144           0 :     dash->dashed = style->dash != NULL;
     145           0 :     if (! dash->dashed)
     146           0 :         return;
     147             : 
     148           0 :     dash->dashes = style->dash;
     149           0 :     dash->num_dashes = style->num_dashes;
     150           0 :     dash->dash_offset = style->dash_offset;
     151             : 
     152           0 :     _cairo_stroker_dash_start (dash);
     153             : }
     154             : 
     155             : static cairo_status_t
     156           0 : _cairo_stroker_init (cairo_stroker_t            *stroker,
     157             :                      const cairo_stroke_style_t *stroke_style,
     158             :                      const cairo_matrix_t       *ctm,
     159             :                      const cairo_matrix_t       *ctm_inverse,
     160             :                      double                      tolerance)
     161             : {
     162             :     cairo_status_t status;
     163             : 
     164           0 :     stroker->style = *stroke_style;
     165           0 :     stroker->ctm = ctm;
     166           0 :     stroker->ctm_inverse = ctm_inverse;
     167           0 :     stroker->tolerance = tolerance;
     168             : 
     169           0 :     stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
     170           0 :     stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
     171             : 
     172           0 :     status = _cairo_pen_init (&stroker->pen,
     173           0 :                               stroke_style->line_width / 2.0,
     174             :                               tolerance, ctm);
     175           0 :     if (unlikely (status))
     176           0 :         return status;
     177             : 
     178           0 :     stroker->has_bounds = FALSE;
     179             : 
     180           0 :     stroker->has_current_face = FALSE;
     181           0 :     stroker->has_first_face = FALSE;
     182           0 :     stroker->has_initial_sub_path = FALSE;
     183             : 
     184           0 :     _cairo_stroker_dash_init (&stroker->dash, stroke_style);
     185             : 
     186           0 :     stroker->add_external_edge = NULL;
     187             : 
     188           0 :     return CAIRO_STATUS_SUCCESS;
     189             : }
     190             : 
     191             : static void
     192           0 : _cairo_stroker_limit (cairo_stroker_t *stroker,
     193             :                       const cairo_box_t *boxes,
     194             :                       int num_boxes)
     195             : {
     196             :     double dx, dy;
     197             :     cairo_fixed_t fdx, fdy;
     198             : 
     199           0 :     stroker->has_bounds = TRUE;
     200           0 :     _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
     201             : 
     202             :     /* Extend the bounds in each direction to account for the maximum area
     203             :      * we might generate trapezoids, to capture line segments that are outside
     204             :      * of the bounds but which might generate rendering that's within bounds.
     205             :      */
     206             : 
     207           0 :     _cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
     208             :                                                 &dx, &dy);
     209             : 
     210           0 :     fdx = _cairo_fixed_from_double (dx);
     211           0 :     fdy = _cairo_fixed_from_double (dy);
     212             : 
     213           0 :     stroker->bounds.p1.x -= fdx;
     214           0 :     stroker->bounds.p2.x += fdx;
     215             : 
     216           0 :     stroker->bounds.p1.y -= fdy;
     217           0 :     stroker->bounds.p2.y += fdy;
     218           0 : }
     219             : 
     220             : static void
     221           0 : _cairo_stroker_fini (cairo_stroker_t *stroker)
     222             : {
     223           0 :     _cairo_pen_fini (&stroker->pen);
     224           0 : }
     225             : 
     226             : static void
     227           0 : _translate_point (cairo_point_t *point, const cairo_point_t *offset)
     228             : {
     229           0 :     point->x += offset->x;
     230           0 :     point->y += offset->y;
     231           0 : }
     232             : 
     233             : static int
     234           0 : _cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
     235             :                                   const cairo_stroke_face_t *out)
     236             : {
     237             :     cairo_slope_t in_slope, out_slope;
     238             : 
     239           0 :     _cairo_slope_init (&in_slope, &in->point, &in->cw);
     240           0 :     _cairo_slope_init (&out_slope, &out->point, &out->cw);
     241             : 
     242           0 :     return _cairo_slope_compare (&in_slope, &out_slope) < 0;
     243             : }
     244             : 
     245             : /**
     246             :  * _cairo_slope_compare_sgn
     247             :  *
     248             :  * Return -1, 0 or 1 depending on the relative slopes of
     249             :  * two lines.
     250             :  */
     251             : static int
     252           0 : _cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
     253             : {
     254           0 :     double  c = (dx1 * dy2 - dx2 * dy1);
     255             : 
     256           0 :     if (c > 0) return 1;
     257           0 :     if (c < 0) return -1;
     258           0 :     return 0;
     259             : }
     260             : 
     261             : static inline int
     262           0 : _range_step (int i, int step, int max)
     263             : {
     264           0 :     i += step;
     265           0 :     if (i < 0)
     266           0 :         i = max - 1;
     267           0 :     if (i >= max)
     268           0 :         i = 0;
     269           0 :     return i;
     270             : }
     271             : 
     272             : /*
     273             :  * Construct a fan around the midpoint using the vertices from pen between
     274             :  * inpt and outpt.
     275             :  */
     276             : static cairo_status_t
     277           0 : _tessellate_fan (cairo_stroker_t *stroker,
     278             :                  const cairo_slope_t *in_vector,
     279             :                  const cairo_slope_t *out_vector,
     280             :                  const cairo_point_t *midpt,
     281             :                  const cairo_point_t *inpt,
     282             :                  const cairo_point_t *outpt,
     283             :                  cairo_bool_t clockwise)
     284             : {
     285           0 :     cairo_point_t stack_points[64], *points = stack_points;
     286             :     int start, stop, step, i, npoints;
     287             :     cairo_status_t status;
     288             : 
     289           0 :     if (clockwise) {
     290           0 :         step  = -1;
     291             : 
     292           0 :         start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
     293             :                                                          in_vector);
     294           0 :         if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
     295             :                                   in_vector) < 0)
     296           0 :             start = _range_step (start, -1, stroker->pen.num_vertices);
     297             : 
     298           0 :         stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
     299             :                                                          out_vector);
     300           0 :         if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
     301             :                                   out_vector) > 0)
     302             :         {
     303           0 :             stop = _range_step (stop, 1, stroker->pen.num_vertices);
     304           0 :             if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
     305             :                                       in_vector) < 0)
     306             :             {
     307           0 :                 goto BEVEL;
     308             :             }
     309             :         }
     310             : 
     311           0 :         npoints = start - stop;
     312             :     } else {
     313           0 :         step  = 1;
     314             : 
     315           0 :         start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
     316             :                                                         in_vector);
     317           0 :         if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
     318             :                                   in_vector) < 0)
     319           0 :             start = _range_step (start, 1, stroker->pen.num_vertices);
     320             : 
     321           0 :         stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
     322             :                                                         out_vector);
     323           0 :         if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
     324             :                                   out_vector) > 0)
     325             :         {
     326           0 :             stop = _range_step (stop, -1, stroker->pen.num_vertices);
     327           0 :             if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
     328             :                                       in_vector) < 0)
     329             :             {
     330           0 :                 goto BEVEL;
     331             :             }
     332             :         }
     333             : 
     334           0 :         npoints = stop - start;
     335             :     }
     336           0 :     stop = _range_step (stop, step, stroker->pen.num_vertices);
     337             : 
     338           0 :     if (npoints < 0)
     339           0 :         npoints += stroker->pen.num_vertices;
     340           0 :     npoints += 3;
     341             : 
     342           0 :     if (npoints <= 1)
     343           0 :         goto BEVEL;
     344             : 
     345           0 :     if (npoints > ARRAY_LENGTH (stack_points)) {
     346           0 :         points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
     347           0 :         if (unlikely (points == NULL))
     348           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     349             :     }
     350             : 
     351             : 
     352             :     /* Construct the fan. */
     353           0 :     npoints = 0;
     354           0 :     points[npoints++] = *inpt;
     355           0 :     for (i = start;
     356             :          i != stop;
     357           0 :         i = _range_step (i, step, stroker->pen.num_vertices))
     358             :     {
     359           0 :         points[npoints] = *midpt;
     360           0 :         _translate_point (&points[npoints], &stroker->pen.vertices[i].point);
     361           0 :         npoints++;
     362             :     }
     363           0 :     points[npoints++] = *outpt;
     364             : 
     365           0 :     if (stroker->add_external_edge != NULL) {
     366           0 :         for (i = 0; i < npoints - 1; i++) {
     367           0 :             if (clockwise) {
     368           0 :                 status = stroker->add_external_edge (stroker->closure,
     369           0 :                                                      &points[i], &points[i+1]);
     370             :             } else {
     371           0 :                 status = stroker->add_external_edge (stroker->closure,
     372           0 :                                                      &points[i+1], &points[i]);
     373             :             }
     374           0 :             if (unlikely (status))
     375           0 :                 break;
     376             :         }
     377             :     } else {
     378           0 :         status = stroker->add_triangle_fan (stroker->closure,
     379             :                                             midpt, points, npoints);
     380             :     }
     381             : 
     382           0 :     if (points != stack_points)
     383           0 :         free (points);
     384             : 
     385           0 :     return status;
     386             : 
     387             : BEVEL:
     388             :     /* Ensure a leak free connection... */
     389           0 :     if (stroker->add_external_edge != NULL) {
     390           0 :         if (clockwise)
     391           0 :             return stroker->add_external_edge (stroker->closure, inpt, outpt);
     392             :         else
     393           0 :             return stroker->add_external_edge (stroker->closure, outpt, inpt);
     394             :     } else {
     395           0 :         stack_points[0] = *midpt;
     396           0 :         stack_points[1] = *inpt;
     397           0 :         stack_points[2] = *outpt;
     398           0 :         return stroker->add_triangle (stroker->closure, stack_points);
     399             :     }
     400             : }
     401             : 
     402             : static cairo_status_t
     403           0 : _cairo_stroker_join (cairo_stroker_t *stroker,
     404             :                      const cairo_stroke_face_t *in,
     405             :                      const cairo_stroke_face_t *out)
     406             : {
     407           0 :     int  clockwise = _cairo_stroker_join_is_clockwise (out, in);
     408             :     const cairo_point_t *inpt, *outpt;
     409             :     cairo_point_t points[4];
     410             :     cairo_status_t status;
     411             : 
     412           0 :     if (in->cw.x  == out->cw.x  && in->cw.y  == out->cw.y &&
     413           0 :         in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
     414             :     {
     415           0 :         return CAIRO_STATUS_SUCCESS;
     416             :     }
     417             : 
     418           0 :     if (clockwise) {
     419           0 :         if (stroker->add_external_edge != NULL) {
     420           0 :             status = stroker->add_external_edge (stroker->closure,
     421             :                                                  &out->cw, &in->point);
     422           0 :             if (unlikely (status))
     423           0 :                 return status;
     424             : 
     425           0 :             status = stroker->add_external_edge (stroker->closure,
     426             :                                                  &in->point, &in->cw);
     427           0 :             if (unlikely (status))
     428           0 :                 return status;
     429             :         }
     430             : 
     431           0 :         inpt = &in->ccw;
     432           0 :         outpt = &out->ccw;
     433             :     } else {
     434           0 :         if (stroker->add_external_edge != NULL) {
     435           0 :             status = stroker->add_external_edge (stroker->closure,
     436             :                                                  &in->ccw, &in->point);
     437           0 :             if (unlikely (status))
     438           0 :                 return status;
     439             : 
     440           0 :             status = stroker->add_external_edge (stroker->closure,
     441             :                                                  &in->point, &out->ccw);
     442           0 :             if (unlikely (status))
     443           0 :                 return status;
     444             :         }
     445             : 
     446           0 :         inpt = &in->cw;
     447           0 :         outpt = &out->cw;
     448             :     }
     449             : 
     450           0 :     switch (stroker->style.line_join) {
     451             :     case CAIRO_LINE_JOIN_ROUND:
     452             :         /* construct a fan around the common midpoint */
     453           0 :         return _tessellate_fan (stroker,
     454             :                                 &in->dev_vector,
     455             :                                 &out->dev_vector,
     456             :                                 &in->point, inpt, outpt,
     457             :                                 clockwise);
     458             : 
     459             :     case CAIRO_LINE_JOIN_MITER:
     460             :     default: {
     461             :         /* dot product of incoming slope vector with outgoing slope vector */
     462           0 :         double  in_dot_out = -in->usr_vector.x * out->usr_vector.x +
     463           0 :                              -in->usr_vector.y * out->usr_vector.y;
     464           0 :         double  ml = stroker->style.miter_limit;
     465             : 
     466             :         /* Check the miter limit -- lines meeting at an acute angle
     467             :          * can generate long miters, the limit converts them to bevel
     468             :          *
     469             :          * Consider the miter join formed when two line segments
     470             :          * meet at an angle psi:
     471             :          *
     472             :          *         /.\
     473             :          *        /. .\
     474             :          *       /./ \.\
     475             :          *      /./psi\.\
     476             :          *
     477             :          * We can zoom in on the right half of that to see:
     478             :          *
     479             :          *          |\
     480             :          *          | \ psi/2
     481             :          *          |  \
     482             :          *          |   \
     483             :          *          |    \
     484             :          *          |     \
     485             :          *        miter    \
     486             :          *       length     \
     487             :          *          |        \
     488             :          *          |        .\
     489             :          *          |    .     \
     490             :          *          |.   line   \
     491             :          *           \    width  \
     492             :          *            \           \
     493             :          *
     494             :          *
     495             :          * The right triangle in that figure, (the line-width side is
     496             :          * shown faintly with three '.' characters), gives us the
     497             :          * following expression relating miter length, angle and line
     498             :          * width:
     499             :          *
     500             :          *      1 /sin (psi/2) = miter_length / line_width
     501             :          *
     502             :          * The right-hand side of this relationship is the same ratio
     503             :          * in which the miter limit (ml) is expressed. We want to know
     504             :          * when the miter length is within the miter limit. That is
     505             :          * when the following condition holds:
     506             :          *
     507             :          *      1/sin(psi/2) <= ml
     508             :          *      1 <= ml sin(psi/2)
     509             :          *      1 <= ml² sin²(psi/2)
     510             :          *      2 <= ml² 2 sin²(psi/2)
     511             :          *                              2·sin²(psi/2) = 1-cos(psi)
     512             :          *      2 <= ml² (1-cos(psi))
     513             :          *
     514             :          *                              in · out = |in| |out| cos (psi)
     515             :          *
     516             :          * in and out are both unit vectors, so:
     517             :          *
     518             :          *                              in · out = cos (psi)
     519             :          *
     520             :          *      2 <= ml² (1 - in · out)
     521             :          *
     522             :          */
     523           0 :         if (2 <= ml * ml * (1 - in_dot_out)) {
     524             :             double              x1, y1, x2, y2;
     525             :             double              mx, my;
     526             :             double              dx1, dx2, dy1, dy2;
     527             :             double              ix, iy;
     528             :             double              fdx1, fdy1, fdx2, fdy2;
     529             :             double              mdx, mdy;
     530             : 
     531             :             /*
     532             :              * we've got the points already transformed to device
     533             :              * space, but need to do some computation with them and
     534             :              * also need to transform the slope from user space to
     535             :              * device space
     536             :              */
     537             :             /* outer point of incoming line face */
     538           0 :             x1 = _cairo_fixed_to_double (inpt->x);
     539           0 :             y1 = _cairo_fixed_to_double (inpt->y);
     540           0 :             dx1 = in->usr_vector.x;
     541           0 :             dy1 = in->usr_vector.y;
     542           0 :             cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
     543             : 
     544             :             /* outer point of outgoing line face */
     545           0 :             x2 = _cairo_fixed_to_double (outpt->x);
     546           0 :             y2 = _cairo_fixed_to_double (outpt->y);
     547           0 :             dx2 = out->usr_vector.x;
     548           0 :             dy2 = out->usr_vector.y;
     549           0 :             cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
     550             : 
     551             :             /*
     552             :              * Compute the location of the outer corner of the miter.
     553             :              * That's pretty easy -- just the intersection of the two
     554             :              * outer edges.  We've got slopes and points on each
     555             :              * of those edges.  Compute my directly, then compute
     556             :              * mx by using the edge with the larger dy; that avoids
     557             :              * dividing by values close to zero.
     558             :              */
     559           0 :             my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
     560           0 :                   (dx1 * dy2 - dx2 * dy1));
     561           0 :             if (fabs (dy1) >= fabs (dy2))
     562           0 :                 mx = (my - y1) * dx1 / dy1 + x1;
     563             :             else
     564           0 :                 mx = (my - y2) * dx2 / dy2 + x2;
     565             : 
     566             :             /*
     567             :              * When the two outer edges are nearly parallel, slight
     568             :              * perturbations in the position of the outer points of the lines
     569             :              * caused by representing them in fixed point form can cause the
     570             :              * intersection point of the miter to move a large amount. If
     571             :              * that moves the miter intersection from between the two faces,
     572             :              * then draw a bevel instead.
     573             :              */
     574             : 
     575           0 :             ix = _cairo_fixed_to_double (in->point.x);
     576           0 :             iy = _cairo_fixed_to_double (in->point.y);
     577             : 
     578             :             /* slope of one face */
     579           0 :             fdx1 = x1 - ix; fdy1 = y1 - iy;
     580             : 
     581             :             /* slope of the other face */
     582           0 :             fdx2 = x2 - ix; fdy2 = y2 - iy;
     583             : 
     584             :             /* slope from the intersection to the miter point */
     585           0 :             mdx = mx - ix; mdy = my - iy;
     586             : 
     587             :             /*
     588             :              * Make sure the miter point line lies between the two
     589             :              * faces by comparing the slopes
     590             :              */
     591           0 :             if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
     592           0 :                 _cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
     593             :             {
     594           0 :                 if (stroker->add_external_edge != NULL) {
     595           0 :                     points[0].x = _cairo_fixed_from_double (mx);
     596           0 :                     points[0].y = _cairo_fixed_from_double (my);
     597             : 
     598           0 :                     if (clockwise) {
     599           0 :                         status = stroker->add_external_edge (stroker->closure,
     600             :                                                              inpt, &points[0]);
     601           0 :                         if (unlikely (status))
     602           0 :                             return status;
     603             : 
     604           0 :                         status = stroker->add_external_edge (stroker->closure,
     605             :                                                              &points[0], outpt);
     606           0 :                         if (unlikely (status))
     607           0 :                             return status;
     608             :                     } else {
     609           0 :                         status = stroker->add_external_edge (stroker->closure,
     610             :                                                              outpt, &points[0]);
     611           0 :                         if (unlikely (status))
     612           0 :                             return status;
     613             : 
     614           0 :                         status = stroker->add_external_edge (stroker->closure,
     615             :                                                              &points[0], inpt);
     616           0 :                         if (unlikely (status))
     617           0 :                             return status;
     618             :                     }
     619             : 
     620           0 :                     return CAIRO_STATUS_SUCCESS;
     621             :                 } else {
     622           0 :                     points[0] = in->point;
     623           0 :                     points[1] = *inpt;
     624           0 :                     points[2].x = _cairo_fixed_from_double (mx);
     625           0 :                     points[2].y = _cairo_fixed_from_double (my);
     626           0 :                     points[3] = *outpt;
     627             : 
     628           0 :                     return stroker->add_convex_quad (stroker->closure, points);
     629             :                 }
     630             :             }
     631             :         }
     632             :     }
     633             : 
     634             :     /* fall through ... */
     635             : 
     636             :     case CAIRO_LINE_JOIN_BEVEL:
     637           0 :         if (stroker->add_external_edge != NULL) {
     638           0 :             if (clockwise) {
     639           0 :                 return stroker->add_external_edge (stroker->closure,
     640             :                                                    inpt, outpt);
     641             :             } else {
     642           0 :                 return stroker->add_external_edge (stroker->closure,
     643             :                                                    outpt, inpt);
     644             :             }
     645             :         } else {
     646           0 :             points[0] = in->point;
     647           0 :             points[1] = *inpt;
     648           0 :             points[2] = *outpt;
     649             : 
     650           0 :             return stroker->add_triangle (stroker->closure, points);
     651             :         }
     652             :     }
     653             : }
     654             : 
     655             : static cairo_status_t
     656           0 : _cairo_stroker_add_cap (cairo_stroker_t *stroker,
     657             :                         const cairo_stroke_face_t *f)
     658             : {
     659           0 :     switch (stroker->style.line_cap) {
     660             :     case CAIRO_LINE_CAP_ROUND: {
     661             :         cairo_slope_t slope;
     662             : 
     663           0 :         slope.dx = -f->dev_vector.dx;
     664           0 :         slope.dy = -f->dev_vector.dy;
     665             : 
     666           0 :         return _tessellate_fan (stroker,
     667             :                                 &f->dev_vector,
     668             :                                 &slope,
     669             :                                 &f->point, &f->cw, &f->ccw,
     670             :                                 FALSE);
     671             : 
     672             :     }
     673             : 
     674             :     case CAIRO_LINE_CAP_SQUARE: {
     675             :         double dx, dy;
     676             :         cairo_slope_t   fvector;
     677             :         cairo_point_t   quad[4];
     678             : 
     679           0 :         dx = f->usr_vector.x;
     680           0 :         dy = f->usr_vector.y;
     681           0 :         dx *= stroker->style.line_width / 2.0;
     682           0 :         dy *= stroker->style.line_width / 2.0;
     683           0 :         cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
     684           0 :         fvector.dx = _cairo_fixed_from_double (dx);
     685           0 :         fvector.dy = _cairo_fixed_from_double (dy);
     686             : 
     687           0 :         quad[0] = f->ccw;
     688           0 :         quad[1].x = f->ccw.x + fvector.dx;
     689           0 :         quad[1].y = f->ccw.y + fvector.dy;
     690           0 :         quad[2].x = f->cw.x + fvector.dx;
     691           0 :         quad[2].y = f->cw.y + fvector.dy;
     692           0 :         quad[3] = f->cw;
     693             : 
     694           0 :         if (stroker->add_external_edge != NULL) {
     695             :             cairo_status_t status;
     696             : 
     697           0 :             status = stroker->add_external_edge (stroker->closure,
     698             :                                                  &quad[0], &quad[1]);
     699           0 :             if (unlikely (status))
     700           0 :                 return status;
     701             : 
     702           0 :             status = stroker->add_external_edge (stroker->closure,
     703             :                                                  &quad[1], &quad[2]);
     704           0 :             if (unlikely (status))
     705           0 :                 return status;
     706             : 
     707           0 :             status = stroker->add_external_edge (stroker->closure,
     708             :                                                  &quad[2], &quad[3]);
     709           0 :             if (unlikely (status))
     710           0 :                 return status;
     711             : 
     712           0 :             return CAIRO_STATUS_SUCCESS;
     713             :         } else {
     714           0 :             return stroker->add_convex_quad (stroker->closure, quad);
     715             :         }
     716             :     }
     717             : 
     718             :     case CAIRO_LINE_CAP_BUTT:
     719             :     default:
     720           0 :         if (stroker->add_external_edge != NULL) {
     721           0 :             return stroker->add_external_edge (stroker->closure,
     722             :                                                &f->ccw, &f->cw);
     723             :         } else {
     724           0 :             return CAIRO_STATUS_SUCCESS;
     725             :         }
     726             :     }
     727             : }
     728             : 
     729             : static cairo_status_t
     730           0 : _cairo_stroker_add_leading_cap (cairo_stroker_t     *stroker,
     731             :                                 const cairo_stroke_face_t *face)
     732             : {
     733             :     cairo_stroke_face_t reversed;
     734             :     cairo_point_t t;
     735             : 
     736           0 :     reversed = *face;
     737             : 
     738             :     /* The initial cap needs an outward facing vector. Reverse everything */
     739           0 :     reversed.usr_vector.x = -reversed.usr_vector.x;
     740           0 :     reversed.usr_vector.y = -reversed.usr_vector.y;
     741           0 :     reversed.dev_vector.dx = -reversed.dev_vector.dx;
     742           0 :     reversed.dev_vector.dy = -reversed.dev_vector.dy;
     743           0 :     t = reversed.cw;
     744           0 :     reversed.cw = reversed.ccw;
     745           0 :     reversed.ccw = t;
     746             : 
     747           0 :     return _cairo_stroker_add_cap (stroker, &reversed);
     748             : }
     749             : 
     750             : static cairo_status_t
     751           0 : _cairo_stroker_add_trailing_cap (cairo_stroker_t     *stroker,
     752             :                                  const cairo_stroke_face_t *face)
     753             : {
     754           0 :     return _cairo_stroker_add_cap (stroker, face);
     755             : }
     756             : 
     757             : static inline cairo_bool_t
     758           0 : _compute_normalized_device_slope (double *dx, double *dy,
     759             :                                   const cairo_matrix_t *ctm_inverse,
     760             :                                   double *mag_out)
     761             : {
     762           0 :     double dx0 = *dx, dy0 = *dy;
     763             :     double mag;
     764             : 
     765           0 :     cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
     766             : 
     767           0 :     if (dx0 == 0.0 && dy0 == 0.0) {
     768           0 :         if (mag_out)
     769           0 :             *mag_out = 0.0;
     770           0 :         return FALSE;
     771             :     }
     772             : 
     773           0 :     if (dx0 == 0.0) {
     774           0 :         *dx = 0.0;
     775           0 :         if (dy0 > 0.0) {
     776           0 :             mag = dy0;
     777           0 :             *dy = 1.0;
     778             :         } else {
     779           0 :             mag = -dy0;
     780           0 :             *dy = -1.0;
     781             :         }
     782           0 :     } else if (dy0 == 0.0) {
     783           0 :         *dy = 0.0;
     784           0 :         if (dx0 > 0.0) {
     785           0 :             mag = dx0;
     786           0 :             *dx = 1.0;
     787             :         } else {
     788           0 :             mag = -dx0;
     789           0 :             *dx = -1.0;
     790             :         }
     791             :     } else {
     792           0 :         mag = hypot (dx0, dy0);
     793           0 :         *dx = dx0 / mag;
     794           0 :         *dy = dy0 / mag;
     795             :     }
     796             : 
     797           0 :     if (mag_out)
     798           0 :         *mag_out = mag;
     799             : 
     800           0 :     return TRUE;
     801             : }
     802             : 
     803             : static void
     804           0 : _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
     805             :                double slope_dx, double slope_dy,
     806             :                cairo_stroker_t *stroker, cairo_stroke_face_t *face)
     807             : {
     808             :     double face_dx, face_dy;
     809             :     cairo_point_t offset_ccw, offset_cw;
     810             : 
     811             :     /*
     812             :      * rotate to get a line_width/2 vector along the face, note that
     813             :      * the vector must be rotated the right direction in device space,
     814             :      * but by 90° in user space. So, the rotation depends on
     815             :      * whether the ctm reflects or not, and that can be determined
     816             :      * by looking at the determinant of the matrix.
     817             :      */
     818           0 :     if (stroker->ctm_det_positive)
     819             :     {
     820           0 :         face_dx = - slope_dy * (stroker->style.line_width / 2.0);
     821           0 :         face_dy = slope_dx * (stroker->style.line_width / 2.0);
     822             :     }
     823             :     else
     824             :     {
     825           0 :         face_dx = slope_dy * (stroker->style.line_width / 2.0);
     826           0 :         face_dy = - slope_dx * (stroker->style.line_width / 2.0);
     827             :     }
     828             : 
     829             :     /* back to device space */
     830           0 :     cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
     831             : 
     832           0 :     offset_ccw.x = _cairo_fixed_from_double (face_dx);
     833           0 :     offset_ccw.y = _cairo_fixed_from_double (face_dy);
     834           0 :     offset_cw.x = -offset_ccw.x;
     835           0 :     offset_cw.y = -offset_ccw.y;
     836             : 
     837           0 :     face->ccw = *point;
     838           0 :     _translate_point (&face->ccw, &offset_ccw);
     839             : 
     840           0 :     face->point = *point;
     841             : 
     842           0 :     face->cw = *point;
     843           0 :     _translate_point (&face->cw, &offset_cw);
     844             : 
     845           0 :     face->usr_vector.x = slope_dx;
     846           0 :     face->usr_vector.y = slope_dy;
     847             : 
     848           0 :     face->dev_vector = *dev_slope;
     849           0 : }
     850             : 
     851             : static cairo_status_t
     852           0 : _cairo_stroker_add_caps (cairo_stroker_t *stroker)
     853             : {
     854             :     cairo_status_t status;
     855             : 
     856             :     /* check for a degenerative sub_path */
     857           0 :     if (stroker->has_initial_sub_path
     858           0 :         && ! stroker->has_first_face
     859           0 :         && ! stroker->has_current_face
     860           0 :         && stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND)
     861             :     {
     862             :         /* pick an arbitrary slope to use */
     863           0 :         double dx = 1.0, dy = 0.0;
     864           0 :         cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
     865             :         cairo_stroke_face_t face;
     866             : 
     867           0 :         _compute_normalized_device_slope (&dx, &dy,
     868             :                                           stroker->ctm_inverse, NULL);
     869             : 
     870             :         /* arbitrarily choose first_point
     871             :          * first_point and current_point should be the same */
     872           0 :         _compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
     873             : 
     874           0 :         status = _cairo_stroker_add_leading_cap (stroker, &face);
     875           0 :         if (unlikely (status))
     876           0 :             return status;
     877             : 
     878           0 :         status = _cairo_stroker_add_trailing_cap (stroker, &face);
     879           0 :         if (unlikely (status))
     880           0 :             return status;
     881             :     }
     882             : 
     883           0 :     if (stroker->has_first_face) {
     884           0 :         status = _cairo_stroker_add_leading_cap (stroker,
     885           0 :                                                  &stroker->first_face);
     886           0 :         if (unlikely (status))
     887           0 :             return status;
     888             :     }
     889             : 
     890           0 :     if (stroker->has_current_face) {
     891           0 :         status = _cairo_stroker_add_trailing_cap (stroker,
     892           0 :                                                   &stroker->current_face);
     893           0 :         if (unlikely (status))
     894           0 :             return status;
     895             :     }
     896             : 
     897           0 :     return CAIRO_STATUS_SUCCESS;
     898             : }
     899             : 
     900             : static cairo_status_t
     901           0 : _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
     902             :                              const cairo_point_t *p1,
     903             :                              const cairo_point_t *p2,
     904             :                              cairo_slope_t *dev_slope,
     905             :                              double slope_dx, double slope_dy,
     906             :                              cairo_stroke_face_t *start,
     907             :                              cairo_stroke_face_t *end)
     908             : {
     909           0 :     _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
     910           0 :     *end = *start;
     911             : 
     912           0 :     if (p1->x == p2->x && p1->y == p2->y)
     913           0 :         return CAIRO_STATUS_SUCCESS;
     914             : 
     915           0 :     end->point = *p2;
     916           0 :     end->ccw.x += p2->x - p1->x;
     917           0 :     end->ccw.y += p2->y - p1->y;
     918           0 :     end->cw.x += p2->x - p1->x;
     919           0 :     end->cw.y += p2->y - p1->y;
     920             : 
     921           0 :     if (stroker->add_external_edge != NULL) {
     922             :         cairo_status_t status;
     923             : 
     924           0 :         status = stroker->add_external_edge (stroker->closure,
     925           0 :                                              &end->cw, &start->cw);
     926           0 :         if (unlikely (status))
     927           0 :             return status;
     928             : 
     929           0 :         status = stroker->add_external_edge (stroker->closure,
     930           0 :                                              &start->ccw, &end->ccw);
     931           0 :         if (unlikely (status))
     932           0 :             return status;
     933             : 
     934           0 :         return CAIRO_STATUS_SUCCESS;
     935             :     } else {
     936             :         cairo_point_t quad[4];
     937             : 
     938           0 :         quad[0] = start->cw;
     939           0 :         quad[1] = end->cw;
     940           0 :         quad[2] = end->ccw;
     941           0 :         quad[3] = start->ccw;
     942             : 
     943           0 :         return stroker->add_convex_quad (stroker->closure, quad);
     944             :     }
     945             : }
     946             : 
     947             : static cairo_status_t
     948           0 : _cairo_stroker_move_to (void *closure,
     949             :                         const cairo_point_t *point)
     950             : {
     951           0 :     cairo_stroker_t *stroker = closure;
     952             :     cairo_status_t status;
     953             : 
     954             :     /* reset the dash pattern for new sub paths */
     955           0 :     _cairo_stroker_dash_start (&stroker->dash);
     956             : 
     957             :     /* Cap the start and end of the previous sub path as needed */
     958           0 :     status = _cairo_stroker_add_caps (stroker);
     959           0 :     if (unlikely (status))
     960           0 :         return status;
     961             : 
     962           0 :     stroker->first_point = *point;
     963           0 :     stroker->current_point = *point;
     964             : 
     965           0 :     stroker->has_first_face = FALSE;
     966           0 :     stroker->has_current_face = FALSE;
     967           0 :     stroker->has_initial_sub_path = FALSE;
     968             : 
     969           0 :     return CAIRO_STATUS_SUCCESS;
     970             : }
     971             : 
     972             : static cairo_status_t
     973           0 : _cairo_stroker_line_to (void *closure,
     974             :                         const cairo_point_t *point)
     975             : {
     976           0 :     cairo_stroker_t *stroker = closure;
     977             :     cairo_stroke_face_t start, end;
     978           0 :     cairo_point_t *p1 = &stroker->current_point;
     979             :     cairo_slope_t dev_slope;
     980             :     double slope_dx, slope_dy;
     981             :     cairo_status_t status;
     982             : 
     983           0 :     stroker->has_initial_sub_path = TRUE;
     984             : 
     985           0 :     if (p1->x == point->x && p1->y == point->y)
     986           0 :         return CAIRO_STATUS_SUCCESS;
     987             : 
     988           0 :     _cairo_slope_init (&dev_slope, p1, point);
     989           0 :     slope_dx = _cairo_fixed_to_double (point->x - p1->x);
     990           0 :     slope_dy = _cairo_fixed_to_double (point->y - p1->y);
     991           0 :     _compute_normalized_device_slope (&slope_dx, &slope_dy,
     992             :                                       stroker->ctm_inverse, NULL);
     993             : 
     994           0 :     status = _cairo_stroker_add_sub_edge (stroker,
     995             :                                           p1, point,
     996             :                                           &dev_slope,
     997             :                                           slope_dx, slope_dy,
     998             :                                           &start, &end);
     999           0 :     if (unlikely (status))
    1000           0 :         return status;
    1001             : 
    1002           0 :     if (stroker->has_current_face) {
    1003             :         /* Join with final face from previous segment */
    1004           0 :         status = _cairo_stroker_join (stroker,
    1005           0 :                                       &stroker->current_face,
    1006             :                                       &start);
    1007           0 :         if (unlikely (status))
    1008           0 :             return status;
    1009           0 :     } else if (! stroker->has_first_face) {
    1010             :         /* Save sub path's first face in case needed for closing join */
    1011           0 :         stroker->first_face = start;
    1012           0 :         stroker->has_first_face = TRUE;
    1013             :     }
    1014           0 :     stroker->current_face = end;
    1015           0 :     stroker->has_current_face = TRUE;
    1016             : 
    1017           0 :     stroker->current_point = *point;
    1018             : 
    1019           0 :     return CAIRO_STATUS_SUCCESS;
    1020             : }
    1021             : 
    1022             : /*
    1023             :  * Dashed lines.  Cap each dash end, join around turns when on
    1024             :  */
    1025             : static cairo_status_t
    1026           0 : _cairo_stroker_line_to_dashed (void *closure,
    1027             :                                const cairo_point_t *p2)
    1028             : {
    1029           0 :     cairo_stroker_t *stroker = closure;
    1030           0 :     double mag, remain, step_length = 0;
    1031             :     double slope_dx, slope_dy;
    1032             :     double dx2, dy2;
    1033             :     cairo_stroke_face_t sub_start, sub_end;
    1034           0 :     cairo_point_t *p1 = &stroker->current_point;
    1035             :     cairo_slope_t dev_slope;
    1036             :     cairo_line_t segment;
    1037             :     cairo_bool_t fully_in_bounds;
    1038             :     cairo_status_t status;
    1039             : 
    1040           0 :     stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
    1041             : 
    1042           0 :     if (p1->x == p2->x && p1->y == p2->y)
    1043           0 :         return CAIRO_STATUS_SUCCESS;
    1044             : 
    1045           0 :     fully_in_bounds = TRUE;
    1046           0 :     if (stroker->has_bounds &&
    1047           0 :         (! _cairo_box_contains_point (&stroker->bounds, p1) ||
    1048           0 :          ! _cairo_box_contains_point (&stroker->bounds, p2)))
    1049             :     {
    1050           0 :         fully_in_bounds = FALSE;
    1051             :     }
    1052             : 
    1053           0 :     _cairo_slope_init (&dev_slope, p1, p2);
    1054             : 
    1055           0 :     slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
    1056           0 :     slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
    1057             : 
    1058           0 :     if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
    1059             :                                             stroker->ctm_inverse, &mag))
    1060             :     {
    1061           0 :         return CAIRO_STATUS_SUCCESS;
    1062             :     }
    1063             : 
    1064           0 :     remain = mag;
    1065           0 :     segment.p1 = *p1;
    1066           0 :     while (remain) {
    1067           0 :         step_length = MIN (stroker->dash.dash_remain, remain);
    1068           0 :         remain -= step_length;
    1069           0 :         dx2 = slope_dx * (mag - remain);
    1070           0 :         dy2 = slope_dy * (mag - remain);
    1071           0 :         cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
    1072           0 :         segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
    1073           0 :         segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
    1074             : 
    1075           0 :         if (stroker->dash.dash_on &&
    1076           0 :             (fully_in_bounds ||
    1077           0 :              (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
    1078           0 :              _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
    1079             :         {
    1080           0 :             status = _cairo_stroker_add_sub_edge (stroker,
    1081             :                                                   &segment.p1, &segment.p2,
    1082             :                                                   &dev_slope,
    1083             :                                                   slope_dx, slope_dy,
    1084             :                                                   &sub_start, &sub_end);
    1085           0 :             if (unlikely (status))
    1086           0 :                 return status;
    1087             : 
    1088           0 :             if (stroker->has_current_face)
    1089             :             {
    1090             :                 /* Join with final face from previous segment */
    1091           0 :                 status = _cairo_stroker_join (stroker,
    1092           0 :                                               &stroker->current_face,
    1093             :                                               &sub_start);
    1094           0 :                 if (unlikely (status))
    1095           0 :                     return status;
    1096             : 
    1097           0 :                 stroker->has_current_face = FALSE;
    1098             :             }
    1099           0 :             else if (! stroker->has_first_face &&
    1100           0 :                        stroker->dash.dash_starts_on)
    1101             :             {
    1102             :                 /* Save sub path's first face in case needed for closing join */
    1103           0 :                 stroker->first_face = sub_start;
    1104           0 :                 stroker->has_first_face = TRUE;
    1105             :             }
    1106             :             else
    1107             :             {
    1108             :                 /* Cap dash start if not connecting to a previous segment */
    1109           0 :                 status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
    1110           0 :                 if (unlikely (status))
    1111           0 :                     return status;
    1112             :             }
    1113             : 
    1114           0 :             if (remain) {
    1115             :                 /* Cap dash end if not at end of segment */
    1116           0 :                 status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
    1117           0 :                 if (unlikely (status))
    1118           0 :                     return status;
    1119             :             } else {
    1120           0 :                 stroker->current_face = sub_end;
    1121           0 :                 stroker->has_current_face = TRUE;
    1122             :             }
    1123             :         } else {
    1124           0 :             if (stroker->has_current_face) {
    1125             :                 /* Cap final face from previous segment */
    1126           0 :                 status = _cairo_stroker_add_trailing_cap (stroker,
    1127           0 :                                                           &stroker->current_face);
    1128           0 :                 if (unlikely (status))
    1129           0 :                     return status;
    1130             : 
    1131           0 :                 stroker->has_current_face = FALSE;
    1132             :             }
    1133             :         }
    1134             : 
    1135           0 :         _cairo_stroker_dash_step (&stroker->dash, step_length);
    1136           0 :         segment.p1 = segment.p2;
    1137             :     }
    1138             : 
    1139           0 :     if (stroker->dash.dash_on && ! stroker->has_current_face) {
    1140             :         /* This segment ends on a transition to dash_on, compute a new face
    1141             :          * and add cap for the beginning of the next dash_on step.
    1142             :          *
    1143             :          * Note: this will create a degenerate cap if this is not the last line
    1144             :          * in the path. Whether this behaviour is desirable or not is debatable.
    1145             :          * On one side these degenerate caps can not be reproduced with regular
    1146             :          * path stroking.
    1147             :          * On the other hand, Acroread 7 also produces the degenerate caps.
    1148             :          */
    1149           0 :         _compute_face (p2, &dev_slope,
    1150             :                        slope_dx, slope_dy,
    1151             :                        stroker,
    1152             :                        &stroker->current_face);
    1153             : 
    1154           0 :         status = _cairo_stroker_add_leading_cap (stroker,
    1155           0 :                                                  &stroker->current_face);
    1156           0 :         if (unlikely (status))
    1157           0 :             return status;
    1158             : 
    1159           0 :         stroker->has_current_face = TRUE;
    1160             :     }
    1161             : 
    1162           0 :     stroker->current_point = *p2;
    1163             : 
    1164           0 :     return CAIRO_STATUS_SUCCESS;
    1165             : }
    1166             : 
    1167             : static cairo_status_t
    1168           0 : _cairo_stroker_curve_to (void *closure,
    1169             :                          const cairo_point_t *b,
    1170             :                          const cairo_point_t *c,
    1171             :                          const cairo_point_t *d)
    1172             : {
    1173           0 :     cairo_stroker_t *stroker = closure;
    1174             :     cairo_spline_t spline;
    1175             :     cairo_line_join_t line_join_save;
    1176             :     cairo_stroke_face_t face;
    1177             :     double slope_dx, slope_dy;
    1178             :     cairo_path_fixed_line_to_func_t *line_to;
    1179           0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    1180             : 
    1181           0 :     line_to = stroker->dash.dashed ?
    1182             :         _cairo_stroker_line_to_dashed :
    1183             :         _cairo_stroker_line_to;
    1184             : 
    1185           0 :     if (! _cairo_spline_init (&spline,
    1186             :                               line_to, stroker,
    1187           0 :                               &stroker->current_point, b, c, d))
    1188             :     {
    1189           0 :         return line_to (closure, d);
    1190             :     }
    1191             : 
    1192             :     /* If the line width is so small that the pen is reduced to a
    1193             :        single point, then we have nothing to do. */
    1194           0 :     if (stroker->pen.num_vertices <= 1)
    1195           0 :         return CAIRO_STATUS_SUCCESS;
    1196             : 
    1197             :     /* Compute the initial face */
    1198           0 :     if (! stroker->dash.dashed || stroker->dash.dash_on) {
    1199           0 :         slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
    1200           0 :         slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
    1201           0 :         if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
    1202             :                                               stroker->ctm_inverse, NULL))
    1203             :         {
    1204           0 :             _compute_face (&stroker->current_point,
    1205             :                            &spline.initial_slope,
    1206             :                            slope_dx, slope_dy,
    1207             :                            stroker, &face);
    1208             :         }
    1209           0 :         if (stroker->has_current_face) {
    1210           0 :             status = _cairo_stroker_join (stroker,
    1211           0 :                                           &stroker->current_face, &face);
    1212           0 :             if (unlikely (status))
    1213           0 :                 return status;
    1214           0 :         } else if (! stroker->has_first_face) {
    1215           0 :             stroker->first_face = face;
    1216           0 :             stroker->has_first_face = TRUE;
    1217             :         }
    1218             : 
    1219           0 :         stroker->current_face = face;
    1220           0 :         stroker->has_current_face = TRUE;
    1221             :     }
    1222             : 
    1223             :     /* Temporarily modify the stroker to use round joins to guarantee
    1224             :      * smooth stroked curves. */
    1225           0 :     line_join_save = stroker->style.line_join;
    1226           0 :     stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
    1227             : 
    1228           0 :     status = _cairo_spline_decompose (&spline, stroker->tolerance);
    1229           0 :     if (unlikely (status))
    1230           0 :         return status;
    1231             : 
    1232             :     /* And join the final face */
    1233           0 :     if (! stroker->dash.dashed || stroker->dash.dash_on) {
    1234           0 :         slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
    1235           0 :         slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
    1236           0 :         if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
    1237             :                                               stroker->ctm_inverse, NULL))
    1238             :         {
    1239           0 :             _compute_face (&stroker->current_point,
    1240             :                            &spline.final_slope,
    1241             :                            slope_dx, slope_dy,
    1242             :                            stroker, &face);
    1243             :         }
    1244             : 
    1245           0 :         status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
    1246           0 :         if (unlikely (status))
    1247           0 :             return status;
    1248             : 
    1249           0 :         stroker->current_face = face;
    1250             :     }
    1251             : 
    1252           0 :     stroker->style.line_join = line_join_save;
    1253             : 
    1254           0 :     return CAIRO_STATUS_SUCCESS;
    1255             : }
    1256             : 
    1257             : static cairo_status_t
    1258           0 : _cairo_stroker_close_path (void *closure)
    1259             : {
    1260           0 :     cairo_stroker_t *stroker = closure;
    1261             :     cairo_status_t status;
    1262             : 
    1263           0 :     if (stroker->dash.dashed)
    1264           0 :         status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
    1265             :     else
    1266           0 :         status = _cairo_stroker_line_to (stroker, &stroker->first_point);
    1267           0 :     if (unlikely (status))
    1268           0 :         return status;
    1269             : 
    1270           0 :     if (stroker->has_first_face && stroker->has_current_face) {
    1271             :         /* Join first and final faces of sub path */
    1272           0 :         status = _cairo_stroker_join (stroker,
    1273           0 :                                       &stroker->current_face,
    1274           0 :                                       &stroker->first_face);
    1275           0 :         if (unlikely (status))
    1276           0 :             return status;
    1277             :     } else {
    1278             :         /* Cap the start and end of the sub path as needed */
    1279           0 :         status = _cairo_stroker_add_caps (stroker);
    1280           0 :         if (unlikely (status))
    1281           0 :             return status;
    1282             :     }
    1283             : 
    1284           0 :     stroker->has_initial_sub_path = FALSE;
    1285           0 :     stroker->has_first_face = FALSE;
    1286           0 :     stroker->has_current_face = FALSE;
    1287             : 
    1288           0 :     return CAIRO_STATUS_SUCCESS;
    1289             : }
    1290             : 
    1291             : cairo_status_t
    1292           0 : _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t  *path,
    1293             :                                     const cairo_stroke_style_t  *stroke_style,
    1294             :                                     const cairo_matrix_t        *ctm,
    1295             :                                     const cairo_matrix_t        *ctm_inverse,
    1296             :                                     double               tolerance,
    1297             :                                     cairo_status_t (*add_triangle) (void *closure,
    1298             :                                                                     const cairo_point_t triangle[3]),
    1299             :                                     cairo_status_t (*add_triangle_fan) (void *closure,
    1300             :                                                                         const cairo_point_t *midpt,
    1301             :                                                                         const cairo_point_t *points,
    1302             :                                                                         int npoints),
    1303             :                                     cairo_status_t (*add_convex_quad) (void *closure,
    1304             :                                                                        const cairo_point_t quad[4]),
    1305             :                                     void *closure)
    1306             : {
    1307             :     cairo_stroker_t stroker;
    1308             :     cairo_status_t status;
    1309             : 
    1310           0 :     status = _cairo_stroker_init (&stroker, stroke_style,
    1311             :                                   ctm, ctm_inverse, tolerance);
    1312           0 :     if (unlikely (status))
    1313           0 :         return status;
    1314             : 
    1315           0 :     stroker.add_triangle = add_triangle;
    1316           0 :     stroker.add_triangle_fan = add_triangle_fan;
    1317           0 :     stroker.add_convex_quad = add_convex_quad;
    1318           0 :     stroker.closure = closure;
    1319             : 
    1320           0 :     status = _cairo_path_fixed_interpret (path,
    1321             :                                           CAIRO_DIRECTION_FORWARD,
    1322             :                                           _cairo_stroker_move_to,
    1323           0 :                                           stroker.dash.dashed ?
    1324             :                                           _cairo_stroker_line_to_dashed :
    1325             :                                           _cairo_stroker_line_to,
    1326             :                                           _cairo_stroker_curve_to,
    1327             :                                           _cairo_stroker_close_path,
    1328             :                                           &stroker);
    1329             : 
    1330           0 :     if (unlikely (status))
    1331           0 :         goto BAIL;
    1332             : 
    1333             :     /* Cap the start and end of the final sub path as needed */
    1334           0 :     status = _cairo_stroker_add_caps (&stroker);
    1335             : 
    1336             : BAIL:
    1337           0 :     _cairo_stroker_fini (&stroker);
    1338             : 
    1339           0 :     return status;
    1340             : }
    1341             : 
    1342             : cairo_status_t
    1343           0 : _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t   *path,
    1344             :                                      const cairo_stroke_style_t *stroke_style,
    1345             :                                      const cairo_matrix_t       *ctm,
    1346             :                                      const cairo_matrix_t       *ctm_inverse,
    1347             :                                      double              tolerance,
    1348             :                                      cairo_polygon_t *polygon)
    1349             : {
    1350             :     cairo_stroker_t stroker;
    1351             :     cairo_status_t status;
    1352             : 
    1353           0 :     status = _cairo_stroker_init (&stroker, stroke_style,
    1354             :                                   ctm, ctm_inverse, tolerance);
    1355           0 :     if (unlikely (status))
    1356           0 :         return status;
    1357             : 
    1358           0 :     stroker.add_external_edge = _cairo_polygon_add_external_edge,
    1359           0 :     stroker.closure = polygon;
    1360             : 
    1361           0 :     if (polygon->num_limits)
    1362           0 :         _cairo_stroker_limit (&stroker, polygon->limits, polygon->num_limits);
    1363             : 
    1364           0 :     status = _cairo_path_fixed_interpret (path,
    1365             :                                           CAIRO_DIRECTION_FORWARD,
    1366             :                                           _cairo_stroker_move_to,
    1367           0 :                                           stroker.dash.dashed ?
    1368             :                                           _cairo_stroker_line_to_dashed :
    1369             :                                           _cairo_stroker_line_to,
    1370             :                                           _cairo_stroker_curve_to,
    1371             :                                           _cairo_stroker_close_path,
    1372             :                                           &stroker);
    1373             : 
    1374           0 :     if (unlikely (status))
    1375           0 :         goto BAIL;
    1376             : 
    1377             :     /* Cap the start and end of the final sub path as needed */
    1378           0 :     status = _cairo_stroker_add_caps (&stroker);
    1379             : 
    1380             : BAIL:
    1381           0 :     _cairo_stroker_fini (&stroker);
    1382             : 
    1383           0 :     return status;
    1384             : }
    1385             : 
    1386             : cairo_status_t
    1387           0 : _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t     *path,
    1388             :                                    const cairo_stroke_style_t   *stroke_style,
    1389             :                                    const cairo_matrix_t *ctm,
    1390             :                                    const cairo_matrix_t *ctm_inverse,
    1391             :                                    double                tolerance,
    1392             :                                    cairo_traps_t        *traps)
    1393             : {
    1394             :     cairo_status_t status;
    1395             :     cairo_polygon_t polygon;
    1396             : 
    1397             :     /* Before we do anything else, we attempt the rectilinear
    1398             :      * stroker. It's careful to generate trapezoids that align to
    1399             :      * device-pixel boundaries when possible. Many backends can render
    1400             :      * those much faster than non-aligned trapezoids, (by using clip
    1401             :      * regions, etc.) */
    1402           0 :     if (path->is_rectilinear) {
    1403           0 :         status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
    1404             :                                                                 stroke_style,
    1405             :                                                                 ctm,
    1406             :                                                                 traps);
    1407           0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    1408           0 :             return status;
    1409             :     }
    1410             : 
    1411           0 :     _cairo_polygon_init (&polygon);
    1412           0 :     if (traps->num_limits)
    1413           0 :         _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
    1414             : 
    1415           0 :     status = _cairo_path_fixed_stroke_to_polygon (path,
    1416             :                                                   stroke_style,
    1417             :                                                   ctm,
    1418             :                                                   ctm_inverse,
    1419             :                                                   tolerance,
    1420             :                                                   &polygon);
    1421           0 :     if (unlikely (status))
    1422           0 :         goto BAIL;
    1423             : 
    1424           0 :     status = _cairo_polygon_status (&polygon);
    1425           0 :     if (unlikely (status))
    1426           0 :         goto BAIL;
    1427             : 
    1428           0 :     status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
    1429             :                                                         CAIRO_FILL_RULE_WINDING);
    1430             : 
    1431             : BAIL:
    1432           0 :     _cairo_polygon_fini (&polygon);
    1433             : 
    1434           0 :     return status;
    1435             : }
    1436             : 
    1437             : typedef struct _segment_t {
    1438             :     cairo_point_t p1, p2;
    1439             :     cairo_bool_t is_horizontal;
    1440             :     cairo_bool_t has_join;
    1441             : } segment_t;
    1442             : 
    1443             : typedef struct _cairo_rectilinear_stroker {
    1444             :     const cairo_stroke_style_t *stroke_style;
    1445             :     const cairo_matrix_t *ctm;
    1446             : 
    1447             :     cairo_fixed_t half_line_width;
    1448             :     cairo_bool_t do_traps;
    1449             :     void *container;
    1450             :     cairo_point_t current_point;
    1451             :     cairo_point_t first_point;
    1452             :     cairo_bool_t open_sub_path;
    1453             : 
    1454             :     cairo_stroker_dash_t dash;
    1455             : 
    1456             :     cairo_bool_t has_bounds;
    1457             :     cairo_box_t bounds;
    1458             : 
    1459             :     int num_segments;
    1460             :     int segments_size;
    1461             :     segment_t *segments;
    1462             :     segment_t segments_embedded[8]; /* common case is a single rectangle */
    1463             : } cairo_rectilinear_stroker_t;
    1464             : 
    1465             : static void
    1466           0 : _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
    1467             :                                   const cairo_box_t *boxes,
    1468             :                                   int num_boxes)
    1469             : {
    1470           0 :     stroker->has_bounds = TRUE;
    1471           0 :     _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
    1472             : 
    1473           0 :     stroker->bounds.p1.x -= stroker->half_line_width;
    1474           0 :     stroker->bounds.p2.x += stroker->half_line_width;
    1475             : 
    1476           0 :     stroker->bounds.p1.y -= stroker->half_line_width;
    1477           0 :     stroker->bounds.p2.y += stroker->half_line_width;
    1478           0 : }
    1479             : 
    1480             : static cairo_bool_t
    1481           0 : _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t    *stroker,
    1482             :                                  const cairo_stroke_style_t     *stroke_style,
    1483             :                                  const cairo_matrix_t           *ctm,
    1484             :                                  cairo_bool_t                    do_traps,
    1485             :                                  void                           *container)
    1486             : {
    1487             :     /* This special-case rectilinear stroker only supports
    1488             :      * miter-joined lines (not curves) and a translation-only matrix
    1489             :      * (though it could probably be extended to support a matrix with
    1490             :      * uniform, integer scaling).
    1491             :      *
    1492             :      * It also only supports horizontal and vertical line_to
    1493             :      * elements. But we don't catch that here, but instead return
    1494             :      * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
    1495             :      * non-rectilinear line_to is encountered.
    1496             :      */
    1497           0 :     if (stroke_style->line_join      != CAIRO_LINE_JOIN_MITER)
    1498           0 :         return FALSE;
    1499             : 
    1500             :     /* If the miter limit turns right angles into bevels, then we
    1501             :      * can't use this optimization. Remember, the ratio is
    1502             :      * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2,
    1503             :      * which we round for safety. */
    1504           0 :     if (stroke_style->miter_limit < M_SQRT2)
    1505           0 :         return FALSE;
    1506             : 
    1507           0 :     if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
    1508           0 :            stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
    1509             :     {
    1510           0 :         return FALSE;
    1511             :     }
    1512             : 
    1513           0 :     if (! _cairo_matrix_has_unity_scale (ctm))
    1514           0 :         return FALSE;
    1515             : 
    1516           0 :     stroker->stroke_style = stroke_style;
    1517           0 :     stroker->ctm = ctm;
    1518             : 
    1519           0 :     stroker->half_line_width =
    1520           0 :         _cairo_fixed_from_double (stroke_style->line_width / 2.0);
    1521           0 :     stroker->open_sub_path = FALSE;
    1522           0 :     stroker->segments = stroker->segments_embedded;
    1523           0 :     stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
    1524           0 :     stroker->num_segments = 0;
    1525             : 
    1526           0 :     _cairo_stroker_dash_init (&stroker->dash, stroke_style);
    1527             : 
    1528           0 :     stroker->has_bounds = FALSE;
    1529             : 
    1530           0 :     stroker->do_traps = do_traps;
    1531           0 :     stroker->container = container;
    1532             : 
    1533           0 :     return TRUE;
    1534             : }
    1535             : 
    1536             : static void
    1537           0 : _cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t    *stroker)
    1538             : {
    1539           0 :     if (stroker->segments != stroker->segments_embedded)
    1540           0 :         free (stroker->segments);
    1541           0 : }
    1542             : 
    1543             : static cairo_status_t
    1544           0 : _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
    1545             :                                         const cairo_point_t     *p1,
    1546             :                                         const cairo_point_t     *p2,
    1547             :                                         cairo_bool_t             is_horizontal,
    1548             :                                         cairo_bool_t             has_join)
    1549             : {
    1550             :     if (CAIRO_INJECT_FAULT ())
    1551             :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1552             : 
    1553           0 :     if (stroker->num_segments == stroker->segments_size) {
    1554           0 :         int new_size = stroker->segments_size * 2;
    1555             :         segment_t *new_segments;
    1556             : 
    1557           0 :         if (stroker->segments == stroker->segments_embedded) {
    1558           0 :             new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t));
    1559           0 :             if (unlikely (new_segments == NULL))
    1560           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1561             : 
    1562           0 :             memcpy (new_segments, stroker->segments,
    1563           0 :                     stroker->num_segments * sizeof (segment_t));
    1564             :         } else {
    1565           0 :             new_segments = _cairo_realloc_ab (stroker->segments,
    1566             :                                               new_size, sizeof (segment_t));
    1567           0 :             if (unlikely (new_segments == NULL))
    1568           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1569             :         }
    1570             : 
    1571           0 :         stroker->segments_size = new_size;
    1572           0 :         stroker->segments = new_segments;
    1573             :     }
    1574             : 
    1575           0 :     stroker->segments[stroker->num_segments].p1 = *p1;
    1576           0 :     stroker->segments[stroker->num_segments].p2 = *p2;
    1577           0 :     stroker->segments[stroker->num_segments].has_join = has_join;
    1578           0 :     stroker->segments[stroker->num_segments].is_horizontal = is_horizontal;
    1579           0 :     stroker->num_segments++;
    1580             : 
    1581           0 :     return CAIRO_STATUS_SUCCESS;
    1582             : }
    1583             : 
    1584             : static cairo_status_t
    1585           0 : _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
    1586             : {
    1587             :     cairo_status_t status;
    1588           0 :     cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    1589           0 :     cairo_fixed_t half_line_width = stroker->half_line_width;
    1590             :     int i;
    1591             : 
    1592           0 :     for (i = 0; i < stroker->num_segments; i++) {
    1593             :         cairo_point_t *a, *b;
    1594             :         cairo_bool_t lengthen_initial, shorten_final, lengthen_final;
    1595             : 
    1596           0 :         a = &stroker->segments[i].p1;
    1597           0 :         b = &stroker->segments[i].p2;
    1598             : 
    1599             :         /* For each segment we generate a single rectangular
    1600             :          * trapezoid. This rectangle is based on a perpendicular
    1601             :          * extension (by half the line width) of the segment endpoints
    1602             :          * after some adjustments of the endpoints to account for caps
    1603             :          * and joins.
    1604             :          */
    1605             : 
    1606             :         /* We adjust the initial point of the segment to extend the
    1607             :          * rectangle to include the previous cap or join, (this
    1608             :          * adjustment applies to all segments except for the first
    1609             :          * segment of open, butt-capped paths).
    1610             :          */
    1611           0 :         lengthen_initial = TRUE;
    1612           0 :         if (i == 0 && stroker->open_sub_path && line_cap == CAIRO_LINE_CAP_BUTT)
    1613           0 :             lengthen_initial = FALSE;
    1614             : 
    1615             :         /* The adjustment of the final point is trickier. For all but
    1616             :          * the last segment we shorten the segment at the final
    1617             :          * endpoint to not overlap with the subsequent join. For the
    1618             :          * last segment we do the same shortening if the path is
    1619             :          * closed. If the path is open and butt-capped we do no
    1620             :          * adjustment, while if it's open and square-capped we do a
    1621             :          * lengthening adjustment instead to include the cap.
    1622             :          */
    1623           0 :         shorten_final = TRUE;
    1624           0 :         lengthen_final = FALSE;
    1625           0 :         if (i == stroker->num_segments - 1 && stroker->open_sub_path) {
    1626           0 :             shorten_final = FALSE;
    1627           0 :             if (line_cap == CAIRO_LINE_CAP_SQUARE)
    1628           0 :                 lengthen_final = TRUE;
    1629             :         }
    1630             : 
    1631             :         /* Perform the adjustments of the endpoints. */
    1632           0 :         if (a->y == b->y) {
    1633           0 :             if (a->x < b->x) {
    1634           0 :                 if (lengthen_initial)
    1635           0 :                     a->x -= half_line_width;
    1636           0 :                 if (shorten_final)
    1637           0 :                     b->x -= half_line_width;
    1638           0 :                 else if (lengthen_final)
    1639           0 :                     b->x += half_line_width;
    1640             :             } else {
    1641           0 :                 if (lengthen_initial)
    1642           0 :                     a->x += half_line_width;
    1643           0 :                 if (shorten_final)
    1644           0 :                     b->x += half_line_width;
    1645           0 :                 else if (lengthen_final)
    1646           0 :                     b->x -= half_line_width;
    1647             :             }
    1648             : 
    1649           0 :             if (a->x > b->x) {
    1650             :                 cairo_point_t *t;
    1651             : 
    1652           0 :                 t = a;
    1653           0 :                 a = b;
    1654           0 :                 b = t;
    1655             :             }
    1656             :         } else {
    1657           0 :             if (a->y < b->y) {
    1658           0 :                 if (lengthen_initial)
    1659           0 :                     a->y -= half_line_width;
    1660           0 :                 if (shorten_final)
    1661           0 :                     b->y -= half_line_width;
    1662           0 :                 else if (lengthen_final)
    1663           0 :                     b->y += half_line_width;
    1664             :             } else {
    1665           0 :                 if (lengthen_initial)
    1666           0 :                     a->y += half_line_width;
    1667           0 :                 if (shorten_final)
    1668           0 :                     b->y += half_line_width;
    1669           0 :                 else if (lengthen_final)
    1670           0 :                     b->y -= half_line_width;
    1671             :             }
    1672             : 
    1673           0 :             if (a->y > b->y) {
    1674             :                 cairo_point_t *t;
    1675             : 
    1676           0 :                 t = a;
    1677           0 :                 a = b;
    1678           0 :                 b = t;
    1679             :             }
    1680             :         }
    1681             : 
    1682             :         /* Form the rectangle by expanding by half the line width in
    1683             :          * either perpendicular direction. */
    1684           0 :         if (a->y == b->y) {
    1685           0 :             a->y -= half_line_width;
    1686           0 :             b->y += half_line_width;
    1687             :         } else {
    1688           0 :             a->x -= half_line_width;
    1689           0 :             b->x += half_line_width;
    1690             :         }
    1691             : 
    1692           0 :         if (stroker->do_traps) {
    1693           0 :             status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
    1694             :         } else {
    1695             :             cairo_box_t box;
    1696             : 
    1697           0 :             box.p1 = *a;
    1698           0 :             box.p2 = *b;
    1699             : 
    1700           0 :             status = _cairo_boxes_add (stroker->container, &box);
    1701             :         }
    1702           0 :         if (unlikely (status))
    1703           0 :             return status;
    1704             :     }
    1705             : 
    1706           0 :     stroker->num_segments = 0;
    1707             : 
    1708           0 :     return CAIRO_STATUS_SUCCESS;
    1709             : }
    1710             : 
    1711             : static cairo_status_t
    1712           0 : _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
    1713             : {
    1714             :     cairo_status_t status;
    1715           0 :     cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    1716           0 :     cairo_fixed_t half_line_width = stroker->half_line_width;
    1717             :     int i;
    1718             : 
    1719           0 :     for (i = 0; i < stroker->num_segments; i++) {
    1720             :         cairo_point_t *a, *b;
    1721             :         cairo_bool_t is_horizontal;
    1722             : 
    1723           0 :         a = &stroker->segments[i].p1;
    1724           0 :         b = &stroker->segments[i].p2;
    1725             : 
    1726           0 :         is_horizontal = stroker->segments[i].is_horizontal;
    1727             : 
    1728             :         /* Handle the joins for a potentially degenerate segment. */
    1729           0 :         if (line_cap == CAIRO_LINE_CAP_BUTT &&
    1730           0 :             stroker->segments[i].has_join &&
    1731           0 :             (i != stroker->num_segments - 1 ||
    1732           0 :              (! stroker->open_sub_path && stroker->dash.dash_starts_on)))
    1733             :         {
    1734           0 :             cairo_point_t p1 = stroker->segments[i].p1;
    1735           0 :             cairo_point_t p2 = stroker->segments[i].p2;
    1736             :             cairo_slope_t out_slope;
    1737           0 :             int j = (i + 1) % stroker->num_segments;
    1738             : 
    1739           0 :             _cairo_slope_init (&out_slope,
    1740           0 :                                &stroker->segments[j].p1,
    1741           0 :                                &stroker->segments[j].p2);
    1742             : 
    1743           0 :             if (is_horizontal) {
    1744           0 :                 if (p1.x <= p2.x) {
    1745           0 :                     p1.x = p2.x;
    1746           0 :                     p2.x += half_line_width;
    1747             :                 } else {
    1748           0 :                     p1.x = p2.x - half_line_width;
    1749             :                 }
    1750           0 :                 if (out_slope.dy >= 0)
    1751           0 :                     p1.y -= half_line_width;
    1752           0 :                 if (out_slope.dy <= 0)
    1753           0 :                     p2.y += half_line_width;
    1754             :             } else {
    1755           0 :                 if (p1.y <= p2.y) {
    1756           0 :                     p1.y = p2.y;
    1757           0 :                     p2.y += half_line_width;
    1758             :                 } else {
    1759           0 :                     p1.y = p2.y - half_line_width;
    1760             :                 }
    1761           0 :                 if (out_slope.dx >= 0)
    1762           0 :                     p1.x -= half_line_width;
    1763           0 :                 if (out_slope.dx <= 0)
    1764           0 :                     p2.x += half_line_width;
    1765             :             }
    1766             : 
    1767           0 :             if (stroker->do_traps) {
    1768           0 :                 status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2);
    1769             :             } else {
    1770             :                 cairo_box_t box;
    1771             : 
    1772           0 :                 box.p1 = p1;
    1773           0 :                 box.p2 = p2;
    1774             : 
    1775           0 :                 status = _cairo_boxes_add (stroker->container, &box);
    1776             :             }
    1777           0 :             if (unlikely (status))
    1778           0 :                 return status;
    1779             :         }
    1780             : 
    1781             :         /* Perform the adjustments of the endpoints. */
    1782           0 :         if (is_horizontal) {
    1783           0 :             if (line_cap == CAIRO_LINE_CAP_SQUARE) {
    1784           0 :                 if (a->x <= b->x) {
    1785           0 :                     a->x -= half_line_width;
    1786           0 :                     b->x += half_line_width;
    1787             :                 } else {
    1788           0 :                     a->x += half_line_width;
    1789           0 :                     b->x -= half_line_width;
    1790             :                 }
    1791             :             }
    1792             : 
    1793           0 :             if (a->x > b->x) {
    1794             :                 cairo_point_t *t;
    1795             : 
    1796           0 :                 t = a;
    1797           0 :                 a = b;
    1798           0 :                 b = t;
    1799             :             }
    1800             : 
    1801           0 :             a->y -= half_line_width;
    1802           0 :             b->y += half_line_width;
    1803             :         } else {
    1804           0 :             if (line_cap == CAIRO_LINE_CAP_SQUARE) {
    1805           0 :                 if (a->y <= b->y) {
    1806           0 :                     a->y -= half_line_width;
    1807           0 :                     b->y += half_line_width;
    1808             :                 } else {
    1809           0 :                     a->y += half_line_width;
    1810           0 :                     b->y -= half_line_width;
    1811             :                 }
    1812             :             }
    1813             : 
    1814           0 :             if (a->y > b->y) {
    1815             :                 cairo_point_t *t;
    1816             : 
    1817           0 :                 t = a;
    1818           0 :                 a = b;
    1819           0 :                 b = t;
    1820             :             }
    1821             : 
    1822           0 :             a->x -= half_line_width;
    1823           0 :             b->x += half_line_width;
    1824             :         }
    1825             : 
    1826           0 :         if (a->x == b->x && a->y == b->y)
    1827           0 :             continue;
    1828             : 
    1829           0 :         if (stroker->do_traps) {
    1830           0 :             status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
    1831             :         } else {
    1832             :             cairo_box_t box;
    1833             : 
    1834           0 :             box.p1 = *a;
    1835           0 :             box.p2 = *b;
    1836             : 
    1837           0 :             status = _cairo_boxes_add (stroker->container, &box);
    1838             :         }
    1839           0 :         if (unlikely (status))
    1840           0 :             return status;
    1841             :     }
    1842             : 
    1843           0 :     stroker->num_segments = 0;
    1844             : 
    1845           0 :     return CAIRO_STATUS_SUCCESS;
    1846             : }
    1847             : 
    1848             : static cairo_status_t
    1849           0 : _cairo_rectilinear_stroker_move_to (void                *closure,
    1850             :                                     const cairo_point_t *point)
    1851             : {
    1852           0 :     cairo_rectilinear_stroker_t *stroker = closure;
    1853             :     cairo_status_t status;
    1854             : 
    1855           0 :     if (stroker->dash.dashed)
    1856           0 :         status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
    1857             :     else
    1858           0 :         status = _cairo_rectilinear_stroker_emit_segments (stroker);
    1859           0 :     if (unlikely (status))
    1860           0 :         return status;
    1861             : 
    1862             :     /* reset the dash pattern for new sub paths */
    1863           0 :     _cairo_stroker_dash_start (&stroker->dash);
    1864             : 
    1865           0 :     stroker->current_point = *point;
    1866           0 :     stroker->first_point = *point;
    1867             : 
    1868           0 :     return CAIRO_STATUS_SUCCESS;
    1869             : }
    1870             : 
    1871             : static cairo_status_t
    1872           0 : _cairo_rectilinear_stroker_line_to (void                *closure,
    1873             :                                     const cairo_point_t *b)
    1874             : {
    1875           0 :     cairo_rectilinear_stroker_t *stroker = closure;
    1876           0 :     cairo_point_t *a = &stroker->current_point;
    1877             :     cairo_status_t status;
    1878             : 
    1879             :     /* We only support horizontal or vertical elements. */
    1880           0 :     assert (a->x == b->x || a->y == b->y);
    1881             : 
    1882             :     /* We don't draw anything for degenerate paths. */
    1883           0 :     if (a->x == b->x && a->y == b->y)
    1884           0 :         return CAIRO_STATUS_SUCCESS;
    1885             : 
    1886           0 :     status = _cairo_rectilinear_stroker_add_segment (stroker, a, b,
    1887           0 :                                                      a->y == b->y,
    1888             :                                                      TRUE);
    1889             : 
    1890           0 :     stroker->current_point = *b;
    1891           0 :     stroker->open_sub_path = TRUE;
    1892             : 
    1893           0 :     return status;
    1894             : }
    1895             : 
    1896             : static cairo_status_t
    1897           0 : _cairo_rectilinear_stroker_line_to_dashed (void         *closure,
    1898             :                                            const cairo_point_t  *point)
    1899             : {
    1900           0 :     cairo_rectilinear_stroker_t *stroker = closure;
    1901           0 :     const cairo_point_t *a = &stroker->current_point;
    1902           0 :     const cairo_point_t *b = point;
    1903             :     cairo_bool_t fully_in_bounds;
    1904             :     double sign, remain;
    1905             :     cairo_fixed_t mag;
    1906             :     cairo_status_t status;
    1907             :     cairo_line_t segment;
    1908           0 :     cairo_bool_t dash_on = FALSE;
    1909             :     cairo_bool_t is_horizontal;
    1910             : 
    1911             :     /* We don't draw anything for degenerate paths. */
    1912           0 :     if (a->x == b->x && a->y == b->y)
    1913           0 :         return CAIRO_STATUS_SUCCESS;
    1914             : 
    1915             :     /* We only support horizontal or vertical elements. */
    1916           0 :     assert (a->x == b->x || a->y == b->y);
    1917             : 
    1918           0 :     fully_in_bounds = TRUE;
    1919           0 :     if (stroker->has_bounds &&
    1920           0 :         (! _cairo_box_contains_point (&stroker->bounds, a) ||
    1921           0 :          ! _cairo_box_contains_point (&stroker->bounds, b)))
    1922             :     {
    1923           0 :         fully_in_bounds = FALSE;
    1924             :     }
    1925             : 
    1926           0 :     is_horizontal = a->y == b->y;
    1927           0 :     if (is_horizontal)
    1928           0 :         mag = b->x - a->x;
    1929             :     else
    1930           0 :         mag = b->y - a->y;
    1931           0 :     if (mag < 0) {
    1932           0 :         remain = _cairo_fixed_to_double (-mag);
    1933           0 :         sign = 1.;
    1934             :     } else {
    1935           0 :         remain = _cairo_fixed_to_double (mag);
    1936           0 :         sign = -1.;
    1937             :     }
    1938             : 
    1939           0 :     segment.p2 = segment.p1 = *a;
    1940           0 :     while (remain > 0.) {
    1941             :         double step_length;
    1942             : 
    1943           0 :         step_length = MIN (stroker->dash.dash_remain, remain);
    1944           0 :         remain -= step_length;
    1945             : 
    1946           0 :         mag = _cairo_fixed_from_double (sign*remain);
    1947           0 :         if (is_horizontal)
    1948           0 :             segment.p2.x = b->x + mag;
    1949             :         else
    1950           0 :             segment.p2.y = b->y + mag;
    1951             : 
    1952           0 :         if (stroker->dash.dash_on &&
    1953           0 :             (fully_in_bounds ||
    1954           0 :              _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
    1955             :         {
    1956           0 :             status = _cairo_rectilinear_stroker_add_segment (stroker,
    1957             :                                                              &segment.p1,
    1958             :                                                              &segment.p2,
    1959             :                                                              is_horizontal,
    1960             :                                                              remain <= 0.);
    1961           0 :             if (unlikely (status))
    1962           0 :                 return status;
    1963             : 
    1964           0 :             dash_on = TRUE;
    1965             :         }
    1966             :         else
    1967             :         {
    1968           0 :             dash_on = FALSE;
    1969             :         }
    1970             : 
    1971           0 :         _cairo_stroker_dash_step (&stroker->dash, step_length);
    1972           0 :         segment.p1 = segment.p2;
    1973             :     }
    1974             : 
    1975           0 :     if (stroker->dash.dash_on && ! dash_on &&
    1976           0 :         (fully_in_bounds ||
    1977           0 :          _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
    1978             :     {
    1979             : 
    1980             :         /* This segment ends on a transition to dash_on, compute a new face
    1981             :          * and add cap for the beginning of the next dash_on step.
    1982             :          */
    1983             : 
    1984           0 :         status = _cairo_rectilinear_stroker_add_segment (stroker,
    1985             :                                                          &segment.p1,
    1986             :                                                          &segment.p1,
    1987             :                                                          is_horizontal,
    1988             :                                                          TRUE);
    1989           0 :         if (unlikely (status))
    1990           0 :             return status;
    1991             :     }
    1992             : 
    1993           0 :     stroker->current_point = *point;
    1994           0 :     stroker->open_sub_path = TRUE;
    1995             : 
    1996           0 :     return CAIRO_STATUS_SUCCESS;
    1997             : }
    1998             : 
    1999             : static cairo_status_t
    2000           0 : _cairo_rectilinear_stroker_close_path (void *closure)
    2001             : {
    2002           0 :     cairo_rectilinear_stroker_t *stroker = closure;
    2003             :     cairo_status_t status;
    2004             : 
    2005             :     /* We don't draw anything for degenerate paths. */
    2006           0 :     if (! stroker->open_sub_path)
    2007           0 :         return CAIRO_STATUS_SUCCESS;
    2008             : 
    2009           0 :     if (stroker->dash.dashed) {
    2010           0 :         status = _cairo_rectilinear_stroker_line_to_dashed (stroker,
    2011           0 :                                                             &stroker->first_point);
    2012             :     } else {
    2013           0 :         status = _cairo_rectilinear_stroker_line_to (stroker,
    2014           0 :                                                      &stroker->first_point);
    2015             :     }
    2016           0 :     if (unlikely (status))
    2017           0 :         return status;
    2018             : 
    2019           0 :     stroker->open_sub_path = FALSE;
    2020             : 
    2021           0 :     if (stroker->dash.dashed)
    2022           0 :         status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
    2023             :     else
    2024           0 :         status = _cairo_rectilinear_stroker_emit_segments (stroker);
    2025           0 :     if (unlikely (status))
    2026           0 :         return status;
    2027             : 
    2028           0 :     return CAIRO_STATUS_SUCCESS;
    2029             : }
    2030             : 
    2031             : cairo_int_status_t
    2032           0 : _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
    2033             :                                                const cairo_stroke_style_t       *stroke_style,
    2034             :                                                const cairo_matrix_t     *ctm,
    2035             :                                                cairo_traps_t            *traps)
    2036             : {
    2037             :     cairo_rectilinear_stroker_t rectilinear_stroker;
    2038             :     cairo_int_status_t status;
    2039             : 
    2040           0 :     assert (path->is_rectilinear);
    2041             : 
    2042           0 :     if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
    2043             :                                            stroke_style, ctm,
    2044             :                                            TRUE, traps))
    2045             :     {
    2046           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2047             :     }
    2048             : 
    2049           0 :     if (traps->num_limits) {
    2050           0 :         _cairo_rectilinear_stroker_limit (&rectilinear_stroker,
    2051             :                                           traps->limits,
    2052             :                                           traps->num_limits);
    2053             :     }
    2054             : 
    2055           0 :     status = _cairo_path_fixed_interpret (path,
    2056             :                                           CAIRO_DIRECTION_FORWARD,
    2057             :                                           _cairo_rectilinear_stroker_move_to,
    2058           0 :                                           rectilinear_stroker.dash.dashed ?
    2059             :                                           _cairo_rectilinear_stroker_line_to_dashed :
    2060             :                                           _cairo_rectilinear_stroker_line_to,
    2061             :                                           NULL,
    2062             :                                           _cairo_rectilinear_stroker_close_path,
    2063             :                                           &rectilinear_stroker);
    2064           0 :     if (unlikely (status))
    2065           0 :         goto BAIL;
    2066             : 
    2067           0 :     if (rectilinear_stroker.dash.dashed)
    2068           0 :         status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    2069             :     else
    2070           0 :         status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
    2071             : 
    2072           0 :     traps->is_rectilinear = 1;
    2073           0 :     traps->is_rectangular = 1;
    2074             :     /* As we incrementally tessellate, we do not eliminate self-intersections */
    2075           0 :     traps->has_intersections = traps->num_traps > 1;
    2076             : BAIL:
    2077           0 :     _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    2078             : 
    2079           0 :     if (unlikely (status))
    2080           0 :         _cairo_traps_clear (traps);
    2081             : 
    2082           0 :     return status;
    2083             : }
    2084             : 
    2085             : cairo_int_status_t
    2086           0 : _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
    2087             :                                                const cairo_stroke_style_t       *stroke_style,
    2088             :                                                const cairo_matrix_t     *ctm,
    2089             :                                                cairo_boxes_t            *boxes)
    2090             : {
    2091             :     cairo_rectilinear_stroker_t rectilinear_stroker;
    2092             :     cairo_int_status_t status;
    2093             : 
    2094           0 :     assert (path->is_rectilinear);
    2095             : 
    2096           0 :     if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
    2097             :                                            stroke_style, ctm,
    2098             :                                            FALSE, boxes))
    2099             :     {
    2100           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2101             :     }
    2102             : 
    2103           0 :     if (boxes->num_limits) {
    2104           0 :         _cairo_rectilinear_stroker_limit (&rectilinear_stroker,
    2105             :                                           boxes->limits,
    2106             :                                           boxes->num_limits);
    2107             :     }
    2108             : 
    2109           0 :     status = _cairo_path_fixed_interpret (path,
    2110             :                                           CAIRO_DIRECTION_FORWARD,
    2111             :                                           _cairo_rectilinear_stroker_move_to,
    2112           0 :                                           rectilinear_stroker.dash.dashed ?
    2113             :                                           _cairo_rectilinear_stroker_line_to_dashed :
    2114             :                                           _cairo_rectilinear_stroker_line_to,
    2115             :                                           NULL,
    2116             :                                           _cairo_rectilinear_stroker_close_path,
    2117             :                                           &rectilinear_stroker);
    2118           0 :     if (unlikely (status))
    2119           0 :         goto BAIL;
    2120             : 
    2121           0 :     if (rectilinear_stroker.dash.dashed)
    2122           0 :         status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    2123             :     else
    2124           0 :         status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
    2125           0 :     if (unlikely (status))
    2126           0 :         goto BAIL;
    2127             : 
    2128             :     /* As we incrementally tessellate, we do not eliminate self-intersections */
    2129           0 :     status = _cairo_bentley_ottmann_tessellate_boxes (boxes,
    2130             :                                                       CAIRO_FILL_RULE_WINDING,
    2131             :                                                       boxes);
    2132           0 :     if (unlikely (status))
    2133           0 :         goto BAIL;
    2134             : 
    2135           0 :     _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    2136             : 
    2137           0 :     return CAIRO_STATUS_SUCCESS;
    2138             : 
    2139             : BAIL:
    2140           0 :     _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    2141           0 :     _cairo_boxes_clear (boxes);
    2142           0 :     return status;
    2143             : }

Generated by: LCOV version 1.13