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