Skip to content

Commit

Permalink
improve svg
Browse files Browse the repository at this point in the history
  • Loading branch information
xianjimli committed Mar 6, 2024
1 parent 144490c commit 66f34a4
Show file tree
Hide file tree
Showing 5 changed files with 407 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static ret_t arc_info_init(arc_info_t* info, pointf_t from, pointf_t to, pointf_
return RET_OK;
}

bool_t arc_info_next(arc_info_t* info, pointf_t* cp1, pointf_t* cp2, pointf_t* to) {
static bool_t arc_info_next(arc_info_t* info, pointf_t* cp1, pointf_t* cp2, pointf_t* to) {
if (info->seg_index == info->num_segs) {
return FALSE;
}
Expand Down
3 changes: 3 additions & 0 deletions docs/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# 最新动态

2024/03/06
* 完善svg支持awtk-widget-shape(感谢陈聪提供补丁)

2024/03/04
* 增加zip_file。
* 修改edit控件支持只读下数据可以拷贝到剪切板上面(感谢智明提供补丁)
Expand Down
291 changes: 288 additions & 3 deletions src/svg/svg_path_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,294 @@
*/

#include "tkc/utils.h"
#include "tkc/mem.h"
#include "svg/svg_path.h"
#include "svg/svg_path_parser.h"
#include "svgtiny/include/svgtiny_arc.h"

/*
* 由于svg改为用svgtiny解析,所以去掉svg/svg_path_parser.c|.h中的代码,但为了兼容保留文件。
*/
typedef struct _svg_path_parser_t {
char* path;
void* ctx;
tk_visit_t on_path;
} svg_path_parser_t;

static ret_t svg_path_parser_parse(svg_path_parser_t* parser) {
char* s = parser->path;
float first_x = 0, first_y = 0;
float last_x = 0, last_y = 0;
float last_cubic_x = 0, last_cubic_y = 0;
float last_quad_x = 0, last_quad_y = 0;

/* parse d and build path */
s = parser->path;
while (*s) {
if (*s == ',') {
*s = ' ';
}
s++;
}

s = parser->path;
while (*s) {
int n;
char command[2];
float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep;

/* moveto (M, m) (2 arguments) */
if (sscanf(s, " %1[Mm] %f %f %n", command, &x, &y, &n) == 3) {
svg_path_move_t path;

do {
if (*command == 'm') {
x += last_x;
y += last_y;
}
first_x = last_cubic_x = last_quad_x = last_x = x;
first_y = last_cubic_y = last_quad_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_move_init(&path, x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %n", &x, &y, &n) == 2);

/* lineto (L, l) (2 arguments) */
} else if (sscanf(s, " %1[Ll] %f %f %n", command, &x, &y, &n) == 3) {
svg_path_line_t path;

do {
if (*command == 'l') {
x += last_x;
y += last_y;
}
last_cubic_x = last_quad_x = last_x = x;
last_cubic_y = last_quad_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_line_init(&path, x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %n", &x, &y, &n) == 2);

/* closepath (Z, z) (no arguments) */
} else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) {
svg_path_t path;

last_x = first_x;
last_y = first_y;
s += n;

memset(&path, 0, sizeof(path));
path.type = SVG_PATH_Z;
parser->on_path(parser->ctx, (svg_path_t*)&path);

/* horizontal lineto (H, h) (1 argument) */
} else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) {
svg_path_line_t path;

do {
if (*command == 'h') {
x += last_x;
}
last_cubic_x = last_quad_x = last_x = x;
last_cubic_y = last_quad_y = last_y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_line_init(&path, x, last_y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %n", &x, &n) == 1);

/* vertical lineto (V, v) (1 argument) */
} else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) {
svg_path_line_t path;

do {
if (*command == 'v') {
y += last_y;
}
last_cubic_x = last_quad_x = last_x;
last_cubic_y = last_quad_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_line_init(&path, last_x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %n", &y, &n) == 1);

/* curveto (C, c) (6 arguments) */
} else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command, &x1, &y1, &x2, &y2, &x, &y, &n) ==
7) {
svg_path_curve_to_t path;

do {
if (*command == 'c') {
x1 += last_x;
y1 += last_y;
x2 += last_x;
y2 += last_y;
x += last_x;
y += last_y;
}
last_cubic_x = x2;
last_cubic_y = y2;
last_quad_x = last_x = x;
last_quad_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_curve_to_init(&path, x1, y1, x2, y2, x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %f %f %f %f %n", &x1, &y1, &x2, &y2, &x, &y, &n) == 6);

/* shorthand/smooth curveto (S, s) (4 arguments) */
} else if (sscanf(s, " %1[Ss] %f %f %f %f %n", command, &x2, &y2, &x, &y, &n) == 5) {
svg_path_curve_to_t path;

do {
x1 = last_x + (last_x - last_cubic_x);
y1 = last_y + (last_y - last_cubic_y);
if (*command == 's') {
x2 += last_x;
y2 += last_y;
x += last_x;
y += last_y;
}
last_cubic_x = x2;
last_cubic_y = y2;
last_quad_x = last_x = x;
last_quad_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_curve_to_init(&path, x1, y1, x2, y2, x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %f %f %n", &x2, &y2, &x, &y, &n) == 4);

/* quadratic Bezier curveto (Q, q) (4 arguments) */
} else if (sscanf(s, " %1[Qq] %f %f %f %f %n", command, &x1, &y1, &x, &y, &n) == 5) {
svg_path_curve_to_t path;
float p[4];

do {
if (*command == 'q') {
x1 += last_x;
y1 += last_y;
x += last_x;
y += last_y;
}
last_quad_x = x1;
last_quad_y = y1;
p[0] = 1. / 3 * last_x + 2. / 3 * x1;
p[1] = 1. / 3 * last_y + 2. / 3 * y1;
p[2] = 2. / 3 * x1 + 1. / 3 * x;
p[3] = 2. / 3 * y1 + 1. / 3 * y;
last_cubic_x = last_x = x;
last_cubic_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_curve_to_init(&path, p[0], p[1], p[2], p[3], x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %f %f %n", &x1, &y1, &x, &y, &n) == 4);

/* shorthand/smooth quadratic Bezier curveto (T, t)
(2 arguments) */
} else if (sscanf(s, " %1[Tt] %f %f %n", command, &x, &y, &n) == 3) {
svg_path_curve_to_t path;
float p[4];

do {
x1 = last_x + (last_x - last_quad_x);
y1 = last_y + (last_y - last_quad_y);
last_quad_x = x1;
last_quad_y = y1;
if (*command == 't') {
x += last_x;
y += last_y;
}
p[0] = 1. / 3 * last_x + 2. / 3 * x1;
p[1] = 1. / 3 * last_y + 2. / 3 * y1;
p[2] = 2. / 3 * x1 + 1. / 3 * x;
p[3] = 2. / 3 * y1 + 1. / 3 * y;
last_cubic_x = last_x = x;
last_cubic_y = last_y = y;
s += n;

memset(&path, 0, sizeof(path));
svg_path_curve_to_init(&path, p[0], p[1], p[2], p[3], x, y);
parser->on_path(parser->ctx, (svg_path_t*)&path);

} while (sscanf(s, "%f %f %n", &x, &y, &n) == 2);

/* elliptical arc (A, a) (7 arguments) */
} else if (sscanf(s, " %1[Aa] %f %f %f %f %f %f %f %n", command, &rx, &ry, &rotation,
&large_arc, &sweep, &x, &y, &n) == 8) {
svg_path_curve_to_t path;

do {
arc_info_t info;
pointf_t cp1 = {0, 0};
pointf_t cp2 = {0, 0};
pointf_t end = {0, 0};
pointf_t r = {rx, ry};
pointf_t from = {last_x, last_y};
pointf_t to = {x, y};
if (*command == 'a') {
to.x += last_x;
to.y += last_y;
}
arc_info_init(&info, from, to, r, rotation, large_arc, sweep);
while (arc_info_next(&info, &cp1, &cp2, &end)) {
memset(&path, 0, sizeof(path));
svg_path_curve_to_init(&path, cp1.x, cp1.y, cp2.x, cp2.y, end.x, end.y);
parser->on_path(parser->ctx, (svg_path_t*)&path);
}

last_x = to.x;
last_y = to.y;
s += n;
} while (sscanf(s, "%f %f %f %f %f %f %f %n", &rx, &ry, &rotation, &large_arc, &sweep, &x, &y,
&n) == 7);

} else {
log_error("parse failed at \"%s\"\n", s);
return RET_FAIL;
}
}

return RET_OK;
}

static ret_t svg_path_parser_init(svg_path_parser_t* parser, const char* path, void* ctx,
tk_visit_t on_path) {
memset(parser, 0x00, sizeof(*parser));

parser->ctx = ctx;
parser->path = (char*)path;
parser->on_path = on_path;

return RET_OK;
}

ret_t svg_path_parse(const char* path, void* ctx, tk_visit_t on_path) {
ret_t ret;
char* p = NULL;
svg_path_parser_t parser;
return_value_if_fail(path != NULL && on_path != NULL, RET_BAD_PARAMS);

p = tk_strdup(path);
return_value_if_fail(p != NULL, RET_OOM);

svg_path_parser_init(&parser, p, ctx, on_path);
ret = svg_path_parser_parse(&parser);
TKMEM_FREE(p);
return ret;
}
24 changes: 21 additions & 3 deletions src/svg/svg_path_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,26 @@

#include "tkc/types_def.h"

/*
* 由于svg改为用svgtiny解析,所以去掉svg/svg_path_parser.c|.h中的代码,但为了兼容保留文件。
*/
BEGIN_C_DECLS

/**
* @class svg_path_t
* @annotation ["fake"]
*/

/**
* @method svg_path_parse
*
* 解析路径。
*
* @param {const char*} path 路径数据。
* @param {void*} ctx 回调函数上下文。
* @param {tk_visit_t} on_path 路径处理回调函数。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t svg_path_parse(const char* path, void* ctx, tk_visit_t on_path);

END_C_DECLS

#endif /*TK_SVG_PATH_BUILDER_H*/
Loading

0 comments on commit 66f34a4

Please sign in to comment.