2018-11-18 19:04:13 +08:00
|
|
|
|
#include "svg/bsvg.h"
|
|
|
|
|
#include "svg/bsvg_builder.h"
|
2024-03-06 17:33:52 +08:00
|
|
|
|
#include "svg/svg_path_parser.h"
|
2018-12-15 17:22:05 +08:00
|
|
|
|
#include "tkc/utils.h"
|
2018-11-18 19:04:13 +08:00
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
#include "svg/bsvg_to_svg.h"
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 11:42:33 +08:00
|
|
|
|
static void test_one_shape(svg_shape_t* shape, const char* str2) {
|
|
|
|
|
str_t str;
|
2018-11-18 19:04:13 +08:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
str_init(&str, 100);
|
2022-11-15 11:42:33 +08:00
|
|
|
|
ASSERT_EQ(bsvg_to_svg_shape(&str, shape), RET_OK);
|
|
|
|
|
ASSERT_STREQ(str.str, str2);
|
2018-11-18 19:04:13 +08:00
|
|
|
|
str_reset(&str);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 11:42:33 +08:00
|
|
|
|
TEST(SvgShape, text) {
|
|
|
|
|
uint8_t buff[128];
|
|
|
|
|
svg_shape_t* shape = svg_shape_text_init((svg_shape_text_t*)&buff, 3.0f, 3.0f);
|
|
|
|
|
char* str = NULL;
|
|
|
|
|
shape->stroke_width = 5;
|
|
|
|
|
shape->fill_type = SVG_COLOR_SOLID;
|
|
|
|
|
svg_color_solid_init(svg_shape_get_fill(shape), color_init(0xff, 0xff, 0xff, 0xff));
|
|
|
|
|
shape->stroke_type = SVG_COLOR_NULL;
|
|
|
|
|
str = svg_shape_text_get_text(shape);
|
|
|
|
|
memcpy(str, "abc123", 7);
|
2018-11-18 19:04:13 +08:00
|
|
|
|
|
2022-11-15 11:42:33 +08:00
|
|
|
|
test_one_shape(shape,
|
|
|
|
|
"<text x=\"3.0\" y=\"3.0\" stroke-width=\"5.0\" fill=\"rgba(255,255,255,1.00)\" "
|
|
|
|
|
"stroke=\"none\">abc123</text>\n");
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SvgShape, path) {
|
2022-11-15 11:42:33 +08:00
|
|
|
|
svg_shape_t s;
|
|
|
|
|
test_one_shape(svg_shape_path_init(&s), "<path d=\"");
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 17:33:52 +08:00
|
|
|
|
static ret_t on_path_parse(void* ctx, const void* data) {
|
|
|
|
|
cmp_path(((const svg_path_t**)ctx)[s_on_path_count], (const svg_path_t*)data);
|
|
|
|
|
s_on_path_count++;
|
|
|
|
|
|
|
|
|
|
return RET_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-18 19:04:13 +08:00
|
|
|
|
static ret_t on_shape_null(void* ctx, const void* data) {
|
|
|
|
|
(void)ctx;
|
|
|
|
|
(void)data;
|
|
|
|
|
|
|
|
|
|
return RET_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 11:42:33 +08:00
|
|
|
|
static void test_one_path(svg_path_t* path, const char* str2) {
|
|
|
|
|
str_t str;
|
2018-11-18 19:04:13 +08:00
|
|
|
|
bsvg_t bsvg;
|
|
|
|
|
bsvg_t* svg = &bsvg;
|
|
|
|
|
uint32_t buff[1024];
|
|
|
|
|
bsvg_builder_t bsvg_builder;
|
|
|
|
|
bsvg_builder_t* w = &bsvg_builder;
|
2022-11-15 11:42:33 +08:00
|
|
|
|
svg_shape_t s;
|
2018-11-18 19:04:13 +08:00
|
|
|
|
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);
|
2021-09-16 16:06:55 +08:00
|
|
|
|
|
2018-11-18 19:04:13 +08:00
|
|
|
|
ASSERT_EQ(bsvg_init(svg, buff, w->buff.cursor), svg);
|
|
|
|
|
ASSERT_EQ(bsvg_visit(svg, path, on_shape_null, on_path), RET_OK);
|
2022-11-15 11:42:33 +08:00
|
|
|
|
|
|
|
|
|
str_init(&str, 100);
|
|
|
|
|
ASSERT_EQ(bsvg_to_svg_path(&str, path), RET_OK);
|
|
|
|
|
ASSERT_STREQ(str.str, str2);
|
|
|
|
|
str_reset(&str);
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SvgPath, move) {
|
|
|
|
|
svg_path_move_t path;
|
2022-11-15 11:42:33 +08:00
|
|
|
|
svg_path_t* p = svg_path_move_init(&path, 1, 2);
|
|
|
|
|
test_one_path(p, " M1.0 2.0");
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SvgPath, line) {
|
|
|
|
|
svg_path_line_t path;
|
2022-11-15 11:42:33 +08:00
|
|
|
|
svg_path_t* p = svg_path_line_init(&path, 1, 2);
|
|
|
|
|
test_one_path(p, " L1.0 2.0");
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SvgPath, curve) {
|
|
|
|
|
svg_path_curve_to_t path;
|
2022-11-15 11:42:33 +08:00
|
|
|
|
svg_path_t* p = svg_path_curve_to_init(&path, 1, 2, 3, 4, 5, 6);
|
|
|
|
|
test_one_path(p, " C1.0 2.0 3.0 4.0 5.0 6.0");
|
2018-11-18 19:04:13 +08:00
|
|
|
|
}
|
2024-03-06 17:33:52 +08:00
|
|
|
|
|
|
|
|
|
static void test_one_path_parse(const char* str, svg_path_t** ctx, uint32_t c) {
|
|
|
|
|
s_on_path_count = 0;
|
|
|
|
|
svg_path_parse(str, ctx, on_path_parse);
|
|
|
|
|
ASSERT_EQ(s_on_path_count, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SVGPathParser, move) {
|
|
|
|
|
svg_path_t* ctx[2];
|
|
|
|
|
svg_path_move_t path[2];
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_move_init(&path[0], 409.6, 281.6);
|
|
|
|
|
ctx[1] = svg_path_move_init(&path[1], 409.6, 281.6);
|
|
|
|
|
test_one_path_parse("M409.6 281.6", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("M409.6 281.6 409.6 281.6", (svg_path_t**)ctx, 2);
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_move_init(&path[0], 409.6, 281.6);
|
|
|
|
|
ctx[1] = svg_path_move_init(&path[1], 409.6 * 2, 281.6 * 2);
|
|
|
|
|
test_one_path_parse("m409.6 281.6", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("m409.6 281.6 409.6 281.6", (svg_path_t**)ctx, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SVGPathParser, line) {
|
|
|
|
|
svg_path_t* ctx[2];
|
|
|
|
|
svg_path_line_t path[2] = {0};
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 128, -128.5);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 128, -128.5);
|
|
|
|
|
test_one_path_parse("L128-128.5", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("L128-128.5 128-128.5", (svg_path_t**)ctx, 2);
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 128, -128.5);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 128 * 2, -128.5 * 2);
|
|
|
|
|
test_one_path_parse("l128-128.5", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("l128-128.5 128-128.5", (svg_path_t**)ctx, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SVGPathParser, hline) {
|
|
|
|
|
svg_path_t* ctx[2];
|
|
|
|
|
svg_path_line_t path[2] = {0};
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 179.2, 0);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 179.2, 0);
|
|
|
|
|
test_one_path_parse("H179.2", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("H179.2 179.2", (svg_path_t**)ctx, 2);
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 179.2, 0);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 179.2 * 2, 0);
|
|
|
|
|
test_one_path_parse("h179.2", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("h179.2 179.2", (svg_path_t**)ctx, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SVGPathParser, vline) {
|
|
|
|
|
svg_path_t* ctx[2];
|
|
|
|
|
svg_path_line_t path[2];
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 0, -179.2);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 0, -179.2);
|
|
|
|
|
test_one_path_parse("V-179.2", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("V-179.2-179.2", (svg_path_t**)ctx, 2);
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_line_init(&path[0], 0, -179.2);
|
|
|
|
|
ctx[1] = svg_path_line_init(&path[1], 0, -179.2 * 2);
|
|
|
|
|
test_one_path_parse("v-179.2", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("v-179.2-179.2", (svg_path_t**)ctx, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SVGPathParser, curve) {
|
|
|
|
|
svg_path_t* ctx[2];
|
|
|
|
|
svg_path_curve_to_t path[2];
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_curve_to_init(&path[0], 1, 2, 3, 4, 5, 6);
|
|
|
|
|
ctx[1] = svg_path_curve_to_init(&path[1], 1, 2, 3, 4, 5, 6);
|
|
|
|
|
test_one_path_parse("C1 2 3 4 5 6", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("C1 2 3 4 5 6 1 2 3 4 5 6 ", (svg_path_t**)ctx, 2);
|
|
|
|
|
|
|
|
|
|
ctx[0] = svg_path_curve_to_init(&path[0], 1, 2, 3, 4, 5, 6);
|
|
|
|
|
ctx[1] = svg_path_curve_to_init(&path[1], 1 + 5, 2 + 6, 3 + 5, 4 + 6, 5 * 2, 6 * 2);
|
|
|
|
|
test_one_path_parse("c1 2 3 4 5 6", (svg_path_t**)ctx, 1);
|
|
|
|
|
test_one_path_parse("c1 2 3 4 5 6 1 2 3 4 5 6 ", (svg_path_t**)ctx, 2);
|
|
|
|
|
}
|