From 219e23855fee17d08acc19432ed53a054a59899d Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 16 Apr 2023 12:22:18 +0200 Subject: [PATCH] svg_loader: paint-order attrib handled @Issue: https://github.com/thorvg/thorvg/issues/1340 --- src/loaders/svg/tvgSvgLoader.cpp | 48 +++++++++++++++++++++++++- src/loaders/svg/tvgSvgLoaderCommon.h | 4 ++- src/loaders/svg/tvgSvgSceneBuilder.cpp | 2 ++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index ee938f96..d6b635c0 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -252,6 +252,36 @@ static SvgMaskType _toMaskType(const char* str) } +//The default rendering order: fill, stroke, markers +//If any is omitted, will be rendered in its default order after the specified ones. +static bool _toPaintOrder(const char* str) +{ + uint8_t position = 1; + uint8_t strokePosition = 0; + uint8_t fillPosition = 0; + + while (*str != '\0') { + str = _skipSpace(str, nullptr); + if (!strncmp(str, "fill", 4)) { + fillPosition = position++; + str += 4; + } else if (!strncmp(str, "stroke", 6)) { + strokePosition = position++; + str += 6; + } else if (!strncmp(str, "markers", 7)) { + str += 7; + } else { + return _toPaintOrder("fill stroke"); + } + } + + if (fillPosition == 0) fillPosition = position++; + if (strokePosition == 0) strokePosition = position++; + + return fillPosition < strokePosition; +} + + #define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default) \ static Type _to##Name1(const char* str) \ { \ @@ -1011,6 +1041,13 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } +static void _handlePaintOrderAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->flags = (SvgStyleFlags)((int)node->style->flags | (int)SvgStyleFlags::PaintOrder); + node->style->paintOrder = _toPaintOrder(value); +} + + static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value) { auto cssClass = &node->style->cssClass; @@ -1061,7 +1098,8 @@ static constexpr struct STYLE_DEF(clip-path, ClipPath, SvgStyleFlags::ClipPath), STYLE_DEF(mask, Mask, SvgStyleFlags::Mask), STYLE_DEF(mask-type, MaskType, SvgStyleFlags::MaskType), - STYLE_DEF(display, Display, SvgStyleFlags::Display) + STYLE_DEF(display, Display, SvgStyleFlags::Display), + STYLE_DEF(paint-order, PaintOrder, SvgStyleFlags::PaintOrder) }; @@ -1263,6 +1301,8 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) node->style->stroke.join = StrokeJoin::Miter; node->style->stroke.scale = 1.0; + node->style->paintOrder = _toPaintOrder("fill stroke"); + //Default display is true("inline"). node->display = true; @@ -2688,6 +2728,9 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren child->color = parent->color; child->curColorSet = parent->curColorSet; } + if (!((int)child->flags & (int)SvgStyleFlags::PaintOrder)) { + child->paintOrder = parent->paintOrder; + } //Fill if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) { child->fill.paint.color = parent->fill.paint.color; @@ -2746,6 +2789,9 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) to->color = from->color; to->curColorSet = true; } + if (((int)from->flags & (int)SvgStyleFlags::PaintOrder)) { + to->paintOrder = from->paintOrder; + } //Fill to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)from->fill.flags); if (((int)from->fill.flags & (int)SvgFillFlags::Paint)) { diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 3bcc031b..c19086fe 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -115,7 +115,8 @@ enum class SvgStyleFlags ClipPath = 0x1000, Mask = 0x2000, MaskType = 0x4000, - Display = 0x8000 + Display = 0x8000, + PaintOrder = 0x10000 }; enum class SvgStopStyleFlags @@ -411,6 +412,7 @@ struct SvgStyleProperty SvgColor color; bool curColorSet; char* cssClass; + bool paintOrder; //true if default (fill, stroke), false otherwise SvgStyleFlags flags; }; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 900dfbf8..e83844ff 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -330,6 +330,8 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri //Apply the fill rule vg->fill((tvg::FillRule)style->fill.fillRule); + //Rendering order + vg->order(!style->paintOrder); //Apply node opacity if (style->opacity < 255) vg->opacity(style->opacity);