This commit is contained in:
xianjimli 2018-11-18 19:04:13 +08:00
parent d6b4b13990
commit e8294ad66e
21 changed files with 2639 additions and 0 deletions

View File

@ -1,4 +1,8 @@
# 最新动态 # 最新动态
* 2018/11/15-19
* SVG解析器和BSVG(二进制格式的SVG)解析器。
* 2018/11/14 * 2018/11/14
* 完善digit\_clock * 完善digit\_clock
* change WITH\_NANOVG\_GL to WITH\_NANOVG\_GPU * change WITH\_NANOVG\_GL to WITH\_NANOVG\_GPU

View File

@ -8,6 +8,7 @@ NANOVG_BACKEND=os.environ['NANOVG_BACKEND'];
sources=Glob('base/*.c') +\ sources=Glob('base/*.c') +\
Glob('ui_loader/*.c') + \ Glob('ui_loader/*.c') + \
Glob('xml/*.c') + \ Glob('xml/*.c') + \
Glob('svg/*.c') + \
Glob('font_loader/*.c') + \ Glob('font_loader/*.c') + \
Glob('blend/*.c') + \ Glob('blend/*.c') + \
Glob('ext_widgets/*.c') + \ Glob('ext_widgets/*.c') + \

66
src/svg/bsvg.c Normal file
View File

@ -0,0 +1,66 @@
/**
* File: bsvg.c
* Author: AWTK Develop Team
* Brief: binary svg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "svg/bsvg.h"
bsvg_t* bsvg_init(bsvg_t* svg, const uint32_t* data, uint32_t size) {
return_value_if_fail(svg != NULL && data != NULL && size > BSVG_MIN_SIZE, NULL);
svg->header = (bsvg_header_t*)data;
return_value_if_fail(svg->header->magic == BSVG_MAGIC, NULL);
svg->data = data;
svg->size = size;
return svg;
}
const uint8_t* bsvg_visit_path(const uint8_t* p, void* ctx, tk_visit_t on_path) {
const svg_path_t* path = (const svg_path_t*)p;
do {
path = (const svg_path_t*)p;
on_path(ctx, path);
p += svg_path_size(path);
} while (path->type != SVG_PATH_NULL);
return p;
}
ret_t bsvg_visit(bsvg_t* svg, void* ctx, tk_visit_t on_shape, tk_visit_t on_path) {
uint32_t size = 0;
const uint8_t* p = NULL;
return_value_if_fail(svg != NULL && on_shape != NULL && on_path != NULL, RET_BAD_PARAMS);
p = ((const uint8_t*)(svg->data) + sizeof(bsvg_header_t));
while ((p - (const uint8_t*)(svg->data)) < svg->size) {
const svg_shape_t* shape = (const svg_shape_t*)p;
on_shape(ctx, shape);
size = svg_shape_size(shape);
if (shape->type == SVG_SHAPE_PATH) {
p = bsvg_visit_path(p + size, ctx, on_path);
} else {
p += size;
}
}
return RET_OK;
}

42
src/svg/bsvg.h Normal file
View File

@ -0,0 +1,42 @@
/**
* File: bsvg.h
* Author: AWTK Develop Team
* Brief: bsvg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_BSVG_H
#define TK_BSVG_H
#include "svg/svg_shape.h"
#include "svg/bsvg_common.h"
BEGIN_C_DECLS
typedef struct _bsvg_t {
uint32_t size;
const uint32_t* data;
bsvg_header_t* header;
} bsvg_t;
const uint8_t* bsvg_visit_path(const uint8_t* p, void* ctx, tk_visit_t on_path);
bsvg_t* bsvg_init(bsvg_t* svg, const uint32_t* data, uint32_t size);
ret_t bsvg_visit(bsvg_t* svg, void* ctx, tk_visit_t on_shape, tk_visit_t on_path);
END_C_DECLS
#endif /*TK_BSVG_H*/

65
src/svg/bsvg_builder.c Normal file
View File

@ -0,0 +1,65 @@
/**
* File: svg_builder.c
* Author: AWTK Develop Team
* Brief: svg builder
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "svg/bsvg_builder.h"
bsvg_builder_t* bsvg_builder_init(bsvg_builder_t* svg, uint32_t* buff, uint32_t size) {
return_value_if_fail(svg != NULL && buff != NULL && size > BSVG_MIN_SIZE, NULL);
svg->header = (bsvg_header_t*)buff;
svg->header->magic = BSVG_MAGIC;
svg->header->version = 1;
svg->current_shape_type = SVG_SHAPE_NULL;
wbuffer_init(&(svg->buff), (uint8_t*)buff, size);
svg->buff.cursor = sizeof(bsvg_header_t);
return svg;
}
ret_t bsvg_builder_add_shape(bsvg_builder_t* svg, const svg_shape_t* shape) {
return_value_if_fail(svg != NULL && shape != NULL, RET_BAD_PARAMS);
if (svg->current_shape_type == SVG_SHAPE_PATH) {
svg_path_t path_null = {SVG_PATH_NULL};
bsvg_builder_add_sub_path(svg, &path_null);
}
svg->current_shape_type = shape->type;
return wbuffer_write_binary(&(svg->buff), shape, svg_shape_size(shape));
}
ret_t bsvg_builder_add_sub_path(bsvg_builder_t* svg, const svg_path_t* path) {
return_value_if_fail(svg != NULL && path != NULL, RET_BAD_PARAMS);
return_value_if_fail(svg->current_shape_type == SVG_SHAPE_PATH, RET_BAD_PARAMS);
return wbuffer_write_binary(&(svg->buff), path, svg_path_size(path));
}
ret_t bsvg_builder_done(bsvg_builder_t* svg) {
svg_shape_t shape;
return_value_if_fail(svg != NULL, RET_BAD_PARAMS);
memset(&shape, 0x00, sizeof(shape));
shape.type = SVG_SHAPE_NULL;
bsvg_builder_add_shape(svg, &shape);
return RET_OK;
}

44
src/svg/bsvg_builder.h Normal file
View File

@ -0,0 +1,44 @@
/**
* File: bsvg_builder.h
* Author: AWTK Develop Team
* Brief: bsvg builder
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_BSVG_BUILDER_H
#define TK_BSVG_BUILDER_H
#include "svg/svg_shape.h"
#include "svg/bsvg_common.h"
BEGIN_C_DECLS
typedef struct _bsvg_builder_t {
wbuffer_t buff;
bsvg_header_t* header;
svg_shape_type_t current_shape_type;
} bsvg_builder_t;
bsvg_builder_t* bsvg_builder_init(bsvg_builder_t* svg, uint32_t* buff, uint32_t size);
ret_t bsvg_builder_add_shape(bsvg_builder_t* svg, const svg_shape_t* shape);
ret_t bsvg_builder_add_sub_path(bsvg_builder_t* svg, const svg_path_t* path);
ret_t bsvg_builder_done(bsvg_builder_t* svg);
END_C_DECLS
#endif /*TK_BSVG_BUILDER_H*/

48
src/svg/bsvg_common.h Normal file
View File

@ -0,0 +1,48 @@
/**
* File: bsvg_common.h
* Author: AWTK Develop Team
* Brief: svg common
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_BSVG_COMMON_H
#define TK_BSVG_COMMON_H
#include "base/rect.h"
#include "svg/svg_shape.h"
BEGIN_C_DECLS
typedef struct _bsvg_header_t {
uint32_t magic;
uint8_t version;
uint8_t line_cap;
uint8_t line_join;
uint8_t stroke_width;
color_t fill;
color_t stroke;
rect_t viewport;
uint32_t w;
uint32_t h;
} bsvg_header_t;
#define BSVG_MAGIC 0x20181115
#define BSVG_MIN_SIZE (sizeof(bsvg_header_t) + sizeof(svg_shape_t))
END_C_DECLS
#endif /*TK_BSVG_COMMON_H*/

296
src/svg/bsvg_to_svg.c Normal file
View File

@ -0,0 +1,296 @@
/**
* File: bsvg_to_svg.c
* Author: AWTK Develop Team
* Brief: bsvg to svg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "base/str.h"
#include "base/utils.h"
#include "svg/bsvg.h"
#include "svg/bsvg_to_svg.h"
typedef struct _ctx_info_t {
str_t* str;
const svg_shape_t* shape;
} ctx_info_t;
ret_t bsvg_to_svg_path(str_t* str, const svg_path_t* path) {
char buff[128];
switch (path->type) {
case SVG_PATH_M: {
const svg_path_move_t* p = (const svg_path_move_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "M %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_M_REL: {
const svg_path_move_t* p = (const svg_path_move_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "m %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_L: {
const svg_path_line_t* p = (const svg_path_line_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "L %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_L_REL: {
const svg_path_line_t* p = (const svg_path_line_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "l %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_H: {
const svg_path_hline_t* p = (const svg_path_hline_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "H %.1f", p->x);
break;
}
case SVG_PATH_H_REL: {
const svg_path_hline_t* p = (const svg_path_hline_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "h %.1f", p->x);
break;
}
case SVG_PATH_V: {
const svg_path_vline_t* p = (const svg_path_vline_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "V %.1f", p->y);
break;
}
case SVG_PATH_V_REL: {
const svg_path_vline_t* p = (const svg_path_vline_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "v %.1f", p->y);
break;
}
case SVG_PATH_C: {
const svg_path_curve_to_t* p = (const svg_path_curve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "C %.1f %.1f %.1f %.1f %.1f %.1f", p->x1, p->y1, p->x2,
p->y2, p->x, p->y);
break;
}
case SVG_PATH_C_REL: {
const svg_path_curve_to_t* p = (const svg_path_curve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "c %.1f %.1f %.1f %.1f %.1f %.1f", p->x1, p->y1, p->x2,
p->y2, p->x, p->y);
break;
}
case SVG_PATH_S: {
const svg_path_scurve_to_t* p = (const svg_path_scurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "S %.1f %.1f %.1f %.1f", p->x2, p->y2, p->x, p->y);
break;
}
case SVG_PATH_S_REL: {
const svg_path_scurve_to_t* p = (const svg_path_scurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "s %.1f %.1f %.1f %.1f", p->x2, p->y2, p->x, p->y);
break;
}
case SVG_PATH_Q: {
const svg_path_qcurve_to_t* p = (const svg_path_qcurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "Q %.1f %.1f %.1f %.1f", p->x1, p->y1, p->x, p->y);
break;
}
case SVG_PATH_Q_REL: {
const svg_path_qcurve_to_t* p = (const svg_path_qcurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "q %.1f %.1f %.1f %.1f", p->x1, p->y1, p->x, p->y);
break;
}
case SVG_PATH_T: {
const svg_path_tcurve_to_t* p = (const svg_path_tcurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "T %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_T_REL: {
const svg_path_tcurve_to_t* p = (const svg_path_tcurve_to_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "t %.1f %.1f", p->x, p->y);
break;
}
case SVG_PATH_A: {
const svg_path_arc_t* p = (const svg_path_arc_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "A %.1f %.1f %.1f %d %d %.1f %.1f", p->rx, p->ry,
p->rotation, p->large_arc, p->sweep, p->x, p->y);
break;
}
case SVG_PATH_A_REL: {
const svg_path_arc_t* p = (const svg_path_arc_t*)path;
tk_snprintf(buff, sizeof(buff) - 1, "a %.1f %.1f %.1f %d %d %.1f %.1f", p->rx, p->ry,
p->rotation, p->large_arc, p->sweep, p->x, p->y);
break;
}
case SVG_PATH_Z: {
tk_snprintf(buff, sizeof(buff) - 1, "Z");
break;
}
case SVG_PATH_NULL:
default: { break; }
}
return str_append(str, buff);
}
ret_t bsvg_to_svg_shape_end(str_t* str, const svg_shape_t* shape) {
char buff[128];
if (shape->line_cap) {
const char* line_cap = "butt";
if (shape->line_cap == 'r') {
line_cap = "round";
} else if (shape->line_cap == 's') {
line_cap = "square";
}
tk_snprintf(buff, sizeof(buff) - 1, " stroke-linecap=\"%s\"", line_cap);
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
}
if (shape->line_join) {
const char* line_join = "miter";
if (shape->line_join == 'r') {
line_join = "round";
} else if (shape->line_join == 'b') {
line_join = "bevel";
}
tk_snprintf(buff, sizeof(buff) - 1, " stroke-linejoin=\"%s\"", line_join);
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
}
if (shape->stroke_width) {
tk_snprintf(buff, sizeof(buff) - 1, " stroke-width==\"%d\"", shape->stroke_width);
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
}
if (shape->fill.rgba.a) {
const rgba_t* rgba = &(shape->fill.rgba);
tk_snprintf(buff, sizeof(buff) - 1, " fill=\"rgba(%d,%d,%d,%.2f)\"", (int)(rgba->r),
(int)(rgba->g), (int)(rgba->b), (float)rgba->a / 255.0f);
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
}
if (shape->stroke.rgba.a) {
const rgba_t* rgba = &(shape->stroke.rgba);
tk_snprintf(buff, sizeof(buff) - 1, " stroke=\"rgba(%d,%d,%d,%.2f)\"", (int)(rgba->r),
(int)(rgba->g), (int)(rgba->b), (float)rgba->a / 255.0f);
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
}
tk_snprintf(buff, sizeof(buff) - 1, "/>\n");
return_value_if_fail(str_append(str, buff) == RET_OK, RET_OOM);
return RET_OK;
}
ret_t bsvg_to_svg_shape(str_t* str, const svg_shape_t* shape) {
char buff[128];
switch (shape->type) {
case SVG_SHAPE_RECT: {
svg_shape_rect_t* s = (svg_shape_rect_t*)shape;
tk_snprintf(
buff, sizeof(buff) - 1,
"<rect x=\"%.1f\" y=\"%.1f\" width=\"%.1f\" height=\"%.1f\" rx=\"%.1f\" ry=\"%.1f\"",
s->x, s->y, s->w, s->h, s->r, s->r);
str_append(str, buff);
break;
}
case SVG_SHAPE_CIRCLE: {
svg_shape_circle_t* s = (svg_shape_circle_t*)shape;
tk_snprintf(buff, sizeof(buff) - 1, "<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%.1f\"", s->cx,
s->cy, s->r);
str_append(str, buff);
break;
}
case SVG_SHAPE_ELLIPSE: {
svg_shape_ellipse_t* s = (svg_shape_ellipse_t*)shape;
tk_snprintf(buff, sizeof(buff) - 1,
"<ellipse cx=\"%.1f\" cy=\"%.1f\" rx=\"%.1f\" ry=\"%.1f\"", s->cx, s->cy, s->rx,
s->ry);
str_append(str, buff);
break;
}
case SVG_SHAPE_LINE: {
svg_shape_line_t* s = (svg_shape_line_t*)shape;
log_debug("line(%f %f %f %f)\n", s->x1, s->y1, s->x2, s->y2);
tk_snprintf(buff, sizeof(buff) - 1, "<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\"",
s->x1, s->y1, s->x2, s->y2);
str_append(str, buff);
break;
}
case SVG_SHAPE_POLYGON: {
uint32_t i = 0;
svg_shape_polygon_t* s = (svg_shape_polygon_t*)shape;
str_append(str, "<polygon points=\"");
for (i = 0; i < s->nr; i++) {
tk_snprintf(buff, sizeof(buff) - 1, "%.1f ", s->data[i]);
str_append(str, buff);
}
str_append_char(str, '\"');
break;
}
case SVG_SHAPE_POLYLINE: {
uint32_t i = 0;
svg_shape_polygon_t* s = (svg_shape_polygon_t*)shape;
str_append(str, "<polyline points=\"");
for (i = 0; i < s->nr; i++) {
tk_snprintf(buff, sizeof(buff) - 1, "%.1f ", s->data[i]);
str_append(str, buff);
}
str_append_char(str, '\"');
break;
}
case SVG_SHAPE_PATH: {
str_append(str, "<path d=\"");
return RET_OK;
}
default: {
assert(!"not supported type");
return RET_OK;
}
}
return bsvg_to_svg_shape_end(str, shape);
}
static ret_t bsvg_to_svg_on_path(void* ctx, const void* data) {
ctx_info_t* info = (ctx_info_t*)ctx;
const svg_path_t* path = (const svg_path_t*)data;
bsvg_to_svg_path(info->str, path);
str_append_char(info->str, '\"');
bsvg_to_svg_shape_end(info->str, info->shape);
return RET_OK;
}
static ret_t bsvg_to_svg_on_shape(void* ctx, const void* data) {
ctx_info_t* info = (ctx_info_t*)ctx;
const svg_shape_t* shape = (const svg_shape_t*)data;
info->shape = shape;
bsvg_to_svg_shape(info->str, shape);
return RET_OK;
}
ret_t bsvg_to_svg(const uint32_t* data, uint32_t size, str_t* str) {
bsvg_t svg;
ctx_info_t ctx;
return_value_if_fail(bsvg_init(&svg, data, size) != NULL, RET_BAD_PARAMS);
ctx.str = str;
ctx.shape = NULL;
return bsvg_visit(&svg, &ctx, bsvg_to_svg_on_shape, bsvg_to_svg_on_path);
}

37
src/svg/bsvg_to_svg.h Normal file
View File

@ -0,0 +1,37 @@
/**
* File: svg_to_bsvg.c
* Author: AWTK Develop Team
* Brief: bsvg to svg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_BSVG_TO_SVG_H
#define TK_BSVG_TO_SVG_H
#include "svg/bsvg.h"
BEGIN_C_DECLS
ret_t svg_to_bsvg(const uint32_t* data, uint32_t size, str_t* str);
/*public for test*/
ret_t bsvg_to_svg_path(str_t* str, const svg_path_t* path);
ret_t bsvg_to_svg_shape(str_t* str, const svg_shape_t* shape);
END_C_DECLS
#endif /*TK_BSVG_TO_SVG_H*/

151
src/svg/svg_debug.c Normal file
View File

@ -0,0 +1,151 @@
/**
* File: svg_debug.c
* Author: AWTK Develop Team
* Brief: svg debug functions
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "svg/bsvg.h"
#include "svg/svg_shape.h"
#include "svg/svg_debug.h"
ret_t svg_path_dump(void* ctx, const svg_path_t* path) {
uint32_t size = 0;
switch (path->type) {
case SVG_PATH_M:
case SVG_PATH_M_REL: {
size = sizeof(svg_path_move_t);
break;
}
case SVG_PATH_L:
case SVG_PATH_L_REL: {
size = sizeof(svg_path_line_t);
break;
}
case SVG_PATH_H:
case SVG_PATH_H_REL: {
size = sizeof(svg_path_hline_t);
break;
}
case SVG_PATH_V:
case SVG_PATH_V_REL: {
size = sizeof(svg_path_vline_t);
break;
}
case SVG_PATH_C:
case SVG_PATH_C_REL: {
size = sizeof(svg_path_curve_to_t);
break;
}
case SVG_PATH_S:
case SVG_PATH_S_REL: {
size = sizeof(svg_path_scurve_to_t);
break;
}
case SVG_PATH_Q:
case SVG_PATH_Q_REL: {
size = sizeof(svg_path_qcurve_to_t);
break;
}
case SVG_PATH_T:
case SVG_PATH_T_REL: {
size = sizeof(svg_path_tcurve_to_t);
break;
}
case SVG_PATH_A:
case SVG_PATH_A_REL: {
size = sizeof(svg_path_arc_t);
break;
}
case SVG_PATH_NULL:
case SVG_PATH_Z: {
size = sizeof(svg_path_t);
break;
}
default: {
assert(!"not supported");
break;
}
}
return RET_OK;
}
ret_t svg_shape_dump(svg_shape_t* shape) {
return_value_if_fail(shape != NULL, RET_BAD_PARAMS);
log_debug("[type=%d fill=0x%08X stroke=0x%08X line_width=%d line_cap=%d line_join=%d]) ",
(int)(shape->type), shape->fill.color, shape->stroke.color, (int)(shape->stroke_width),
(int)(shape->line_cap), (int)(shape->line_join));
switch (shape->type) {
case SVG_SHAPE_RECT: {
svg_shape_rect_t* s = (svg_shape_rect_t*)shape;
log_debug("rect(%f %f %f %f %f);\n", s->x, s->y, s->w, s->h, s->r);
break;
}
case SVG_SHAPE_CIRCLE: {
svg_shape_circle_t* s = (svg_shape_circle_t*)shape;
log_debug("circle(%f %f %f);\n", s->cx, s->cy, s->r);
break;
}
case SVG_SHAPE_ELLIPSE: {
svg_shape_ellipse_t* s = (svg_shape_ellipse_t*)shape;
log_debug("ellipse(%f %f %f %f)\n", s->cx, s->cy, s->rx, s->ry);
break;
}
case SVG_SHAPE_LINE: {
svg_shape_line_t* s = (svg_shape_line_t*)shape;
log_debug("line(%f %f %f %f)\n", s->x1, s->y1, s->x2, s->y2);
break;
}
case SVG_SHAPE_POLYGON: {
uint32_t i = 0;
svg_shape_polygon_t* s = (svg_shape_polygon_t*)shape;
log_debug("polygon(");
for (i = 0; i < s->nr; i++) {
log_debug("%f ", s->data[i]);
}
log_debug(")\n");
break;
}
case SVG_SHAPE_POLYLINE: {
uint32_t i = 0;
svg_shape_polyline_t* s = (svg_shape_polyline_t*)shape;
log_debug("polyline(");
for (i = 0; i < s->nr; i++) {
log_debug("%f ", s->data[i]);
}
log_debug(")\n");
break;
}
case SVG_SHAPE_PATH: {
svg_shape_path_t* s = (svg_shape_path_t*)shape;
bsvg_visit_path((const uint8_t*)(s->path), NULL, (tk_visit_t)svg_path_dump);
break;
}
default: {
assert(!"not supported type");
break;
}
}
return RET_OK;
}

34
src/svg/svg_debug.h Normal file
View File

@ -0,0 +1,34 @@
/**
* File: svg_debug.h
* Author: AWTK Develop Team
* Brief: svg debug functions
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SVG_DEBUG_H
#define TK_SVG_DEBUG_H
#include "svg/svg_shape.h"
BEGIN_C_DECLS
ret_t svg_shape_dump(svg_shape_t* shape);
ret_t svg_path_dump(void* ctx, const svg_path_t* path);
END_C_DECLS
#endif /*TK_SVG_DEBUG_H*/

276
src/svg/svg_path.c Normal file
View File

@ -0,0 +1,276 @@
/**
* File: svg_path.c
* Author: AWTK Develop Team
* Brief: svg path
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "svg/svg_path.h"
svg_path_t* svg_path_move_init(svg_path_move_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->path.type = SVG_PATH_M;
return (svg_path_t*)path;
}
svg_path_t* svg_path_move_rel_init(svg_path_move_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->path.type = SVG_PATH_M_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_line_init(svg_path_line_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->path.type = SVG_PATH_L;
return (svg_path_t*)path;
}
svg_path_t* svg_path_line_rel_init(svg_path_line_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->path.type = SVG_PATH_L_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_hline_init(svg_path_hline_t* path, float_t x) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->path.type = SVG_PATH_H;
return (svg_path_t*)path;
}
svg_path_t* svg_path_hline_rel_init(svg_path_hline_t* path, float_t x) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->path.type = SVG_PATH_H_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_vline_init(svg_path_vline_t* path, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->y = y;
path->path.type = SVG_PATH_V;
return (svg_path_t*)path;
}
svg_path_t* svg_path_vline_rel_init(svg_path_vline_t* path, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->y = y;
path->path.type = SVG_PATH_V_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_curve_to_init(svg_path_curve_to_t* path, float_t x1, float_t y1, float_t x2,
float_t y2, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->x1 = x1;
path->y1 = y1;
path->x2 = x2;
path->y2 = y2;
path->path.type = SVG_PATH_C;
return (svg_path_t*)path;
}
svg_path_t* svg_path_curve_to_rel_init(svg_path_curve_to_t* path, float_t x1, float_t y1,
float_t x2, float_t y2, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
svg_path_curve_to_init(path, x1, y1, x2, y2, x, y);
path->path.type = SVG_PATH_C_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_scurve_to_init(svg_path_scurve_to_t* path, float_t x2, float_t y2, float_t x,
float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->x2 = x2;
path->y2 = y2;
path->path.type = SVG_PATH_S;
return (svg_path_t*)path;
}
svg_path_t* svg_path_scurve_to_rel_init(svg_path_scurve_to_t* path, float_t x2, float_t y2,
float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
svg_path_scurve_to_init(path, x2, y2, x, y);
path->path.type = SVG_PATH_S_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_qcurve_to_init(svg_path_qcurve_to_t* path, float_t x1, float_t y1, float_t x,
float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->x1 = x1;
path->y1 = y1;
path->path.type = SVG_PATH_Q;
return (svg_path_t*)path;
}
svg_path_t* svg_path_qcurve_to_rel_init(svg_path_qcurve_to_t* path, float_t x1, float_t y1,
float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
svg_path_qcurve_to_init(path, x1, y1, x, y);
path->path.type = SVG_PATH_Q_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_tcurve_to_init(svg_path_tcurve_to_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->path.type = SVG_PATH_T;
return (svg_path_t*)path;
}
svg_path_t* svg_path_tcurve_to_rel_init(svg_path_tcurve_to_t* path, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
svg_path_tcurve_to_init(path, x, y);
path->path.type = SVG_PATH_T_REL;
return (svg_path_t*)path;
}
svg_path_t* svg_path_arc_init(svg_path_arc_t* path, float_t rx, float_t ry, float_t rotation,
bool_t large_arc, bool_t sweep, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
path->x = x;
path->y = y;
path->rx = rx;
path->ry = ry;
path->sweep = sweep;
path->rotation = rotation;
path->large_arc = large_arc;
path->path.type = SVG_PATH_A;
return (svg_path_t*)path;
}
svg_path_t* svg_path_arc_rel_init(svg_path_arc_t* path, float_t rx, float_t ry, float_t rotation,
bool_t large_arc, bool_t sweep, float_t x, float_t y) {
return_value_if_fail(path != NULL, NULL);
svg_path_arc_init(path, rx, ry, rotation, large_arc, sweep, x, y);
path->path.type = SVG_PATH_A_REL;
return (svg_path_t*)path;
}
uint32_t svg_path_size(const svg_path_t* path) {
uint32_t size = 0;
switch (path->type) {
case SVG_PATH_M:
case SVG_PATH_M_REL: {
size = sizeof(svg_path_move_t);
break;
}
case SVG_PATH_L:
case SVG_PATH_L_REL: {
size = sizeof(svg_path_line_t);
break;
}
case SVG_PATH_H:
case SVG_PATH_H_REL: {
size = sizeof(svg_path_hline_t);
break;
}
case SVG_PATH_V:
case SVG_PATH_V_REL: {
size = sizeof(svg_path_vline_t);
break;
}
case SVG_PATH_C:
case SVG_PATH_C_REL: {
size = sizeof(svg_path_curve_to_t);
break;
}
case SVG_PATH_S:
case SVG_PATH_S_REL: {
size = sizeof(svg_path_scurve_to_t);
break;
}
case SVG_PATH_Q:
case SVG_PATH_Q_REL: {
size = sizeof(svg_path_qcurve_to_t);
break;
}
case SVG_PATH_T:
case SVG_PATH_T_REL: {
size = sizeof(svg_path_tcurve_to_t);
break;
}
case SVG_PATH_A:
case SVG_PATH_A_REL: {
size = sizeof(svg_path_arc_t);
break;
}
case SVG_PATH_NULL:
case SVG_PATH_Z: {
size = sizeof(svg_path_t);
break;
}
default: {
assert(!"not supported");
break;
}
}
return size;
}

166
src/svg/svg_path.h Normal file
View File

@ -0,0 +1,166 @@
/**
* File: svg_path.h
* Author: AWTK Develop Team
* Brief: svg path
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SVG_PATH_H
#define TK_SVG_PATH_H
#include "base/color.h"
#include "base/buffer.h"
BEGIN_C_DECLS
typedef struct _svg_path_t {
uint32_t type;
} svg_path_t;
typedef enum _svg_path_type_t {
SVG_PATH_NULL = 0,
SVG_PATH_M,
SVG_PATH_M_REL,
SVG_PATH_L,
SVG_PATH_L_REL,
SVG_PATH_H,
SVG_PATH_H_REL,
SVG_PATH_V,
SVG_PATH_V_REL,
SVG_PATH_C,
SVG_PATH_C_REL,
SVG_PATH_S,
SVG_PATH_S_REL,
SVG_PATH_Q,
SVG_PATH_Q_REL,
SVG_PATH_T,
SVG_PATH_T_REL,
SVG_PATH_A,
SVG_PATH_A_REL,
SVG_PATH_Z,
} svg_path_type_t;
typedef struct _svg_path_move_t {
svg_path_t path;
float_t x;
float_t y;
} svg_path_move_t;
typedef struct _svg_path_line_t {
svg_path_t path;
float_t x;
float_t y;
} svg_path_line_t;
typedef struct _svg_path_hline_t {
svg_path_t path;
float_t x;
} svg_path_hline_t;
typedef struct _svg_path_vline_t {
svg_path_t path;
float_t y;
} svg_path_vline_t;
typedef struct _svg_path_curve_to_t {
svg_path_t path;
float_t x1;
float_t y1;
float_t x2;
float_t y2;
float_t x;
float_t y;
} svg_path_curve_to_t;
typedef struct _svg_path_scurve_to_t {
svg_path_t path;
float_t x2;
float_t y2;
float_t x;
float_t y;
} svg_path_scurve_to_t;
typedef struct _svg_path_qcurve_to_t {
svg_path_t path;
float_t x1;
float_t y1;
float_t x;
float_t y;
} svg_path_qcurve_to_t;
typedef struct _svg_path_tcurve_to_t {
svg_path_t path;
float_t x;
float_t y;
} svg_path_tcurve_to_t;
typedef struct _svg_path_arc_t {
svg_path_t path;
float_t rx;
float_t ry;
float_t rotation;
uint16_t large_arc;
uint16_t sweep;
float_t x;
float_t y;
} svg_path_arc_t;
uint32_t svg_path_size(const svg_path_t* path);
svg_path_t* svg_path_move_init(svg_path_move_t* path, float_t x, float_t y);
svg_path_t* svg_path_move_rel_init(svg_path_move_t* path, float_t x, float_t y);
svg_path_t* svg_path_line_init(svg_path_line_t* path, float_t x, float_t y);
svg_path_t* svg_path_line_rel_init(svg_path_line_t* path, float_t x, float_t y);
svg_path_t* svg_path_hline_init(svg_path_hline_t* path, float_t x);
svg_path_t* svg_path_hline_rel_init(svg_path_hline_t* path, float_t x);
svg_path_t* svg_path_vline_init(svg_path_vline_t* path, float_t y);
svg_path_t* svg_path_vline_rel_init(svg_path_vline_t* path, float_t y);
svg_path_t* svg_path_curve_to_init(svg_path_curve_to_t* path, float_t x1, float_t y1, float_t x2,
float_t y2, float_t x, float_t y);
svg_path_t* svg_path_curve_to_rel_init(svg_path_curve_to_t* path, float_t x1, float_t y1,
float_t x2, float_t y2, float_t x, float_t y);
svg_path_t* svg_path_scurve_to_init(svg_path_scurve_to_t* path, float_t x2, float_t y2, float_t x,
float_t y);
svg_path_t* svg_path_scurve_to_rel_init(svg_path_scurve_to_t* path, float_t x2, float_t y2,
float_t x, float_t y);
svg_path_t* svg_path_qcurve_to_init(svg_path_qcurve_to_t* path, float_t x1, float_t y1, float_t x,
float_t y);
svg_path_t* svg_path_qcurve_to_rel_init(svg_path_qcurve_to_t* path, float_t x1, float_t y1,
float_t x, float_t y);
svg_path_t* svg_path_tcurve_to_init(svg_path_tcurve_to_t* path, float_t x, float_t y);
svg_path_t* svg_path_tcurve_to_rel_init(svg_path_tcurve_to_t* path, float_t x, float_t y);
svg_path_t* svg_path_arc_init(svg_path_arc_t* path, float_t rx, float_t ry, float_t rotation,
bool_t large_arc, bool_t sweep, float_t x, float_t y);
svg_path_t* svg_path_arc_rel_init(svg_path_arc_t* path, float_t rx, float_t ry, float_t rotation,
bool_t large_arc, bool_t sweep, float_t x, float_t y);
END_C_DECLS
#endif /*TK_SVG_PATH_H*/

292
src/svg/svg_path_parser.c Normal file
View File

@ -0,0 +1,292 @@
/**
* File: svg_path_parser.c
* Author: AWTK Develop Team
* Brief: svg path_parser
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-17 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "base/utils.h"
#include "svg/svg_path.h"
#include "svg/svg_path_parser.h"
typedef struct _svg_path_parser_t {
const char* p;
const char* path;
void* ctx;
tk_visit_t on_path;
} svg_path_parser_t;
typedef enum _token_type_t { TOKEN_NUMBER, TOKEN_CMD, TOKEN_EOF } token_type_t;
static token_type_t svg_path_parser_next_token_type(svg_path_parser_t* parser) {
const char* p = parser->p;
while (*p == ' ' || *p == ',') {
p++;
}
parser->p = p;
if (!*p) {
return TOKEN_EOF;
}
if (isalpha(*p)) {
return TOKEN_CMD;
} else {
return TOKEN_NUMBER;
}
}
static char svg_path_parser_get_cmd(svg_path_parser_t* parser) {
char c = parser->p[0];
parser->p++;
return c;
}
static float_t svg_path_parser_get_number(svg_path_parser_t* parser) {
uint32_t i = 0;
const char* p = NULL;
char token[TK_NUM_MAX_LEN + 1];
return_value_if_fail(svg_path_parser_next_token_type(parser) == TOKEN_NUMBER, RET_BAD_PARAMS);
p = parser->p;
if (*p == '+' || *p == '-') {
token[i++] = *p++;
}
while (*p == '.' || (*p >= '0' && *p <= '9')) {
token[i++] = *p++;
}
token[i] = '\0';
parser->p = p;
return tk_atof(token);
}
static ret_t svg_path_parser_parse_cmd(svg_path_parser_t* parser, char c) {
float_t x = 0;
float_t y = 0;
float_t x1 = 0;
float_t y1 = 0;
float_t x2 = 0;
float_t y2 = 0;
switch (c) {
case 'M':
case 'm': {
svg_path_move_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'M') {
svg_path_move_init(&path, x, y);
} else {
svg_path_move_rel_init(&path, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'Z':
case 'z': {
svg_path_t path = {SVG_PATH_Z};
parser->on_path(parser->ctx, (svg_path_t*)&path);
break;
}
case 'L':
case 'l': {
svg_path_line_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'L') {
svg_path_line_init(&path, x, y);
} else {
svg_path_line_rel_init(&path, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'H':
case 'h': {
svg_path_hline_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x = svg_path_parser_get_number(parser);
if (c == 'H') {
svg_path_hline_init(&path, x);
} else {
svg_path_hline_rel_init(&path, x);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'V':
case 'v': {
svg_path_vline_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
y = svg_path_parser_get_number(parser);
if (c == 'V') {
svg_path_vline_init(&path, y);
} else {
svg_path_vline_rel_init(&path, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'C':
case 'c': {
svg_path_curve_to_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x1 = svg_path_parser_get_number(parser);
y1 = svg_path_parser_get_number(parser);
x2 = svg_path_parser_get_number(parser);
y2 = svg_path_parser_get_number(parser);
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'C') {
svg_path_curve_to_init(&path, x1, y1, x2, y2, x, y);
} else {
svg_path_curve_to_rel_init(&path, x1, y1, x2, y2, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'S':
case 's': {
svg_path_scurve_to_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x2 = svg_path_parser_get_number(parser);
y2 = svg_path_parser_get_number(parser);
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'S') {
svg_path_scurve_to_init(&path, x2, y2, x, y);
} else {
svg_path_scurve_to_rel_init(&path, x2, y2, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'Q':
case 'q': {
svg_path_qcurve_to_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x1 = svg_path_parser_get_number(parser);
y1 = svg_path_parser_get_number(parser);
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'Q') {
svg_path_qcurve_to_init(&path, x1, y1, x, y);
} else {
svg_path_qcurve_to_rel_init(&path, x1, y1, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'T':
case 't': {
svg_path_tcurve_to_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'T') {
svg_path_tcurve_to_init(&path, x, y);
} else {
svg_path_tcurve_to_rel_init(&path, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
case 'A':
case 'a': {
svg_path_arc_t path;
while (svg_path_parser_next_token_type(parser) == TOKEN_NUMBER) {
float_t rx = svg_path_parser_get_number(parser);
float_t ry = svg_path_parser_get_number(parser);
float_t rotation = svg_path_parser_get_number(parser);
float_t large_arc = svg_path_parser_get_number(parser);
float_t sweep = svg_path_parser_get_number(parser);
x = svg_path_parser_get_number(parser);
y = svg_path_parser_get_number(parser);
if (c == 'A') {
svg_path_arc_init(&path, rx, ry, rotation, large_arc, sweep, x, y);
} else {
svg_path_arc_rel_init(&path, rx, ry, rotation, large_arc, sweep, x, y);
}
parser->on_path(parser->ctx, (svg_path_t*)&path);
}
break;
}
default:
break;
}
return RET_OK;
}
static ret_t svg_path_parser_parse(svg_path_parser_t* parser) {
token_type_t type = svg_path_parser_next_token_type(parser);
while (type != TOKEN_EOF) {
if (type == TOKEN_CMD) {
char c = svg_path_parser_get_cmd(parser);
svg_path_parser_parse_cmd(parser, c);
} else {
assert(!"unexpected number");
svg_path_parser_get_number(parser);
}
type = svg_path_parser_next_token_type(parser);
}
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->p = path;
parser->ctx = ctx;
parser->on_path = on_path;
return RET_OK;
}
ret_t svg_path_parse(const char* path, void* ctx, tk_visit_t on_path) {
svg_path_parser_t parser;
return_value_if_fail(path != NULL && on_path != NULL, RET_BAD_PARAMS);
svg_path_parser_init(&parser, path, ctx, on_path);
return svg_path_parser_parse(&parser);
}

33
src/svg/svg_path_parser.h Normal file
View File

@ -0,0 +1,33 @@
/**
* File: svg_path_parser.h
* Author: AWTK Develop Team
* Brief: svg path_parser
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-17 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SVG_PATH_BUILDER_H
#define TK_SVG_PATH_BUILDER_H
#include "base/types_def.h"
BEGIN_C_DECLS
ret_t svg_path_parse(const char* path, void* ctx, tk_visit_t on_path);
END_C_DECLS
#endif /*TK_SVG_PATH_BUILDER_H*/

159
src/svg/svg_shape.c Normal file
View File

@ -0,0 +1,159 @@
/**
* File: svg_shape.c
* Author: AWTK Develop Team
* Brief: svg shape
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "svg/svg_shape.h"
uint32_t svg_shape_size(const svg_shape_t* shape) {
uint32_t size = 0;
switch (shape->type) {
case SVG_SHAPE_RECT: {
size = sizeof(svg_shape_rect_t);
break;
}
case SVG_SHAPE_CIRCLE: {
size = sizeof(svg_shape_circle_t);
break;
}
case SVG_SHAPE_ELLIPSE: {
size = sizeof(svg_shape_ellipse_t);
break;
}
case SVG_SHAPE_LINE: {
size = sizeof(svg_shape_line_t);
break;
}
case SVG_SHAPE_POLYGON: {
svg_shape_polygon_t* s = (svg_shape_polygon_t*)shape;
size = sizeof(svg_shape_polygon_t) + s->nr * 2 * sizeof(float_t) - sizeof(s->data);
break;
}
case SVG_SHAPE_POLYLINE: {
svg_shape_polyline_t* s = (svg_shape_polyline_t*)shape;
size = sizeof(svg_shape_polyline_t) + s->nr * 2 * sizeof(float_t) - sizeof(s->data);
break;
}
case SVG_SHAPE_PATH: {
size = sizeof(svg_shape_path_t);
break;
}
case SVG_SHAPE_NULL: {
size = sizeof(svg_shape_t);
break;
}
default: {
assert(!"not supported type");
break;
}
}
return size;
}
svg_shape_t* svg_shape_rect_init(svg_shape_rect_t* s, float_t x, float_t y, float_t w, float_t h,
float_t r) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->x = x;
s->y = y;
s->w = w;
s->h = h;
s->r = r;
s->shape.type = SVG_SHAPE_RECT;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_circle_init(svg_shape_circle_t* s, float_t cx, float_t cy, float_t r) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->r = r;
s->cx = cx;
s->cy = cy;
s->shape.type = SVG_SHAPE_CIRCLE;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_ellipse_init(svg_shape_ellipse_t* s, float_t cx, float_t cy, float_t rx,
float_t ry) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->rx = rx;
s->ry = ry;
s->cx = cx;
s->cy = cy;
s->shape.type = SVG_SHAPE_ELLIPSE;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_line_init(svg_shape_line_t* s, float_t x1, float_t y1, float_t x2,
float_t y2) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->x1 = x1;
s->y1 = y1;
s->x2 = x2;
s->y2 = y2;
s->shape.type = SVG_SHAPE_LINE;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_polygon_init(svg_shape_polygon_t* s) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->nr = 0;
s->shape.type = SVG_SHAPE_POLYGON;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_polyline_init(svg_shape_polyline_t* s) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->nr = 0;
s->shape.type = SVG_SHAPE_POLYLINE;
return (svg_shape_t*)s;
}
svg_shape_t* svg_shape_path_init(svg_shape_path_t* s) {
return_value_if_fail(s != NULL, NULL);
memset(s, 0x00, sizeof(*s));
s->shape.type = SVG_SHAPE_PATH;
return (svg_shape_t*)s;
}

114
src/svg/svg_shape.h Normal file
View File

@ -0,0 +1,114 @@
/**
* File: svg_shape.h
* Author: AWTK Develop Team
* Brief: svg shape
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SVG_SHAPE_H
#define TK_SVG_SHAPE_H
#include "svg/svg_path.h"
BEGIN_C_DECLS
typedef enum _svg_shape_type_t {
SVG_SHAPE_NULL = 0,
SVG_SHAPE_RECT,
SVG_SHAPE_CIRCLE,
SVG_SHAPE_ELLIPSE,
SVG_SHAPE_LINE,
SVG_SHAPE_POLYGON,
SVG_SHAPE_POLYLINE,
SVG_SHAPE_PATH
} svg_shape_type_t;
typedef struct _svg_shape_t {
uint8_t type;
uint8_t line_cap;
uint8_t line_join;
uint8_t stroke_width;
color_t fill;
color_t stroke;
} svg_shape_t;
typedef struct _svg_shape_rect_t {
svg_shape_t shape;
float_t x;
float_t y;
float_t w;
float_t h;
float_t r;
} svg_shape_rect_t;
typedef struct _svg_shape_circle_t {
svg_shape_t shape;
float_t cx;
float_t cy;
float_t r;
} svg_shape_circle_t;
typedef struct _svg_shape_ellipse_t {
svg_shape_t shape;
float_t cx;
float_t cy;
float_t rx;
float_t ry;
} svg_shape_ellipse_t;
typedef struct _svg_shape_line_t {
svg_shape_t shape;
float_t x1;
float_t y1;
float_t x2;
float_t y2;
} svg_shape_line_t;
typedef struct _svg_shape_polyline_t {
svg_shape_t shape;
uint32_t nr;
float_t data[1];
} svg_shape_polyline_t;
typedef struct _svg_shape_polygon_t {
svg_shape_t shape;
uint32_t nr;
float_t data[1];
} svg_shape_polygon_t;
typedef struct _svg_shape_path_t {
svg_shape_t shape;
svg_path_t path[1];
} svg_shape_path_t;
uint32_t svg_shape_size(const svg_shape_t* shape);
svg_shape_t* svg_shape_rect_init(svg_shape_rect_t* s, float_t x, float_t y, float_t w, float_t h,
float_t r);
svg_shape_t* svg_shape_circle_init(svg_shape_circle_t* s, float_t cx, float_t cy, float_t r);
svg_shape_t* svg_shape_ellipse_init(svg_shape_ellipse_t* s, float_t cx, float_t cy, float_t rx,
float_t ry);
svg_shape_t* svg_shape_line_init(svg_shape_line_t* s, float_t x1, float_t y1, float_t x2,
float_t y2);
svg_shape_t* svg_shape_polygon_init(svg_shape_polygon_t* s);
svg_shape_t* svg_shape_polyline_init(svg_shape_polyline_t* s);
svg_shape_t* svg_shape_path_init(svg_shape_path_t* s);
END_C_DECLS
#endif /*TK_SVG_SHAPE_H*/

226
src/svg/svg_to_bsvg.c Normal file
View File

@ -0,0 +1,226 @@
/**
* File: svg_to_bsvg.c
* Author: AWTK Develop Team
* Brief: svg to bsvg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "base/mem.h"
#include "base/utils.h"
#include "base/color_parser.h"
#include "xml/xml_parser.h"
#include "svg/svg_to_bsvg.h"
#include "svg/svg_path_parser.h"
#include "svg/bsvg_builder.h"
typedef struct _xml_builder_t {
XmlBuilder builder;
bsvg_builder_t bsvg;
} xml_builder_t;
static void svg_on_svg_tag(bsvg_builder_t* svg, const char** attrs) {
uint32_t i = 0;
int32_t x = 0;
int32_t y = 0;
int32_t w = 0;
int32_t h = 0;
while (attrs[i] != NULL) {
const char* k = attrs[i];
const char* v = attrs[i + 1];
if (tk_str_eq(k, "viewBox")) {
tk_sscanf(v, "%d %d %d %d", &x, &y, &w, &h);
svg->header->viewport.x = x;
svg->header->viewport.y = y;
svg->header->viewport.w = w;
svg->header->viewport.h = h;
} else if (tk_str_eq(k, "width")) {
svg->header->w = tk_atoi(v);
} else if (tk_str_eq(k, "height")) {
svg->header->h = tk_atoi(v);
}
i += 2;
}
return;
}
static ret_t svg_on_sub_path(void* ctx, const void* data) {
bsvg_builder_t* svg = (bsvg_builder_t*)ctx;
const svg_path_t* path = (const svg_path_t*)data;
bsvg_builder_add_sub_path(svg, path);
return RET_OK;
}
static void svg_init_shape(svg_shape_t* shape, const char** attrs) {
uint32_t i = 0;
while (attrs[i] != NULL) {
const char* k = attrs[i];
const char* v = attrs[i + 1];
if (tk_str_eq(k, "stroke-linecap")) {
shape->line_cap = v[0];
} else if (tk_str_eq(k, "stroke-linejoin")) {
shape->line_join = v[0];
} else if (tk_str_eq(k, "stroke-width")) {
shape->stroke_width = tk_atoi(v);
} else if (tk_str_eq(k, "stroke")) {
shape->stroke = color_parse_simple(v);
} else if (tk_str_eq(k, "fill")) {
shape->fill = color_parse_simple(v);
}
i += 2;
}
return;
}
static void svg_on_shape_path(bsvg_builder_t* svg, const char** attrs) {
uint32_t i = 0;
svg_shape_path_t s;
svg_shape_path_init(&s);
svg_init_shape((svg_shape_t*)&s, attrs);
bsvg_builder_add_shape(svg, (svg_shape_t*)&s);
while (attrs[i] != NULL) {
const char* k = attrs[i];
const char* v = attrs[i + 1];
if (tk_str_eq(k, "d")) {
svg_path_parse(v, svg, svg_on_sub_path);
}
i += 2;
}
return;
}
static void svg_on_shape_rect(bsvg_builder_t* svg, const char** attrs) {
float_t x = 0;
float_t y = 0;
float_t w = 0;
float_t h = 0;
float_t r = 0;
uint32_t i = 0;
svg_shape_rect_t s;
while (attrs[i] != NULL) {
const char* k = attrs[i];
const char* v = attrs[i + 1];
if (tk_str_eq(k, "x")) {
x = tk_atof(v);
} else if (tk_str_eq(k, "y")) {
y = tk_atof(v);
} else if (tk_str_eq(k, "w")) {
w = tk_atof(v);
} else if (tk_str_eq(k, "h")) {
h = tk_atof(v);
} else if (tk_str_eq(k, "rx")) {
r = tk_atof(v);
}
i += 2;
}
svg_shape_rect_init(&s, x, y, w, h, r);
svg_init_shape((svg_shape_t*)&s, attrs);
bsvg_builder_add_shape(svg, (svg_shape_t*)&s);
return;
}
static void svg_on_shape_circle(bsvg_builder_t* svg, const char** attrs) {
float_t x = 0;
float_t y = 0;
float_t r = 0;
uint32_t i = 0;
svg_shape_circle_t s;
while (attrs[i] != NULL) {
const char* k = attrs[i];
const char* v = attrs[i + 1];
if (tk_str_eq(k, "x")) {
x = tk_atof(v);
} else if (tk_str_eq(k, "y")) {
y = tk_atof(v);
} else if (tk_str_eq(k, "r")) {
r = tk_atof(v);
}
i += 2;
}
svg_shape_circle_init(&s, x, y, r);
svg_init_shape((svg_shape_t*)&s, attrs);
bsvg_builder_add_shape(svg, (svg_shape_t*)&s);
return;
}
static void svg_on_start(XmlBuilder* thiz, const char* tag, const char** attrs) {
xml_builder_t* b = (xml_builder_t*)thiz;
bsvg_builder_t* svg = &(b->bsvg);
if (tk_str_eq(tag, "svg")) {
svg_on_svg_tag(svg, attrs);
} else if (tk_str_eq(tag, "path")) {
svg_on_shape_path(svg, attrs);
} else if (tk_str_eq(tag, "rect")) {
svg_on_shape_rect(svg, attrs);
} else if (tk_str_eq(tag, "circle")) {
svg_on_shape_circle(svg, attrs);
}
return;
}
static void svg_on_error(XmlBuilder* thiz, int line, int row, const char* message) {
(void)thiz;
printf("parse error: %d:%d %s\n", line, row, message);
return;
}
static XmlBuilder* builder_init(xml_builder_t* b, uint32_t* buff, uint32_t buff_size) {
memset(b, 0x00, sizeof(*b));
b->builder.on_start = svg_on_start;
b->builder.on_error = svg_on_error;
bsvg_builder_init(&(b->bsvg), buff, buff_size);
return &(b->builder);
}
ret_t svg_to_bsvg(const char* xml, uint32_t size, uint32_t** out, uint32_t* out_size) {
xml_builder_t b;
uint32_t* buff = NULL;
uint32_t buff_size = size + 100;
return_value_if_fail(xml != NULL && out != NULL && out_size != NULL, RET_BAD_PARAMS);
buff = (uint32_t*)TKMEM_ALLOC(buff_size);
return_value_if_fail(buff != NULL, RET_OOM);
XmlParser* parser = xml_parser_create();
xml_parser_set_builder(parser, builder_init(&b, buff, buff_size));
xml_parser_parse(parser, xml, size);
*out = buff;
*out_size = b.bsvg.buff.cursor;
return RET_OK;
}

33
src/svg/svg_to_bsvg.h Normal file
View File

@ -0,0 +1,33 @@
/**
* File: svg_to_bsvg.c
* Author: AWTK Develop Team
* Brief: svg to bsvg
*
* Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SVG_TO_BSVG_H
#define TK_SVG_TO_BSVG_H
#include "svg/bsvg.h"
BEGIN_C_DECLS
ret_t svg_to_bsvg(const char* xml, uint32_t size, uint32_t** out, uint32_t* out_size);
END_C_DECLS
#endif /*TK_SVG_TO_BSVG_H*/

519
tests/svg_test.cc Normal file
View File

@ -0,0 +1,519 @@
#include "svg/bsvg.h"
#include "svg/bsvg_builder.h"
#include "svg/svg_path_parser.h"
#include "base/utils.h"
#include "gtest/gtest.h"
#include "svg/bsvg_to_svg.h"
#include <string>
using std::string;
static void cmp_shape(const svg_shape_t* shape1, const svg_shape_t* shape2) {
if (shape2->type != SVG_SHAPE_NULL) {
ASSERT_EQ(shape1->type, shape2->type);
ASSERT_EQ(memcmp(shape1, shape2, svg_shape_size(shape1)), 0);
}
}
static ret_t on_shape(void* ctx, const void* data) {
cmp_shape((const svg_shape_t*)ctx, (const svg_shape_t*)data);
return RET_OK;
}
static ret_t on_path_null(void* ctx, const void* data) {
(void)ctx;
(void)data;
return RET_OK;
}
static void test_one_shape(svg_shape_t* shape) {
string str;
bsvg_t bsvg;
bsvg_t* svg = &bsvg;
uint32_t buff[1024];
bsvg_builder_t bsvg_builder;
bsvg_builder_t* w = &bsvg_builder;
ASSERT_EQ(bsvg_builder_init(w, buff, sizeof(buff)), w);
ASSERT_EQ(w->header->magic, BSVG_MAGIC);
ASSERT_EQ(w->buff.cursor, sizeof(bsvg_header_t));
ASSERT_EQ(bsvg_builder_add_shape(w, shape), RET_OK);
ASSERT_EQ(bsvg_builder_done(w), RET_OK);
ASSERT_EQ(bsvg_init(svg, buff, w->buff.cursor), svg);
ASSERT_EQ(bsvg_visit(svg, shape, on_shape, on_path_null), RET_OK);
}
TEST(SvgShape, rect) {
str_t str;
str_init(&str, 100);
svg_shape_rect_t s;
test_one_shape(svg_shape_rect_init(&s, 10, 20, 30, 40, 5));
s.shape.line_cap = 'r';
s.shape.line_join = 'b';
s.shape.stroke_width = 5;
s.shape.fill = color_init(0xff, 0xff, 0xff, 0xff);
s.shape.stroke = color_init(0, 0, 0, 0xff);
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)&s), RET_OK);
ASSERT_EQ(
string(str.str),
string("<rect x=\"10.0\" y=\"20.0\" width=\"30.0\" height=\"40.0\" rx=\"5.0\" ry=\"5.0\" "
"stroke-linecap=\"round\" stroke-linejoin=\"bevel\" stroke-width==\"5\" "
"fill=\"rgba(255,255,255,1.00)\" stroke=\"rgba(0,0,0,1.00)\"/>\n"));
str_reset(&str);
}
TEST(SvgShape, line) {
str_t str;
str_init(&str, 100);
svg_shape_line_t s;
test_one_shape(svg_shape_line_init(&s, 10, 20, 30, 40));
s.shape.line_cap = 'r';
s.shape.line_join = 'm';
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)&s), RET_OK);
ASSERT_EQ(string(str.str), string("<line x1=\"10.0\" y1=\"20.0\" x2=\"30.0\" y2=\"40.0\" "
"stroke-linecap=\"round\" stroke-linejoin=\"miter\"/>\n"));
str_reset(&str);
}
TEST(SvgShape, circle) {
str_t str;
str_init(&str, 100);
svg_shape_circle_t s;
test_one_shape(svg_shape_circle_init(&s, 10, 20, 30));
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)&s), RET_OK);
ASSERT_EQ(string(str.str), string("<circle cx=\"10.0\" cy=\"20.0\" r=\"30.0\"/>\n"));
str_reset(&str);
}
TEST(SvgShape, ellipse) {
str_t str;
str_init(&str, 100);
svg_shape_ellipse_t s;
test_one_shape(svg_shape_ellipse_init(&s, 10, 20, 30, 40));
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)&s), RET_OK);
ASSERT_EQ(string(str.str),
string("<ellipse cx=\"10.0\" cy=\"20.0\" rx=\"30.0\" ry=\"40.0\"/>\n"));
str_reset(&str);
}
TEST(SvgShape, polygon) {
str_t str;
str_init(&str, 100);
uint32_t buff[100];
svg_shape_polygon_t* s = (svg_shape_polygon_t*)(buff);
svg_shape_polygon_init(s);
s->nr = 4;
s->data[0] = 1;
s->data[1] = 2;
s->data[2] = 3;
s->data[3] = 4;
test_one_shape((svg_shape_t*)s);
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)s), RET_OK);
ASSERT_EQ(string(str.str), string("<polygon points=\"1.0 2.0 3.0 4.0 \"/>\n"));
str_reset(&str);
}
TEST(SvgShape, polyline) {
str_t str;
str_init(&str, 100);
uint32_t buff[100];
svg_shape_polyline_t* s = (svg_shape_polyline_t*)(buff);
svg_shape_polyline_init(s);
s->nr = 4;
s->data[0] = 1;
s->data[1] = 2;
s->data[2] = 3;
s->data[3] = 4;
test_one_shape((svg_shape_t*)s);
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)s), RET_OK);
ASSERT_EQ(string(str.str), string("<polyline points=\"1.0 2.0 3.0 4.0 \"/>\n"));
str_reset(&str);
}
TEST(SvgShape, path) {
str_t str;
str_init(&str, 100);
svg_shape_path_t s;
test_one_shape(svg_shape_path_init(&s));
ASSERT_EQ(bsvg_to_svg_shape(&str, (const svg_shape_t*)&s), RET_OK);
ASSERT_EQ(string(str.str), string("<path d=\""));
str_reset(&str);
}
static void cmp_path(const svg_path_t* path1, const svg_path_t* path2) {
if (path2->type != SVG_PATH_NULL) {
ASSERT_EQ(path1->type, path2->type);
ASSERT_EQ(memcmp(path1, path2, svg_path_size(path1)), 0);
}
}
static uint32_t s_on_path_count = 0;
static ret_t on_path(void* ctx, const void* data) {
cmp_path((const svg_path_t*)ctx, (const svg_path_t*)data);
s_on_path_count++;
return RET_OK;
}
static ret_t on_shape_null(void* ctx, const void* data) {
(void)ctx;
(void)data;
return RET_OK;
}
static void test_one_path(svg_path_t* path) {
string str;
bsvg_t bsvg;
svg_shape_path_t s;
bsvg_t* svg = &bsvg;
uint32_t buff[1024];
bsvg_builder_t bsvg_builder;
bsvg_builder_t* w = &bsvg_builder;
svg_shape_t* shape = svg_shape_path_init(&s);
ASSERT_EQ(bsvg_builder_init(w, buff, sizeof(buff)), w);
ASSERT_EQ(w->header->magic, BSVG_MAGIC);
ASSERT_EQ(w->buff.cursor, sizeof(bsvg_header_t));
ASSERT_EQ(bsvg_builder_add_shape(w, shape), RET_OK);
;
ASSERT_EQ(bsvg_builder_add_sub_path(w, path), RET_OK);
ASSERT_EQ(bsvg_builder_done(w), RET_OK);
;
ASSERT_EQ(bsvg_init(svg, buff, w->buff.cursor), svg);
ASSERT_EQ(bsvg_visit(svg, path, on_shape_null, on_path), RET_OK);
}
TEST(SvgPath, move) {
str_t s;
str_init(&s, 100);
svg_path_move_t path;
test_one_path(svg_path_move_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("M 1.0 2.0"));
test_one_path(svg_path_move_rel_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("m 1.0 2.0"));
str_reset(&s);
}
TEST(SvgPath, line) {
str_t s;
str_init(&s, 100);
svg_path_line_t path;
test_one_path(svg_path_line_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("L 1.0 2.0"));
test_one_path(svg_path_line_rel_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("l 1.0 2.0"));
str_reset(&s);
}
TEST(SvgPath, hline) {
str_t s;
str_init(&s, 100);
svg_path_hline_t path;
test_one_path(svg_path_hline_init(&path, 12));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("H 12.0"));
test_one_path(svg_path_hline_rel_init(&path, 12));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("h 12.0"));
str_reset(&s);
}
TEST(SvgPath, vline) {
str_t s;
str_init(&s, 100);
svg_path_vline_t path;
test_one_path(svg_path_vline_init(&path, 12));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("V 12.0"));
test_one_path(svg_path_vline_rel_init(&path, 12));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("v 12.0"));
str_reset(&s);
}
TEST(SvgPath, curve) {
str_t s;
str_init(&s, 100);
svg_path_curve_to_t path;
test_one_path(svg_path_curve_to_init(&path, 1, 2, 3, 4, 5, 6));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("C 1.0 2.0 3.0 4.0 5.0 6.0"));
test_one_path(svg_path_curve_to_rel_init(&path, 1, 2, 3, 4, 5, 6));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("c 1.0 2.0 3.0 4.0 5.0 6.0"));
str_reset(&s);
}
TEST(SvgPath, scurve) {
str_t s;
str_init(&s, 100);
svg_path_scurve_to_t path;
test_one_path(svg_path_scurve_to_init(&path, 1, 2, 3, 4));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("S 1.0 2.0 3.0 4.0"));
test_one_path(svg_path_scurve_to_rel_init(&path, 1, 2, 3, 4));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("s 1.0 2.0 3.0 4.0"));
str_reset(&s);
}
TEST(SvgPath, qcurve) {
str_t s;
str_init(&s, 100);
svg_path_qcurve_to_t path;
test_one_path(svg_path_qcurve_to_init(&path, 1, 2, 3, 4));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("Q 1.0 2.0 3.0 4.0"));
test_one_path(svg_path_qcurve_to_rel_init(&path, 1, 2, 3, 4));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("q 1.0 2.0 3.0 4.0"));
str_reset(&s);
}
TEST(SvgPath, tcurve) {
str_t s;
str_init(&s, 100);
svg_path_tcurve_to_t path;
test_one_path(svg_path_tcurve_to_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("T 1.0 2.0"));
test_one_path(svg_path_tcurve_to_rel_init(&path, 1, 2));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("t 1.0 2.0"));
str_reset(&s);
}
TEST(SvgPath, arc) {
str_t s;
str_init(&s, 100);
svg_path_arc_t path;
test_one_path(svg_path_arc_init(&path, 1, 2, 3, 1, 1, 6, 7));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("A 1.0 2.0 3.0 1 1 6.0 7.0"));
test_one_path(svg_path_arc_rel_init(&path, 1, 2, 3, 1, 1, 6, 7));
str_set(&s, "");
bsvg_to_svg_path(&s, (svg_path_t*)&path);
ASSERT_EQ(string(s.str), string("a 1.0 2.0 3.0 1 1 6.0 7.0"));
str_reset(&s);
}
TEST(SVGPathParser, move) {
svg_path_move_t path;
svg_path_move_init(&path, 409.6, 281.6);
svg_path_parse("M409.6 281.6", &path, on_path);
s_on_path_count = 0;
svg_path_parse("M409.6 281.6 409.6 281.6", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_move_rel_init(&path, 409.6, 281.6);
svg_path_parse("m409.6 281.6", &path, on_path);
s_on_path_count = 0;
svg_path_parse("m409.6 281.6 409.6 281.6", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, line) {
svg_path_line_t path;
svg_path_line_init(&path, 128, -128.5);
svg_path_parse("L128-128.5", &path, on_path);
s_on_path_count = 0;
svg_path_parse("L128-128.5 128-128.5", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_line_rel_init(&path, 128, -128.5);
svg_path_parse("l128-128.5", &path, on_path);
s_on_path_count = 0;
svg_path_parse("l128-128.5 128-128.5", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, hline) {
svg_path_hline_t path;
svg_path_hline_init(&path, 179.2);
svg_path_parse("H179.2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("H179.2 179.2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_hline_rel_init(&path, 179.2);
svg_path_parse("h179.2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("h179.2 179.2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, vline) {
svg_path_vline_t path;
svg_path_vline_init(&path, -179.2);
svg_path_parse("V-179.2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("V-179.2-179.2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_vline_rel_init(&path, -179.2);
svg_path_parse("v-179.2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("v-179.2-179.2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, curve) {
svg_path_curve_to_t path;
svg_path_curve_to_init(&path, 1, 2, 3, 4, 5, 6);
svg_path_parse("C1 2 3 4 5 6", &path, on_path);
s_on_path_count = 0;
svg_path_parse("C1 2 3 4 5 6 1 2 3 4 5 6 ", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_curve_to_rel_init(&path, 1, 2, 3, 4, 5, 6);
svg_path_parse("c1 2 3 4 5 6", &path, on_path);
s_on_path_count = 0;
svg_path_parse("c1 2 3 4 5 6 1 2 3 4 5 6 ", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, scurve) {
svg_path_scurve_to_t path;
svg_path_scurve_to_init(&path, 1, 2, 3, 4);
svg_path_parse("S1 2 3 4", &path, on_path);
s_on_path_count = 0;
svg_path_parse("S1 2 3 4 1 2 3 4", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_scurve_to_rel_init(&path, 1, 2, 3, 4);
svg_path_parse("s1 2 3 4", &path, on_path);
s_on_path_count = 0;
svg_path_parse("s1 2 3 4 1 2 3 4", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, qcurve) {
svg_path_qcurve_to_t path;
svg_path_qcurve_to_init(&path, 1, 2, 3, 4);
svg_path_parse("Q1 2 3 4", &path, on_path);
s_on_path_count = 0;
svg_path_parse("Q1 2 3 4 1 2 3 4", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_qcurve_to_rel_init(&path, 1, 2, 3, 4);
svg_path_parse("q1 2 3 4", &path, on_path);
s_on_path_count = 0;
svg_path_parse("q1 2 3 4 1 2 3 4", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, tcurve) {
svg_path_tcurve_to_t path;
svg_path_tcurve_to_init(&path, 1, 2);
svg_path_parse("T1 2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("T1 2 1 2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_tcurve_to_rel_init(&path, 1, 2);
svg_path_parse("t1 2", &path, on_path);
s_on_path_count = 0;
svg_path_parse("t1 2 1 2", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}
TEST(SVGPathParser, arc) {
svg_path_arc_t path;
svg_path_arc_init(&path, 1, 2, 3, 1, 1, 6, 7);
svg_path_parse("A1 2 3 1 1 6 7", &path, on_path);
s_on_path_count = 0;
svg_path_parse("A1 2 3 1 1 6 7 1 2 3 1 1 6 7", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
svg_path_arc_rel_init(&path, 1, 2, 3, 1, 1, 6, 7);
svg_path_parse("a1 2 3 1 1 6 7", &path, on_path);
s_on_path_count = 0;
svg_path_parse("a1 2 3 1 1 6 7 1 2 3 1 1 6 7", &path, on_path);
ASSERT_EQ(s_on_path_count, 2);
}

33
tests/svg_to_bsvg_test.cc Normal file
View File

@ -0,0 +1,33 @@
#include "base/rect.h"
#include "base/utils.h"
#include "gtest/gtest.h"
#include "svg/svg_to_bsvg.h"
static const char* s_template = \
"<?xml version=\"1.0\" standalone=\"no\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
"\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"><svg t=\"1542187942584\" "
"class=\"icon\" style=\"\" viewBox=\"0 0 1024 1024\" version=\"1.1\" "
"xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1907\" "
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"16\" height=\"16\"><defs><style "
"type=\"text/css\"></style></defs>%s</svg>";
static char s_buff[1024];
TEST(SVGToBSVG, path) {
uint32_t* out = NULL;
uint32_t out_length = 0;
const char* content = "<path d=\"M409.6 281.6v460.8l128-128h179.2L409.6 281.6z\" p-id=\"1908\">";
tk_snprintf(s_buff, sizeof(s_buff)-1, s_template, content);
svg_to_bsvg(s_buff, strlen(s_buff), &out, &out_length);
}
TEST(SVGToBSVG, rect) {
uint32_t* out = NULL;
uint32_t out_length = 0;
const char* content = "<rect x=\"10\" y=\"10\" width=\"30\" height=\"30\" stroke=\"black\" fill=\"transparent\" stroke-width=\"5\"/>";
tk_snprintf(s_buff, sizeof(s_buff)-1, s_template, content);
svg_to_bsvg(s_buff, strlen(s_buff), &out, &out_length);
}