diff options
Diffstat (limited to 'src/gallium/state_trackers/vega/path.c')
-rw-r--r-- | src/gallium/state_trackers/vega/path.c | 2077 |
1 files changed, 0 insertions, 2077 deletions
diff --git a/src/gallium/state_trackers/vega/path.c b/src/gallium/state_trackers/vega/path.c deleted file mode 100644 index 6448e642cd6..00000000000 --- a/src/gallium/state_trackers/vega/path.c +++ /dev/null @@ -1,2077 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "path.h" - -#include "stroker.h" -#include "polygon.h" -#include "bezier.h" -#include "matrix.h" -#include "vg_context.h" -#include "util_array.h" -#include "arc.h" -#include "path_utils.h" -#include "paint.h" -#include "shader.h" - -#include "util/u_memory.h" - -#include <assert.h> - -#define DEBUG_PATH 0 - -struct path { - struct vg_object base; - VGbitfield caps; - VGboolean dirty; - VGboolean dirty_stroke; - - VGPathDatatype datatype; - - VGfloat scale; - VGfloat bias; - - VGint num_segments; - - struct array * segments; - struct array * control_points; - - struct { - struct polygon_array polygon_array; - struct matrix matrix; - } fill_polys; - - struct { - struct path *path; - struct matrix matrix; - VGfloat stroke_width; - VGfloat miter_limit; - VGCapStyle cap_style; - VGJoinStyle join_style; - } stroked; -}; - - -static INLINE void data_at(void **data, - struct path *p, - VGint start, VGint count, - VGfloat *out) -{ - VGPathDatatype dt = p->datatype; - VGint i; - VGint end = start + count; - VGfloat *itr = out; - - switch(dt) { - case VG_PATH_DATATYPE_S_8: { - VGbyte **bdata = (VGbyte **)data; - for (i = start; i < end; ++i) { - *itr = (*bdata)[i]; - ++itr; - } - *bdata += count; - } - break; - case VG_PATH_DATATYPE_S_16: { - VGshort **bdata = (VGshort **)data; - for (i = start; i < end; ++i) { - *itr = (*bdata)[i]; - ++itr; - } - *bdata += count; - } - break; - case VG_PATH_DATATYPE_S_32: { - VGint **bdata = (VGint **)data; - for (i = start; i < end; ++i) { - *itr = (*bdata)[i]; - ++itr; - } - *bdata += count; - } - break; - case VG_PATH_DATATYPE_F: { - VGfloat **fdata = (VGfloat **)data; - for (i = start; i < end; ++i) { - *itr = (*fdata)[i]; - ++itr; - } - *fdata += count; - } - break; - default: - debug_assert(!"Unknown path datatype!"); - } -} - - -void vg_float_to_datatype(VGPathDatatype datatype, - VGubyte *common_data, - const VGfloat *data, - VGint num_coords) -{ - VGint i; - switch(datatype) { - case VG_PATH_DATATYPE_S_8: { - for (i = 0; i < num_coords; ++i) { - common_data[i] = (VGubyte)data[i]; - } - } - break; - case VG_PATH_DATATYPE_S_16: { - VGshort *buf = (VGshort*)common_data; - for (i = 0; i < num_coords; ++i) { - buf[i] = (VGshort)data[i]; - } - } - break; - case VG_PATH_DATATYPE_S_32: { - VGint *buf = (VGint*)common_data; - for (i = 0; i < num_coords; ++i) { - buf[i] = (VGint)data[i]; - } - } - break; - case VG_PATH_DATATYPE_F: { - memcpy(common_data, data, sizeof(VGfloat) * num_coords); - } - break; - default: - debug_assert(!"Unknown path datatype!"); - } -} - -static void coords_adjust_by_scale_bias(struct path *p, - void *pdata, VGint num_coords, - VGfloat scale, VGfloat bias, - VGPathDatatype datatype) -{ - VGfloat data[8]; - void *coords = (VGfloat *)pdata; - VGubyte *common_data = (VGubyte *)pdata; - VGint size_dst = size_for_datatype(datatype); - VGint i; - - for (i = 0; i < num_coords; ++i) { - data_at(&coords, p, 0, 1, data); - data[0] = data[0] * scale + bias; - vg_float_to_datatype(datatype, common_data, data, 1); - common_data += size_dst; - } -} - -struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias, - VGint segmentCapacityHint, - VGint coordCapacityHint, - VGbitfield capabilities) -{ - struct path *path = CALLOC_STRUCT(path); - - vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH); - path->caps = capabilities & VG_PATH_CAPABILITY_ALL; - vg_context_add_object(vg_current_context(), &path->base); - - path->datatype = dt; - path->scale = scale; - path->bias = bias; - - path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); - path->control_points = array_create(size_for_datatype(dt)); - - path->dirty = VG_TRUE; - path->dirty_stroke = VG_TRUE; - - return path; -} - -static void polygon_array_cleanup(struct polygon_array *polyarray) -{ - if (polyarray->array) { - VGint i; - - for (i = 0; i < polyarray->array->num_elements; i++) { - struct polygon *p = ((struct polygon **) polyarray->array->data)[i]; - polygon_destroy(p); - } - - array_destroy(polyarray->array); - polyarray->array = NULL; - } -} - -void path_destroy(struct path *p) -{ - vg_context_remove_object(vg_current_context(), &p->base); - - array_destroy(p->segments); - array_destroy(p->control_points); - - polygon_array_cleanup(&p->fill_polys.polygon_array); - - if (p->stroked.path) - path_destroy(p->stroked.path); - - vg_free_object(&p->base); - - FREE(p); -} - -VGbitfield path_capabilities(struct path *p) -{ - return p->caps; -} - -void path_set_capabilities(struct path *p, VGbitfield bf) -{ - p->caps = (bf & VG_PATH_CAPABILITY_ALL); -} - -void path_append_data(struct path *p, - VGint numSegments, - const VGubyte * pathSegments, - const void * pathData) -{ - VGint old_segments = p->num_segments; - VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments); - array_append_data(p->segments, pathSegments, numSegments); - array_append_data(p->control_points, pathData, num_new_coords); - - p->num_segments += numSegments; - if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) { - VGubyte *coords = (VGubyte*)p->control_points->data; - coords_adjust_by_scale_bias(p, - coords + old_segments * p->control_points->datatype_size, - num_new_coords, - p->scale, p->bias, p->datatype); - } - p->dirty = VG_TRUE; - p->dirty_stroke = VG_TRUE; -} - -VGint path_num_segments(struct path *p) -{ - return p->num_segments; -} - -static INLINE void map_if_relative(VGfloat ox, VGfloat oy, - VGboolean relative, - VGfloat *x, VGfloat *y) -{ - if (relative) { - if (x) - *x += ox; - if (y) - *y += oy; - } -} - -static INLINE void close_polygon(struct polygon *current, - VGfloat sx, VGfloat sy, - VGfloat ox, VGfloat oy, - struct matrix *matrix) -{ - if (!floatsEqual(sx, ox) || - !floatsEqual(sy, oy)) { - VGfloat x0 = sx; - VGfloat y0 = sy; - matrix_map_point(matrix, x0, y0, &x0, &y0); - polygon_vertex_append(current, x0, y0); - } -} - -static void convert_path(struct path *p, - VGPathDatatype to, - void *dst, - VGint num_coords) -{ - VGfloat data[8]; - void *coords = (VGfloat *)p->control_points->data; - VGubyte *common_data = (VGubyte *)dst; - VGint size_dst = size_for_datatype(to); - VGint i; - - for (i = 0; i < num_coords; ++i) { - data_at(&coords, p, 0, 1, data); - vg_float_to_datatype(to, common_data, data, 1); - common_data += size_dst; - } -} - -static void polygon_array_calculate_bounds( struct polygon_array *polyarray ) -{ - struct array *polys = polyarray->array; - VGfloat min_x, max_x; - VGfloat min_y, max_y; - VGfloat bounds[4]; - unsigned i; - - assert(polys); - - if (!polys->num_elements) { - polyarray->min_x = 0.0f; - polyarray->min_y = 0.0f; - polyarray->max_x = 0.0f; - polyarray->max_y = 0.0f; - return; - } - - polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds); - min_x = bounds[0]; - min_y = bounds[1]; - max_x = bounds[0] + bounds[2]; - max_y = bounds[1] + bounds[3]; - for (i = 1; i < polys->num_elements; ++i) { - struct polygon *p = (((struct polygon**)polys->data)[i]); - polygon_bounding_rect(p, bounds); - min_x = MIN2(min_x, bounds[0]); - min_y = MIN2(min_y, bounds[1]); - max_x = MAX2(max_x, bounds[0] + bounds[2]); - max_y = MAX2(max_y, bounds[1] + bounds[3]); - } - - polyarray->min_x = min_x; - polyarray->min_y = min_y; - polyarray->max_x = max_x; - polyarray->max_y = max_y; -} - - -static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix) -{ - VGint i; - struct polygon *current = 0; - VGfloat sx, sy, px, py, ox, oy; - VGfloat x0, y0, x1, y1, x2, y2, x3, y3; - VGfloat data[8]; - void *coords = (VGfloat *)p->control_points->data; - struct array *array; - - memset(data, 0, sizeof(data)); - - if (p->fill_polys.polygon_array.array) - { - if (memcmp( &p->fill_polys.matrix, - matrix, - sizeof *matrix ) == 0 && p->dirty == VG_FALSE) - { - return &p->fill_polys.polygon_array; - } - else { - polygon_array_cleanup(&p->fill_polys.polygon_array); - } - } - - /* an array of pointers to polygons */ - array = array_create(sizeof(struct polygon *)); - - sx = sy = px = py = ox = oy = 0.f; - - if (p->num_segments) - current = polygon_create(32); - - for (i = 0; i < p->num_segments; ++i) { - VGubyte segment = ((VGubyte*)(p->segments->data))[i]; - VGint command = SEGMENT_COMMAND(segment); - VGboolean relative = SEGMENT_ABS_REL(segment); - - switch(command) { - case VG_CLOSE_PATH: - close_polygon(current, sx, sy, ox, oy, matrix); - ox = sx; - oy = sy; - break; - case VG_MOVE_TO: - if (current && polygon_vertex_count(current) > 0) { - /* add polygon */ - close_polygon(current, sx, sy, ox, oy, matrix); - array_append_data(array, ¤t, 1); - current = polygon_create(32); - } - data_at(&coords, p, 0, 2, data); - x0 = data[0]; - y0 = data[1]; - map_if_relative(ox, oy, relative, &x0, &y0); - sx = x0; - sy = y0; - ox = x0; - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - polygon_vertex_append(current, x0, y0); - break; - case VG_LINE_TO: - data_at(&coords, p, 0, 2, data); - x0 = data[0]; - y0 = data[1]; - map_if_relative(ox, oy, relative, &x0, &y0); - ox = x0; - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - polygon_vertex_append(current, x0, y0); - break; - case VG_HLINE_TO: - data_at(&coords, p, 0, 1, data); - x0 = data[0]; - y0 = oy; - map_if_relative(ox, oy, relative, &x0, 0); - ox = x0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - polygon_vertex_append(current, x0, y0); - break; - case VG_VLINE_TO: - data_at(&coords, p, 0, 1, data); - x0 = ox; - y0 = data[0]; - map_if_relative(ox, oy, relative, 0, &y0); - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - polygon_vertex_append(current, x0, y0); - break; - case VG_CUBIC_TO: { - struct bezier bezier; - data_at(&coords, p, 0, 6, data); - x0 = ox; - y0 = oy; - x1 = data[0]; - y1 = data[1]; - x2 = data[2]; - y2 = data[3]; - x3 = data[4]; - y3 = data[5]; - map_if_relative(ox, oy, relative, &x1, &y1); - map_if_relative(ox, oy, relative, &x2, &y2); - map_if_relative(ox, oy, relative, &x3, &y3); - ox = x3; - oy = y3; - px = x2; - py = y2; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - bezier_init(&bezier, x0, y0, x1, y1, - x2, y2, x3, y3); - bezier_add_to_polygon(&bezier, current); - } - break; - case VG_QUAD_TO: { - struct bezier bezier; - data_at(&coords, p, 0, 4, data); - x0 = ox; - y0 = oy; - x1 = data[0]; - y1 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(ox, oy, relative, &x1, &y1); - map_if_relative(ox, oy, relative, &x3, &y3); - px = x1; - py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - ox = x3; - oy = y3; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - bezier_init(&bezier, x0, y0, x1, y1, - x2, y2, x3, y3); - bezier_add_to_polygon(&bezier, current); - } - break; - case VG_SQUAD_TO: { - struct bezier bezier; - data_at(&coords, p, 0, 2, data); - x0 = ox; - y0 = oy; - x1 = 2*ox-px; - y1 = 2*oy-py; - x3 = data[0]; - y3 = data[1]; - map_if_relative(ox, oy, relative, &x3, &y3); - px = x1; - py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - ox = x3; - oy = y3; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - bezier_init(&bezier, x0, y0, x1, y1, - x2, y2, x3, y3); - bezier_add_to_polygon(&bezier, current); - } - break; - case VG_SCUBIC_TO: { - struct bezier bezier; - data_at(&coords, p, 0, 4, data); - x0 = ox; - y0 = oy; - x1 = 2*ox-px; - y1 = 2*oy-py; - x2 = data[0]; - y2 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(ox, oy, relative, &x2, &y2); - map_if_relative(ox, oy, relative, &x3, &y3); - ox = x3; - oy = y3; - px = x2; - py = y2; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - bezier_init(&bezier, x0, y0, x1, y1, - x2, y2, x3, y3); - bezier_add_to_polygon(&bezier, current); - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - VGfloat rh, rv, rot; - struct arc arc; - - data_at(&coords, p, 0, 5, data); - x0 = ox; - y0 = oy; - rh = data[0]; - rv = data[1]; - rot = data[2]; - x1 = data[3]; - y1 = data[4]; - map_if_relative(ox, oy, relative, &x1, &y1); -#if 0 - debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", - x0, y0, x1, y1, rh, rv, rot); -#endif - arc_init(&arc, command, x0, y0, x1, y1, - rh, rv, rot); - arc_add_to_polygon(&arc, current, - matrix); - ox = x1; - oy = y1; - px = x1; - py = y1; - } - break; - default: - abort(); - assert(!"Unknown segment!"); - } - } - if (current) { - if (polygon_vertex_count(current) > 0) { - close_polygon(current, sx, sy, ox, oy, matrix); - array_append_data(array, ¤t, 1); - } else - polygon_destroy(current); - } - - p->fill_polys.polygon_array.array = array; - p->fill_polys.matrix = *matrix; - - polygon_array_calculate_bounds( &p->fill_polys.polygon_array ); - - p->dirty = VG_FALSE; - - return &p->fill_polys.polygon_array; -} - -VGbyte path_datatype_size(struct path *p) -{ - return size_for_datatype(p->datatype); -} - -VGPathDatatype path_datatype(struct path *p) -{ - return p->datatype; -} - -VGfloat path_scale(struct path *p) -{ - return p->scale; -} - -VGfloat path_bias(struct path *p) -{ - return p->bias; -} - -VGint path_num_coords(struct path *p) -{ - return num_elements_for_segments((VGubyte*)p->segments->data, - p->num_segments); -} - -void path_modify_coords(struct path *p, - VGint startIndex, - VGint numSegments, - const void * pathData) -{ - VGubyte *segments = (VGubyte*)(p->segments->data); - VGint count = num_elements_for_segments(&segments[startIndex], numSegments); - VGint start_cp = num_elements_for_segments(segments, startIndex); - - array_change_data(p->control_points, pathData, start_cp, count); - coords_adjust_by_scale_bias(p, - ((VGubyte*)p->control_points->data) + - (startIndex * p->control_points->datatype_size), - path_num_coords(p), - p->scale, p->bias, p->datatype); - p->dirty = VG_TRUE; - p->dirty_stroke = VG_TRUE; -} - -void path_for_each_segment(struct path *path, - path_for_each_cb cb, - void *user_data) -{ - VGint i; - struct path_for_each_data p; - VGfloat data[8]; - void *coords = (VGfloat *)path->control_points->data; - - p.coords = data; - p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f; - p.user_data = user_data; - - for (i = 0; i < path->num_segments; ++i) { - VGint command; - VGboolean relative; - - p.segment = ((VGubyte*)(path->segments->data))[i]; - command = SEGMENT_COMMAND(p.segment); - relative = SEGMENT_ABS_REL(p.segment); - - switch(command) { - case VG_CLOSE_PATH: - cb(path, &p); - break; - case VG_MOVE_TO: - data_at(&coords, path, 0, 2, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - cb(path, &p); - p.sx = data[0]; - p.sy = data[1]; - p.ox = data[0]; - p.oy = data[1]; - p.px = data[0]; - p.py = data[1]; - break; - case VG_LINE_TO: - data_at(&coords, path, 0, 2, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - cb(path, &p); - p.ox = data[0]; - p.oy = data[1]; - p.px = data[0]; - p.py = data[1]; - break; - case VG_HLINE_TO: - data_at(&coords, path, 0, 1, data); - map_if_relative(p.ox, p.oy, relative, &data[0], 0); - p.segment = VG_LINE_TO; - data[1] = p.oy; - cb(path, &p); - p.ox = data[0]; - p.oy = data[1]; - p.px = data[0]; - p.py = data[1]; - break; - case VG_VLINE_TO: - data_at(&coords, path, 0, 1, data); - map_if_relative(p.ox, p.oy, relative, 0, &data[0]); - p.segment = VG_LINE_TO; - data[1] = data[0]; - data[0] = p.ox; - cb(path, &p); - p.ox = data[0]; - p.oy = data[1]; - p.px = data[0]; - p.py = data[1]; - break; - case VG_CUBIC_TO: { - data_at(&coords, path, 0, 6, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); - map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]); - cb(path, &p); - p.px = data[2]; - p.py = data[3]; - p.ox = data[4]; - p.oy = data[5]; - } - break; - case VG_QUAD_TO: { - data_at(&coords, path, 0, 4, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); - cb(path, &p); - p.px = data[0]; - p.py = data[1]; - p.ox = data[2]; - p.oy = data[3]; - } - break; - case VG_SQUAD_TO: { - data_at(&coords, path, 0, 2, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - cb(path, &p); - p.px = 2*p.ox-p.px; - p.py = 2*p.oy-p.py; - p.ox = data[2]; - p.oy = data[3]; - } - break; - case VG_SCUBIC_TO: { - data_at(&coords, path, 0, 4, data); - map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); - map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); - cb(path, &p); - p.px = data[0]; - p.py = data[1]; - p.ox = data[2]; - p.oy = data[3]; - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - data_at(&coords, path, 0, 5, data); - map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]); -#if 0 - debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", - p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]); -#endif - cb(path, &p); - p.ox = data[3]; - p.oy = data[4]; - p.px = data[3]; - p.py = data[4]; - } - break; - default: - abort(); - assert(!"Unknown segment!"); - } - } -} - -struct transform_data { - struct array *segments; - struct array *coords; - - struct matrix *matrix; - - VGPathDatatype datatype; -}; - -static VGboolean transform_cb(struct path *p, - struct path_for_each_data *pd) -{ - struct transform_data *td = (struct transform_data *)pd->user_data; - VGint num_coords = num_elements_for_segments(&pd->segment, 1); - VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */ - VGfloat data[8]; - VGubyte common_data[sizeof(VGfloat)*8]; - - memcpy(data, pd->coords, sizeof(VGfloat) * num_coords); - - switch(segment) { - case VG_CLOSE_PATH: - break; - case VG_MOVE_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - break; - case VG_LINE_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - break; - case VG_HLINE_TO: - case VG_VLINE_TO: - assert(0); - break; - case VG_QUAD_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - matrix_map_point(td->matrix, - data[2], data[3], &data[2], &data[3]); - break; - case VG_CUBIC_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - matrix_map_point(td->matrix, - data[2], data[3], &data[2], &data[3]); - matrix_map_point(td->matrix, - data[4], data[5], &data[4], &data[5]); - break; - case VG_SQUAD_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - break; - case VG_SCUBIC_TO: - matrix_map_point(td->matrix, - data[0], data[1], &data[0], &data[1]); - matrix_map_point(td->matrix, - data[2], data[3], &data[2], &data[3]); - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - struct arc arc; - struct path *path = path_create(td->datatype, - 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); - arc_init(&arc, segment, - pd->ox, pd->oy, data[3], data[4], - data[0], data[1], data[2]); - - arc_to_path(&arc, path, td->matrix); - - num_coords = path_num_coords(path); - - array_append_data(td->segments, path->segments->data, - path->num_segments); - array_append_data(td->coords, path->control_points->data, - num_coords); - path_destroy(path); - - return VG_TRUE; - } - break; - default: - break; - } - - vg_float_to_datatype(td->datatype, common_data, data, num_coords); - - array_append_data(td->segments, &pd->segment, 1); - array_append_data(td->coords, common_data, num_coords); - return VG_TRUE; -} - -void path_transform(struct path *dst, struct path *src) -{ - struct transform_data data; - struct vg_context *ctx = dst->base.ctx; - - data.segments = dst->segments; - data.coords = dst->control_points; - data.matrix = &ctx->state.vg.path_user_to_surface_matrix; - data.datatype = dst->datatype; - - path_for_each_segment(src, transform_cb, (void*)&data); - - dst->num_segments = dst->segments->num_elements; - dst->dirty = VG_TRUE; - dst->dirty_stroke = VG_TRUE; -} - -void path_append_path(struct path *dst, - struct path *src) -{ - VGint num_coords = path_num_coords(src); - void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords); - array_append_data(dst->segments, - src->segments->data, - src->num_segments); - convert_path(src, dst->datatype, - dst_data, num_coords); - array_append_data(dst->control_points, - dst_data, - num_coords); - free(dst_data); - - dst->num_segments += src->num_segments; - dst->dirty = VG_TRUE; - dst->dirty_stroke = VG_TRUE; -} - -static INLINE VGboolean is_segment_arc(VGubyte segment) -{ - VGubyte scommand = SEGMENT_COMMAND(segment); - return (scommand == VG_SCCWARC_TO || - scommand == VG_SCWARC_TO || - scommand == VG_LCCWARC_TO || - scommand == VG_LCWARC_TO); -} - -struct path_iter_data { - struct path *path; - VGubyte segment; - void *coords; - VGfloat px, py, ox, oy, sx, sy; -}; -static INLINE VGubyte normalize_coords(struct path_iter_data *pd, - VGint *num_coords, - VGfloat *data) -{ - VGint command = SEGMENT_COMMAND(pd->segment); - VGboolean relative = SEGMENT_ABS_REL(pd->segment); - - switch(command) { - case VG_CLOSE_PATH: - *num_coords = 0; - pd->ox = pd->sx; - pd->oy = pd->sy; - return VG_CLOSE_PATH; - break; - case VG_MOVE_TO: - data_at(&pd->coords, pd->path, 0, 2, data); - map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); - pd->sx = data[0]; - pd->sy = data[1]; - pd->ox = data[0]; - pd->oy = data[1]; - pd->px = data[0]; - pd->py = data[1]; - *num_coords = 2; - return VG_MOVE_TO_ABS; - break; - case VG_LINE_TO: - data_at(&pd->coords, pd->path, 0, 2, data); - map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); - pd->ox = data[0]; - pd->oy = data[1]; - pd->px = data[0]; - pd->py = data[1]; - *num_coords = 2; - return VG_LINE_TO_ABS; - break; - case VG_HLINE_TO: - data_at(&pd->coords, pd->path, 0, 1, data); - map_if_relative(pd->ox, pd->oy, relative, &data[0], 0); - data[1] = pd->oy; - pd->ox = data[0]; - pd->oy = data[1]; - pd->px = data[0]; - pd->py = data[1]; - *num_coords = 2; - return VG_LINE_TO_ABS; - break; - case VG_VLINE_TO: - data_at(&pd->coords, pd->path, 0, 1, data); - map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]); - data[1] = data[0]; - data[0] = pd->ox; - pd->ox = data[0]; - pd->oy = data[1]; - pd->px = data[0]; - pd->py = data[1]; - *num_coords = 2; - return VG_LINE_TO_ABS; - break; - case VG_CUBIC_TO: { - data_at(&pd->coords, pd->path, 0, 6, data); - map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); - map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]); - map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]); - pd->px = data[2]; - pd->py = data[3]; - pd->ox = data[4]; - pd->oy = data[5]; - *num_coords = 6; - return VG_CUBIC_TO_ABS; - } - break; - case VG_QUAD_TO: { - VGfloat x0, y0, x1, y1, x2, y2, x3, y3; - data_at(&pd->coords, pd->path, 0, 4, data); - x0 = pd->ox; - y0 = pd->oy; - x1 = data[0]; - y1 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(pd->ox, pd->oy, relative, &x1, &y1); - map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); - pd->px = x1; - pd->py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - pd->ox = x3; - pd->oy = y3; - data[0] = x1; - data[1] = y1; - data[2] = x2; - data[3] = y2; - data[4] = x3; - data[5] = y3; - *num_coords = 6; - return VG_CUBIC_TO_ABS; - } - break; - case VG_SQUAD_TO: { - VGfloat x0, y0, x1, y1, x2, y2, x3, y3; - data_at(&pd->coords, pd->path, 0, 2, data); - x0 = pd->ox; - y0 = pd->oy; - x1 = 2 * pd->ox - pd->px; - y1 = 2 * pd->oy - pd->py; - x3 = data[0]; - y3 = data[1]; - map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); - pd->px = x1; - pd->py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - pd->ox = x3; - pd->oy = y3; - data[0] = x1; - data[1] = y1; - data[2] = x2; - data[3] = y2; - data[4] = x3; - data[5] = y3; - *num_coords = 6; - return VG_CUBIC_TO_ABS; - } - break; - case VG_SCUBIC_TO: { - VGfloat x1, y1, x2, y2, x3, y3; - data_at(&pd->coords, pd->path, 0, 4, data); - x1 = 2*pd->ox-pd->px; - y1 = 2*pd->oy-pd->py; - x2 = data[0]; - y2 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(pd->ox, pd->oy, relative, &x2, &y2); - map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); - pd->ox = x3; - pd->oy = y3; - pd->px = x2; - pd->py = y2; - data[0] = x1; - data[1] = y1; - data[2] = x2; - data[3] = y2; - data[4] = x3; - data[5] = y3; - *num_coords = 6; - return VG_CUBIC_TO_ABS; - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - data_at(&pd->coords, pd->path, 0, 5, data); - map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]); - pd->ox = data[3]; - pd->oy = data[4]; - pd->px = data[3]; - pd->py = data[4]; - *num_coords = 5; - return command | VG_ABSOLUTE; - } - break; - default: - abort(); - assert(!"Unknown segment!"); - return 0; - } -} - -static void linearly_interpolate(VGfloat *result, - const VGfloat *start, - const VGfloat *end, - VGfloat amount, - VGint number) -{ - VGint i; - for (i = 0; i < number; ++i) { - result[i] = start[i] + (end[i] - start[i]) * amount; - } -} - -VGboolean path_interpolate(struct path *dst, - struct path *start, struct path *end, - VGfloat amount) -{ - /* temporary path that we can discard if it will turn - * out that start is not compatible with end */ - struct path *res_path = path_create(dst->datatype, - 1.0, 0.0, - 0, 0, dst->caps); - VGint i; - VGfloat start_coords[8]; - VGfloat end_coords[8]; - VGfloat results[8]; - VGubyte common_data[sizeof(VGfloat)*8]; - struct path_iter_data start_iter, end_iter; - - memset(&start_iter, 0, sizeof(struct path_iter_data)); - memset(&end_iter, 0, sizeof(struct path_iter_data)); - - start_iter.path = start; - start_iter.coords = start->control_points->data; - end_iter.path = end; - end_iter.coords = end->control_points->data; - - for (i = 0; i < start->num_segments; ++i) { - VGubyte segment; - VGubyte ssegment, esegment; - VGint snum_coords, enum_coords; - start_iter.segment = ((VGubyte*)(start->segments->data))[i]; - end_iter.segment = ((VGubyte*)(end->segments->data))[i]; - - ssegment = normalize_coords(&start_iter, &snum_coords, - start_coords); - esegment = normalize_coords(&end_iter, &enum_coords, - end_coords); - - if (is_segment_arc(ssegment)) { - if (!is_segment_arc(esegment)) { - path_destroy(res_path); - return VG_FALSE; - } - if (amount > 0.5) - segment = esegment; - else - segment = ssegment; - } else if (is_segment_arc(esegment)) { - path_destroy(res_path); - return VG_FALSE; - } - else if (ssegment != esegment) { - path_destroy(res_path); - return VG_FALSE; - } - else - segment = ssegment; - - linearly_interpolate(results, start_coords, end_coords, - amount, snum_coords); - vg_float_to_datatype(dst->datatype, common_data, results, snum_coords); - path_append_data(res_path, 1, &segment, common_data); - } - - path_append_path(dst, res_path); - path_destroy(res_path); - - dst->dirty = VG_TRUE; - dst->dirty_stroke = VG_TRUE; - - return VG_TRUE; -} - -void path_clear(struct path *p, VGbitfield capabilities) -{ - path_set_capabilities(p, capabilities); - array_destroy(p->segments); - array_destroy(p->control_points); - p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); - p->control_points = array_create(size_for_datatype(p->datatype)); - p->num_segments = 0; - p->dirty = VG_TRUE; - p->dirty_stroke = VG_TRUE; -} - -struct path * path_create_stroke(struct path *p, - struct matrix *matrix) -{ - VGint i; - VGfloat sx, sy, px, py, ox, oy; - VGfloat x0, y0, x1, y1, x2, y2, x3, y3; - VGfloat data[8]; - void *coords = (VGfloat *)p->control_points->data; - int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0); - struct dash_stroker stroker; - struct vg_state *vg_state = &p->base.ctx->state.vg; - - if (p->stroked.path) - { - /* ### compare the dash patterns to see if we can cache them. - * for now we simply always bail out if the path is dashed. - */ - if (memcmp( &p->stroked.matrix, - matrix, - sizeof *matrix ) == 0 && - !dashed && !p->dirty_stroke && - floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) && - floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) && - p->stroked.cap_style == vg_state->stroke.cap_style && - p->stroked.join_style == vg_state->stroke.join_style) - { - return p->stroked.path; - } - else { - path_destroy( p->stroked.path ); - p->stroked.path = NULL; - } - } - - - sx = sy = px = py = ox = oy = 0.f; - - if (dashed) - dash_stroker_init((struct stroker *)&stroker, vg_state); - else - stroker_init((struct stroker *)&stroker, vg_state); - - stroker_begin((struct stroker *)&stroker); - - for (i = 0; i < p->num_segments; ++i) { - VGubyte segment = ((VGubyte*)(p->segments->data))[i]; - VGint command = SEGMENT_COMMAND(segment); - VGboolean relative = SEGMENT_ABS_REL(segment); - - switch(command) { - case VG_CLOSE_PATH: { - VGfloat x0 = sx; - VGfloat y0 = sy; - matrix_map_point(matrix, x0, y0, &x0, &y0); - stroker_line_to((struct stroker *)&stroker, x0, y0); - } - break; - case VG_MOVE_TO: - data_at(&coords, p, 0, 2, data); - x0 = data[0]; - y0 = data[1]; - map_if_relative(ox, oy, relative, &x0, &y0); - sx = x0; - sy = y0; - ox = x0; - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - stroker_move_to((struct stroker *)&stroker, x0, y0); - break; - case VG_LINE_TO: - data_at(&coords, p, 0, 2, data); - x0 = data[0]; - y0 = data[1]; - map_if_relative(ox, oy, relative, &x0, &y0); - ox = x0; - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - stroker_line_to((struct stroker *)&stroker, x0, y0); - break; - case VG_HLINE_TO: - data_at(&coords, p, 0, 1, data); - x0 = data[0]; - y0 = oy; - map_if_relative(ox, oy, relative, &x0, 0); - ox = x0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - stroker_line_to((struct stroker *)&stroker, x0, y0); - break; - case VG_VLINE_TO: - data_at(&coords, p, 0, 1, data); - x0 = ox; - y0 = data[0]; - map_if_relative(ox, oy, relative, 0, &y0); - oy = y0; - px = x0; - py = y0; - matrix_map_point(matrix, x0, y0, &x0, &y0); - stroker_line_to((struct stroker *)&stroker, x0, y0); - break; - case VG_CUBIC_TO: { - data_at(&coords, p, 0, 6, data); - x0 = ox; - y0 = oy; - x1 = data[0]; - y1 = data[1]; - x2 = data[2]; - y2 = data[3]; - x3 = data[4]; - y3 = data[5]; - map_if_relative(ox, oy, relative, &x1, &y1); - map_if_relative(ox, oy, relative, &x2, &y2); - map_if_relative(ox, oy, relative, &x3, &y3); - if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && - floatsEqual(x1, x2) && floatsEqual(y1, y2) && - floatsEqual(x2, x3) && floatsEqual(y2, y3)) { - /*ignore the empty segment */ - continue; - } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { - /* if dup vertex, emit a line */ - ox = x3; - oy = y3; - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_line_to((struct stroker *)&stroker, x3, y3); - continue; - } - ox = x3; - oy = y3; - px = x2; - py = y2; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); - } - break; - case VG_QUAD_TO: { - data_at(&coords, p, 0, 4, data); - x0 = ox; - y0 = oy; - x1 = data[0]; - y1 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(ox, oy, relative, &x1, &y1); - map_if_relative(ox, oy, relative, &x3, &y3); - px = x1; - py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && - floatsEqual(x1, x2) && floatsEqual(y1, y2) && - floatsEqual(x2, x3) && floatsEqual(y2, y3)) { - /*ignore the empty segment */ - continue; - } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { - /* if dup vertex, emit a line */ - ox = x3; - oy = y3; - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_line_to((struct stroker *)&stroker, x3, y3); - continue; - } - ox = x3; - oy = y3; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); - } - break; - case VG_SQUAD_TO: { - data_at(&coords, p, 0, 2, data); - x0 = ox; - y0 = oy; - x1 = 2*ox-px; - y1 = 2*oy-py; - x3 = data[0]; - y3 = data[1]; - map_if_relative(ox, oy, relative, &x3, &y3); - px = x1; - py = y1; - { /* form a cubic out of it */ - x2 = (x3 + 2*x1) / 3.f; - y2 = (y3 + 2*y1) / 3.f; - x1 = (x0 + 2*x1) / 3.f; - y1 = (y0 + 2*y1) / 3.f; - } - if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && - floatsEqual(x1, x2) && floatsEqual(y1, y2) && - floatsEqual(x2, x3) && floatsEqual(y2, y3)) { - /*ignore the empty segment */ - continue; - } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { - /* if dup vertex, emit a line */ - ox = x3; - oy = y3; - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_line_to((struct stroker *)&stroker, x3, y3); - continue; - } - ox = x3; - oy = y3; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); - } - break; - case VG_SCUBIC_TO: { - data_at(&coords, p, 0, 4, data); - x0 = ox; - y0 = oy; - x1 = 2*ox-px; - y1 = 2*oy-py; - x2 = data[0]; - y2 = data[1]; - x3 = data[2]; - y3 = data[3]; - map_if_relative(ox, oy, relative, &x2, &y2); - map_if_relative(ox, oy, relative, &x3, &y3); - if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && - floatsEqual(x1, x2) && floatsEqual(y1, y2) && - floatsEqual(x2, x3) && floatsEqual(y2, y3)) { - /*ignore the empty segment */ - continue; - } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { - /* if dup vertex, emit a line */ - ox = x3; - oy = y3; - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_line_to((struct stroker *)&stroker, x3, y3); - continue; - } - ox = x3; - oy = y3; - px = x2; - py = y2; - assert(matrix_is_affine(matrix)); - matrix_map_point(matrix, x0, y0, &x0, &y0); - matrix_map_point(matrix, x1, y1, &x1, &y1); - matrix_map_point(matrix, x2, y2, &x2, &y2); - matrix_map_point(matrix, x3, y3, &x3, &y3); - stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - VGfloat rh, rv, rot; - struct arc arc; - - data_at(&coords, p, 0, 5, data); - x0 = ox; - y0 = oy; - rh = data[0]; - rv = data[1]; - rot = data[2]; - x1 = data[3]; - y1 = data[4]; - map_if_relative(ox, oy, relative, &x1, &y1); - if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) { - /* if dup vertex, emit a line */ - ox = x1; - oy = y1; - matrix_map_point(matrix, x1, y1, &x1, &y1); - stroker_line_to((struct stroker *)&stroker, x1, y1); - continue; - } - arc_init(&arc, command, x0, y0, x1, y1, - rh, rv, rot); - arc_stroke_cb(&arc, (struct stroker *)&stroker, - matrix); - ox = x1; - oy = y1; - px = x1; - py = y1; - } - break; - default: - abort(); - assert(!"Unknown segment!"); - } - } - - stroker_end((struct stroker *)&stroker); - - if (dashed) - dash_stroker_cleanup((struct dash_stroker *)&stroker); - else - stroker_cleanup((struct stroker *)&stroker); - - p->stroked.path = stroker.base.path; - p->stroked.matrix = *matrix; - p->dirty_stroke = VG_FALSE; - p->stroked.stroke_width = vg_state->stroke.line_width.f; - p->stroked.miter_limit = vg_state->stroke.miter_limit.f; - p->stroked.cap_style = vg_state->stroke.cap_style; - p->stroked.join_style = vg_state->stroke.join_style; - - return stroker.base.path; -} - -void path_render(struct path *p, VGbitfield paintModes, - struct matrix *mat) -{ - struct vg_context *ctx = vg_current_context(); - struct matrix paint_matrix; - - vg_validate_state(ctx); - - shader_set_drawing_image(ctx->shader, VG_FALSE); - shader_set_image(ctx->shader, 0); -#if 0 - fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n", - mat->m[0], mat->m[1], mat->m[2], - mat->m[3], mat->m[4], mat->m[5], - mat->m[6], mat->m[7], mat->m[8]); -#endif - if ((paintModes & VG_FILL_PATH) && - vg_get_paint_matrix(ctx, - &ctx->state.vg.fill_paint_to_user_matrix, - mat, - &paint_matrix)) { - /* First the fill */ - shader_set_surface_matrix(ctx->shader, mat); - shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); - shader_set_paint_matrix(ctx->shader, &paint_matrix); - shader_bind(ctx->shader); - path_fill(p); - } - - if ((paintModes & VG_STROKE_PATH) && - vg_get_paint_matrix(ctx, - &ctx->state.vg.stroke_paint_to_user_matrix, - mat, - &paint_matrix)) { - /* 8.7.5: "line width less than or equal to 0 prevents stroking from - * taking place."*/ - if (ctx->state.vg.stroke.line_width.f <= 0) - return; - shader_set_surface_matrix(ctx->shader, mat); - shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint); - shader_set_paint_matrix(ctx->shader, &paint_matrix); - shader_bind(ctx->shader); - path_stroke(p); - } -} - -void path_fill(struct path *p) -{ - struct vg_context *ctx = vg_current_context(); - struct matrix identity; - - matrix_load_identity(&identity); - - { - struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity); - struct array *polys = polygon_array->array; - - if (!polygon_array || !polys || !polys->num_elements) { - return; - } - polygon_array_fill(polygon_array, ctx); - } -} - -void path_stroke(struct path *p) -{ - struct vg_context *ctx = vg_current_context(); - VGFillRule old_fill = ctx->state.vg.fill_rule; - struct matrix identity; - struct path *stroke; - - matrix_load_identity(&identity); - stroke = path_create_stroke(p, &identity); - if (stroke && !path_is_empty(stroke)) { - ctx->state.vg.fill_rule = VG_NON_ZERO; - - path_fill(stroke); - - ctx->state.vg.fill_rule = old_fill; - } -} - -void path_move_to(struct path *p, float x, float y) -{ - VGubyte segment = VG_MOVE_TO_ABS; - VGubyte common_data[sizeof(VGfloat) * 2]; - VGfloat data[2] = {x, y}; - - vg_float_to_datatype(p->datatype, common_data, data, 2); - path_append_data(p, 1, &segment, common_data); -} - -void path_line_to(struct path *p, float x, float y) -{ - VGubyte segment = VG_LINE_TO_ABS; - VGubyte common_data[sizeof(VGfloat) * 2]; - VGfloat data[2] = {x, y}; - - vg_float_to_datatype(p->datatype, common_data, data, 2); - - path_append_data(p, 1, &segment, common_data); -} - -void path_cubic_to(struct path *p, float px1, float py1, - float px2, float py2, - float x, float y) -{ - VGubyte segment = VG_CUBIC_TO_ABS; - VGubyte common_data[sizeof(VGfloat) * 6]; - VGfloat data[6]; - - data[0] = px1; data[1] = py1; - data[2] = px2; data[3] = py2; - data[4] = x; data[5] = y; - - vg_float_to_datatype(p->datatype, common_data, data, 6); - - path_append_data(p, 1, &segment, common_data); -} - -static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/, - VGfloat *bounds) -{ - bounds[0] = MIN2(line[0], line[2]); - bounds[1] = MIN2(line[1], line[3]); - bounds[2] = MAX2(line[0], line[2]) - bounds[0]; - bounds[3] = MAX2(line[1], line[3]) - bounds[1]; -} - -static INLINE void unite_bounds(VGfloat *bounds, - VGfloat *el) -{ - VGfloat cx1, cy1, cx2, cy2; - VGfloat nx1, ny1, nx2, ny2; - - cx1 = bounds[0]; - cy1 = bounds[1]; - cx2 = bounds[0] + bounds[2]; - cy2 = bounds[1] + bounds[3]; - - nx1 = el[0]; - ny1 = el[1]; - nx2 = el[0] + el[2]; - ny2 = el[1] + el[3]; - - bounds[0] = MIN2(cx1, nx1); - bounds[1] = MIN2(cy1, ny1); - bounds[2] = MAX2(cx2, nx2) - bounds[0]; - bounds[3] = MAX2(cy2, ny2) - bounds[1]; -} - -static INLINE void set_bounds(VGfloat *bounds, - VGfloat *element_bounds, - VGboolean *initialized) -{ - if (!(*initialized)) { - memcpy(bounds, element_bounds, 4 * sizeof(VGfloat)); - *initialized = VG_TRUE; - } else - unite_bounds(bounds, element_bounds); -} - -void path_bounding_rect(struct path *p, float *x, float *y, - float *w, float *h) -{ - VGint i; - VGfloat coords[8]; - struct path_iter_data iter; - VGint num_coords; - VGfloat bounds[4]; - VGfloat element_bounds[4]; - VGfloat ox, oy; - VGboolean bounds_inited = VG_FALSE; - - memset(&iter, 0, sizeof(struct path_iter_data)); - memset(&bounds, 0, sizeof(bounds)); - - if (!p->num_segments) { - bounds[2] = -1; - bounds[3] = -1; - } - - - iter.path = p; - iter.coords = p->control_points->data; - - for (i = 0; i < p->num_segments; ++i) { - VGubyte segment; - iter.segment = ((VGubyte*)(p->segments->data))[i]; - - ox = iter.ox; - oy = iter.oy; - - segment = normalize_coords(&iter, &num_coords, coords); - - switch(segment) { - case VG_CLOSE_PATH: - case VG_MOVE_TO_ABS: - break; - case VG_LINE_TO_ABS: { - VGfloat line[4] = {ox, oy, coords[0], coords[1]}; - line_bounds(line, element_bounds); - set_bounds(bounds, element_bounds, &bounds_inited); - } - break; - case VG_CUBIC_TO_ABS: { - struct bezier bezier; - bezier_init(&bezier, ox, oy, - coords[0], coords[1], - coords[2], coords[3], - coords[4], coords[5]); - bezier_exact_bounds(&bezier, element_bounds); - set_bounds(bounds, element_bounds, &bounds_inited); - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - struct arc arc; - struct matrix identity; - struct path *path = path_create(VG_PATH_DATATYPE_F, - 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); - - matrix_load_identity(&identity); - arc_init(&arc, segment, - ox, oy, coords[3], coords[4], - coords[0], coords[1], coords[2]); - - arc_to_path(&arc, path, &identity); - - path_bounding_rect(path, element_bounds + 0, element_bounds + 1, - element_bounds + 2, element_bounds + 3); - set_bounds(bounds, element_bounds, &bounds_inited); - } - break; - default: - assert(0); - } - } - - *x = bounds[0]; - *y = bounds[1]; - *w = bounds[2]; - *h = bounds[3]; -} - -float path_length(struct path *p, int start_segment, int num_segments) -{ - VGint i; - VGfloat coords[8]; - struct path_iter_data iter; - VGint num_coords; - VGfloat length = 0; - VGfloat ox, oy; - VGboolean in_range = VG_FALSE; - - memset(&iter, 0, sizeof(struct path_iter_data)); - - iter.path = p; - iter.coords = p->control_points->data; - - for (i = 0; i < (start_segment + num_segments); ++i) { - VGubyte segment; - - iter.segment = ((VGubyte*)(p->segments->data))[i]; - - ox = iter.ox; - oy = iter.oy; - - segment = normalize_coords(&iter, &num_coords, coords); - - in_range = (i >= start_segment) && i <= (start_segment + num_segments); - if (!in_range) - continue; - - switch(segment) { - case VG_MOVE_TO_ABS: - break; - case VG_CLOSE_PATH: { - VGfloat line[4] = {ox, oy, iter.sx, iter.sy}; - length += line_lengthv(line); - } - break; - case VG_LINE_TO_ABS: { - VGfloat line[4] = {ox, oy, coords[0], coords[1]}; - length += line_lengthv(line); - } - break; - case VG_CUBIC_TO_ABS: { - struct bezier bezier; - bezier_init(&bezier, ox, oy, - coords[0], coords[1], - coords[2], coords[3], - coords[4], coords[5]); - length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR); - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - struct arc arc; - struct matrix identity; - struct path *path = path_create(VG_PATH_DATATYPE_F, - 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); - - matrix_load_identity(&identity); - arc_init(&arc, segment, - ox, oy, coords[3], coords[4], - coords[0], coords[1], coords[2]); - - arc_to_path(&arc, path, &identity); - - length += path_length(path, 0, path_num_segments(path)); - } - break; - default: - assert(0); - } - } - - return length; -} - -static INLINE VGboolean point_on_current_segment(VGfloat distance, - VGfloat length, - VGfloat segment_length) -{ - return - (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) || - ((distance > length || floatsEqual(distance, length)) && - (floatsEqual(distance, length + segment_length) || - distance < (length + segment_length)))); -} - -static VGboolean path_point_segment(struct path_iter_data iter, - struct path_iter_data prev_iter, - VGfloat coords[8], - VGfloat distance, - VGfloat length, VGfloat *current_length, - VGfloat *point, VGfloat *normal) -{ - switch (iter.segment) { - case VG_MOVE_TO_ABS: - break; - case VG_CLOSE_PATH: { - VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; - VGboolean on_current_segment = VG_FALSE; - *current_length = line_lengthv(line); - on_current_segment = point_on_current_segment(distance, - length, - *current_length); - if (on_current_segment) { - VGfloat at = (distance - length) / line_lengthv(line); - line_normal_vector(line, normal); - line_point_at(line, at, point); - return VG_TRUE; - } - } - break; - case VG_LINE_TO_ABS: { - VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; - VGboolean on_current_segment = VG_FALSE; - *current_length = line_lengthv(line); - on_current_segment = point_on_current_segment(distance, - length, - *current_length); - if (on_current_segment) { - VGfloat at = (distance - length) / line_lengthv(line); - line_normal_vector(line, normal); - line_point_at(line, at, point); - return VG_TRUE; - } - } - break; - case VG_CUBIC_TO_ABS: { - struct bezier bezier; - bezier_init(&bezier, prev_iter.ox, prev_iter.oy, - coords[0], coords[1], - coords[2], coords[3], - coords[4], coords[5]); - *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR); - if (point_on_current_segment(distance, length, *current_length)) { - bezier_point_at_length(&bezier, distance - length, - point, normal); - return VG_TRUE; - } - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - struct arc arc; - struct matrix identity; - struct path *path = path_create(VG_PATH_DATATYPE_F, - 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); - - matrix_load_identity(&identity); - arc_init(&arc, iter.segment, - prev_iter.ox, prev_iter.oy, coords[3], coords[4], - coords[0], coords[1], coords[2]); - - arc_to_path(&arc, path, &identity); - - *current_length = path_length(path, 0, path_num_segments(path)); - if (point_on_current_segment(distance, length, *current_length)) { - path_point(path, 0, path_num_segments(path), - distance - length, point, normal); - return VG_TRUE; - } - } - break; - default: - assert(0); - } - return VG_FALSE; -} - -void path_point(struct path *p, VGint start_segment, VGint num_segments, - VGfloat distance, VGfloat *point, VGfloat *normal) -{ - VGint i; - VGfloat coords[8]; - struct path_iter_data iter, prev_iter; - VGint num_coords; - VGfloat length = 0; - VGfloat current_length = 0; - - memset(&iter, 0, sizeof(struct path_iter_data)); - memset(&prev_iter, 0, sizeof(struct path_iter_data)); - - point[0] = 0; - point[1] = 0; - - normal[0] = 0; - normal[1] = -1; - - iter.path = p; - iter.coords = p->control_points->data; - if (distance < 0) - distance = 0; - - for (i = 0; i < (start_segment + num_segments); ++i) { - VGboolean outside_range = (i < start_segment || - i >= (start_segment + num_segments)); - - prev_iter = iter; - - iter.segment = ((VGubyte*)(p->segments->data))[i]; - iter.segment = normalize_coords(&iter, &num_coords, coords); - - if (outside_range) - continue; - - if (path_point_segment(iter, prev_iter, coords, - distance, length, ¤t_length, - point, normal)) - return; - - length += current_length; - } - - /* - *OpenVG 1.0 - 8.6.11 vgPointAlongPath - * - * If distance is greater than or equal to the path length - *(i.e., the value returned by vgPathLength when called with the same - *startSegment and numSegments parameters), the visual ending point of - *the path is used. - */ - { - switch (iter.segment) { - case VG_MOVE_TO_ABS: - break; - case VG_CLOSE_PATH: { - VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; - line_normal_vector(line, normal); - line_point_at(line, 1.f, point); - } - break; - case VG_LINE_TO_ABS: { - VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; - line_normal_vector(line, normal); - line_point_at(line, 1.f, point); - } - break; - case VG_CUBIC_TO_ABS: { - struct bezier bezier; - bezier_init(&bezier, prev_iter.ox, prev_iter.oy, - coords[0], coords[1], - coords[2], coords[3], - coords[4], coords[5]); - bezier_point_at_t(&bezier, 1.f, point, normal); - } - break; - case VG_SCCWARC_TO: - case VG_SCWARC_TO: - case VG_LCCWARC_TO: - case VG_LCWARC_TO: { - struct arc arc; - struct matrix identity; - struct path *path = path_create(VG_PATH_DATATYPE_F, - 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); - - matrix_load_identity(&identity); - arc_init(&arc, iter.segment, - prev_iter.ox, prev_iter.oy, coords[3], coords[4], - coords[0], coords[1], coords[2]); - - arc_to_path(&arc, path, &identity); - - path_point(path, 0, path_num_segments(path), - /* to make sure we're bigger than len * 2 it */ - 2 * path_length(path, 0, path_num_segments(path)), - point, normal); - } - break; - default: - assert(0); - } - } -} - -VGboolean path_is_empty(struct path *p) -{ - return p->segments->num_elements == 0; -} |