mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-11-30 02:58:26 +08:00
add svg
This commit is contained in:
parent
d6b4b13990
commit
e8294ad66e
@ -1,4 +1,8 @@
|
||||
# 最新动态
|
||||
|
||||
* 2018/11/15-19
|
||||
* SVG解析器和BSVG(二进制格式的SVG)解析器。
|
||||
|
||||
* 2018/11/14
|
||||
* 完善digit\_clock
|
||||
* change WITH\_NANOVG\_GL to WITH\_NANOVG\_GPU
|
||||
|
@ -8,6 +8,7 @@ NANOVG_BACKEND=os.environ['NANOVG_BACKEND'];
|
||||
sources=Glob('base/*.c') +\
|
||||
Glob('ui_loader/*.c') + \
|
||||
Glob('xml/*.c') + \
|
||||
Glob('svg/*.c') + \
|
||||
Glob('font_loader/*.c') + \
|
||||
Glob('blend/*.c') + \
|
||||
Glob('ext_widgets/*.c') + \
|
||||
|
66
src/svg/bsvg.c
Normal file
66
src/svg/bsvg.c
Normal 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
42
src/svg/bsvg.h
Normal 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
65
src/svg/bsvg_builder.c
Normal 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
44
src/svg/bsvg_builder.h
Normal 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
48
src/svg/bsvg_common.h
Normal 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
296
src/svg/bsvg_to_svg.c
Normal 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
37
src/svg/bsvg_to_svg.h
Normal 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
151
src/svg/svg_debug.c
Normal 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
34
src/svg/svg_debug.h
Normal 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
276
src/svg/svg_path.c
Normal 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
166
src/svg/svg_path.h
Normal 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
292
src/svg/svg_path_parser.c
Normal 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
33
src/svg/svg_path_parser.h
Normal 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
159
src/svg/svg_shape.c
Normal 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
114
src/svg/svg_shape.h
Normal 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
226
src/svg/svg_to_bsvg.c
Normal 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
33
src/svg/svg_to_bsvg.h
Normal 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
519
tests/svg_test.cc
Normal 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
33
tests/svg_to_bsvg_test.cc
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user