Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009 VMware, Inc.  All Rights Reserved.
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a
  6.  * copy of this software and associated documentation files (the
  7.  * "Software"), to deal in the Software without restriction, including
  8.  * without limitation the rights to use, copy, modify, merge, publish,
  9.  * distribute, sub license, and/or sell copies of the Software, and to
  10.  * permit persons to whom the Software is furnished to do so, subject to
  11.  * the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice (including the
  14.  * next paragraph) shall be included in all copies or substantial portions
  15.  * of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  20.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  21.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24.  *
  25.  **************************************************************************/
  26.  
  27. #include "path.h"
  28.  
  29. #include "stroker.h"
  30. #include "polygon.h"
  31. #include "bezier.h"
  32. #include "matrix.h"
  33. #include "vg_context.h"
  34. #include "util_array.h"
  35. #include "arc.h"
  36. #include "path_utils.h"
  37. #include "paint.h"
  38. #include "shader.h"
  39.  
  40. #include "util/u_memory.h"
  41.  
  42. #include <assert.h>
  43.  
  44. #define DEBUG_PATH 0
  45.  
  46. struct path {
  47.    struct vg_object base;
  48.    VGbitfield caps;
  49.    VGboolean dirty;
  50.    VGboolean dirty_stroke;
  51.  
  52.    VGPathDatatype datatype;
  53.  
  54.    VGfloat scale;
  55.    VGfloat bias;
  56.  
  57.    VGint num_segments;
  58.  
  59.    struct array * segments;
  60.    struct array * control_points;
  61.  
  62.    struct {
  63.       struct polygon_array polygon_array;
  64.       struct matrix matrix;
  65.    } fill_polys;
  66.  
  67.    struct {
  68.       struct path *path;
  69.       struct matrix matrix;
  70.       VGfloat stroke_width;
  71.       VGfloat miter_limit;
  72.       VGCapStyle cap_style;
  73.       VGJoinStyle join_style;
  74.    } stroked;
  75. };
  76.  
  77.  
  78. static INLINE void data_at(void **data,
  79.                            struct path *p,
  80.                            VGint start, VGint count,
  81.                            VGfloat *out)
  82. {
  83.    VGPathDatatype dt = p->datatype;
  84.    VGint i;
  85.    VGint end = start + count;
  86.    VGfloat *itr = out;
  87.  
  88.    switch(dt) {
  89.    case VG_PATH_DATATYPE_S_8: {
  90.       VGbyte **bdata = (VGbyte **)data;
  91.       for (i = start; i < end; ++i) {
  92.          *itr = (*bdata)[i];
  93.          ++itr;
  94.       }
  95.       *bdata += count;
  96.    }
  97.       break;
  98.    case VG_PATH_DATATYPE_S_16: {
  99.       VGshort **bdata = (VGshort **)data;
  100.       for (i = start; i < end; ++i) {
  101.          *itr = (*bdata)[i];
  102.          ++itr;
  103.       }
  104.       *bdata += count;
  105.    }
  106.       break;
  107.    case VG_PATH_DATATYPE_S_32: {
  108.       VGint **bdata = (VGint **)data;
  109.       for (i = start; i < end; ++i) {
  110.          *itr = (*bdata)[i];
  111.          ++itr;
  112.       }
  113.       *bdata += count;
  114.    }
  115.       break;
  116.    case VG_PATH_DATATYPE_F: {
  117.       VGfloat **fdata = (VGfloat **)data;
  118.       for (i = start; i < end; ++i) {
  119.          *itr = (*fdata)[i];
  120.          ++itr;
  121.       }
  122.       *fdata += count;
  123.    }
  124.       break;
  125.    default:
  126.       debug_assert(!"Unknown path datatype!");
  127.    }
  128. }
  129.  
  130.  
  131. void vg_float_to_datatype(VGPathDatatype datatype,
  132.                           VGubyte *common_data,
  133.                           const VGfloat *data,
  134.                           VGint num_coords)
  135. {
  136.    VGint i;
  137.    switch(datatype) {
  138.    case VG_PATH_DATATYPE_S_8: {
  139.       for (i = 0; i < num_coords; ++i) {
  140.          common_data[i] = (VGubyte)data[i];
  141.       }
  142.    }
  143.       break;
  144.    case VG_PATH_DATATYPE_S_16: {
  145.       VGshort *buf = (VGshort*)common_data;
  146.       for (i = 0; i < num_coords; ++i) {
  147.          buf[i] = (VGshort)data[i];
  148.       }
  149.    }
  150.       break;
  151.    case VG_PATH_DATATYPE_S_32: {
  152.       VGint *buf = (VGint*)common_data;
  153.       for (i = 0; i < num_coords; ++i) {
  154.          buf[i] = (VGint)data[i];
  155.       }
  156.    }
  157.       break;
  158.    case VG_PATH_DATATYPE_F: {
  159.       memcpy(common_data, data, sizeof(VGfloat) * num_coords);
  160.    }
  161.       break;
  162.    default:
  163.       debug_assert(!"Unknown path datatype!");
  164.    }
  165. }
  166.  
  167. static void coords_adjust_by_scale_bias(struct path *p,
  168.                                         void *pdata, VGint num_coords,
  169.                                         VGfloat scale, VGfloat bias,
  170.                                         VGPathDatatype datatype)
  171. {
  172.    VGfloat data[8];
  173.    void *coords = (VGfloat *)pdata;
  174.    VGubyte *common_data = (VGubyte *)pdata;
  175.    VGint size_dst = size_for_datatype(datatype);
  176.    VGint i;
  177.  
  178.    for (i = 0; i < num_coords; ++i) {
  179.       data_at(&coords, p, 0, 1, data);
  180.       data[0] = data[0] * scale + bias;
  181.       vg_float_to_datatype(datatype, common_data, data, 1);
  182.       common_data += size_dst;
  183.    }
  184. }
  185.  
  186. struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
  187.                           VGint segmentCapacityHint,
  188.                           VGint coordCapacityHint,
  189.                           VGbitfield capabilities)
  190. {
  191.    struct path *path = CALLOC_STRUCT(path);
  192.  
  193.    vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH);
  194.    path->caps = capabilities & VG_PATH_CAPABILITY_ALL;
  195.    vg_context_add_object(vg_current_context(), &path->base);
  196.  
  197.    path->datatype = dt;
  198.    path->scale = scale;
  199.    path->bias = bias;
  200.  
  201.    path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
  202.    path->control_points = array_create(size_for_datatype(dt));
  203.  
  204.    path->dirty = VG_TRUE;
  205.    path->dirty_stroke = VG_TRUE;
  206.  
  207.    return path;
  208. }
  209.  
  210. static void polygon_array_cleanup(struct polygon_array *polyarray)
  211. {
  212.    if (polyarray->array) {
  213.       VGint i;
  214.  
  215.       for (i = 0; i < polyarray->array->num_elements; i++) {
  216.          struct polygon *p = ((struct polygon **) polyarray->array->data)[i];
  217.          polygon_destroy(p);
  218.       }
  219.  
  220.       array_destroy(polyarray->array);
  221.       polyarray->array = NULL;
  222.    }
  223. }
  224.  
  225. void path_destroy(struct path *p)
  226. {
  227.    vg_context_remove_object(vg_current_context(), &p->base);
  228.  
  229.    array_destroy(p->segments);
  230.    array_destroy(p->control_points);
  231.  
  232.    polygon_array_cleanup(&p->fill_polys.polygon_array);
  233.  
  234.    if (p->stroked.path)
  235.       path_destroy(p->stroked.path);
  236.  
  237.    vg_free_object(&p->base);
  238.  
  239.    FREE(p);
  240. }
  241.  
  242. VGbitfield path_capabilities(struct path *p)
  243. {
  244.    return p->caps;
  245. }
  246.  
  247. void path_set_capabilities(struct path *p, VGbitfield bf)
  248. {
  249.    p->caps = (bf & VG_PATH_CAPABILITY_ALL);
  250. }
  251.  
  252. void path_append_data(struct path *p,
  253.                       VGint numSegments,
  254.                       const VGubyte * pathSegments,
  255.                       const void * pathData)
  256. {
  257.    VGint old_segments = p->num_segments;
  258.    VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments);
  259.    array_append_data(p->segments, pathSegments, numSegments);
  260.    array_append_data(p->control_points, pathData, num_new_coords);
  261.  
  262.    p->num_segments += numSegments;
  263.    if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) {
  264.       VGubyte *coords = (VGubyte*)p->control_points->data;
  265.       coords_adjust_by_scale_bias(p,
  266.                                   coords + old_segments * p->control_points->datatype_size,
  267.                                   num_new_coords,
  268.                                   p->scale, p->bias, p->datatype);
  269.    }
  270.    p->dirty = VG_TRUE;
  271.    p->dirty_stroke = VG_TRUE;
  272. }
  273.  
  274. VGint path_num_segments(struct path *p)
  275. {
  276.    return p->num_segments;
  277. }
  278.  
  279. static INLINE void map_if_relative(VGfloat ox, VGfloat oy,
  280.                                    VGboolean relative,
  281.                                    VGfloat *x, VGfloat *y)
  282. {
  283.    if (relative) {
  284.       if (x)
  285.          *x += ox;
  286.       if (y)
  287.          *y += oy;
  288.    }
  289. }
  290.  
  291. static INLINE void close_polygon(struct polygon *current,
  292.                                  VGfloat sx, VGfloat sy,
  293.                                  VGfloat ox, VGfloat oy,
  294.                                  struct  matrix *matrix)
  295. {
  296.    if (!floatsEqual(sx, ox) ||
  297.        !floatsEqual(sy, oy)) {
  298.       VGfloat x0 = sx;
  299.       VGfloat y0 = sy;
  300.       matrix_map_point(matrix, x0, y0, &x0, &y0);
  301.       polygon_vertex_append(current, x0, y0);
  302.    }
  303. }
  304.  
  305. static void convert_path(struct path *p,
  306.                           VGPathDatatype to,
  307.                           void *dst,
  308.                           VGint num_coords)
  309. {
  310.    VGfloat data[8];
  311.    void *coords = (VGfloat *)p->control_points->data;
  312.    VGubyte *common_data = (VGubyte *)dst;
  313.    VGint size_dst = size_for_datatype(to);
  314.    VGint i;
  315.  
  316.    for (i = 0; i < num_coords; ++i) {
  317.       data_at(&coords, p, 0, 1, data);
  318.       vg_float_to_datatype(to, common_data, data, 1);
  319.       common_data += size_dst;
  320.    }
  321. }
  322.  
  323. static void polygon_array_calculate_bounds( struct polygon_array *polyarray )
  324. {
  325.    struct array *polys = polyarray->array;
  326.    VGfloat min_x, max_x;
  327.    VGfloat min_y, max_y;
  328.    VGfloat bounds[4];
  329.    unsigned i;
  330.  
  331.    assert(polys);
  332.  
  333.    if (!polys->num_elements) {
  334.       polyarray->min_x = 0.0f;
  335.       polyarray->min_y = 0.0f;
  336.       polyarray->max_x = 0.0f;
  337.       polyarray->max_y = 0.0f;
  338.       return;
  339.    }
  340.  
  341.    polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds);
  342.    min_x = bounds[0];
  343.    min_y = bounds[1];
  344.    max_x = bounds[0] + bounds[2];
  345.    max_y = bounds[1] + bounds[3];
  346.    for (i = 1; i < polys->num_elements; ++i) {
  347.       struct polygon *p = (((struct polygon**)polys->data)[i]);
  348.       polygon_bounding_rect(p, bounds);
  349.       min_x = MIN2(min_x, bounds[0]);
  350.       min_y = MIN2(min_y, bounds[1]);
  351.       max_x = MAX2(max_x, bounds[0] + bounds[2]);
  352.       max_y = MAX2(max_y, bounds[1] + bounds[3]);
  353.    }
  354.  
  355.    polyarray->min_x = min_x;
  356.    polyarray->min_y = min_y;
  357.    polyarray->max_x = max_x;
  358.    polyarray->max_y = max_y;
  359. }
  360.  
  361.  
  362. static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix)
  363. {
  364.    VGint i;
  365.    struct polygon *current = 0;
  366.    VGfloat sx, sy, px, py, ox, oy;
  367.    VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
  368.    VGfloat data[8];
  369.    void *coords = (VGfloat *)p->control_points->data;
  370.    struct array *array;
  371.  
  372.    memset(data, 0, sizeof(data));
  373.  
  374.    if (p->fill_polys.polygon_array.array)
  375.    {
  376.       if (memcmp( &p->fill_polys.matrix,
  377.                   matrix,
  378.                   sizeof *matrix ) == 0 && p->dirty == VG_FALSE)
  379.       {
  380.          return &p->fill_polys.polygon_array;
  381.       }
  382.       else {
  383.          polygon_array_cleanup(&p->fill_polys.polygon_array);
  384.       }
  385.    }
  386.  
  387.    /* an array of pointers to polygons */
  388.    array = array_create(sizeof(struct polygon *));
  389.  
  390.    sx = sy = px = py = ox = oy = 0.f;
  391.  
  392.    if (p->num_segments)
  393.       current = polygon_create(32);
  394.  
  395.    for (i = 0; i < p->num_segments; ++i) {
  396.       VGubyte segment = ((VGubyte*)(p->segments->data))[i];
  397.       VGint command = SEGMENT_COMMAND(segment);
  398.       VGboolean relative = SEGMENT_ABS_REL(segment);
  399.  
  400.       switch(command) {
  401.       case VG_CLOSE_PATH:
  402.          close_polygon(current, sx, sy, ox, oy, matrix);
  403.          ox = sx;
  404.          oy = sy;
  405.          break;
  406.       case VG_MOVE_TO:
  407.          if (current && polygon_vertex_count(current) > 0) {
  408.             /* add polygon */
  409.             close_polygon(current, sx, sy, ox, oy, matrix);
  410.             array_append_data(array, &current, 1);
  411.             current = polygon_create(32);
  412.          }
  413.          data_at(&coords, p, 0, 2, data);
  414.          x0 = data[0];
  415.          y0 = data[1];
  416.          map_if_relative(ox, oy, relative, &x0, &y0);
  417.          sx = x0;
  418.          sy = y0;
  419.          ox = x0;
  420.          oy = y0;
  421.          px = x0;
  422.          py = y0;
  423.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  424.          polygon_vertex_append(current, x0, y0);
  425.          break;
  426.       case VG_LINE_TO:
  427.          data_at(&coords, p, 0, 2, data);
  428.          x0 = data[0];
  429.          y0 = data[1];
  430.          map_if_relative(ox, oy, relative, &x0, &y0);
  431.          ox = x0;
  432.          oy = y0;
  433.          px = x0;
  434.          py = y0;
  435.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  436.          polygon_vertex_append(current, x0, y0);
  437.          break;
  438.       case VG_HLINE_TO:
  439.          data_at(&coords, p, 0, 1, data);
  440.          x0 = data[0];
  441.          y0 = oy;
  442.          map_if_relative(ox, oy, relative, &x0, 0);
  443.          ox = x0;
  444.          px = x0;
  445.          py = y0;
  446.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  447.          polygon_vertex_append(current, x0, y0);
  448.          break;
  449.       case VG_VLINE_TO:
  450.          data_at(&coords, p, 0, 1, data);
  451.          x0 = ox;
  452.          y0 = data[0];
  453.          map_if_relative(ox, oy, relative, 0, &y0);
  454.          oy = y0;
  455.          px = x0;
  456.          py = y0;
  457.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  458.          polygon_vertex_append(current, x0, y0);
  459.          break;
  460.       case VG_CUBIC_TO: {
  461.          struct bezier bezier;
  462.          data_at(&coords, p, 0, 6, data);
  463.          x0 = ox;
  464.          y0 = oy;
  465.          x1 = data[0];
  466.          y1 = data[1];
  467.          x2 = data[2];
  468.          y2 = data[3];
  469.          x3 = data[4];
  470.          y3 = data[5];
  471.          map_if_relative(ox, oy, relative, &x1, &y1);
  472.          map_if_relative(ox, oy, relative, &x2, &y2);
  473.          map_if_relative(ox, oy, relative, &x3, &y3);
  474.          ox = x3;
  475.          oy = y3;
  476.          px = x2;
  477.          py = y2;
  478.          assert(matrix_is_affine(matrix));
  479.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  480.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  481.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  482.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  483.          bezier_init(&bezier, x0, y0, x1, y1,
  484.                        x2, y2, x3, y3);
  485.          bezier_add_to_polygon(&bezier, current);
  486.       }
  487.          break;
  488.       case VG_QUAD_TO: {
  489.          struct bezier bezier;
  490.          data_at(&coords, p, 0, 4, data);
  491.          x0 = ox;
  492.          y0 = oy;
  493.          x1 = data[0];
  494.          y1 = data[1];
  495.          x3 = data[2];
  496.          y3 = data[3];
  497.          map_if_relative(ox, oy, relative, &x1, &y1);
  498.          map_if_relative(ox, oy, relative, &x3, &y3);
  499.          px = x1;
  500.          py = y1;
  501.          { /* form a cubic out of it */
  502.             x2 = (x3 + 2*x1) / 3.f;
  503.             y2 = (y3 + 2*y1) / 3.f;
  504.             x1 = (x0 + 2*x1) / 3.f;
  505.             y1 = (y0 + 2*y1) / 3.f;
  506.          }
  507.          ox = x3;
  508.          oy = y3;
  509.          assert(matrix_is_affine(matrix));
  510.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  511.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  512.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  513.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  514.          bezier_init(&bezier, x0, y0, x1, y1,
  515.                        x2, y2, x3, y3);
  516.          bezier_add_to_polygon(&bezier, current);
  517.       }
  518.          break;
  519.       case VG_SQUAD_TO: {
  520.          struct bezier bezier;
  521.          data_at(&coords, p, 0, 2, data);
  522.          x0 = ox;
  523.          y0 = oy;
  524.          x1 = 2*ox-px;
  525.          y1 = 2*oy-py;
  526.          x3 = data[0];
  527.          y3 = data[1];
  528.          map_if_relative(ox, oy, relative, &x3, &y3);
  529.          px = x1;
  530.          py = y1;
  531.          { /* form a cubic out of it */
  532.             x2 = (x3 + 2*x1) / 3.f;
  533.             y2 = (y3 + 2*y1) / 3.f;
  534.             x1 = (x0 + 2*x1) / 3.f;
  535.             y1 = (y0 + 2*y1) / 3.f;
  536.          }
  537.          ox = x3;
  538.          oy = y3;
  539.          assert(matrix_is_affine(matrix));
  540.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  541.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  542.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  543.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  544.          bezier_init(&bezier, x0, y0, x1, y1,
  545.                      x2, y2, x3, y3);
  546.          bezier_add_to_polygon(&bezier, current);
  547.       }
  548.          break;
  549.       case VG_SCUBIC_TO: {
  550.          struct bezier bezier;
  551.          data_at(&coords, p, 0, 4, data);
  552.          x0 = ox;
  553.          y0 = oy;
  554.          x1 = 2*ox-px;
  555.          y1 = 2*oy-py;
  556.          x2 = data[0];
  557.          y2 = data[1];
  558.          x3 = data[2];
  559.          y3 = data[3];
  560.          map_if_relative(ox, oy, relative, &x2, &y2);
  561.          map_if_relative(ox, oy, relative, &x3, &y3);
  562.          ox = x3;
  563.          oy = y3;
  564.          px = x2;
  565.          py = y2;
  566.          assert(matrix_is_affine(matrix));
  567.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  568.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  569.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  570.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  571.          bezier_init(&bezier, x0, y0, x1, y1,
  572.                               x2, y2, x3, y3);
  573.          bezier_add_to_polygon(&bezier, current);
  574.       }
  575.          break;
  576.       case VG_SCCWARC_TO:
  577.       case VG_SCWARC_TO:
  578.       case VG_LCCWARC_TO:
  579.       case VG_LCWARC_TO: {
  580.          VGfloat rh, rv, rot;
  581.          struct arc arc;
  582.  
  583.          data_at(&coords, p, 0, 5, data);
  584.          x0  = ox;
  585.          y0  = oy;
  586.          rh  = data[0];
  587.          rv  = data[1];
  588.          rot = data[2];
  589.          x1  = data[3];
  590.          y1  = data[4];
  591.          map_if_relative(ox, oy, relative, &x1, &y1);
  592. #if 0
  593.          debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
  594.                       x0, y0, x1, y1, rh, rv, rot);
  595. #endif
  596.          arc_init(&arc, command, x0, y0, x1, y1,
  597.                   rh, rv, rot);
  598.          arc_add_to_polygon(&arc, current,
  599.                             matrix);
  600.          ox = x1;
  601.          oy = y1;
  602.          px = x1;
  603.          py = y1;
  604.       }
  605.          break;
  606.       default:
  607.          abort();
  608.          assert(!"Unknown segment!");
  609.       }
  610.    }
  611.    if (current) {
  612.       if (polygon_vertex_count(current) > 0) {
  613.          close_polygon(current, sx, sy, ox, oy, matrix);
  614.          array_append_data(array, &current, 1);
  615.       } else
  616.          polygon_destroy(current);
  617.    }
  618.  
  619.    p->fill_polys.polygon_array.array = array;
  620.    p->fill_polys.matrix = *matrix;
  621.  
  622.    polygon_array_calculate_bounds( &p->fill_polys.polygon_array );
  623.  
  624.    p->dirty = VG_FALSE;
  625.  
  626.    return &p->fill_polys.polygon_array;
  627. }
  628.  
  629. VGbyte path_datatype_size(struct path *p)
  630. {
  631.    return size_for_datatype(p->datatype);
  632. }
  633.  
  634. VGPathDatatype path_datatype(struct path *p)
  635. {
  636.    return p->datatype;
  637. }
  638.  
  639. VGfloat path_scale(struct path *p)
  640. {
  641.    return p->scale;
  642. }
  643.  
  644. VGfloat path_bias(struct path *p)
  645. {
  646.    return p->bias;
  647. }
  648.  
  649. VGint path_num_coords(struct path *p)
  650. {
  651.    return num_elements_for_segments((VGubyte*)p->segments->data,
  652.                                     p->num_segments);
  653. }
  654.  
  655. void path_modify_coords(struct path *p,
  656.                         VGint startIndex,
  657.                         VGint numSegments,
  658.                         const void * pathData)
  659. {
  660.    VGubyte *segments = (VGubyte*)(p->segments->data);
  661.    VGint count = num_elements_for_segments(&segments[startIndex], numSegments);
  662.    VGint start_cp = num_elements_for_segments(segments, startIndex);
  663.  
  664.    array_change_data(p->control_points, pathData, start_cp, count);
  665.    coords_adjust_by_scale_bias(p,
  666.                                ((VGubyte*)p->control_points->data) +
  667.                                (startIndex * p->control_points->datatype_size),
  668.                                path_num_coords(p),
  669.                                p->scale, p->bias, p->datatype);
  670.    p->dirty = VG_TRUE;
  671.    p->dirty_stroke = VG_TRUE;
  672. }
  673.  
  674. void path_for_each_segment(struct path *path,
  675.                            path_for_each_cb cb,
  676.                            void *user_data)
  677. {
  678.    VGint i;
  679.    struct path_for_each_data p;
  680.    VGfloat data[8];
  681.    void *coords = (VGfloat *)path->control_points->data;
  682.  
  683.    p.coords = data;
  684.    p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f;
  685.    p.user_data = user_data;
  686.  
  687.    for (i = 0; i < path->num_segments; ++i) {
  688.       VGint command;
  689.       VGboolean relative;
  690.  
  691.       p.segment = ((VGubyte*)(path->segments->data))[i];
  692.       command = SEGMENT_COMMAND(p.segment);
  693.       relative = SEGMENT_ABS_REL(p.segment);
  694.  
  695.       switch(command) {
  696.       case VG_CLOSE_PATH:
  697.          cb(path, &p);
  698.          break;
  699.       case VG_MOVE_TO:
  700.          data_at(&coords, path, 0, 2, data);
  701.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  702.          cb(path, &p);
  703.          p.sx = data[0];
  704.          p.sy = data[1];
  705.          p.ox = data[0];
  706.          p.oy = data[1];
  707.          p.px = data[0];
  708.          p.py = data[1];
  709.          break;
  710.       case VG_LINE_TO:
  711.          data_at(&coords, path, 0, 2, data);
  712.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  713.          cb(path, &p);
  714.          p.ox = data[0];
  715.          p.oy = data[1];
  716.          p.px = data[0];
  717.          p.py = data[1];
  718.          break;
  719.       case VG_HLINE_TO:
  720.          data_at(&coords, path, 0, 1, data);
  721.          map_if_relative(p.ox, p.oy, relative, &data[0], 0);
  722.          p.segment = VG_LINE_TO;
  723.          data[1] = p.oy;
  724.          cb(path, &p);
  725.          p.ox = data[0];
  726.          p.oy = data[1];
  727.          p.px = data[0];
  728.          p.py = data[1];
  729.          break;
  730.       case VG_VLINE_TO:
  731.          data_at(&coords, path, 0, 1, data);
  732.          map_if_relative(p.ox, p.oy, relative, 0, &data[0]);
  733.          p.segment = VG_LINE_TO;
  734.          data[1] = data[0];
  735.          data[0] = p.ox;
  736.          cb(path, &p);
  737.          p.ox = data[0];
  738.          p.oy = data[1];
  739.          p.px = data[0];
  740.          p.py = data[1];
  741.          break;
  742.       case VG_CUBIC_TO: {
  743.          data_at(&coords, path, 0, 6, data);
  744.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  745.          map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
  746.          map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]);
  747.          cb(path, &p);
  748.          p.px = data[2];
  749.          p.py = data[3];
  750.          p.ox = data[4];
  751.          p.oy = data[5];
  752.       }
  753.          break;
  754.       case VG_QUAD_TO: {
  755.          data_at(&coords, path, 0, 4, data);
  756.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  757.          map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
  758.          cb(path, &p);
  759.          p.px = data[0];
  760.          p.py = data[1];
  761.          p.ox = data[2];
  762.          p.oy = data[3];
  763.       }
  764.          break;
  765.       case VG_SQUAD_TO: {
  766.          data_at(&coords, path, 0, 2, data);
  767.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  768.          cb(path, &p);
  769.          p.px = 2*p.ox-p.px;
  770.          p.py = 2*p.oy-p.py;
  771.          p.ox = data[2];
  772.          p.oy = data[3];
  773.       }
  774.          break;
  775.       case VG_SCUBIC_TO: {
  776.          data_at(&coords, path, 0, 4, data);
  777.          map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
  778.          map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
  779.          cb(path, &p);
  780.          p.px = data[0];
  781.          p.py = data[1];
  782.          p.ox = data[2];
  783.          p.oy = data[3];
  784.       }
  785.          break;
  786.       case VG_SCCWARC_TO:
  787.       case VG_SCWARC_TO:
  788.       case VG_LCCWARC_TO:
  789.       case VG_LCWARC_TO: {
  790.          data_at(&coords, path, 0, 5, data);
  791.          map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]);
  792. #if 0
  793.          debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
  794.                       p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]);
  795. #endif
  796.          cb(path, &p);
  797.          p.ox = data[3];
  798.          p.oy = data[4];
  799.          p.px = data[3];
  800.          p.py = data[4];
  801.       }
  802.          break;
  803.       default:
  804.          abort();
  805.          assert(!"Unknown segment!");
  806.       }
  807.    }
  808. }
  809.  
  810. struct transform_data {
  811.    struct array *segments;
  812.    struct array *coords;
  813.  
  814.    struct matrix *matrix;
  815.  
  816.    VGPathDatatype datatype;
  817. };
  818.  
  819. static VGboolean transform_cb(struct path *p,
  820.                               struct path_for_each_data *pd)
  821. {
  822.    struct transform_data *td = (struct transform_data *)pd->user_data;
  823.    VGint num_coords = num_elements_for_segments(&pd->segment, 1);
  824.    VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */
  825.    VGfloat data[8];
  826.    VGubyte common_data[sizeof(VGfloat)*8];
  827.  
  828.    memcpy(data, pd->coords, sizeof(VGfloat) * num_coords);
  829.  
  830.    switch(segment) {
  831.    case VG_CLOSE_PATH:
  832.       break;
  833.    case VG_MOVE_TO:
  834.       matrix_map_point(td->matrix,
  835.                        data[0], data[1], &data[0], &data[1]);
  836.       break;
  837.    case VG_LINE_TO:
  838.       matrix_map_point(td->matrix,
  839.                        data[0], data[1], &data[0], &data[1]);
  840.       break;
  841.    case VG_HLINE_TO:
  842.    case VG_VLINE_TO:
  843.       assert(0);
  844.       break;
  845.    case VG_QUAD_TO:
  846.       matrix_map_point(td->matrix,
  847.                        data[0], data[1], &data[0], &data[1]);
  848.       matrix_map_point(td->matrix,
  849.                        data[2], data[3], &data[2], &data[3]);
  850.       break;
  851.    case VG_CUBIC_TO:
  852.       matrix_map_point(td->matrix,
  853.                        data[0], data[1], &data[0], &data[1]);
  854.       matrix_map_point(td->matrix,
  855.                        data[2], data[3], &data[2], &data[3]);
  856.       matrix_map_point(td->matrix,
  857.                        data[4], data[5], &data[4], &data[5]);
  858.       break;
  859.    case VG_SQUAD_TO:
  860.       matrix_map_point(td->matrix,
  861.                        data[0], data[1], &data[0], &data[1]);
  862.       break;
  863.    case VG_SCUBIC_TO:
  864.       matrix_map_point(td->matrix,
  865.                        data[0], data[1], &data[0], &data[1]);
  866.       matrix_map_point(td->matrix,
  867.                        data[2], data[3], &data[2], &data[3]);
  868.       break;
  869.    case VG_SCCWARC_TO:
  870.    case VG_SCWARC_TO:
  871.    case VG_LCCWARC_TO:
  872.    case VG_LCWARC_TO: {
  873.       struct arc arc;
  874.       struct path *path = path_create(td->datatype,
  875.                                       1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
  876.       arc_init(&arc, segment,
  877.                pd->ox, pd->oy, data[3], data[4],
  878.                data[0], data[1], data[2]);
  879.  
  880.       arc_to_path(&arc, path, td->matrix);
  881.  
  882.       num_coords = path_num_coords(path);
  883.  
  884.       array_append_data(td->segments, path->segments->data,
  885.                         path->num_segments);
  886.       array_append_data(td->coords, path->control_points->data,
  887.                         num_coords);
  888.       path_destroy(path);
  889.  
  890.       return VG_TRUE;
  891.    }
  892.       break;
  893.    default:
  894.       break;
  895.    }
  896.  
  897.    vg_float_to_datatype(td->datatype, common_data, data, num_coords);
  898.  
  899.    array_append_data(td->segments, &pd->segment, 1);
  900.    array_append_data(td->coords, common_data, num_coords);
  901.    return VG_TRUE;
  902. }
  903.  
  904. void path_transform(struct path *dst, struct path *src)
  905. {
  906.    struct transform_data data;
  907.    struct vg_context *ctx = dst->base.ctx;
  908.  
  909.    data.segments =  dst->segments;
  910.    data.coords   =  dst->control_points;
  911.    data.matrix   = &ctx->state.vg.path_user_to_surface_matrix;
  912.    data.datatype = dst->datatype;
  913.  
  914.    path_for_each_segment(src, transform_cb, (void*)&data);
  915.  
  916.    dst->num_segments = dst->segments->num_elements;
  917.    dst->dirty = VG_TRUE;
  918.    dst->dirty_stroke = VG_TRUE;
  919. }
  920.  
  921. void path_append_path(struct path *dst,
  922.                       struct path *src)
  923. {
  924.    VGint num_coords = path_num_coords(src);
  925.    void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords);
  926.    array_append_data(dst->segments,
  927.                      src->segments->data,
  928.                      src->num_segments);
  929.    convert_path(src, dst->datatype,
  930.                 dst_data, num_coords);
  931.    array_append_data(dst->control_points,
  932.                      dst_data,
  933.                      num_coords);
  934.    free(dst_data);
  935.  
  936.    dst->num_segments += src->num_segments;
  937.    dst->dirty = VG_TRUE;
  938.    dst->dirty_stroke = VG_TRUE;
  939. }
  940.  
  941. static INLINE VGboolean is_segment_arc(VGubyte segment)
  942. {
  943.    VGubyte scommand = SEGMENT_COMMAND(segment);
  944.    return (scommand == VG_SCCWARC_TO ||
  945.            scommand == VG_SCWARC_TO ||
  946.            scommand == VG_LCCWARC_TO ||
  947.            scommand == VG_LCWARC_TO);
  948. }
  949.  
  950. struct path_iter_data {
  951.    struct path *path;
  952.    VGubyte segment;
  953.    void *coords;
  954.    VGfloat px, py, ox, oy, sx, sy;
  955. };
  956. static INLINE VGubyte normalize_coords(struct path_iter_data *pd,
  957.                                        VGint *num_coords,
  958.                                        VGfloat *data)
  959. {
  960.    VGint command = SEGMENT_COMMAND(pd->segment);
  961.    VGboolean relative = SEGMENT_ABS_REL(pd->segment);
  962.  
  963.    switch(command) {
  964.    case VG_CLOSE_PATH:
  965.       *num_coords = 0;
  966.       pd->ox = pd->sx;
  967.       pd->oy = pd->sy;
  968.       return VG_CLOSE_PATH;
  969.       break;
  970.    case VG_MOVE_TO:
  971.       data_at(&pd->coords, pd->path, 0, 2, data);
  972.       map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
  973.       pd->sx = data[0];
  974.       pd->sy = data[1];
  975.       pd->ox = data[0];
  976.       pd->oy = data[1];
  977.       pd->px = data[0];
  978.       pd->py = data[1];
  979.       *num_coords = 2;
  980.       return VG_MOVE_TO_ABS;
  981.       break;
  982.    case VG_LINE_TO:
  983.       data_at(&pd->coords, pd->path, 0, 2, data);
  984.       map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
  985.       pd->ox = data[0];
  986.       pd->oy = data[1];
  987.       pd->px = data[0];
  988.       pd->py = data[1];
  989.       *num_coords = 2;
  990.       return VG_LINE_TO_ABS;
  991.       break;
  992.    case VG_HLINE_TO:
  993.       data_at(&pd->coords, pd->path, 0, 1, data);
  994.       map_if_relative(pd->ox, pd->oy, relative, &data[0], 0);
  995.       data[1] = pd->oy;
  996.       pd->ox = data[0];
  997.       pd->oy = data[1];
  998.       pd->px = data[0];
  999.       pd->py = data[1];
  1000.       *num_coords = 2;
  1001.       return VG_LINE_TO_ABS;
  1002.       break;
  1003.    case VG_VLINE_TO:
  1004.       data_at(&pd->coords, pd->path, 0, 1, data);
  1005.       map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]);
  1006.       data[1] = data[0];
  1007.       data[0] = pd->ox;
  1008.       pd->ox = data[0];
  1009.       pd->oy = data[1];
  1010.       pd->px = data[0];
  1011.       pd->py = data[1];
  1012.       *num_coords = 2;
  1013.       return VG_LINE_TO_ABS;
  1014.       break;
  1015.    case VG_CUBIC_TO: {
  1016.       data_at(&pd->coords, pd->path, 0, 6, data);
  1017.       map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
  1018.       map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]);
  1019.       map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]);
  1020.       pd->px = data[2];
  1021.       pd->py = data[3];
  1022.       pd->ox = data[4];
  1023.       pd->oy = data[5];
  1024.       *num_coords = 6;
  1025.       return VG_CUBIC_TO_ABS;
  1026.    }
  1027.       break;
  1028.    case VG_QUAD_TO: {
  1029.       VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
  1030.       data_at(&pd->coords, pd->path, 0, 4, data);
  1031.       x0 = pd->ox;
  1032.       y0 = pd->oy;
  1033.       x1 = data[0];
  1034.       y1 = data[1];
  1035.       x3 = data[2];
  1036.       y3 = data[3];
  1037.       map_if_relative(pd->ox, pd->oy, relative, &x1, &y1);
  1038.       map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
  1039.       pd->px = x1;
  1040.       pd->py = y1;
  1041.       { /* form a cubic out of it */
  1042.          x2 = (x3 + 2*x1) / 3.f;
  1043.          y2 = (y3 + 2*y1) / 3.f;
  1044.          x1 = (x0 + 2*x1) / 3.f;
  1045.          y1 = (y0 + 2*y1) / 3.f;
  1046.       }
  1047.       pd->ox = x3;
  1048.       pd->oy = y3;
  1049.       data[0] = x1;
  1050.       data[1] = y1;
  1051.       data[2] = x2;
  1052.       data[3] = y2;
  1053.       data[4] = x3;
  1054.       data[5] = y3;
  1055.       *num_coords = 6;
  1056.       return VG_CUBIC_TO_ABS;
  1057.    }
  1058.       break;
  1059.    case VG_SQUAD_TO: {
  1060.       VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
  1061.       data_at(&pd->coords, pd->path, 0, 2, data);
  1062.       x0 = pd->ox;
  1063.       y0 = pd->oy;
  1064.       x1 = 2 * pd->ox - pd->px;
  1065.       y1 = 2 * pd->oy - pd->py;
  1066.       x3 = data[0];
  1067.       y3 = data[1];
  1068.       map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
  1069.       pd->px = x1;
  1070.       pd->py = y1;
  1071.       { /* form a cubic out of it */
  1072.          x2 = (x3 + 2*x1) / 3.f;
  1073.          y2 = (y3 + 2*y1) / 3.f;
  1074.          x1 = (x0 + 2*x1) / 3.f;
  1075.          y1 = (y0 + 2*y1) / 3.f;
  1076.       }
  1077.       pd->ox = x3;
  1078.       pd->oy = y3;
  1079.       data[0] = x1;
  1080.       data[1] = y1;
  1081.       data[2] = x2;
  1082.       data[3] = y2;
  1083.       data[4] = x3;
  1084.       data[5] = y3;
  1085.       *num_coords = 6;
  1086.       return VG_CUBIC_TO_ABS;
  1087.    }
  1088.       break;
  1089.    case VG_SCUBIC_TO: {
  1090.       VGfloat x1, y1, x2, y2, x3, y3;
  1091.       data_at(&pd->coords, pd->path, 0, 4, data);
  1092.       x1 = 2*pd->ox-pd->px;
  1093.       y1 = 2*pd->oy-pd->py;
  1094.       x2 = data[0];
  1095.       y2 = data[1];
  1096.       x3 = data[2];
  1097.       y3 = data[3];
  1098.       map_if_relative(pd->ox, pd->oy, relative, &x2, &y2);
  1099.       map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
  1100.       pd->ox = x3;
  1101.       pd->oy = y3;
  1102.       pd->px = x2;
  1103.       pd->py = y2;
  1104.       data[0] = x1;
  1105.       data[1] = y1;
  1106.       data[2] = x2;
  1107.       data[3] = y2;
  1108.       data[4] = x3;
  1109.       data[5] = y3;
  1110.       *num_coords = 6;
  1111.       return VG_CUBIC_TO_ABS;
  1112.    }
  1113.       break;
  1114.    case VG_SCCWARC_TO:
  1115.    case VG_SCWARC_TO:
  1116.    case VG_LCCWARC_TO:
  1117.    case VG_LCWARC_TO: {
  1118.       data_at(&pd->coords, pd->path, 0, 5, data);
  1119.       map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]);
  1120.       pd->ox = data[3];
  1121.       pd->oy = data[4];
  1122.       pd->px = data[3];
  1123.       pd->py = data[4];
  1124.       *num_coords = 5;
  1125.       return command | VG_ABSOLUTE;
  1126.    }
  1127.       break;
  1128.    default:
  1129.       abort();
  1130.       assert(!"Unknown segment!");
  1131.       return 0;
  1132.    }
  1133. }
  1134.  
  1135. static void linearly_interpolate(VGfloat *result,
  1136.                                  const VGfloat *start,
  1137.                                  const VGfloat *end,
  1138.                                  VGfloat amount,
  1139.                                  VGint number)
  1140. {
  1141.    VGint i;
  1142.    for (i = 0; i < number; ++i) {
  1143.       result[i] = start[i] + (end[i] - start[i]) * amount;
  1144.    }
  1145. }
  1146.  
  1147. VGboolean path_interpolate(struct path *dst,
  1148.                            struct path *start, struct path *end,
  1149.                            VGfloat amount)
  1150. {
  1151.    /* temporary path that we can discard if it will turn
  1152.     * out that start is not compatible with end */
  1153.    struct path *res_path = path_create(dst->datatype,
  1154.                                        1.0, 0.0,
  1155.                                        0, 0, dst->caps);
  1156.    VGint i;
  1157.    VGfloat start_coords[8];
  1158.    VGfloat end_coords[8];
  1159.    VGfloat results[8];
  1160.    VGubyte common_data[sizeof(VGfloat)*8];
  1161.    struct path_iter_data start_iter, end_iter;
  1162.  
  1163.    memset(&start_iter, 0, sizeof(struct path_iter_data));
  1164.    memset(&end_iter, 0, sizeof(struct path_iter_data));
  1165.  
  1166.    start_iter.path = start;
  1167.    start_iter.coords = start->control_points->data;
  1168.    end_iter.path = end;
  1169.    end_iter.coords = end->control_points->data;
  1170.  
  1171.    for (i = 0; i < start->num_segments; ++i) {
  1172.       VGubyte segment;
  1173.       VGubyte ssegment, esegment;
  1174.       VGint snum_coords, enum_coords;
  1175.       start_iter.segment = ((VGubyte*)(start->segments->data))[i];
  1176.       end_iter.segment = ((VGubyte*)(end->segments->data))[i];
  1177.  
  1178.       ssegment = normalize_coords(&start_iter, &snum_coords,
  1179.                                   start_coords);
  1180.       esegment = normalize_coords(&end_iter, &enum_coords,
  1181.                                   end_coords);
  1182.  
  1183.       if (is_segment_arc(ssegment)) {
  1184.          if (!is_segment_arc(esegment)) {
  1185.             path_destroy(res_path);
  1186.             return VG_FALSE;
  1187.          }
  1188.          if (amount > 0.5)
  1189.             segment = esegment;
  1190.          else
  1191.             segment = ssegment;
  1192.       } else if (is_segment_arc(esegment)) {
  1193.          path_destroy(res_path);
  1194.          return VG_FALSE;
  1195.       }
  1196.       else if (ssegment != esegment) {
  1197.          path_destroy(res_path);
  1198.          return VG_FALSE;
  1199.       }
  1200.       else
  1201.          segment = ssegment;
  1202.  
  1203.       linearly_interpolate(results, start_coords, end_coords,
  1204.                            amount, snum_coords);
  1205.       vg_float_to_datatype(dst->datatype, common_data, results, snum_coords);
  1206.       path_append_data(res_path, 1, &segment, common_data);
  1207.    }
  1208.  
  1209.    path_append_path(dst, res_path);
  1210.    path_destroy(res_path);
  1211.  
  1212.    dst->dirty = VG_TRUE;
  1213.    dst->dirty_stroke = VG_TRUE;
  1214.  
  1215.    return VG_TRUE;
  1216. }
  1217.  
  1218. void path_clear(struct path *p, VGbitfield capabilities)
  1219. {
  1220.    path_set_capabilities(p, capabilities);
  1221.    array_destroy(p->segments);
  1222.    array_destroy(p->control_points);
  1223.    p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
  1224.    p->control_points = array_create(size_for_datatype(p->datatype));
  1225.    p->num_segments = 0;
  1226.    p->dirty = VG_TRUE;
  1227.    p->dirty_stroke = VG_TRUE;
  1228. }
  1229.  
  1230. struct path * path_create_stroke(struct path *p,
  1231.                                  struct matrix *matrix)
  1232. {
  1233.    VGint i;
  1234.    VGfloat sx, sy, px, py, ox, oy;
  1235.    VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
  1236.    VGfloat data[8];
  1237.    void *coords = (VGfloat *)p->control_points->data;
  1238.    int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0);
  1239.    struct dash_stroker stroker;
  1240.    struct vg_state *vg_state = &p->base.ctx->state.vg;
  1241.  
  1242.    if (p->stroked.path)
  1243.    {
  1244.       /* ### compare the dash patterns to see if we can cache them.
  1245.        *     for now we simply always bail out if the path is dashed.
  1246.        */
  1247.       if (memcmp( &p->stroked.matrix,
  1248.                   matrix,
  1249.                   sizeof *matrix ) == 0 &&
  1250.           !dashed && !p->dirty_stroke &&
  1251.           floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) &&
  1252.           floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) &&
  1253.           p->stroked.cap_style == vg_state->stroke.cap_style &&
  1254.           p->stroked.join_style == vg_state->stroke.join_style)
  1255.       {
  1256.          return p->stroked.path;
  1257.       }
  1258.       else {
  1259.          path_destroy( p->stroked.path );
  1260.          p->stroked.path = NULL;
  1261.       }
  1262.    }
  1263.  
  1264.  
  1265.    sx = sy = px = py = ox = oy = 0.f;
  1266.  
  1267.    if (dashed)
  1268.       dash_stroker_init((struct stroker *)&stroker, vg_state);
  1269.    else
  1270.       stroker_init((struct stroker *)&stroker, vg_state);
  1271.  
  1272.    stroker_begin((struct stroker *)&stroker);
  1273.  
  1274.    for (i = 0; i < p->num_segments; ++i) {
  1275.       VGubyte segment = ((VGubyte*)(p->segments->data))[i];
  1276.       VGint command = SEGMENT_COMMAND(segment);
  1277.       VGboolean relative = SEGMENT_ABS_REL(segment);
  1278.  
  1279.       switch(command) {
  1280.       case VG_CLOSE_PATH: {
  1281.             VGfloat x0 = sx;
  1282.             VGfloat y0 = sy;
  1283.             matrix_map_point(matrix, x0, y0, &x0, &y0);
  1284.             stroker_line_to((struct stroker *)&stroker, x0, y0);
  1285.       }
  1286.          break;
  1287.       case VG_MOVE_TO:
  1288.          data_at(&coords, p, 0, 2, data);
  1289.          x0 = data[0];
  1290.          y0 = data[1];
  1291.          map_if_relative(ox, oy, relative, &x0, &y0);
  1292.          sx = x0;
  1293.          sy = y0;
  1294.          ox = x0;
  1295.          oy = y0;
  1296.          px = x0;
  1297.          py = y0;
  1298.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1299.          stroker_move_to((struct stroker *)&stroker, x0, y0);
  1300.          break;
  1301.       case VG_LINE_TO:
  1302.          data_at(&coords, p, 0, 2, data);
  1303.          x0 = data[0];
  1304.          y0 = data[1];
  1305.          map_if_relative(ox, oy, relative, &x0, &y0);
  1306.          ox = x0;
  1307.          oy = y0;
  1308.          px = x0;
  1309.          py = y0;
  1310.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1311.          stroker_line_to((struct stroker *)&stroker, x0, y0);
  1312.          break;
  1313.       case VG_HLINE_TO:
  1314.          data_at(&coords, p, 0, 1, data);
  1315.          x0 = data[0];
  1316.          y0 = oy;
  1317.          map_if_relative(ox, oy, relative, &x0, 0);
  1318.          ox = x0;
  1319.          px = x0;
  1320.          py = y0;
  1321.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1322.          stroker_line_to((struct stroker *)&stroker, x0, y0);
  1323.          break;
  1324.       case VG_VLINE_TO:
  1325.          data_at(&coords, p, 0, 1, data);
  1326.          x0 = ox;
  1327.          y0 = data[0];
  1328.          map_if_relative(ox, oy, relative, 0, &y0);
  1329.          oy = y0;
  1330.          px = x0;
  1331.          py = y0;
  1332.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1333.          stroker_line_to((struct stroker *)&stroker, x0, y0);
  1334.          break;
  1335.       case VG_CUBIC_TO: {
  1336.          data_at(&coords, p, 0, 6, data);
  1337.          x0 = ox;
  1338.          y0 = oy;
  1339.          x1 = data[0];
  1340.          y1 = data[1];
  1341.          x2 = data[2];
  1342.          y2 = data[3];
  1343.          x3 = data[4];
  1344.          y3 = data[5];
  1345.          map_if_relative(ox, oy, relative, &x1, &y1);
  1346.          map_if_relative(ox, oy, relative, &x2, &y2);
  1347.          map_if_relative(ox, oy, relative, &x3, &y3);
  1348.          if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
  1349.              floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
  1350.              floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
  1351.             /*ignore the empty segment */
  1352.             continue;
  1353.          } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
  1354.             /* if dup vertex, emit a line */
  1355.             ox = x3;
  1356.             oy = y3;
  1357.             matrix_map_point(matrix, x3, y3, &x3, &y3);
  1358.             stroker_line_to((struct stroker *)&stroker, x3, y3);
  1359.             continue;
  1360.          }
  1361.          ox = x3;
  1362.          oy = y3;
  1363.          px = x2;
  1364.          py = y2;
  1365.          assert(matrix_is_affine(matrix));
  1366.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1367.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  1368.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  1369.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  1370.          stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
  1371.       }
  1372.          break;
  1373.       case VG_QUAD_TO: {
  1374.          data_at(&coords, p, 0, 4, data);
  1375.          x0 = ox;
  1376.          y0 = oy;
  1377.          x1 = data[0];
  1378.          y1 = data[1];
  1379.          x3 = data[2];
  1380.          y3 = data[3];
  1381.          map_if_relative(ox, oy, relative, &x1, &y1);
  1382.          map_if_relative(ox, oy, relative, &x3, &y3);
  1383.          px = x1;
  1384.          py = y1;
  1385.          { /* form a cubic out of it */
  1386.             x2 = (x3 + 2*x1) / 3.f;
  1387.             y2 = (y3 + 2*y1) / 3.f;
  1388.             x1 = (x0 + 2*x1) / 3.f;
  1389.             y1 = (y0 + 2*y1) / 3.f;
  1390.          }
  1391.          if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
  1392.              floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
  1393.              floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
  1394.             /*ignore the empty segment */
  1395.             continue;
  1396.          } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
  1397.             /* if dup vertex, emit a line */
  1398.             ox = x3;
  1399.             oy = y3;
  1400.             matrix_map_point(matrix, x3, y3, &x3, &y3);
  1401.             stroker_line_to((struct stroker *)&stroker, x3, y3);
  1402.             continue;
  1403.          }
  1404.          ox = x3;
  1405.          oy = y3;
  1406.          assert(matrix_is_affine(matrix));
  1407.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1408.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  1409.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  1410.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  1411.          stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
  1412.       }
  1413.          break;
  1414.       case VG_SQUAD_TO: {
  1415.          data_at(&coords, p, 0, 2, data);
  1416.          x0 = ox;
  1417.          y0 = oy;
  1418.          x1 = 2*ox-px;
  1419.          y1 = 2*oy-py;
  1420.          x3 = data[0];
  1421.          y3 = data[1];
  1422.          map_if_relative(ox, oy, relative, &x3, &y3);
  1423.          px = x1;
  1424.          py = y1;
  1425.          { /* form a cubic out of it */
  1426.             x2 = (x3 + 2*x1) / 3.f;
  1427.             y2 = (y3 + 2*y1) / 3.f;
  1428.             x1 = (x0 + 2*x1) / 3.f;
  1429.             y1 = (y0 + 2*y1) / 3.f;
  1430.          }
  1431.          if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
  1432.              floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
  1433.              floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
  1434.             /*ignore the empty segment */
  1435.             continue;
  1436.          } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
  1437.             /* if dup vertex, emit a line */
  1438.             ox = x3;
  1439.             oy = y3;
  1440.             matrix_map_point(matrix, x3, y3, &x3, &y3);
  1441.             stroker_line_to((struct stroker *)&stroker, x3, y3);
  1442.             continue;
  1443.          }
  1444.          ox = x3;
  1445.          oy = y3;
  1446.          assert(matrix_is_affine(matrix));
  1447.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1448.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  1449.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  1450.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  1451.          stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
  1452.       }
  1453.          break;
  1454.       case VG_SCUBIC_TO: {
  1455.          data_at(&coords, p, 0, 4, data);
  1456.          x0 = ox;
  1457.          y0 = oy;
  1458.          x1 = 2*ox-px;
  1459.          y1 = 2*oy-py;
  1460.          x2 = data[0];
  1461.          y2 = data[1];
  1462.          x3 = data[2];
  1463.          y3 = data[3];
  1464.          map_if_relative(ox, oy, relative, &x2, &y2);
  1465.          map_if_relative(ox, oy, relative, &x3, &y3);
  1466.          if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
  1467.              floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
  1468.              floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
  1469.             /*ignore the empty segment */
  1470.             continue;
  1471.          } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
  1472.             /* if dup vertex, emit a line */
  1473.             ox = x3;
  1474.             oy = y3;
  1475.             matrix_map_point(matrix, x3, y3, &x3, &y3);
  1476.             stroker_line_to((struct stroker *)&stroker, x3, y3);
  1477.             continue;
  1478.          }
  1479.          ox = x3;
  1480.          oy = y3;
  1481.          px = x2;
  1482.          py = y2;
  1483.          assert(matrix_is_affine(matrix));
  1484.          matrix_map_point(matrix, x0, y0, &x0, &y0);
  1485.          matrix_map_point(matrix, x1, y1, &x1, &y1);
  1486.          matrix_map_point(matrix, x2, y2, &x2, &y2);
  1487.          matrix_map_point(matrix, x3, y3, &x3, &y3);
  1488.          stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
  1489.       }
  1490.          break;
  1491.       case VG_SCCWARC_TO:
  1492.       case VG_SCWARC_TO:
  1493.       case VG_LCCWARC_TO:
  1494.       case VG_LCWARC_TO: {
  1495.          VGfloat rh, rv, rot;
  1496.          struct arc arc;
  1497.  
  1498.          data_at(&coords, p, 0, 5, data);
  1499.          x0  = ox;
  1500.          y0  = oy;
  1501.          rh  = data[0];
  1502.          rv  = data[1];
  1503.          rot = data[2];
  1504.          x1  = data[3];
  1505.          y1  = data[4];
  1506.          map_if_relative(ox, oy, relative, &x1, &y1);
  1507.          if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) {
  1508.             /* if dup vertex, emit a line */
  1509.             ox = x1;
  1510.             oy = y1;
  1511.             matrix_map_point(matrix, x1, y1, &x1, &y1);
  1512.             stroker_line_to((struct stroker *)&stroker, x1, y1);
  1513.             continue;
  1514.          }
  1515.          arc_init(&arc, command, x0, y0, x1, y1,
  1516.                   rh, rv, rot);
  1517.          arc_stroke_cb(&arc, (struct stroker *)&stroker,
  1518.                        matrix);
  1519.          ox = x1;
  1520.          oy = y1;
  1521.          px = x1;
  1522.          py = y1;
  1523.       }
  1524.          break;
  1525.       default:
  1526.          abort();
  1527.          assert(!"Unknown segment!");
  1528.       }
  1529.    }
  1530.  
  1531.    stroker_end((struct stroker *)&stroker);
  1532.  
  1533.    if (dashed)
  1534.       dash_stroker_cleanup((struct dash_stroker *)&stroker);
  1535.    else
  1536.       stroker_cleanup((struct stroker *)&stroker);
  1537.  
  1538.    p->stroked.path = stroker.base.path;
  1539.    p->stroked.matrix = *matrix;
  1540.    p->dirty_stroke = VG_FALSE;
  1541.    p->stroked.stroke_width = vg_state->stroke.line_width.f;
  1542.    p->stroked.miter_limit = vg_state->stroke.miter_limit.f;
  1543.    p->stroked.cap_style = vg_state->stroke.cap_style;
  1544.    p->stroked.join_style = vg_state->stroke.join_style;
  1545.  
  1546.    return stroker.base.path;
  1547. }
  1548.  
  1549. void path_render(struct path *p, VGbitfield paintModes,
  1550.                  struct matrix *mat)
  1551. {
  1552.    struct vg_context *ctx = vg_current_context();
  1553.    struct matrix paint_matrix;
  1554.  
  1555.    vg_validate_state(ctx);
  1556.  
  1557.    shader_set_drawing_image(ctx->shader, VG_FALSE);
  1558.    shader_set_image(ctx->shader, 0);
  1559. #if 0
  1560.    fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
  1561.            mat->m[0], mat->m[1], mat->m[2],
  1562.            mat->m[3], mat->m[4], mat->m[5],
  1563.            mat->m[6], mat->m[7], mat->m[8]);
  1564. #endif
  1565.    if ((paintModes & VG_FILL_PATH) &&
  1566.        vg_get_paint_matrix(ctx,
  1567.                            &ctx->state.vg.fill_paint_to_user_matrix,
  1568.                            mat,
  1569.                            &paint_matrix)) {
  1570.       /* First the fill */
  1571.       shader_set_surface_matrix(ctx->shader, mat);
  1572.       shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
  1573.       shader_set_paint_matrix(ctx->shader, &paint_matrix);
  1574.       shader_bind(ctx->shader);
  1575.       path_fill(p);
  1576.    }
  1577.  
  1578.    if ((paintModes & VG_STROKE_PATH) &&
  1579.        vg_get_paint_matrix(ctx,
  1580.                            &ctx->state.vg.stroke_paint_to_user_matrix,
  1581.                            mat,
  1582.                            &paint_matrix)) {
  1583.       /* 8.7.5: "line width less than or equal to 0 prevents stroking from
  1584.        *  taking place."*/
  1585.       if (ctx->state.vg.stroke.line_width.f <= 0)
  1586.          return;
  1587.       shader_set_surface_matrix(ctx->shader, mat);
  1588.       shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint);
  1589.       shader_set_paint_matrix(ctx->shader, &paint_matrix);
  1590.       shader_bind(ctx->shader);
  1591.       path_stroke(p);
  1592.    }
  1593. }
  1594.  
  1595. void path_fill(struct path *p)
  1596. {
  1597.    struct vg_context *ctx = vg_current_context();
  1598.    struct matrix identity;
  1599.  
  1600.    matrix_load_identity(&identity);
  1601.  
  1602.    {
  1603.       struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity);
  1604.       struct array *polys = polygon_array->array;
  1605.  
  1606.       if (!polygon_array || !polys || !polys->num_elements) {
  1607.          return;
  1608.       }
  1609.       polygon_array_fill(polygon_array, ctx);
  1610.    }
  1611. }
  1612.  
  1613. void path_stroke(struct path *p)
  1614. {
  1615.    struct vg_context *ctx = vg_current_context();
  1616.    VGFillRule old_fill = ctx->state.vg.fill_rule;
  1617.    struct matrix identity;
  1618.    struct path *stroke;
  1619.  
  1620.    matrix_load_identity(&identity);
  1621.    stroke = path_create_stroke(p, &identity);
  1622.    if (stroke && !path_is_empty(stroke)) {
  1623.       ctx->state.vg.fill_rule = VG_NON_ZERO;
  1624.  
  1625.       path_fill(stroke);
  1626.  
  1627.       ctx->state.vg.fill_rule = old_fill;
  1628.    }
  1629. }
  1630.  
  1631. void path_move_to(struct path *p, float x, float y)
  1632. {
  1633.    VGubyte segment = VG_MOVE_TO_ABS;
  1634.    VGubyte common_data[sizeof(VGfloat) * 2];
  1635.    VGfloat data[2] = {x, y};
  1636.  
  1637.    vg_float_to_datatype(p->datatype, common_data, data, 2);
  1638.    path_append_data(p, 1, &segment, common_data);
  1639. }
  1640.  
  1641. void path_line_to(struct path *p, float x, float y)
  1642. {
  1643.    VGubyte segment = VG_LINE_TO_ABS;
  1644.    VGubyte common_data[sizeof(VGfloat) * 2];
  1645.    VGfloat data[2] = {x, y};
  1646.  
  1647.    vg_float_to_datatype(p->datatype, common_data, data, 2);
  1648.  
  1649.    path_append_data(p, 1, &segment, common_data);
  1650. }
  1651.  
  1652. void path_cubic_to(struct path *p, float px1, float py1,
  1653.                    float px2, float py2,
  1654.                    float x, float y)
  1655. {
  1656.    VGubyte segment = VG_CUBIC_TO_ABS;
  1657.    VGubyte common_data[sizeof(VGfloat) * 6];
  1658.    VGfloat data[6];
  1659.  
  1660.    data[0] = px1; data[1] = py1;
  1661.    data[2] = px2; data[3] = py2;
  1662.    data[4] = x;   data[5] = y;
  1663.  
  1664.    vg_float_to_datatype(p->datatype, common_data, data, 6);
  1665.  
  1666.    path_append_data(p, 1, &segment, common_data);
  1667. }
  1668.  
  1669. static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/,
  1670.                                VGfloat *bounds)
  1671. {
  1672.    bounds[0] = MIN2(line[0], line[2]);
  1673.    bounds[1] = MIN2(line[1], line[3]);
  1674.    bounds[2] = MAX2(line[0], line[2]) - bounds[0];
  1675.    bounds[3] = MAX2(line[1], line[3]) - bounds[1];
  1676. }
  1677.  
  1678. static INLINE void unite_bounds(VGfloat *bounds,
  1679.                                 VGfloat *el)
  1680. {
  1681.    VGfloat cx1, cy1, cx2, cy2;
  1682.    VGfloat nx1, ny1, nx2, ny2;
  1683.  
  1684.    cx1 = bounds[0];
  1685.    cy1 = bounds[1];
  1686.    cx2 = bounds[0] + bounds[2];
  1687.    cy2 = bounds[1] + bounds[3];
  1688.  
  1689.    nx1 = el[0];
  1690.    ny1 = el[1];
  1691.    nx2 = el[0] + el[2];
  1692.    ny2 = el[1] + el[3];
  1693.  
  1694.    bounds[0] = MIN2(cx1, nx1);
  1695.    bounds[1] = MIN2(cy1, ny1);
  1696.    bounds[2] = MAX2(cx2, nx2) - bounds[0];
  1697.    bounds[3] = MAX2(cy2, ny2) - bounds[1];
  1698. }
  1699.  
  1700. static INLINE void set_bounds(VGfloat *bounds,
  1701.                               VGfloat *element_bounds,
  1702.                               VGboolean *initialized)
  1703. {
  1704.    if (!(*initialized)) {
  1705.       memcpy(bounds, element_bounds, 4 * sizeof(VGfloat));
  1706.       *initialized = VG_TRUE;
  1707.    } else
  1708.       unite_bounds(bounds, element_bounds);
  1709. }
  1710.  
  1711. void path_bounding_rect(struct path *p, float *x, float *y,
  1712.                         float *w, float *h)
  1713. {
  1714.    VGint i;
  1715.    VGfloat coords[8];
  1716.    struct path_iter_data iter;
  1717.    VGint num_coords;
  1718.    VGfloat bounds[4];
  1719.    VGfloat element_bounds[4];
  1720.    VGfloat ox, oy;
  1721.    VGboolean bounds_inited = VG_FALSE;
  1722.  
  1723.    memset(&iter, 0, sizeof(struct path_iter_data));
  1724.    memset(&bounds, 0, sizeof(bounds));
  1725.  
  1726.    if (!p->num_segments) {
  1727.       bounds[2] = -1;
  1728.       bounds[3] = -1;
  1729.    }
  1730.  
  1731.  
  1732.    iter.path = p;
  1733.    iter.coords = p->control_points->data;
  1734.  
  1735.    for (i = 0; i < p->num_segments; ++i) {
  1736.       VGubyte segment;
  1737.       iter.segment = ((VGubyte*)(p->segments->data))[i];
  1738.  
  1739.       ox = iter.ox;
  1740.       oy = iter.oy;
  1741.  
  1742.       segment = normalize_coords(&iter, &num_coords, coords);
  1743.  
  1744.       switch(segment) {
  1745.       case VG_CLOSE_PATH:
  1746.       case VG_MOVE_TO_ABS:
  1747.          break;
  1748.       case VG_LINE_TO_ABS: {
  1749.          VGfloat line[4] = {ox, oy, coords[0], coords[1]};
  1750.          line_bounds(line, element_bounds);
  1751.          set_bounds(bounds, element_bounds, &bounds_inited);
  1752.       }
  1753.          break;
  1754.       case VG_CUBIC_TO_ABS: {
  1755.          struct bezier bezier;
  1756.          bezier_init(&bezier, ox, oy,
  1757.                      coords[0], coords[1],
  1758.                      coords[2], coords[3],
  1759.                      coords[4], coords[5]);
  1760.          bezier_exact_bounds(&bezier, element_bounds);
  1761.          set_bounds(bounds, element_bounds, &bounds_inited);
  1762.       }
  1763.          break;
  1764.       case VG_SCCWARC_TO:
  1765.       case VG_SCWARC_TO:
  1766.       case VG_LCCWARC_TO:
  1767.       case VG_LCWARC_TO: {
  1768.          struct arc arc;
  1769.          struct matrix identity;
  1770.          struct path *path = path_create(VG_PATH_DATATYPE_F,
  1771.                                          1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
  1772.  
  1773.          matrix_load_identity(&identity);
  1774.          arc_init(&arc, segment,
  1775.                   ox, oy, coords[3], coords[4],
  1776.                   coords[0], coords[1], coords[2]);
  1777.  
  1778.          arc_to_path(&arc, path, &identity);
  1779.  
  1780.          path_bounding_rect(path, element_bounds + 0, element_bounds + 1,
  1781.                             element_bounds + 2, element_bounds + 3);
  1782.          set_bounds(bounds, element_bounds, &bounds_inited);
  1783.       }
  1784.          break;
  1785.       default:
  1786.          assert(0);
  1787.       }
  1788.    }
  1789.  
  1790.    *x = bounds[0];
  1791.    *y = bounds[1];
  1792.    *w = bounds[2];
  1793.    *h = bounds[3];
  1794. }
  1795.  
  1796. float path_length(struct path *p, int start_segment, int num_segments)
  1797. {
  1798.    VGint i;
  1799.    VGfloat coords[8];
  1800.    struct path_iter_data iter;
  1801.    VGint num_coords;
  1802.    VGfloat length = 0;
  1803.    VGfloat ox, oy;
  1804.    VGboolean in_range = VG_FALSE;
  1805.  
  1806.    memset(&iter, 0, sizeof(struct path_iter_data));
  1807.  
  1808.    iter.path = p;
  1809.    iter.coords = p->control_points->data;
  1810.  
  1811.    for (i = 0; i < (start_segment + num_segments); ++i) {
  1812.       VGubyte segment;
  1813.  
  1814.       iter.segment = ((VGubyte*)(p->segments->data))[i];
  1815.  
  1816.       ox = iter.ox;
  1817.       oy = iter.oy;
  1818.  
  1819.       segment = normalize_coords(&iter, &num_coords, coords);
  1820.  
  1821.       in_range = (i >= start_segment) && i <= (start_segment + num_segments);
  1822.       if (!in_range)
  1823.          continue;
  1824.  
  1825.       switch(segment) {
  1826.       case VG_MOVE_TO_ABS:
  1827.          break;
  1828.       case VG_CLOSE_PATH: {
  1829.          VGfloat line[4] = {ox, oy, iter.sx, iter.sy};
  1830.          length += line_lengthv(line);
  1831.       }
  1832.          break;
  1833.       case VG_LINE_TO_ABS: {
  1834.          VGfloat line[4] = {ox, oy, coords[0], coords[1]};
  1835.          length += line_lengthv(line);
  1836.       }
  1837.          break;
  1838.       case VG_CUBIC_TO_ABS: {
  1839.          struct bezier bezier;
  1840.          bezier_init(&bezier, ox, oy,
  1841.                      coords[0], coords[1],
  1842.                      coords[2], coords[3],
  1843.                      coords[4], coords[5]);
  1844.          length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
  1845.       }
  1846.          break;
  1847.       case VG_SCCWARC_TO:
  1848.       case VG_SCWARC_TO:
  1849.       case VG_LCCWARC_TO:
  1850.       case VG_LCWARC_TO: {
  1851.          struct arc arc;
  1852.          struct matrix identity;
  1853.          struct path *path = path_create(VG_PATH_DATATYPE_F,
  1854.                                          1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
  1855.  
  1856.          matrix_load_identity(&identity);
  1857.          arc_init(&arc, segment,
  1858.                   ox, oy, coords[3], coords[4],
  1859.                   coords[0], coords[1], coords[2]);
  1860.  
  1861.          arc_to_path(&arc, path, &identity);
  1862.  
  1863.          length += path_length(path, 0, path_num_segments(path));
  1864.       }
  1865.          break;
  1866.       default:
  1867.          assert(0);
  1868.       }
  1869.    }
  1870.  
  1871.    return length;
  1872. }
  1873.  
  1874. static INLINE VGboolean point_on_current_segment(VGfloat distance,
  1875.                                                  VGfloat length,
  1876.                                                  VGfloat segment_length)
  1877. {
  1878.    return
  1879.       (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) ||
  1880.        ((distance > length || floatsEqual(distance, length)) &&
  1881.         (floatsEqual(distance, length + segment_length) ||
  1882.          distance < (length + segment_length))));
  1883. }
  1884.  
  1885. static VGboolean path_point_segment(struct path_iter_data iter,
  1886.                                     struct path_iter_data prev_iter,
  1887.                                     VGfloat coords[8],
  1888.                                     VGfloat distance,
  1889.                                     VGfloat length, VGfloat *current_length,
  1890.                                     VGfloat *point, VGfloat *normal)
  1891. {
  1892.    switch (iter.segment) {
  1893.    case VG_MOVE_TO_ABS:
  1894.       break;
  1895.    case VG_CLOSE_PATH: {
  1896.       VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
  1897.       VGboolean on_current_segment = VG_FALSE;
  1898.       *current_length = line_lengthv(line);
  1899.       on_current_segment = point_on_current_segment(distance,
  1900.                                                     length,
  1901.                                                     *current_length);
  1902.       if (on_current_segment) {
  1903.          VGfloat at = (distance - length) / line_lengthv(line);
  1904.          line_normal_vector(line, normal);
  1905.          line_point_at(line, at, point);
  1906.          return VG_TRUE;
  1907.       }
  1908.    }
  1909.       break;
  1910.    case VG_LINE_TO_ABS: {
  1911.       VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
  1912.       VGboolean on_current_segment = VG_FALSE;
  1913.       *current_length = line_lengthv(line);
  1914.       on_current_segment = point_on_current_segment(distance,
  1915.                                                     length,
  1916.                                                     *current_length);
  1917.       if (on_current_segment) {
  1918.          VGfloat at = (distance - length) / line_lengthv(line);
  1919.          line_normal_vector(line, normal);
  1920.          line_point_at(line, at, point);
  1921.          return VG_TRUE;
  1922.       }
  1923.    }
  1924.       break;
  1925.    case VG_CUBIC_TO_ABS: {
  1926.       struct bezier bezier;
  1927.       bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
  1928.                   coords[0], coords[1],
  1929.                   coords[2], coords[3],
  1930.                   coords[4], coords[5]);
  1931.       *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
  1932.       if (point_on_current_segment(distance, length, *current_length)) {
  1933.          bezier_point_at_length(&bezier, distance - length,
  1934.                                 point, normal);
  1935.          return VG_TRUE;
  1936.       }
  1937.    }
  1938.       break;
  1939.    case VG_SCCWARC_TO:
  1940.    case VG_SCWARC_TO:
  1941.    case VG_LCCWARC_TO:
  1942.    case VG_LCWARC_TO: {
  1943.       struct arc arc;
  1944.       struct matrix identity;
  1945.       struct path *path = path_create(VG_PATH_DATATYPE_F,
  1946.                                       1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
  1947.  
  1948.       matrix_load_identity(&identity);
  1949.       arc_init(&arc, iter.segment,
  1950.                prev_iter.ox, prev_iter.oy, coords[3], coords[4],
  1951.                coords[0], coords[1], coords[2]);
  1952.  
  1953.       arc_to_path(&arc, path, &identity);
  1954.  
  1955.       *current_length = path_length(path, 0, path_num_segments(path));
  1956.       if (point_on_current_segment(distance, length, *current_length)) {
  1957.          path_point(path, 0, path_num_segments(path),
  1958.                     distance - length, point, normal);
  1959.          return VG_TRUE;
  1960.       }
  1961.    }
  1962.       break;
  1963.    default:
  1964.       assert(0);
  1965.    }
  1966.    return VG_FALSE;
  1967. }
  1968.  
  1969. void path_point(struct path *p, VGint start_segment, VGint num_segments,
  1970.                 VGfloat distance, VGfloat *point, VGfloat *normal)
  1971. {
  1972.    VGint i;
  1973.    VGfloat coords[8];
  1974.    struct path_iter_data iter, prev_iter;
  1975.    VGint num_coords;
  1976.    VGfloat length = 0;
  1977.    VGfloat current_length = 0;
  1978.  
  1979.    memset(&iter, 0, sizeof(struct path_iter_data));
  1980.    memset(&prev_iter, 0, sizeof(struct path_iter_data));
  1981.  
  1982.    point[0] = 0;
  1983.    point[1] = 0;
  1984.  
  1985.    normal[0] = 0;
  1986.    normal[1] = -1;
  1987.  
  1988.    iter.path = p;
  1989.    iter.coords = p->control_points->data;
  1990.    if (distance < 0)
  1991.       distance = 0;
  1992.  
  1993.    for (i = 0; i < (start_segment + num_segments); ++i) {
  1994.       VGboolean outside_range = (i < start_segment ||
  1995.                                  i >= (start_segment + num_segments));
  1996.  
  1997.       prev_iter = iter;
  1998.  
  1999.       iter.segment = ((VGubyte*)(p->segments->data))[i];
  2000.       iter.segment = normalize_coords(&iter, &num_coords, coords);
  2001.  
  2002.       if (outside_range)
  2003.          continue;
  2004.  
  2005.       if (path_point_segment(iter, prev_iter, coords,
  2006.                              distance, length, &current_length,
  2007.                              point, normal))
  2008.          return;
  2009.  
  2010.       length += current_length;
  2011.    }
  2012.  
  2013.    /*
  2014.     *OpenVG 1.0 - 8.6.11 vgPointAlongPath
  2015.     *
  2016.     * If distance is greater than or equal to the path length
  2017.     *(i.e., the value returned by vgPathLength when called with the same
  2018.     *startSegment and numSegments parameters), the visual ending point of
  2019.     *the path is used.
  2020.     */
  2021.    {
  2022.       switch (iter.segment) {
  2023.       case VG_MOVE_TO_ABS:
  2024.          break;
  2025.       case VG_CLOSE_PATH: {
  2026.          VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
  2027.          line_normal_vector(line, normal);
  2028.          line_point_at(line, 1.f, point);
  2029.       }
  2030.          break;
  2031.       case VG_LINE_TO_ABS: {
  2032.          VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
  2033.          line_normal_vector(line, normal);
  2034.          line_point_at(line, 1.f, point);
  2035.       }
  2036.          break;
  2037.       case VG_CUBIC_TO_ABS: {
  2038.          struct bezier bezier;
  2039.          bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
  2040.                      coords[0], coords[1],
  2041.                      coords[2], coords[3],
  2042.                      coords[4], coords[5]);
  2043.          bezier_point_at_t(&bezier, 1.f, point, normal);
  2044.       }
  2045.          break;
  2046.       case VG_SCCWARC_TO:
  2047.       case VG_SCWARC_TO:
  2048.       case VG_LCCWARC_TO:
  2049.       case VG_LCWARC_TO: {
  2050.          struct arc arc;
  2051.          struct matrix identity;
  2052.          struct path *path = path_create(VG_PATH_DATATYPE_F,
  2053.                                          1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
  2054.  
  2055.          matrix_load_identity(&identity);
  2056.          arc_init(&arc, iter.segment,
  2057.                   prev_iter.ox, prev_iter.oy, coords[3], coords[4],
  2058.                   coords[0], coords[1], coords[2]);
  2059.  
  2060.          arc_to_path(&arc, path, &identity);
  2061.  
  2062.          path_point(path, 0, path_num_segments(path),
  2063.                     /* to make sure we're bigger than len * 2 it */
  2064.                     2 * path_length(path, 0, path_num_segments(path)),
  2065.                     point, normal);
  2066.       }
  2067.          break;
  2068.       default:
  2069.          assert(0);
  2070.       }
  2071.    }
  2072. }
  2073.  
  2074. VGboolean path_is_empty(struct path *p)
  2075. {
  2076.    return p->segments->num_elements == 0;
  2077. }
  2078.