Skip to content

Commit 44630a7

Browse files
author
zhangjipeng
committed
fix svg use gradient
1 parent 3bbd5b8 commit 44630a7

4 files changed

Lines changed: 88 additions & 49 deletions

File tree

ext/svg/psx_svg_render.cpp

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,26 @@ static INLINE char* dup_string_val(const _svg_list_builder_state* state, const p
206206
return ret;
207207
}
208208

209-
static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_attrs* attrs, int32_t attr_id, const psx_svg_attr* val)
209+
static INLINE ps_draw_attrs* get_current_attrs(_svg_list_builder_state* state)
210+
{
211+
ps_draw_attrs* attrs = state->draw_attrs;
212+
if (attrs->ref_count == 0) {
213+
return attrs;
214+
}
215+
216+
attrs = (ps_draw_attrs*)state->list->alloc(sizeof(ps_draw_attrs));
217+
// copy attrs
218+
copy_draw_attrs(attrs, state->draw_attrs);
219+
attrs->ref_count = 0;
220+
state->draw_attrs = attrs;
221+
return attrs;
222+
}
223+
224+
static INLINE void set_draw_attr(_svg_list_builder_state* state, int32_t attr_id, const psx_svg_attr* val)
210225
{
211226
switch (attr_id) {
212227
case SVG_ATTR_FILL: {
228+
ps_draw_attrs* attrs = get_current_attrs(state);
213229
if (val->class_type == SVG_ATTR_VALUE_NONE) {
214230
attrs->flags &= ~RENDER_FILL;
215231
return;
@@ -232,6 +248,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
232248
break;
233249
}
234250
case SVG_ATTR_FILL_RULE: {
251+
ps_draw_attrs* attrs = get_current_attrs(state);
235252
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
236253
attrs->flags &= ~RENDER_ATTR_FILL_RULE;
237254
return;
@@ -241,6 +258,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
241258
break;
242259
}
243260
case SVG_ATTR_FILL_OPACITY: {
261+
ps_draw_attrs* attrs = get_current_attrs(state);
244262
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
245263
attrs->flags &= ~RENDER_ATTR_FILL_OPACITY;
246264
return;
@@ -250,6 +268,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
250268
break;
251269
}
252270
case SVG_ATTR_STROKE: {
271+
ps_draw_attrs* attrs = get_current_attrs(state);
253272
if (val->class_type == SVG_ATTR_VALUE_NONE) {
254273
attrs->flags &= ~RENDER_STROKE;
255274
return;
@@ -272,6 +291,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
272291
break;
273292
}
274293
case SVG_ATTR_STROKE_OPACITY: {
294+
ps_draw_attrs* attrs = get_current_attrs(state);
275295
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
276296
attrs->flags &= ~RENDER_ATTR_STROKE_OPACITY;
277297
return;
@@ -281,6 +301,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
281301
break;
282302
}
283303
case SVG_ATTR_STROKE_WIDTH: {
304+
ps_draw_attrs* attrs = get_current_attrs(state);
284305
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
285306
attrs->flags &= ~RENDER_ATTR_STROKE_WIDTH;
286307
return;
@@ -290,6 +311,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
290311
break;
291312
}
292313
case SVG_ATTR_STROKE_LINECAP: {
314+
ps_draw_attrs* attrs = get_current_attrs(state);
293315
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
294316
attrs->flags &= ~RENDER_ATTR_STROKE_LINECAP;
295317
return;
@@ -299,6 +321,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
299321
break;
300322
}
301323
case SVG_ATTR_STROKE_LINEJOIN: {
324+
ps_draw_attrs* attrs = get_current_attrs(state);
302325
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
303326
attrs->flags &= ~RENDER_ATTR_STROKE_LINEJOIN;
304327
return;
@@ -308,6 +331,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
308331
break;
309332
}
310333
case SVG_ATTR_STROKE_MITER_LIMIT: {
334+
ps_draw_attrs* attrs = get_current_attrs(state);
311335
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
312336
attrs->flags &= ~RENDER_ATTR_STROKE_MITER_LIMIT;
313337
return;
@@ -317,6 +341,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
317341
break;
318342
}
319343
case SVG_ATTR_STROKE_DASH_ARRAY: {
344+
ps_draw_attrs* attrs = get_current_attrs(state);
320345
if (val->class_type == SVG_ATTR_VALUE_NONE) {
321346
attrs->stroke_dash_array = NULL;
322347
attrs->stroke_dash_num = 0;
@@ -341,6 +366,7 @@ static INLINE void set_draw_attr(const _svg_list_builder_state* state, ps_draw_a
341366
break;
342367
}
343368
case SVG_ATTR_STROKE_DASH_OFFSET: {
369+
ps_draw_attrs* attrs = get_current_attrs(state);
344370
if (val->class_type == SVG_ATTR_VALUE_INHERIT) {
345371
attrs->flags &= ~RENDER_ATTR_STROKE_DASH_OFFSET;
346372
return;
@@ -360,21 +386,6 @@ static INLINE ps_draw_attrs* draw_attrs_create(svg_render_list_impl* list)
360386
return attrs;
361387
}
362388

363-
static INLINE ps_draw_attrs* get_current_attrs(_svg_list_builder_state* state)
364-
{
365-
ps_draw_attrs* attrs = state->draw_attrs;
366-
if (attrs->ref_count == 0) {
367-
return attrs;
368-
}
369-
370-
attrs = (ps_draw_attrs*)state->list->alloc(sizeof(ps_draw_attrs));
371-
// copy attrs
372-
copy_draw_attrs(attrs, state->draw_attrs);
373-
attrs->ref_count = 0;
374-
state->draw_attrs = attrs;
375-
return attrs;
376-
}
377-
378389
enum {
379390
RENDER_NORMAL = 0,
380391
RENDER_IN_DEFS = 1,
@@ -468,15 +479,8 @@ class render_obj_base : public psx_svg_render_obj
468479
ps_reset_line_dash(ctx);
469480
}
470481
}
471-
}
472-
}
473482

474-
void paint(ps_context* ctx) const
475-
{
476-
if (m_draw_attrs) {
477-
ps_draw_attrs* attrs = m_draw_attrs;
478-
479-
if (attrs->flags & RENDER_ATTR_REF_FILL) {
483+
if (m_draw_attrs->flags & RENDER_ATTR_REF_FILL) {
480484
render_obj_base* head = m_head;
481485
while (head) {
482486
if (head->id()) {
@@ -489,7 +493,7 @@ class render_obj_base : public psx_svg_render_obj
489493
}
490494
}
491495

492-
if (attrs->flags & RENDER_ATTR_REF_STROKE) {
496+
if (m_draw_attrs->flags & RENDER_ATTR_REF_STROKE) {
493497
render_obj_base* head = m_head;
494498
while (head) {
495499
if (head->id()) {
@@ -501,6 +505,13 @@ class render_obj_base : public psx_svg_render_obj
501505
head = head->next();
502506
}
503507
}
508+
}
509+
}
510+
511+
void paint(ps_context* ctx) const
512+
{
513+
if (m_draw_attrs) {
514+
ps_draw_attrs* attrs = m_draw_attrs;
504515

505516
if (m_global_matrix) {
506517
ps_transform(ctx, m_global_matrix);
@@ -577,8 +588,7 @@ void render_obj_base::set_attr(const psx_svg_attr* attr, _svg_list_builder_state
577588
}
578589
set_matrix((psx_svg_matrix*)attr->value.val);
579590
} else {
580-
ps_draw_attrs* draw_attrs = get_current_attrs(state);
581-
set_draw_attr(state, draw_attrs, attr->attr_id, attr);
591+
set_draw_attr(state, attr->attr_id, attr);
582592
}
583593
}
584594

@@ -713,8 +723,7 @@ class svg_render_viewport : public render_obj_base
713723
case SVG_ATTR_VIEWPORT_FILL: {
714724
if (attr->class_type == SVG_ATTR_VALUE_INITIAL
715725
&& attr->val_type == SVG_ATTR_VALUE_DATA) {
716-
ps_draw_attrs* draw_attrs = get_current_attrs(state);
717-
set_draw_attr(state, draw_attrs, SVG_ATTR_FILL, attr);
726+
set_draw_attr(state, SVG_ATTR_FILL, attr);
718727
m_fill = true;
719728
} else if (attr->class_type == SVG_ATTR_VALUE_NONE) {
720729
m_fill = false;
@@ -723,8 +732,7 @@ class svg_render_viewport : public render_obj_base
723732
break;
724733
case SVG_ATTR_VIEWPORT_FILL_OPACITY: {
725734
if (attr->class_type == SVG_ATTR_VALUE_INITIAL) {
726-
ps_draw_attrs* draw_attrs = get_current_attrs(state);
727-
set_draw_attr(state, draw_attrs, SVG_ATTR_FILL_OPACITY, attr);
735+
set_draw_attr(state, SVG_ATTR_FILL_OPACITY, attr);
728736
}
729737
}
730738
break;
@@ -1031,8 +1039,8 @@ class svg_render_polyline : public render_obj_base
10311039
if (matrix) {
10321040
ps_transform(ctx, matrix);
10331041
}
1034-
ps_set_path(ctx, m_path);
10351042

1043+
ps_set_path(ctx, m_path);
10361044
paint(ctx);
10371045
}
10381046

@@ -1136,6 +1144,15 @@ class svg_render_use : public render_obj_base
11361144
}
11371145
}
11381146

1147+
void prepare(ps_context* ctx) const
1148+
{
1149+
render_obj_base::prepare(ctx);
1150+
get_xlink();
1151+
if (m_linked) {
1152+
m_linked->prepare(ctx);
1153+
}
1154+
}
1155+
11391156
void render(ps_context* ctx, const ps_matrix* matrix)
11401157
{
11411158
ps_translate(ctx, m_x, m_y);
@@ -1147,9 +1164,6 @@ class svg_render_use : public render_obj_base
11471164
get_xlink();
11481165

11491166
if (m_linked) {
1150-
m_linked->prepare(ctx);
1151-
prepare(ctx); // FIXME: use other !!!
1152-
// FIXME: use with own gradient !!!!!!
11531167
m_linked->render(ctx, NULL);
11541168
}
11551169
}
@@ -1328,7 +1342,7 @@ class svg_render_content : public render_obj_base
13281342
{
13291343
}
13301344

1331-
virtual void render_content(ps_context* ctx, ps_path* contents, ps_matrix* offset_matrix, float yoffset, bool rebuild_path)
1345+
virtual void build_content(ps_context* ctx, ps_path* contents, ps_matrix* offset_matrix, float yoffset, bool rebuild_path)
13321346
{
13331347
if (!rebuild_path) {
13341348
return;
@@ -1403,13 +1417,8 @@ class svg_render_text : public render_obj_base
14031417
this->svg_render_text::~svg_render_text();
14041418
}
14051419

1406-
void render(ps_context* ctx, const ps_matrix* matrix)
1420+
void prepare(ps_context* ctx) const
14071421
{
1408-
ps_transform(ctx, m_matrix);
1409-
if (matrix) {
1410-
ps_transform(ctx, matrix);
1411-
}
1412-
14131422
ps_font* old_font = ps_set_font(ctx, m_font);
14141423
ps_font_info info;
14151424
ps_get_font_info(ctx, &info);
@@ -1425,14 +1434,28 @@ class svg_render_text : public render_obj_base
14251434
// draw text contents and spans
14261435
for (uint32_t i = 0; i < psx_array_size(&m_contents); i++) {
14271436
svg_render_content* content = *(psx_array_get(&m_contents, i, svg_render_content*));
1428-
content->render_content(ctx, m_path, mtx, -info.ascent, build_path);
1437+
content->build_content(ctx, m_path, mtx, -info.ascent, build_path);
14291438
}
14301439
ps_matrix_unref(mtx);
14311440

14321441
ps_set_font(ctx, old_font);
1442+
render_obj_base::prepare(ctx);
1443+
}
14331444

1434-
ps_set_path(ctx, m_path);
1445+
void render(ps_context* ctx, const ps_matrix* matrix)
1446+
{
1447+
ps_transform(ctx, m_matrix);
1448+
if (matrix) {
1449+
ps_transform(ctx, matrix);
1450+
}
1451+
1452+
// draw text contents and spans
1453+
for (uint32_t i = 0; i < psx_array_size(&m_contents); i++) {
1454+
svg_render_content* content = *(psx_array_get(&m_contents, i, svg_render_content*));
1455+
content->render(ctx, NULL);
1456+
}
14351457

1458+
ps_set_path(ctx, m_path);
14361459
paint(ctx);
14371460
}
14381461

@@ -1521,11 +1544,8 @@ class svg_render_tspan : public svg_render_content
15211544
this->svg_render_tspan::~svg_render_tspan();
15221545
}
15231546

1524-
virtual void render_content(ps_context* ctx, ps_path*, ps_matrix* offset_matrix, float, bool)
1547+
virtual void build_content(ps_context* ctx, ps_path*, ps_matrix* offset_matrix, float, bool)
15251548
{
1526-
ps_save(ctx);
1527-
prepare(ctx);
1528-
15291549
ps_font* old_font = ps_set_font(ctx, m_font);
15301550
ps_font_info info;
15311551
ps_get_font_info(ctx, &info);
@@ -1555,9 +1575,13 @@ class svg_render_tspan : public svg_render_content
15551575
}
15561576

15571577
ps_set_font(ctx, old_font);
1578+
}
15581579

1580+
void render(ps_context* ctx, const ps_matrix* matrix)
1581+
{
1582+
ps_save(ctx);
1583+
prepare(ctx);
15591584
ps_set_path(ctx, m_path);
1560-
15611585
paint(ctx);
15621586
ps_restore(ctx);
15631587
}

unit_tests/ext_svg_render.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,21 @@ TEST_F(SVGRenderTest, ComplexPath)
403403
"</svg>";
404404
draw_svg(svg_complex_9);
405405
EXPECT_SYS_SNAPSHOT_EQ(svg_complex_9);
406+
407+
408+
const char* svg_complex_10 = "<svg width=\"400\" height=\"400\" viewBox=\"0 0 800 800\">"
409+
"<defs>"
410+
"<circle id=\"g1\" cx=\"100\" cy=\"100\" r=\"40\"/>"
411+
"<linearGradient id=\"gad\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">"
412+
"<stop offset=\"0\" stop-color=\"red\" />"
413+
"<stop offset=\"0.5\" stop-color=\"green\" />"
414+
"<stop offset=\"1\" stop-color=\"blue\" />"
415+
"</linearGradient></defs>"
416+
"<use xlink:href=\"#g1\" x=\"50\" y=\"0\" />"
417+
"<use xlink:href=\"#g1\" x=\"250\" y=\"0\" fill=\"url(#gad)\" />"
418+
"</svg>";
419+
draw_svg(svg_complex_10);
420+
EXPECT_SYS_SNAPSHOT_EQ(svg_complex_10);
406421
}
407422

408423
TEST_F(SVGRenderTest, GroupTest)
1.69 KB
Loading
1 KB
Loading

0 commit comments

Comments
 (0)