Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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-box-inline.h"
  43. #include "cairo-boxes-private.h"
  44. #include "cairo-error-private.h"
  45. #include "cairo-path-fixed-private.h"
  46. #include "cairo-slope-private.h"
  47. #include "cairo-stroke-dash-private.h"
  48. #include "cairo-traps-private.h"
  49.  
  50. typedef struct cairo_stroker {
  51.     cairo_stroke_style_t style;
  52.  
  53.     const cairo_matrix_t *ctm;
  54.     const cairo_matrix_t *ctm_inverse;
  55.     double half_line_width;
  56.     double tolerance;
  57.     double spline_cusp_tolerance;
  58.     double ctm_determinant;
  59.     cairo_bool_t ctm_det_positive;
  60.  
  61.     void *closure;
  62.     cairo_status_t (*add_external_edge) (void *closure,
  63.                                          const cairo_point_t *p1,
  64.                                          const cairo_point_t *p2);
  65.     cairo_status_t (*add_triangle) (void *closure,
  66.                                     const cairo_point_t triangle[3]);
  67.     cairo_status_t (*add_triangle_fan) (void *closure,
  68.                                         const cairo_point_t *midpt,
  69.                                         const cairo_point_t *points,
  70.                                         int npoints);
  71.     cairo_status_t (*add_convex_quad) (void *closure,
  72.                                        const cairo_point_t quad[4]);
  73.  
  74.     cairo_pen_t   pen;
  75.  
  76.     cairo_point_t current_point;
  77.     cairo_point_t first_point;
  78.  
  79.     cairo_bool_t has_initial_sub_path;
  80.  
  81.     cairo_bool_t has_current_face;
  82.     cairo_stroke_face_t current_face;
  83.  
  84.     cairo_bool_t has_first_face;
  85.     cairo_stroke_face_t first_face;
  86.  
  87.     cairo_stroker_dash_t dash;
  88.  
  89.     cairo_bool_t has_bounds;
  90.     cairo_box_t bounds;
  91. } cairo_stroker_t;
  92.  
  93. static void
  94. _cairo_stroker_limit (cairo_stroker_t *stroker,
  95.                       const cairo_path_fixed_t *path,
  96.                       const cairo_box_t *boxes,
  97.                       int num_boxes)
  98. {
  99.     double dx, dy;
  100.     cairo_fixed_t fdx, fdy;
  101.  
  102.     stroker->has_bounds = TRUE;
  103.     _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
  104.  
  105.     /* Extend the bounds in each direction to account for the maximum area
  106.      * we might generate trapezoids, to capture line segments that are outside
  107.      * of the bounds but which might generate rendering that's within bounds.
  108.      */
  109.  
  110.     _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
  111.                                                 stroker->ctm, &dx, &dy);
  112.  
  113.     fdx = _cairo_fixed_from_double (dx);
  114.     fdy = _cairo_fixed_from_double (dy);
  115.  
  116.     stroker->bounds.p1.x -= fdx;
  117.     stroker->bounds.p2.x += fdx;
  118.  
  119.     stroker->bounds.p1.y -= fdy;
  120.     stroker->bounds.p2.y += fdy;
  121. }
  122.  
  123. static cairo_status_t
  124. _cairo_stroker_init (cairo_stroker_t            *stroker,
  125.                      const cairo_path_fixed_t   *path,
  126.                      const cairo_stroke_style_t *stroke_style,
  127.                      const cairo_matrix_t       *ctm,
  128.                      const cairo_matrix_t       *ctm_inverse,
  129.                      double                      tolerance,
  130.                      const cairo_box_t          *limits,
  131.                      int                         num_limits)
  132. {
  133.     cairo_status_t status;
  134.  
  135.     stroker->style = *stroke_style;
  136.     stroker->ctm = ctm;
  137.     stroker->ctm_inverse = ctm_inverse;
  138.     stroker->tolerance = tolerance;
  139.     stroker->half_line_width = stroke_style->line_width / 2.0;
  140.  
  141.     /* To test whether we need to join two segments of a spline using
  142.      * a round-join or a bevel-join, we can inspect the angle between the
  143.      * two segments. If the difference between the chord distance
  144.      * (half-line-width times the cosine of the bisection angle) and the
  145.      * half-line-width itself is greater than tolerance then we need to
  146.      * inject a point.
  147.      */
  148.     stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
  149.     stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
  150.     stroker->spline_cusp_tolerance *= 2;
  151.     stroker->spline_cusp_tolerance -= 1;
  152.  
  153.     stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
  154.     stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
  155.  
  156.     status = _cairo_pen_init (&stroker->pen,
  157.                               stroker->half_line_width, tolerance, ctm);
  158.     if (unlikely (status))
  159.         return status;
  160.  
  161.     stroker->has_current_face = FALSE;
  162.     stroker->has_first_face = FALSE;
  163.     stroker->has_initial_sub_path = FALSE;
  164.  
  165.     _cairo_stroker_dash_init (&stroker->dash, stroke_style);
  166.  
  167.     stroker->add_external_edge = NULL;
  168.  
  169.     stroker->has_bounds = FALSE;
  170.     if (num_limits)
  171.         _cairo_stroker_limit (stroker, path, limits, num_limits);
  172.  
  173.     return CAIRO_STATUS_SUCCESS;
  174. }
  175.  
  176. static void
  177. _cairo_stroker_fini (cairo_stroker_t *stroker)
  178. {
  179.     _cairo_pen_fini (&stroker->pen);
  180. }
  181.  
  182. static void
  183. _translate_point (cairo_point_t *point, const cairo_point_t *offset)
  184. {
  185.     point->x += offset->x;
  186.     point->y += offset->y;
  187. }
  188.  
  189. static int
  190. _cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
  191.                                   const cairo_stroke_face_t *out)
  192. {
  193.     cairo_slope_t in_slope, out_slope;
  194.  
  195.     _cairo_slope_init (&in_slope, &in->point, &in->cw);
  196.     _cairo_slope_init (&out_slope, &out->point, &out->cw);
  197.  
  198.     return _cairo_slope_compare (&in_slope, &out_slope) < 0;
  199. }
  200.  
  201. /**
  202.  * _cairo_slope_compare_sgn:
  203.  *
  204.  * Return -1, 0 or 1 depending on the relative slopes of
  205.  * two lines.
  206.  **/
  207. static int
  208. _cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
  209. {
  210.     double  c = (dx1 * dy2 - dx2 * dy1);
  211.  
  212.     if (c > 0) return 1;
  213.     if (c < 0) return -1;
  214.     return 0;
  215. }
  216.  
  217. static inline int
  218. _range_step (int i, int step, int max)
  219. {
  220.     i += step;
  221.     if (i < 0)
  222.         i = max - 1;
  223.     if (i >= max)
  224.         i = 0;
  225.     return i;
  226. }
  227.  
  228. /*
  229.  * Construct a fan around the midpoint using the vertices from pen between
  230.  * inpt and outpt.
  231.  */
  232. static cairo_status_t
  233. _tessellate_fan (cairo_stroker_t *stroker,
  234.                  const cairo_slope_t *in_vector,
  235.                  const cairo_slope_t *out_vector,
  236.                  const cairo_point_t *midpt,
  237.                  const cairo_point_t *inpt,
  238.                  const cairo_point_t *outpt,
  239.                  cairo_bool_t clockwise)
  240. {
  241.     cairo_point_t stack_points[64], *points = stack_points;
  242.     cairo_pen_t *pen = &stroker->pen;
  243.     int start, stop, num_points = 0;
  244.     cairo_status_t status;
  245.  
  246.     if (stroker->has_bounds &&
  247.         ! _cairo_box_contains_point (&stroker->bounds, midpt))
  248.         goto BEVEL;
  249.  
  250.     assert (stroker->pen.num_vertices);
  251.  
  252.     if (clockwise) {
  253.         _cairo_pen_find_active_ccw_vertices (pen,
  254.                                              in_vector, out_vector,
  255.                                              &start, &stop);
  256.         if (stroker->add_external_edge) {
  257.             cairo_point_t last;
  258.             last = *inpt;
  259.             while (start != stop) {
  260.                 cairo_point_t p = *midpt;
  261.                 _translate_point (&p, &pen->vertices[start].point);
  262.  
  263.                 status = stroker->add_external_edge (stroker->closure,
  264.                                                      &last, &p);
  265.                 if (unlikely (status))
  266.                     return status;
  267.                 last = p;
  268.  
  269.                 if (start-- == 0)
  270.                     start += pen->num_vertices;
  271.             }
  272.             status = stroker->add_external_edge (stroker->closure,
  273.                                                  &last, outpt);
  274.         } else {
  275.             if (start == stop)
  276.                 goto BEVEL;
  277.  
  278.             num_points = stop - start;
  279.             if (num_points < 0)
  280.                 num_points += pen->num_vertices;
  281.             num_points += 2;
  282.             if (num_points > ARRAY_LENGTH(stack_points)) {
  283.                 points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
  284.                 if (unlikely (points == NULL))
  285.                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  286.             }
  287.  
  288.             points[0] = *inpt;
  289.             num_points = 1;
  290.             while (start != stop) {
  291.                 points[num_points] = *midpt;
  292.                 _translate_point (&points[num_points], &pen->vertices[start].point);
  293.                 num_points++;
  294.  
  295.                 if (start-- == 0)
  296.                     start += pen->num_vertices;
  297.             }
  298.             points[num_points++] = *outpt;
  299.         }
  300.     } else {
  301.         _cairo_pen_find_active_cw_vertices (pen,
  302.                                             in_vector, out_vector,
  303.                                             &start, &stop);
  304.         if (stroker->add_external_edge) {
  305.             cairo_point_t last;
  306.             last = *inpt;
  307.             while (start != stop) {
  308.                 cairo_point_t p = *midpt;
  309.                 _translate_point (&p, &pen->vertices[start].point);
  310.  
  311.                 status = stroker->add_external_edge (stroker->closure,
  312.                                                      &p, &last);
  313.                 if (unlikely (status))
  314.                     return status;
  315.                 last = p;
  316.  
  317.                 if (++start == pen->num_vertices)
  318.                     start = 0;
  319.             }
  320.             status = stroker->add_external_edge (stroker->closure,
  321.                                                  outpt, &last);
  322.         } else {
  323.             if (start == stop)
  324.                 goto BEVEL;
  325.  
  326.             num_points = stop - start;
  327.             if (num_points < 0)
  328.                 num_points += pen->num_vertices;
  329.             num_points += 2;
  330.             if (num_points > ARRAY_LENGTH(stack_points)) {
  331.                 points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
  332.                 if (unlikely (points == NULL))
  333.                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  334.             }
  335.  
  336.             points[0] = *inpt;
  337.             num_points = 1;
  338.             while (start != stop) {
  339.                 points[num_points] = *midpt;
  340.                 _translate_point (&points[num_points], &pen->vertices[start].point);
  341.                 num_points++;
  342.  
  343.                 if (++start == pen->num_vertices)
  344.                     start = 0;
  345.             }
  346.             points[num_points++] = *outpt;
  347.         }
  348.     }
  349.  
  350.     if (num_points) {
  351.         status = stroker->add_triangle_fan (stroker->closure,
  352.                                             midpt, points, num_points);
  353.     }
  354.  
  355.     if (points != stack_points)
  356.         free (points);
  357.  
  358.     return status;
  359.  
  360. BEVEL:
  361.     /* Ensure a leak free connection... */
  362.     if (stroker->add_external_edge != NULL) {
  363.         if (clockwise)
  364.             return stroker->add_external_edge (stroker->closure, inpt, outpt);
  365.         else
  366.             return stroker->add_external_edge (stroker->closure, outpt, inpt);
  367.     } else {
  368.         stack_points[0] = *midpt;
  369.         stack_points[1] = *inpt;
  370.         stack_points[2] = *outpt;
  371.         return stroker->add_triangle (stroker->closure, stack_points);
  372.     }
  373. }
  374.  
  375. static cairo_status_t
  376. _cairo_stroker_join (cairo_stroker_t *stroker,
  377.                      const cairo_stroke_face_t *in,
  378.                      const cairo_stroke_face_t *out)
  379. {
  380.     int  clockwise = _cairo_stroker_join_is_clockwise (out, in);
  381.     const cairo_point_t *inpt, *outpt;
  382.     cairo_point_t points[4];
  383.     cairo_status_t status;
  384.  
  385.     if (in->cw.x  == out->cw.x  && in->cw.y  == out->cw.y &&
  386.         in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
  387.     {
  388.         return CAIRO_STATUS_SUCCESS;
  389.     }
  390.  
  391.     if (clockwise) {
  392.         if (stroker->add_external_edge != NULL) {
  393.             status = stroker->add_external_edge (stroker->closure,
  394.                                                  &out->cw, &in->point);
  395.             if (unlikely (status))
  396.                 return status;
  397.  
  398.             status = stroker->add_external_edge (stroker->closure,
  399.                                                  &in->point, &in->cw);
  400.             if (unlikely (status))
  401.                 return status;
  402.         }
  403.  
  404.         inpt = &in->ccw;
  405.         outpt = &out->ccw;
  406.     } else {
  407.         if (stroker->add_external_edge != NULL) {
  408.             status = stroker->add_external_edge (stroker->closure,
  409.                                                  &in->ccw, &in->point);
  410.             if (unlikely (status))
  411.                 return status;
  412.  
  413.             status = stroker->add_external_edge (stroker->closure,
  414.                                                  &in->point, &out->ccw);
  415.             if (unlikely (status))
  416.                 return status;
  417.         }
  418.  
  419.         inpt = &in->cw;
  420.         outpt = &out->cw;
  421.     }
  422.  
  423.     switch (stroker->style.line_join) {
  424.     case CAIRO_LINE_JOIN_ROUND:
  425.         /* construct a fan around the common midpoint */
  426.         return _tessellate_fan (stroker,
  427.                                 &in->dev_vector,
  428.                                 &out->dev_vector,
  429.                                 &in->point, inpt, outpt,
  430.                                 clockwise);
  431.  
  432.     case CAIRO_LINE_JOIN_MITER:
  433.     default: {
  434.         /* dot product of incoming slope vector with outgoing slope vector */
  435.         double  in_dot_out = -in->usr_vector.x * out->usr_vector.x +
  436.                              -in->usr_vector.y * out->usr_vector.y;
  437.         double  ml = stroker->style.miter_limit;
  438.  
  439.         /* Check the miter limit -- lines meeting at an acute angle
  440.          * can generate long miters, the limit converts them to bevel
  441.          *
  442.          * Consider the miter join formed when two line segments
  443.          * meet at an angle psi:
  444.          *
  445.          *         /.\
  446.          *        /. .\
  447.          *       /./ \.\
  448.          *      /./psi\.\
  449.          *
  450.          * We can zoom in on the right half of that to see:
  451.          *
  452.          *          |\
  453.          *          | \ psi/2
  454.          *          |  \
  455.          *          |   \
  456.          *          |    \
  457.          *          |     \
  458.          *        miter    \
  459.          *       length     \
  460.          *          |        \
  461.          *          |        .\
  462.          *          |    .     \
  463.          *          |.   line   \
  464.          *           \    width  \
  465.          *            \           \
  466.          *
  467.          *
  468.          * The right triangle in that figure, (the line-width side is
  469.          * shown faintly with three '.' characters), gives us the
  470.          * following expression relating miter length, angle and line
  471.          * width:
  472.          *
  473.          *      1 /sin (psi/2) = miter_length / line_width
  474.          *
  475.          * The right-hand side of this relationship is the same ratio
  476.          * in which the miter limit (ml) is expressed. We want to know
  477.          * when the miter length is within the miter limit. That is
  478.          * when the following condition holds:
  479.          *
  480.          *      1/sin(psi/2) <= ml
  481.          *      1 <= ml sin(psi/2)
  482.          *      1 <= ml² sin²(psi/2)
  483.          *      2 <= ml² 2 sin²(psi/2)
  484.          *                              2·sin²(psi/2) = 1-cos(psi)
  485.          *      2 <= ml² (1-cos(psi))
  486.          *
  487.          *                              in · out = |in| |out| cos (psi)
  488.          *
  489.          * in and out are both unit vectors, so:
  490.          *
  491.          *                              in · out = cos (psi)
  492.          *
  493.          *      2 <= ml² (1 - in · out)
  494.          *
  495.          */
  496.         if (2 <= ml * ml * (1 - in_dot_out)) {
  497.             double              x1, y1, x2, y2;
  498.             double              mx, my;
  499.             double              dx1, dx2, dy1, dy2;
  500.             double              ix, iy;
  501.             double              fdx1, fdy1, fdx2, fdy2;
  502.             double              mdx, mdy;
  503.  
  504.             /*
  505.              * we've got the points already transformed to device
  506.              * space, but need to do some computation with them and
  507.              * also need to transform the slope from user space to
  508.              * device space
  509.              */
  510.             /* outer point of incoming line face */
  511.             x1 = _cairo_fixed_to_double (inpt->x);
  512.             y1 = _cairo_fixed_to_double (inpt->y);
  513.             dx1 = in->usr_vector.x;
  514.             dy1 = in->usr_vector.y;
  515.             cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
  516.  
  517.             /* outer point of outgoing line face */
  518.             x2 = _cairo_fixed_to_double (outpt->x);
  519.             y2 = _cairo_fixed_to_double (outpt->y);
  520.             dx2 = out->usr_vector.x;
  521.             dy2 = out->usr_vector.y;
  522.             cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
  523.  
  524.             /*
  525.              * Compute the location of the outer corner of the miter.
  526.              * That's pretty easy -- just the intersection of the two
  527.              * outer edges.  We've got slopes and points on each
  528.              * of those edges.  Compute my directly, then compute
  529.              * mx by using the edge with the larger dy; that avoids
  530.              * dividing by values close to zero.
  531.              */
  532.             my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
  533.                   (dx1 * dy2 - dx2 * dy1));
  534.             if (fabs (dy1) >= fabs (dy2))
  535.                 mx = (my - y1) * dx1 / dy1 + x1;
  536.             else
  537.                 mx = (my - y2) * dx2 / dy2 + x2;
  538.  
  539.             /*
  540.              * When the two outer edges are nearly parallel, slight
  541.              * perturbations in the position of the outer points of the lines
  542.              * caused by representing them in fixed point form can cause the
  543.              * intersection point of the miter to move a large amount. If
  544.              * that moves the miter intersection from between the two faces,
  545.              * then draw a bevel instead.
  546.              */
  547.  
  548.             ix = _cairo_fixed_to_double (in->point.x);
  549.             iy = _cairo_fixed_to_double (in->point.y);
  550.  
  551.             /* slope of one face */
  552.             fdx1 = x1 - ix; fdy1 = y1 - iy;
  553.  
  554.             /* slope of the other face */
  555.             fdx2 = x2 - ix; fdy2 = y2 - iy;
  556.  
  557.             /* slope from the intersection to the miter point */
  558.             mdx = mx - ix; mdy = my - iy;
  559.  
  560.             /*
  561.              * Make sure the miter point line lies between the two
  562.              * faces by comparing the slopes
  563.              */
  564.             if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
  565.                 _cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
  566.             {
  567.                 if (stroker->add_external_edge != NULL) {
  568.                     points[0].x = _cairo_fixed_from_double (mx);
  569.                     points[0].y = _cairo_fixed_from_double (my);
  570.  
  571.                     if (clockwise) {
  572.                         status = stroker->add_external_edge (stroker->closure,
  573.                                                              inpt, &points[0]);
  574.                         if (unlikely (status))
  575.                             return status;
  576.  
  577.                         status = stroker->add_external_edge (stroker->closure,
  578.                                                              &points[0], outpt);
  579.                         if (unlikely (status))
  580.                             return status;
  581.                     } else {
  582.                         status = stroker->add_external_edge (stroker->closure,
  583.                                                              outpt, &points[0]);
  584.                         if (unlikely (status))
  585.                             return status;
  586.  
  587.                         status = stroker->add_external_edge (stroker->closure,
  588.                                                              &points[0], inpt);
  589.                         if (unlikely (status))
  590.                             return status;
  591.                     }
  592.  
  593.                     return CAIRO_STATUS_SUCCESS;
  594.                 } else {
  595.                     points[0] = in->point;
  596.                     points[1] = *inpt;
  597.                     points[2].x = _cairo_fixed_from_double (mx);
  598.                     points[2].y = _cairo_fixed_from_double (my);
  599.                     points[3] = *outpt;
  600.  
  601.                     return stroker->add_convex_quad (stroker->closure, points);
  602.                 }
  603.             }
  604.         }
  605.     }
  606.  
  607.     /* fall through ... */
  608.  
  609.     case CAIRO_LINE_JOIN_BEVEL:
  610.         if (stroker->add_external_edge != NULL) {
  611.             if (clockwise) {
  612.                 return stroker->add_external_edge (stroker->closure,
  613.                                                    inpt, outpt);
  614.             } else {
  615.                 return stroker->add_external_edge (stroker->closure,
  616.                                                    outpt, inpt);
  617.             }
  618.         } else {
  619.             points[0] = in->point;
  620.             points[1] = *inpt;
  621.             points[2] = *outpt;
  622.  
  623.             return stroker->add_triangle (stroker->closure, points);
  624.         }
  625.     }
  626. }
  627.  
  628. static cairo_status_t
  629. _cairo_stroker_add_cap (cairo_stroker_t *stroker,
  630.                         const cairo_stroke_face_t *f)
  631. {
  632.     switch (stroker->style.line_cap) {
  633.     case CAIRO_LINE_CAP_ROUND: {
  634.         cairo_slope_t slope;
  635.  
  636.         slope.dx = -f->dev_vector.dx;
  637.         slope.dy = -f->dev_vector.dy;
  638.  
  639.         return _tessellate_fan (stroker,
  640.                                 &f->dev_vector,
  641.                                 &slope,
  642.                                 &f->point, &f->cw, &f->ccw,
  643.                                 FALSE);
  644.  
  645.     }
  646.  
  647.     case CAIRO_LINE_CAP_SQUARE: {
  648.         double dx, dy;
  649.         cairo_slope_t   fvector;
  650.         cairo_point_t   quad[4];
  651.  
  652.         dx = f->usr_vector.x;
  653.         dy = f->usr_vector.y;
  654.         dx *= stroker->half_line_width;
  655.         dy *= stroker->half_line_width;
  656.         cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
  657.         fvector.dx = _cairo_fixed_from_double (dx);
  658.         fvector.dy = _cairo_fixed_from_double (dy);
  659.  
  660.         quad[0] = f->ccw;
  661.         quad[1].x = f->ccw.x + fvector.dx;
  662.         quad[1].y = f->ccw.y + fvector.dy;
  663.         quad[2].x = f->cw.x + fvector.dx;
  664.         quad[2].y = f->cw.y + fvector.dy;
  665.         quad[3] = f->cw;
  666.  
  667.         if (stroker->add_external_edge != NULL) {
  668.             cairo_status_t status;
  669.  
  670.             status = stroker->add_external_edge (stroker->closure,
  671.                                                  &quad[0], &quad[1]);
  672.             if (unlikely (status))
  673.                 return status;
  674.  
  675.             status = stroker->add_external_edge (stroker->closure,
  676.                                                  &quad[1], &quad[2]);
  677.             if (unlikely (status))
  678.                 return status;
  679.  
  680.             status = stroker->add_external_edge (stroker->closure,
  681.                                                  &quad[2], &quad[3]);
  682.             if (unlikely (status))
  683.                 return status;
  684.  
  685.             return CAIRO_STATUS_SUCCESS;
  686.         } else {
  687.             return stroker->add_convex_quad (stroker->closure, quad);
  688.         }
  689.     }
  690.  
  691.     case CAIRO_LINE_CAP_BUTT:
  692.     default:
  693.         if (stroker->add_external_edge != NULL) {
  694.             return stroker->add_external_edge (stroker->closure,
  695.                                                &f->ccw, &f->cw);
  696.         } else {
  697.             return CAIRO_STATUS_SUCCESS;
  698.         }
  699.     }
  700. }
  701.  
  702. static cairo_status_t
  703. _cairo_stroker_add_leading_cap (cairo_stroker_t     *stroker,
  704.                                 const cairo_stroke_face_t *face)
  705. {
  706.     cairo_stroke_face_t reversed;
  707.     cairo_point_t t;
  708.  
  709.     reversed = *face;
  710.  
  711.     /* The initial cap needs an outward facing vector. Reverse everything */
  712.     reversed.usr_vector.x = -reversed.usr_vector.x;
  713.     reversed.usr_vector.y = -reversed.usr_vector.y;
  714.     reversed.dev_vector.dx = -reversed.dev_vector.dx;
  715.     reversed.dev_vector.dy = -reversed.dev_vector.dy;
  716.     t = reversed.cw;
  717.     reversed.cw = reversed.ccw;
  718.     reversed.ccw = t;
  719.  
  720.     return _cairo_stroker_add_cap (stroker, &reversed);
  721. }
  722.  
  723. static cairo_status_t
  724. _cairo_stroker_add_trailing_cap (cairo_stroker_t     *stroker,
  725.                                  const cairo_stroke_face_t *face)
  726. {
  727.     return _cairo_stroker_add_cap (stroker, face);
  728. }
  729.  
  730. static inline cairo_bool_t
  731. _compute_normalized_device_slope (double *dx, double *dy,
  732.                                   const cairo_matrix_t *ctm_inverse,
  733.                                   double *mag_out)
  734. {
  735.     double dx0 = *dx, dy0 = *dy;
  736.     double mag;
  737.  
  738.     cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
  739.  
  740.     if (dx0 == 0.0 && dy0 == 0.0) {
  741.         if (mag_out)
  742.             *mag_out = 0.0;
  743.         return FALSE;
  744.     }
  745.  
  746.     if (dx0 == 0.0) {
  747.         *dx = 0.0;
  748.         if (dy0 > 0.0) {
  749.             mag = dy0;
  750.             *dy = 1.0;
  751.         } else {
  752.             mag = -dy0;
  753.             *dy = -1.0;
  754.         }
  755.     } else if (dy0 == 0.0) {
  756.         *dy = 0.0;
  757.         if (dx0 > 0.0) {
  758.             mag = dx0;
  759.             *dx = 1.0;
  760.         } else {
  761.             mag = -dx0;
  762.             *dx = -1.0;
  763.         }
  764.     } else {
  765.         mag = hypot (dx0, dy0);
  766.         *dx = dx0 / mag;
  767.         *dy = dy0 / mag;
  768.     }
  769.  
  770.     if (mag_out)
  771.         *mag_out = mag;
  772.  
  773.     return TRUE;
  774. }
  775.  
  776. static void
  777. _compute_face (const cairo_point_t *point,
  778.                const cairo_slope_t *dev_slope,
  779.                double slope_dx,
  780.                double slope_dy,
  781.                cairo_stroker_t *stroker,
  782.                cairo_stroke_face_t *face)
  783. {
  784.     double face_dx, face_dy;
  785.     cairo_point_t offset_ccw, offset_cw;
  786.  
  787.     /*
  788.      * rotate to get a line_width/2 vector along the face, note that
  789.      * the vector must be rotated the right direction in device space,
  790.      * but by 90° in user space. So, the rotation depends on
  791.      * whether the ctm reflects or not, and that can be determined
  792.      * by looking at the determinant of the matrix.
  793.      */
  794.     if (stroker->ctm_det_positive)
  795.     {
  796.         face_dx = - slope_dy * stroker->half_line_width;
  797.         face_dy = slope_dx * stroker->half_line_width;
  798.     }
  799.     else
  800.     {
  801.         face_dx = slope_dy * stroker->half_line_width;
  802.         face_dy = - slope_dx * stroker->half_line_width;
  803.     }
  804.  
  805.     /* back to device space */
  806.     cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
  807.  
  808.     offset_ccw.x = _cairo_fixed_from_double (face_dx);
  809.     offset_ccw.y = _cairo_fixed_from_double (face_dy);
  810.     offset_cw.x = -offset_ccw.x;
  811.     offset_cw.y = -offset_ccw.y;
  812.  
  813.     face->ccw = *point;
  814.     _translate_point (&face->ccw, &offset_ccw);
  815.  
  816.     face->point = *point;
  817.  
  818.     face->cw = *point;
  819.     _translate_point (&face->cw, &offset_cw);
  820.  
  821.     face->usr_vector.x = slope_dx;
  822.     face->usr_vector.y = slope_dy;
  823.  
  824.     face->dev_vector = *dev_slope;
  825. }
  826.  
  827. static cairo_status_t
  828. _cairo_stroker_add_caps (cairo_stroker_t *stroker)
  829. {
  830.     cairo_status_t status;
  831.  
  832.     /* check for a degenerative sub_path */
  833.     if (stroker->has_initial_sub_path
  834.         && ! stroker->has_first_face
  835.         && ! stroker->has_current_face
  836.         && stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
  837.     {
  838.         /* pick an arbitrary slope to use */
  839.         double dx = 1.0, dy = 0.0;
  840.         cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
  841.         cairo_stroke_face_t face;
  842.  
  843.         _compute_normalized_device_slope (&dx, &dy,
  844.                                           stroker->ctm_inverse, NULL);
  845.  
  846.         /* arbitrarily choose first_point
  847.          * first_point and current_point should be the same */
  848.         _compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
  849.  
  850.         status = _cairo_stroker_add_leading_cap (stroker, &face);
  851.         if (unlikely (status))
  852.             return status;
  853.  
  854.         status = _cairo_stroker_add_trailing_cap (stroker, &face);
  855.         if (unlikely (status))
  856.             return status;
  857.     }
  858.  
  859.     if (stroker->has_first_face) {
  860.         status = _cairo_stroker_add_leading_cap (stroker,
  861.                                                  &stroker->first_face);
  862.         if (unlikely (status))
  863.             return status;
  864.     }
  865.  
  866.     if (stroker->has_current_face) {
  867.         status = _cairo_stroker_add_trailing_cap (stroker,
  868.                                                   &stroker->current_face);
  869.         if (unlikely (status))
  870.             return status;
  871.     }
  872.  
  873.     return CAIRO_STATUS_SUCCESS;
  874. }
  875.  
  876. static cairo_status_t
  877. _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
  878.                              const cairo_point_t *p1,
  879.                              const cairo_point_t *p2,
  880.                              cairo_slope_t *dev_slope,
  881.                              double slope_dx, double slope_dy,
  882.                              cairo_stroke_face_t *start,
  883.                              cairo_stroke_face_t *end)
  884. {
  885.     _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
  886.     *end = *start;
  887.  
  888.     if (p1->x == p2->x && p1->y == p2->y)
  889.         return CAIRO_STATUS_SUCCESS;
  890.  
  891.     end->point = *p2;
  892.     end->ccw.x += p2->x - p1->x;
  893.     end->ccw.y += p2->y - p1->y;
  894.     end->cw.x += p2->x - p1->x;
  895.     end->cw.y += p2->y - p1->y;
  896.  
  897.     if (stroker->add_external_edge != NULL) {
  898.         cairo_status_t status;
  899.  
  900.         status = stroker->add_external_edge (stroker->closure,
  901.                                              &end->cw, &start->cw);
  902.         if (unlikely (status))
  903.             return status;
  904.  
  905.         status = stroker->add_external_edge (stroker->closure,
  906.                                              &start->ccw, &end->ccw);
  907.         if (unlikely (status))
  908.             return status;
  909.  
  910.         return CAIRO_STATUS_SUCCESS;
  911.     } else {
  912.         cairo_point_t quad[4];
  913.  
  914.         quad[0] = start->cw;
  915.         quad[1] = end->cw;
  916.         quad[2] = end->ccw;
  917.         quad[3] = start->ccw;
  918.  
  919.         return stroker->add_convex_quad (stroker->closure, quad);
  920.     }
  921. }
  922.  
  923. static cairo_status_t
  924. _cairo_stroker_move_to (void *closure,
  925.                         const cairo_point_t *point)
  926. {
  927.     cairo_stroker_t *stroker = closure;
  928.     cairo_status_t status;
  929.  
  930.     /* reset the dash pattern for new sub paths */
  931.     _cairo_stroker_dash_start (&stroker->dash);
  932.  
  933.     /* Cap the start and end of the previous sub path as needed */
  934.     status = _cairo_stroker_add_caps (stroker);
  935.     if (unlikely (status))
  936.         return status;
  937.  
  938.     stroker->first_point = *point;
  939.     stroker->current_point = *point;
  940.  
  941.     stroker->has_first_face = FALSE;
  942.     stroker->has_current_face = FALSE;
  943.     stroker->has_initial_sub_path = FALSE;
  944.  
  945.     return CAIRO_STATUS_SUCCESS;
  946. }
  947.  
  948. static cairo_status_t
  949. _cairo_stroker_line_to (void *closure,
  950.                         const cairo_point_t *point)
  951. {
  952.     cairo_stroker_t *stroker = closure;
  953.     cairo_stroke_face_t start, end;
  954.     cairo_point_t *p1 = &stroker->current_point;
  955.     cairo_slope_t dev_slope;
  956.     double slope_dx, slope_dy;
  957.     cairo_status_t status;
  958.  
  959.     stroker->has_initial_sub_path = TRUE;
  960.  
  961.     if (p1->x == point->x && p1->y == point->y)
  962.         return CAIRO_STATUS_SUCCESS;
  963.  
  964.     _cairo_slope_init (&dev_slope, p1, point);
  965.     slope_dx = _cairo_fixed_to_double (point->x - p1->x);
  966.     slope_dy = _cairo_fixed_to_double (point->y - p1->y);
  967.     _compute_normalized_device_slope (&slope_dx, &slope_dy,
  968.                                       stroker->ctm_inverse, NULL);
  969.  
  970.     status = _cairo_stroker_add_sub_edge (stroker,
  971.                                           p1, point,
  972.                                           &dev_slope,
  973.                                           slope_dx, slope_dy,
  974.                                           &start, &end);
  975.     if (unlikely (status))
  976.         return status;
  977.  
  978.     if (stroker->has_current_face) {
  979.         /* Join with final face from previous segment */
  980.         status = _cairo_stroker_join (stroker,
  981.                                       &stroker->current_face,
  982.                                       &start);
  983.         if (unlikely (status))
  984.             return status;
  985.     } else if (! stroker->has_first_face) {
  986.         /* Save sub path's first face in case needed for closing join */
  987.         stroker->first_face = start;
  988.         stroker->has_first_face = TRUE;
  989.     }
  990.     stroker->current_face = end;
  991.     stroker->has_current_face = TRUE;
  992.  
  993.     stroker->current_point = *point;
  994.  
  995.     return CAIRO_STATUS_SUCCESS;
  996. }
  997.  
  998. static cairo_status_t
  999. _cairo_stroker_spline_to (void *closure,
  1000.                           const cairo_point_t *point,
  1001.                           const cairo_slope_t *tangent)
  1002. {
  1003.     cairo_stroker_t *stroker = closure;
  1004.     cairo_stroke_face_t new_face;
  1005.     double slope_dx, slope_dy;
  1006.     cairo_point_t points[3];
  1007.     cairo_point_t intersect_point;
  1008.  
  1009.     stroker->has_initial_sub_path = TRUE;
  1010.  
  1011.     if (stroker->current_point.x == point->x &&
  1012.         stroker->current_point.y == point->y)
  1013.         return CAIRO_STATUS_SUCCESS;
  1014.  
  1015.     slope_dx = _cairo_fixed_to_double (tangent->dx);
  1016.     slope_dy = _cairo_fixed_to_double (tangent->dy);
  1017.  
  1018.     if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
  1019.                                             stroker->ctm_inverse, NULL))
  1020.         return CAIRO_STATUS_SUCCESS;
  1021.  
  1022.     _compute_face (point, tangent,
  1023.                    slope_dx, slope_dy,
  1024.                    stroker, &new_face);
  1025.  
  1026.     assert (stroker->has_current_face);
  1027.  
  1028.     if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x +
  1029.          new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) {
  1030.  
  1031.         const cairo_point_t *inpt, *outpt;
  1032.         int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
  1033.                                                           &stroker->current_face);
  1034.  
  1035.         if (clockwise) {
  1036.             inpt = &stroker->current_face.cw;
  1037.             outpt = &new_face.cw;
  1038.         } else {
  1039.             inpt = &stroker->current_face.ccw;
  1040.             outpt = &new_face.ccw;
  1041.         }
  1042.  
  1043.         _tessellate_fan (stroker,
  1044.                          &stroker->current_face.dev_vector,
  1045.                          &new_face.dev_vector,
  1046.                          &stroker->current_face.point,
  1047.                          inpt, outpt,
  1048.                          clockwise);
  1049.     }
  1050.  
  1051.     if (_slow_segment_intersection (&stroker->current_face.cw,
  1052.                                     &stroker->current_face.ccw,
  1053.                                     &new_face.cw,
  1054.                                     &new_face.ccw,
  1055.                                     &intersect_point)) {
  1056.         points[0] = stroker->current_face.ccw;
  1057.         points[1] = new_face.ccw;
  1058.         points[2] = intersect_point;
  1059.         stroker->add_triangle (stroker->closure, points);
  1060.  
  1061.         points[0] = stroker->current_face.cw;
  1062.         points[1] = new_face.cw;
  1063.         stroker->add_triangle (stroker->closure, points);
  1064.     } else {
  1065.         points[0] = stroker->current_face.ccw;
  1066.         points[1] = stroker->current_face.cw;
  1067.         points[2] = new_face.cw;
  1068.         stroker->add_triangle (stroker->closure, points);
  1069.  
  1070.         points[0] = stroker->current_face.ccw;
  1071.         points[1] = new_face.cw;
  1072.         points[2] = new_face.ccw;
  1073.         stroker->add_triangle (stroker->closure, points);
  1074.     }
  1075.  
  1076.     stroker->current_face = new_face;
  1077.     stroker->has_current_face = TRUE;
  1078.     stroker->current_point = *point;
  1079.  
  1080.     return CAIRO_STATUS_SUCCESS;
  1081. }
  1082.  
  1083. /*
  1084.  * Dashed lines.  Cap each dash end, join around turns when on
  1085.  */
  1086. static cairo_status_t
  1087. _cairo_stroker_line_to_dashed (void *closure,
  1088.                                const cairo_point_t *p2)
  1089. {
  1090.     cairo_stroker_t *stroker = closure;
  1091.     double mag, remain, step_length = 0;
  1092.     double slope_dx, slope_dy;
  1093.     double dx2, dy2;
  1094.     cairo_stroke_face_t sub_start, sub_end;
  1095.     cairo_point_t *p1 = &stroker->current_point;
  1096.     cairo_slope_t dev_slope;
  1097.     cairo_line_t segment;
  1098.     cairo_bool_t fully_in_bounds;
  1099.     cairo_status_t status;
  1100.  
  1101.     stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
  1102.  
  1103.     if (p1->x == p2->x && p1->y == p2->y)
  1104.         return CAIRO_STATUS_SUCCESS;
  1105.  
  1106.     fully_in_bounds = TRUE;
  1107.     if (stroker->has_bounds &&
  1108.         (! _cairo_box_contains_point (&stroker->bounds, p1) ||
  1109.          ! _cairo_box_contains_point (&stroker->bounds, p2)))
  1110.     {
  1111.         fully_in_bounds = FALSE;
  1112.     }
  1113.  
  1114.     _cairo_slope_init (&dev_slope, p1, p2);
  1115.  
  1116.     slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
  1117.     slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
  1118.  
  1119.     if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
  1120.                                             stroker->ctm_inverse, &mag))
  1121.     {
  1122.         return CAIRO_STATUS_SUCCESS;
  1123.     }
  1124.  
  1125.     remain = mag;
  1126.     segment.p1 = *p1;
  1127.     while (remain) {
  1128.         step_length = MIN (stroker->dash.dash_remain, remain);
  1129.         remain -= step_length;
  1130.         dx2 = slope_dx * (mag - remain);
  1131.         dy2 = slope_dy * (mag - remain);
  1132.         cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
  1133.         segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
  1134.         segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
  1135.  
  1136.         if (stroker->dash.dash_on &&
  1137.             (fully_in_bounds ||
  1138.              (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
  1139.              _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
  1140.         {
  1141.             status = _cairo_stroker_add_sub_edge (stroker,
  1142.                                                   &segment.p1, &segment.p2,
  1143.                                                   &dev_slope,
  1144.                                                   slope_dx, slope_dy,
  1145.                                                   &sub_start, &sub_end);
  1146.             if (unlikely (status))
  1147.                 return status;
  1148.  
  1149.             if (stroker->has_current_face)
  1150.             {
  1151.                 /* Join with final face from previous segment */
  1152.                 status = _cairo_stroker_join (stroker,
  1153.                                               &stroker->current_face,
  1154.                                               &sub_start);
  1155.                 if (unlikely (status))
  1156.                     return status;
  1157.  
  1158.                 stroker->has_current_face = FALSE;
  1159.             }
  1160.             else if (! stroker->has_first_face &&
  1161.                        stroker->dash.dash_starts_on)
  1162.             {
  1163.                 /* Save sub path's first face in case needed for closing join */
  1164.                 stroker->first_face = sub_start;
  1165.                 stroker->has_first_face = TRUE;
  1166.             }
  1167.             else
  1168.             {
  1169.                 /* Cap dash start if not connecting to a previous segment */
  1170.                 status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
  1171.                 if (unlikely (status))
  1172.                     return status;
  1173.             }
  1174.  
  1175.             if (remain) {
  1176.                 /* Cap dash end if not at end of segment */
  1177.                 status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
  1178.                 if (unlikely (status))
  1179.                     return status;
  1180.             } else {
  1181.                 stroker->current_face = sub_end;
  1182.                 stroker->has_current_face = TRUE;
  1183.             }
  1184.         } else {
  1185.             if (stroker->has_current_face) {
  1186.                 /* Cap final face from previous segment */
  1187.                 status = _cairo_stroker_add_trailing_cap (stroker,
  1188.                                                           &stroker->current_face);
  1189.                 if (unlikely (status))
  1190.                     return status;
  1191.  
  1192.                 stroker->has_current_face = FALSE;
  1193.             }
  1194.         }
  1195.  
  1196.         _cairo_stroker_dash_step (&stroker->dash, step_length);
  1197.         segment.p1 = segment.p2;
  1198.     }
  1199.  
  1200.     if (stroker->dash.dash_on && ! stroker->has_current_face) {
  1201.         /* This segment ends on a transition to dash_on, compute a new face
  1202.          * and add cap for the beginning of the next dash_on step.
  1203.          *
  1204.          * Note: this will create a degenerate cap if this is not the last line
  1205.          * in the path. Whether this behaviour is desirable or not is debatable.
  1206.          * On one side these degenerate caps can not be reproduced with regular
  1207.          * path stroking.
  1208.          * On the other hand, Acroread 7 also produces the degenerate caps.
  1209.          */
  1210.         _compute_face (p2, &dev_slope,
  1211.                        slope_dx, slope_dy,
  1212.                        stroker,
  1213.                        &stroker->current_face);
  1214.  
  1215.         status = _cairo_stroker_add_leading_cap (stroker,
  1216.                                                  &stroker->current_face);
  1217.         if (unlikely (status))
  1218.             return status;
  1219.  
  1220.         stroker->has_current_face = TRUE;
  1221.     }
  1222.  
  1223.     stroker->current_point = *p2;
  1224.  
  1225.     return CAIRO_STATUS_SUCCESS;
  1226. }
  1227.  
  1228. static cairo_status_t
  1229. _cairo_stroker_curve_to (void *closure,
  1230.                          const cairo_point_t *b,
  1231.                          const cairo_point_t *c,
  1232.                          const cairo_point_t *d)
  1233. {
  1234.     cairo_stroker_t *stroker = closure;
  1235.     cairo_spline_t spline;
  1236.     cairo_line_join_t line_join_save;
  1237.     cairo_stroke_face_t face;
  1238.     double slope_dx, slope_dy;
  1239.     cairo_spline_add_point_func_t line_to;
  1240.     cairo_spline_add_point_func_t spline_to;
  1241.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  1242.  
  1243.     line_to = stroker->dash.dashed ?
  1244.         (cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
  1245.         (cairo_spline_add_point_func_t) _cairo_stroker_line_to;
  1246.  
  1247.     /* spline_to is only capable of rendering non-degenerate splines. */
  1248.     spline_to = stroker->dash.dashed ?
  1249.         (cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
  1250.         (cairo_spline_add_point_func_t) _cairo_stroker_spline_to;
  1251.  
  1252.     if (! _cairo_spline_init (&spline,
  1253.                               spline_to,
  1254.                               stroker,
  1255.                               &stroker->current_point, b, c, d))
  1256.     {
  1257.         cairo_slope_t fallback_slope;
  1258.         _cairo_slope_init (&fallback_slope, &stroker->current_point, d);
  1259.         return line_to (closure, d, &fallback_slope);
  1260.     }
  1261.  
  1262.     /* If the line width is so small that the pen is reduced to a
  1263.        single point, then we have nothing to do. */
  1264.     if (stroker->pen.num_vertices <= 1)
  1265.         return CAIRO_STATUS_SUCCESS;
  1266.  
  1267.     /* Compute the initial face */
  1268.     if (! stroker->dash.dashed || stroker->dash.dash_on) {
  1269.         slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
  1270.         slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
  1271.         if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
  1272.                                               stroker->ctm_inverse, NULL))
  1273.         {
  1274.             _compute_face (&stroker->current_point,
  1275.                            &spline.initial_slope,
  1276.                            slope_dx, slope_dy,
  1277.                            stroker, &face);
  1278.         }
  1279.         if (stroker->has_current_face) {
  1280.             status = _cairo_stroker_join (stroker,
  1281.                                           &stroker->current_face, &face);
  1282.             if (unlikely (status))
  1283.                 return status;
  1284.         } else if (! stroker->has_first_face) {
  1285.             stroker->first_face = face;
  1286.             stroker->has_first_face = TRUE;
  1287.         }
  1288.  
  1289.         stroker->current_face = face;
  1290.         stroker->has_current_face = TRUE;
  1291.     }
  1292.  
  1293.     /* Temporarily modify the stroker to use round joins to guarantee
  1294.      * smooth stroked curves. */
  1295.     line_join_save = stroker->style.line_join;
  1296.     stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
  1297.  
  1298.     status = _cairo_spline_decompose (&spline, stroker->tolerance);
  1299.     if (unlikely (status))
  1300.         return status;
  1301.  
  1302.     /* And join the final face */
  1303.     if (! stroker->dash.dashed || stroker->dash.dash_on) {
  1304.         slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
  1305.         slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
  1306.         if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
  1307.                                               stroker->ctm_inverse, NULL))
  1308.         {
  1309.             _compute_face (&stroker->current_point,
  1310.                            &spline.final_slope,
  1311.                            slope_dx, slope_dy,
  1312.                            stroker, &face);
  1313.         }
  1314.  
  1315.         status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
  1316.         if (unlikely (status))
  1317.             return status;
  1318.  
  1319.         stroker->current_face = face;
  1320.     }
  1321.  
  1322.     stroker->style.line_join = line_join_save;
  1323.  
  1324.     return CAIRO_STATUS_SUCCESS;
  1325. }
  1326.  
  1327. static cairo_status_t
  1328. _cairo_stroker_close_path (void *closure)
  1329. {
  1330.     cairo_stroker_t *stroker = closure;
  1331.     cairo_status_t status;
  1332.  
  1333.     if (stroker->dash.dashed)
  1334.         status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
  1335.     else
  1336.         status = _cairo_stroker_line_to (stroker, &stroker->first_point);
  1337.     if (unlikely (status))
  1338.         return status;
  1339.  
  1340.     if (stroker->has_first_face && stroker->has_current_face) {
  1341.         /* Join first and final faces of sub path */
  1342.         status = _cairo_stroker_join (stroker,
  1343.                                       &stroker->current_face,
  1344.                                       &stroker->first_face);
  1345.         if (unlikely (status))
  1346.             return status;
  1347.     } else {
  1348.         /* Cap the start and end of the sub path as needed */
  1349.         status = _cairo_stroker_add_caps (stroker);
  1350.         if (unlikely (status))
  1351.             return status;
  1352.     }
  1353.  
  1354.     stroker->has_initial_sub_path = FALSE;
  1355.     stroker->has_first_face = FALSE;
  1356.     stroker->has_current_face = FALSE;
  1357.  
  1358.     return CAIRO_STATUS_SUCCESS;
  1359. }
  1360.  
  1361. cairo_status_t
  1362. _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t  *path,
  1363.                                     const cairo_stroke_style_t  *stroke_style,
  1364.                                     const cairo_matrix_t        *ctm,
  1365.                                     const cairo_matrix_t        *ctm_inverse,
  1366.                                     double               tolerance,
  1367.                                     cairo_status_t (*add_triangle) (void *closure,
  1368.                                                                     const cairo_point_t triangle[3]),
  1369.                                     cairo_status_t (*add_triangle_fan) (void *closure,
  1370.                                                                         const cairo_point_t *midpt,
  1371.                                                                         const cairo_point_t *points,
  1372.                                                                         int npoints),
  1373.                                     cairo_status_t (*add_convex_quad) (void *closure,
  1374.                                                                        const cairo_point_t quad[4]),
  1375.                                     void *closure)
  1376. {
  1377.     cairo_stroker_t stroker;
  1378.     cairo_status_t status;
  1379.  
  1380.     status = _cairo_stroker_init (&stroker, path, stroke_style,
  1381.                                   ctm, ctm_inverse, tolerance,
  1382.                                   NULL, 0);
  1383.     if (unlikely (status))
  1384.         return status;
  1385.  
  1386.     stroker.add_triangle = add_triangle;
  1387.     stroker.add_triangle_fan = add_triangle_fan;
  1388.     stroker.add_convex_quad = add_convex_quad;
  1389.     stroker.closure = closure;
  1390.  
  1391.     status = _cairo_path_fixed_interpret (path,
  1392.                                           _cairo_stroker_move_to,
  1393.                                           stroker.dash.dashed ?
  1394.                                           _cairo_stroker_line_to_dashed :
  1395.                                           _cairo_stroker_line_to,
  1396.                                           _cairo_stroker_curve_to,
  1397.                                           _cairo_stroker_close_path,
  1398.                                           &stroker);
  1399.  
  1400.     if (unlikely (status))
  1401.         goto BAIL;
  1402.  
  1403.     /* Cap the start and end of the final sub path as needed */
  1404.     status = _cairo_stroker_add_caps (&stroker);
  1405.  
  1406. BAIL:
  1407.     _cairo_stroker_fini (&stroker);
  1408.  
  1409.     return status;
  1410. }
  1411.  
  1412. cairo_status_t
  1413. _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t    *path,
  1414.                                             const cairo_stroke_style_t  *stroke_style,
  1415.                                             const cairo_matrix_t        *ctm,
  1416.                                             const cairo_matrix_t        *ctm_inverse,
  1417.                                             double               tolerance,
  1418.                                             cairo_polygon_t *polygon)
  1419. {
  1420.     cairo_stroker_t stroker;
  1421.     cairo_status_t status;
  1422.  
  1423.     status = _cairo_stroker_init (&stroker, path, stroke_style,
  1424.                                   ctm, ctm_inverse, tolerance,
  1425.                                   polygon->limits, polygon->num_limits);
  1426.     if (unlikely (status))
  1427.         return status;
  1428.  
  1429.     stroker.add_external_edge = _cairo_polygon_add_external_edge,
  1430.     stroker.closure = polygon;
  1431.  
  1432.     status = _cairo_path_fixed_interpret (path,
  1433.                                           _cairo_stroker_move_to,
  1434.                                           stroker.dash.dashed ?
  1435.                                           _cairo_stroker_line_to_dashed :
  1436.                                           _cairo_stroker_line_to,
  1437.                                           _cairo_stroker_curve_to,
  1438.                                           _cairo_stroker_close_path,
  1439.                                           &stroker);
  1440.  
  1441.     if (unlikely (status))
  1442.         goto BAIL;
  1443.  
  1444.     /* Cap the start and end of the final sub path as needed */
  1445.     status = _cairo_stroker_add_caps (&stroker);
  1446.  
  1447. BAIL:
  1448.     _cairo_stroker_fini (&stroker);
  1449.  
  1450.     return status;
  1451. }
  1452.  
  1453. cairo_int_status_t
  1454. _cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t     *path,
  1455.                                            const cairo_stroke_style_t   *stroke_style,
  1456.                                            const cairo_matrix_t *ctm,
  1457.                                            const cairo_matrix_t *ctm_inverse,
  1458.                                            double                tolerance,
  1459.                                            cairo_traps_t        *traps)
  1460. {
  1461.     cairo_int_status_t status;
  1462.     cairo_polygon_t polygon;
  1463.  
  1464.     _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
  1465.     status = _cairo_path_fixed_stroke_to_polygon (path,
  1466.                                                   stroke_style,
  1467.                                                   ctm,
  1468.                                                   ctm_inverse,
  1469.                                                   tolerance,
  1470.                                                   &polygon);
  1471.     if (unlikely (status))
  1472.         goto BAIL;
  1473.  
  1474.     status = _cairo_polygon_status (&polygon);
  1475.     if (unlikely (status))
  1476.         goto BAIL;
  1477.  
  1478.     status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
  1479.                                                         CAIRO_FILL_RULE_WINDING);
  1480.  
  1481. BAIL:
  1482.     _cairo_polygon_fini (&polygon);
  1483.  
  1484.     return status;
  1485. }
  1486.